{
"event": "PreToolUse",
"tool_name": "Read",
"tool_input": {
"file_path": "\/var\/www\/mcp-servers\/mcp_contracts\/config.py"
}
}
{
"tool_response": {
"type": "text",
"file": {
"filePath": "\/var\/www\/mcp-servers\/mcp_contracts\/infrastructure\/protokoll_logger.py",
"content": "\"\"\"Protokoll Logger für MCP-Contracts - Schreibt in mcp_log\"\"\"\nimport sys\nfrom datetime import datetime\n\nsys.path.insert(0, \"\/var\/www\/mcp-servers\/mcp_contracts\")\nfrom domain.contracts import LogEntry\nfrom infrastructure.db_connection import DatabaseConnection\n\n\nclass ProtokollLogger:\n \"\"\"Fail-Safe Logger für mcp_log Tabelle\"\"\"\n\n def log(self, entry: LogEntry) -> None:\n \"\"\"\n Schreibt Log-Eintrag in die Datenbank.\n\n WICHTIG: Fehler werden zu stderr geloggt, aber NIEMALS\n an den Client weitergegeben. Logging darf die Tool-Ausführung\n nicht blockieren.\n \"\"\"\n try:\n with DatabaseConnection.get_log_connection() as conn:\n with conn.cursor() as cursor:\n sql = \"\"\"\n INSERT INTO mcp_log\n (timestamp, client_name, request, status, duration_ms, error_message)\n VALUES (%s, %s, %s, %s, %s, %s)\n \"\"\"\n\n # Request auf 500 Zeichen kürzen\n request_truncated = entry.request[:500] if entry.request else \"\"\n\n # Tool-Name in Request einbauen\n if entry.tool_name:\n request_truncated = f\"[{entry.tool_name}] {request_truncated}\"\n\n cursor.execute(sql, (\n entry.timestamp,\n entry.client_name,\n request_truncated[:500],\n entry.status,\n entry.duration_ms,\n entry.error_message[:500] if entry.error_message else None,\n ))\n\n except Exception as e:\n # CRITICAL: Nur zu stderr loggen, NICHT an Client weitergeben\n print(f\"CRITICAL: MCP-Contracts log failed: {e}\", file=sys.stderr)\n\n\n# Singleton-Instanz\n_logger_instance = None\n\n\ndef get_logger() -> ProtokollLogger:\n \"\"\"Gibt Singleton-Logger zurück\"\"\"\n global _logger_instance\n if _logger_instance is None:\n _logger_instance = ProtokollLogger()\n return _logger_instance\n",
"numLines": 61,
"startLine": 1,
"totalLines": 61
}
}
}