{
"tool_response": {
"type": "update",
"filePath": "\/var\/www\/mcp-servers\/mcp-docs\/tools\/docs_tools.py",
"content": "\"\"\"\nMCP-Tools for Documentation Management.\n\nThis module delegates to the modularized docs_tools package.\nFor backward compatibility, it re-exports the main registration function.\n\"\"\"\n\nfrom docs_tools import register_docs_tools\n\n__all__ = [\"register_docs_tools\"]\n",
"structuredPatch": [
{
"oldStart": 1,
"oldLines": 526,
"newStart": 1,
"newLines": 10,
"lines": [
"-\"\"\"MCP-Tools für Dokumentations-Management\"\"\"",
"-import json",
"-import sys",
"-import time",
"-from datetime import datetime",
"-from typing import Optional",
"+\"\"\"",
"+MCP-Tools for Documentation Management.",
" ",
"-sys.path.insert(0, \"\/opt\/mcp-servers\/mcp-docs\")",
"-from domain.dokumentation import Dokumentation, DocStatus, LogEntry",
"-from infrastructure.docs_repository import DocsRepository, get_repository",
"-from infrastructure.protokoll_logger import get_logger",
"+This module delegates to the modularized docs_tools package.",
"+For backward compatibility, it re-exports the main registration function.",
"+\"\"\"",
" ",
"+from docs_tools import register_docs_tools",
" ",
"-def register_docs_tools(mcp):",
"- \"\"\"Registriert alle Dokumentations-Tools beim MCP-Server\"\"\"",
"-",
"- @mcp.tool()",
"- def docs_list(",
"- status: Optional[str] = None,",
"- parent_id: Optional[int] = None,",
"- search: Optional[str] = None,",
"- compact: bool = True,",
"- limit: int = 20",
"- ) -> dict:",
"- \"\"\"",
"- Listet alle Dokumente aus der Datenbank.",
"-",
"- Args:",
"- status: Filter nach Status (draft, published, archived)",
"- parent_id: Filter nach Parent-ID",
"- search: Volltextsuche in Titel\/Beschreibung",
"- compact: True = nur id\/path\/title\/status (Token-sparend)",
"- limit: Maximale Anzahl Ergebnisse",
"-",
"- Returns:",
"- Liste der Dokumente",
"- \"\"\"",
"- start_time = time.time()",
"- logger = get_logger()",
"- repo = get_repository()",
"-",
"- try:",
"- docs = repo.find_all(",
"- status=status,",
"- parent_id=parent_id,",
"- search=search,",
"- limit=limit",
"- )",
"- total = repo.count(status=status, parent_id=parent_id, search=search)",
"-",
"- result = {",
"- \"success\": True,",
"- \"docs\": [d.to_dict_compact() if compact else d.to_dict() for d in docs],",
"- \"total\": total,",
"- \"limit\": limit,",
"- \"compact\": compact",
"- }",
"-",
"- logger.log(LogEntry(",
"- tool_name=\"docs_list\",",
"- request=json.dumps({\"status\": status, \"parent_id\": parent_id, \"search\": search, \"limit\": limit}),",
"- status=\"success\",",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"-",
"- return result",
"-",
"- except Exception as e:",
"- logger.log(LogEntry(",
"- tool_name=\"docs_list\",",
"- request=json.dumps({\"status\": status, \"search\": search}),",
"- status=\"error\",",
"- error_message=str(e),",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"- return {\"success\": False, \"error\": str(e)}",
"-",
"- @mcp.tool()",
"- def docs_get(",
"- id: Optional[int] = None,",
"- path: Optional[str] = None,",
"- include_children: bool = False,",
"- include_breadcrumb: bool = False",
"- ) -> dict:",
"- \"\"\"",
"- Holt ein Dokument nach ID oder Pfad.",
"-",
"- Args:",
"- id: Dokument-ID",
"- path: Dokument-Pfad (alternativ zu ID)",
"- include_children: Kind-Dokumente einschließen",
"- include_breadcrumb: Breadcrumb-Pfad einschließen",
"-",
"- Returns:",
"- Dokument mit Details",
"- \"\"\"",
"- start_time = time.time()",
"- logger = get_logger()",
"- repo = get_repository()",
"-",
"- try:",
"- if id is None and path is None:",
"- return {\"success\": False, \"error\": \"Entweder id oder path muss angegeben werden\"}",
"-",
"- doc = None",
"- if id is not None:",
"- doc = repo.find_by_id(id)",
"- elif path is not None:",
"- doc = repo.find_by_path(path)",
"-",
"- if not doc:",
"- return {\"success\": False, \"error\": \"Dokument nicht gefunden\"}",
"-",
"- result = {",
"- \"success\": True,",
"- \"doc\": doc.to_dict()",
"- }",
"-",
"- if include_children and doc.id:",
"- children = repo.find_children(doc.id)",
"- result[\"children\"] = [c.to_dict_compact() for c in children]",
"-",
"- if include_breadcrumb and doc.id:",
"- result[\"breadcrumb\"] = repo.get_breadcrumb(doc.id)",
"-",
"- logger.log(LogEntry(",
"- tool_name=\"docs_get\",",
"- request=json.dumps({\"id\": id, \"path\": path}),",
"- status=\"success\",",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"-",
"- return result",
"-",
"- except Exception as e:",
"- logger.log(LogEntry(",
"- tool_name=\"docs_get\",",
"- request=json.dumps({\"id\": id, \"path\": path}),",
"- status=\"error\",",
"- error_message=str(e),",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"- return {\"success\": False, \"error\": str(e)}",
"-",
"- @mcp.tool()",
"- def docs_create(",
"- title: str,",
"- slug: str,",
"- content: str = \"\",",
"- description: Optional[str] = None,",
"- parent_id: Optional[int] = None,",
"- status: str = \"draft\",",
"- sort_order: int = 0",
"- ) -> dict:",
"- \"\"\"",
"- Erstellt ein neues Dokument.",
"-",
"- Args:",
"- title: Dokumenttitel (required)",
"- slug: URL-Slug (required)",
"- content: HTML-Inhalt",
"- description: Kurzbeschreibung",
"- parent_id: ID des Parent-Dokuments",
"- status: Status (draft, published, archived)",
"- sort_order: Sortierung innerhalb Parent",
"-",
"- Returns:",
"- Erstelltes Dokument",
"- \"\"\"",
"- start_time = time.time()",
"- logger = get_logger()",
"- repo = get_repository()",
"-",
"- try:",
"- # Pfad berechnen",
"- if parent_id is not None:",
"- parent = repo.find_by_id(parent_id)",
"- if not parent:",
"- return {\"success\": False, \"error\": f\"Parent mit ID {parent_id} nicht gefunden\"}",
"- path = f\"{parent.path}\/{slug}\"",
"- depth = parent.depth + 1",
"- else:",
"- path = f\"\/{slug}\"",
"- depth = 0",
"-",
"- # Prüfen ob Pfad bereits existiert",
"- existing = repo.find_by_path(path)",
"- if existing:",
"- return {\"success\": False, \"error\": f\"Pfad '{path}' existiert bereits\"}",
"-",
"- doc = Dokumentation(",
"- parent_id=parent_id,",
"- slug=slug,",
"- path=path,",
"- title=title,",
"- description=description,",
"- content=content,",
"- status=DocStatus(status) if status in [\"draft\", \"published\", \"archived\"] else DocStatus.DRAFT,",
"- sort_order=sort_order,",
"- depth=depth",
"- )",
"-",
"- new_id = repo.create(doc)",
"- created_doc = repo.find_by_id(new_id)",
"-",
"- logger.log(LogEntry(",
"- tool_name=\"docs_create\",",
"- request=json.dumps({\"title\": title, \"slug\": slug, \"parent_id\": parent_id}),",
"- status=\"success\",",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"-",
"- return {",
"- \"success\": True,",
"- \"doc\": created_doc.to_dict() if created_doc else None,",
"- \"message\": f\"Dokument '{title}' erstellt mit ID {new_id}\"",
"- }",
"-",
"- except Exception as e:",
"- logger.log(LogEntry(",
"- tool_name=\"docs_create\",",
"- request=json.dumps({\"title\": title, \"slug\": slug}),",
"- status=\"error\",",
"- error_message=str(e),",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"- return {\"success\": False, \"error\": str(e)}",
"-",
"- @mcp.tool()",
"- def docs_update(",
"- id: int,",
"- title: Optional[str] = None,",
"- content: Optional[str] = None,",
"- description: Optional[str] = None,",
"- status: Optional[str] = None",
"- ) -> dict:",
"- \"\"\"",
"- Aktualisiert ein Dokument.",
"-",
"- Args:",
"- id: Dokument-ID (required)",
"- title: Neuer Titel",
"- content: Neuer Inhalt",
"- description: Neue Beschreibung",
"- status: Neuer Status (draft, published, archived)",
"-",
"- Returns:",
"- Aktualisiertes Dokument",
"- \"\"\"",
"- start_time = time.time()",
"- logger = get_logger()",
"- repo = get_repository()",
"-",
"- try:",
"- doc = repo.find_by_id(id)",
"- if not doc:",
"- return {\"success\": False, \"error\": f\"Dokument mit ID {id} nicht gefunden\"}",
"-",
"- updates = {}",
"- if title is not None:",
"- updates[\"title\"] = title",
"- if content is not None:",
"- updates[\"content\"] = content",
"- if description is not None:",
"- updates[\"description\"] = description",
"- if status is not None and status in [\"draft\", \"published\", \"archived\"]:",
"- updates[\"status\"] = status",
"-",
"- if not updates:",
"- return {\"success\": False, \"error\": \"Keine Änderungen angegeben\"}",
"-",
"- success = repo.update(id, updates)",
"- if success:",
"- updated_doc = repo.find_by_id(id)",
"-",
"- logger.log(LogEntry(",
"- tool_name=\"docs_update\",",
"- request=json.dumps({\"id\": id, \"updates\": list(updates.keys())}),",
"- status=\"success\",",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"-",
"- return {",
"- \"success\": True,",
"- \"doc\": updated_doc.to_dict() if updated_doc else None,",
"- \"message\": f\"Dokument #{id} aktualisiert\"",
"- }",
"- else:",
"- return {\"success\": False, \"error\": \"Update fehlgeschlagen\"}",
"-",
"- except Exception as e:",
"- logger.log(LogEntry(",
"- tool_name=\"docs_update\",",
"- request=json.dumps({\"id\": id}),",
"- status=\"error\",",
"- error_message=str(e),",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"- return {\"success\": False, \"error\": str(e)}",
"-",
"- @mcp.tool()",
"- def docs_delete(id: int) -> dict:",
"- \"\"\"",
"- Löscht ein Dokument.",
"-",
"- Args:",
"- id: Dokument-ID (required)",
"-",
"- Returns:",
"- Bestätigung",
"- \"\"\"",
"- start_time = time.time()",
"- logger = get_logger()",
"- repo = get_repository()",
"-",
"- try:",
"- doc = repo.find_by_id(id)",
"- if not doc:",
"- return {\"success\": False, \"error\": f\"Dokument mit ID {id} nicht gefunden\"}",
"-",
"- success = repo.delete(id)",
"-",
"- logger.log(LogEntry(",
"- tool_name=\"docs_delete\",",
"- request=json.dumps({\"id\": id, \"title\": doc.title}),",
"- status=\"success\" if success else \"error\",",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"-",
"- return {",
"- \"success\": success,",
"- \"message\": f\"Dokument '{doc.title}' (ID {id}) gelöscht\" if success else \"Löschen fehlgeschlagen\"",
"- }",
"-",
"- except ValueError as e:",
"- # Kinder vorhanden",
"- logger.log(LogEntry(",
"- tool_name=\"docs_delete\",",
"- request=json.dumps({\"id\": id}),",
"- status=\"denied\",",
"- error_message=str(e),",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"- return {\"success\": False, \"error\": str(e)}",
"-",
"- except Exception as e:",
"- logger.log(LogEntry(",
"- tool_name=\"docs_delete\",",
"- request=json.dumps({\"id\": id}),",
"- status=\"error\",",
"- error_message=str(e),",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"- return {\"success\": False, \"error\": str(e)}",
"-",
"- @mcp.tool()",
"- def docs_move(",
"- id: int,",
"- new_parent_id: Optional[int] = None,",
"- new_sort_order: Optional[int] = None",
"- ) -> dict:",
"- \"\"\"",
"- Verschiebt ein Dokument zu einem neuen Parent.",
"-",
"- Args:",
"- id: Dokument-ID (required)",
"- new_parent_id: Neue Parent-ID (None für Root)",
"- new_sort_order: Neue Sortierung",
"-",
"- Returns:",
"- Aktualisiertes Dokument",
"- \"\"\"",
"- start_time = time.time()",
"- logger = get_logger()",
"- repo = get_repository()",
"-",
"- try:",
"- doc = repo.find_by_id(id)",
"- if not doc:",
"- return {\"success\": False, \"error\": f\"Dokument mit ID {id} nicht gefunden\"}",
"-",
"- success = repo.move(id, new_parent_id, new_sort_order)",
"- if success:",
"- updated_doc = repo.find_by_id(id)",
"-",
"- logger.log(LogEntry(",
"- tool_name=\"docs_move\",",
"- request=json.dumps({\"id\": id, \"new_parent_id\": new_parent_id}),",
"- status=\"success\",",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"-",
"- return {",
"- \"success\": True,",
"- \"doc\": updated_doc.to_dict_compact() if updated_doc else None,",
"- \"message\": f\"Dokument #{id} verschoben\"",
"- }",
"- else:",
"- return {\"success\": False, \"error\": \"Verschieben fehlgeschlagen\"}",
"-",
"- except Exception as e:",
"- logger.log(LogEntry(",
"- tool_name=\"docs_move\",",
"- request=json.dumps({\"id\": id}),",
"- status=\"error\",",
"- error_message=str(e),",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"- return {\"success\": False, \"error\": str(e)}",
"-",
"- @mcp.tool()",
"- def docs_hierarchy() -> dict:",
"- \"\"\"",
"- Gibt den kompletten Dokumentationsbaum zurück.",
"-",
"- Returns:",
"- Hierarchischer Baum aller Dokumente",
"- \"\"\"",
"- start_time = time.time()",
"- logger = get_logger()",
"- repo = get_repository()",
"-",
"- try:",
"- hierarchy = repo.get_hierarchy()",
"-",
"- logger.log(LogEntry(",
"- tool_name=\"docs_hierarchy\",",
"- request=\"{}\",",
"- status=\"success\",",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"-",
"- return {",
"- \"success\": True,",
"- \"hierarchy\": hierarchy",
"- }",
"-",
"- except Exception as e:",
"- logger.log(LogEntry(",
"- tool_name=\"docs_hierarchy\",",
"- request=\"{}\",",
"- status=\"error\",",
"- error_message=str(e),",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"- return {\"success\": False, \"error\": str(e)}",
"-",
"- @mcp.tool()",
"- def docs_search(query: str, limit: int = 20) -> dict:",
"- \"\"\"",
"- Volltextsuche in allen Dokumenten.",
"-",
"- Args:",
"- query: Suchbegriff (required)",
"- limit: Maximale Anzahl Ergebnisse",
"-",
"- Returns:",
"- Liste der gefundenen Dokumente",
"- \"\"\"",
"- start_time = time.time()",
"- logger = get_logger()",
"- repo = get_repository()",
"-",
"- try:",
"- docs = repo.find_all(search=query, limit=limit)",
"-",
"- logger.log(LogEntry(",
"- tool_name=\"docs_search\",",
"- request=json.dumps({\"query\": query, \"limit\": limit}),",
"- status=\"success\",",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"-",
"- return {",
"- \"success\": True,",
"- \"query\": query,",
"- \"results\": [d.to_dict_compact() for d in docs],",
"- \"count\": len(docs)",
"- }",
"-",
"- except Exception as e:",
"- logger.log(LogEntry(",
"- tool_name=\"docs_search\",",
"- request=json.dumps({\"query\": query}),",
"- status=\"error\",",
"- error_message=str(e),",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"- return {\"success\": False, \"error\": str(e)}",
"-",
"- @mcp.tool()",
"- def docs_statistics() -> dict:",
"- \"\"\"",
"- Gibt Statistiken über alle Dokumente zurück.",
"-",
"- Returns:",
"- Statistiken: Dokumente nach Status, Tiefe, etc.",
"- \"\"\"",
"- start_time = time.time()",
"- logger = get_logger()",
"- repo = get_repository()",
"-",
"- try:",
"- stats = repo.get_statistics()",
"-",
"- logger.log(LogEntry(",
"- tool_name=\"docs_statistics\",",
"- request=\"{}\",",
"- status=\"success\",",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"-",
"- return {",
"- \"success\": True,",
"- \"statistics\": stats",
"- }",
"-",
"- except Exception as e:",
"- logger.log(LogEntry(",
"- tool_name=\"docs_statistics\",",
"- request=\"{}\",",
"- status=\"error\",",
"- error_message=str(e),",
"- duration_ms=int((time.time() - start_time) * 1000)",
"- ))",
"- return {\"success\": False, \"error\": str(e)}",
"+__all__ = [\"register_docs_tools\"]"
]
}
],
"originalFile": "\"\"\"MCP-Tools für Dokumentations-Management\"\"\"\nimport json\nimport sys\nimport time\nfrom datetime import datetime\nfrom typing import Optional\n\nsys.path.insert(0, \"\/opt\/mcp-servers\/mcp-docs\")\nfrom domain.dokumentation import Dokumentation, DocStatus, LogEntry\nfrom infrastructure.docs_repository import DocsRepository, get_repository\nfrom infrastructure.protokoll_logger import get_logger\n\n\ndef register_docs_tools(mcp):\n \"\"\"Registriert alle Dokumentations-Tools beim MCP-Server\"\"\"\n\n @mcp.tool()\n def docs_list(\n status: Optional[str] = None,\n parent_id: Optional[int] = None,\n search: Optional[str] = None,\n compact: bool = True,\n limit: int = 20\n ) -> dict:\n \"\"\"\n Listet alle Dokumente aus der Datenbank.\n\n Args:\n status: Filter nach Status (draft, published, archived)\n parent_id: Filter nach Parent-ID\n search: Volltextsuche in Titel\/Beschreibung\n compact: True = nur id\/path\/title\/status (Token-sparend)\n limit: Maximale Anzahl Ergebnisse\n\n Returns:\n Liste der Dokumente\n \"\"\"\n start_time = time.time()\n logger = get_logger()\n repo = get_repository()\n\n try:\n docs = repo.find_all(\n status=status,\n parent_id=parent_id,\n search=search,\n limit=limit\n )\n total = repo.count(status=status, parent_id=parent_id, search=search)\n\n result = {\n \"success\": True,\n \"docs\": [d.to_dict_compact() if compact else d.to_dict() for d in docs],\n \"total\": total,\n \"limit\": limit,\n \"compact\": compact\n }\n\n logger.log(LogEntry(\n tool_name=\"docs_list\",\n request=json.dumps({\"status\": status, \"parent_id\": parent_id, \"search\": search, \"limit\": limit}),\n status=\"success\",\n duration_ms=int((time.time() - start_time) * 1000)\n ))\n\n return result\n\n except Exception as e:\n logger.log(LogEntry(\n tool_name=\"docs_list\",\n request=json.dumps({\"status\": status, \"search\": search}),\n status=\"error\",\n error_message=str(e),\n duration_ms=int((time.time() - start_time) * 1000)\n ))\n return {\"success\": False, \"error\": str(e)}\n\n @mcp.tool()\n def docs_get(\n id: Optional[int] = None,\n path: Optional[str] = None,\n include_children: bool = False,\n include_breadcrumb: bool = False\n ) -> dict:\n \"\"\"\n Holt ein Dokument nach ID oder Pfad.\n\n Args:\n id: Dokument-ID\n path: Dokument-Pfad (alternativ zu ID)\n include_children: Kind-Dokumente einschließen\n include_breadcrumb: Breadcrumb-Pfad einschließen\n\n Returns:\n Dokument mit Details\n \"\"\"\n start_time = time.time()\n logger = get_logger()\n repo = get_repository()\n\n try:\n if id is None and path is None:\n return {\"success\": False, \"error\": \"Entweder id oder path muss angegeben werden\"}\n\n doc = None\n if id is not None:\n doc = repo.find_by_id(id)\n elif path is not None:\n doc = repo.find_by_path(path)\n\n if not doc:\n return {\"success\": False, \"error\": \"Dokument nicht gefunden\"}\n\n result = {\n \"success\": True,\n \"doc\": doc.to_dict()\n }\n\n if include_children and doc.id:\n children = repo.find_children(doc.id)\n result[\"children\"] = [c.to_dict_compact() for c in children]\n\n if include_breadcrumb and doc.id:\n result[\"breadcrumb\"] = repo.get_breadcrumb(doc.id)\n\n logger.log(LogEntry(\n tool_name=\"docs_get\",\n request=json.dumps({\"id\": id, \"path\": path}),\n status=\"success\",\n duration_ms=int((time.time() - start_time) * 1000)\n ))\n\n return result\n\n except Exception as e:\n logger.log(LogEntry(\n tool_name=\"docs_get\",\n request=json.dumps({\"id\": id, \"path\": path}),\n status=\"error\",\n error_message=str(e),\n duration_ms=int((time.time() - start_time) * 1000)\n ))\n return {\"success\": False, \"error\": str(e)}\n\n @mcp.tool()\n def docs_create(\n title: str,\n slug: str,\n content: str = \"\",\n description: Optional[str] = None,\n parent_id: Optional[int] = None,\n status: str = \"draft\",\n sort_order: int = 0\n ) -> dict:\n \"\"\"\n Erstellt ein neues Dokument.\n\n Args:\n title: Dokumenttitel (required)\n slug: URL-Slug (required)\n content: HTML-Inhalt\n description: Kurzbeschreibung\n parent_id: ID des Parent-Dokuments\n status: Status (draft, published, archived)\n sort_order: Sortierung innerhalb Parent\n\n Returns:\n Erstelltes Dokument\n \"\"\"\n start_time = time.time()\n logger = get_logger()\n repo = get_repository()\n\n try:\n # Pfad berechnen\n if parent_id is not None:\n parent = repo.find_by_id(parent_id)\n if not parent:\n return {\"success\": False, \"error\": f\"Parent mit ID {parent_id} nicht gefunden\"}\n path = f\"{parent.path}\/{slug}\"\n depth = parent.depth + 1\n else:\n path = f\"\/{slug}\"\n depth = 0\n\n # Prüfen ob Pfad bereits existiert\n existing = repo.find_by_path(path)\n if existing:\n return {\"success\": False, \"error\": f\"Pfad '{path}' existiert bereits\"}\n\n doc = Dokumentation(\n parent_id=parent_id,\n slug=slug,\n path=path,\n title=title,\n description=description,\n content=content,\n status=DocStatus(status) if status in [\"draft\", \"published\", \"archived\"] else DocStatus.DRAFT,\n sort_order=sort_order,\n depth=depth\n )\n\n new_id = repo.create(doc)\n created_doc = repo.find_by_id(new_id)\n\n logger.log(LogEntry(\n tool_name=\"docs_create\",\n request=json.dumps({\"title\": title, \"slug\": slug, \"parent_id\": parent_id}),\n status=\"success\",\n duration_ms=int((time.time() - start_time) * 1000)\n ))\n\n return {\n \"success\": True,\n \"doc\": created_doc.to_dict() if created_doc else None,\n \"message\": f\"Dokument '{title}' erstellt mit ID {new_id}\"\n }\n\n except Exception as e:\n logger.log(LogEntry(\n tool_name=\"docs_create\",\n request=json.dumps({\"title\": title, \"slug\": slug}),\n status=\"error\",\n error_message=str(e),\n duration_ms=int((time.time() - start_time) * 1000)\n ))\n return {\"success\": False, \"error\": str(e)}\n\n @mcp.tool()\n def docs_update(\n id: int,\n title: Optional[str] = None,\n content: Optional[str] = None,\n description: Optional[str] = None,\n status: Optional[str] = None\n ) -> dict:\n \"\"\"\n Aktualisiert ein Dokument.\n\n Args:\n id: Dokument-ID (required)\n title: Neuer Titel\n content: Neuer Inhalt\n description: Neue Beschreibung\n status: Neuer Status (draft, published, archived)\n\n Returns:\n Aktualisiertes Dokument\n \"\"\"\n start_time = time.time()\n logger = get_logger()\n repo = get_repository()\n\n try:\n doc = repo.find_by_id(id)\n if not doc:\n return {\"success\": False, \"error\": f\"Dokument mit ID {id} nicht gefunden\"}\n\n updates = {}\n if title is not None:\n updates[\"title\"] = title\n if content is not None:\n updates[\"content\"] = content\n if description is not None:\n updates[\"description\"] = description\n if status is not None and status in [\"draft\", \"published\", \"archived\"]:\n updates[\"status\"] = status\n\n if not updates:\n return {\"success\": False, \"error\": \"Keine Änderungen angegeben\"}\n\n success = repo.update(id, updates)\n if success:\n updated_doc = repo.find_by_id(id)\n\n logger.log(LogEntry(\n tool_name=\"docs_update\",\n request=json.dumps({\"id\": id, \"updates\": list(updates.keys())}),\n status=\"success\",\n duration_ms=int((time.time() - start_time) * 1000)\n ))\n\n return {\n \"success\": True,\n \"doc\": updated_doc.to_dict() if updated_doc else None,\n \"message\": f\"Dokument #{id} aktualisiert\"\n }\n else:\n return {\"success\": False, \"error\": \"Update fehlgeschlagen\"}\n\n except Exception as e:\n logger.log(LogEntry(\n tool_name=\"docs_update\",\n request=json.dumps({\"id\": id}),\n status=\"error\",\n error_message=str(e),\n duration_ms=int((time.time() - start_time) * 1000)\n ))\n return {\"success\": False, \"error\": str(e)}\n\n @mcp.tool()\n def docs_delete(id: int) -> dict:\n \"\"\"\n Löscht ein Dokument.\n\n Args:\n id: Dokument-ID (required)\n\n Returns:\n ... [TRUNCATED-5e6c4089c15e875f]"
}
}