Protokoll #29786

ID29786
Zeitstempel2025-12-29 14:51:01.862513
Clientroot
IP145.224.72.140
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens5,294 (Input: 2,643, Output: 2,651)
Dauer204 ms
Request-Zeit2025-12-29 14:51:01.862513
Response-Zeit2025-12-29 14:51:02.066868

Request

{
    "event": "PreToolUse",
    "tool_name": "mcp__mcp-docs__docs_update",
    "tool_input": {
        "id": 156,
        "content": "<h1>MCP Server Refactoring Plan<\/h1>\n\n<p><strong>Version:<\/strong> 1.2<br>\n<strong>Erstellt:<\/strong> 2025-12-28<br>\n<strong>Aktualisiert:<\/strong> 2025-12-28 (nach Supervision Runde 2)<br>\n<strong>Status:<\/strong> Final<br>\n<strong>Task:<\/strong> #507<\/p>\n\n<hr>\n\n<h2>1. Executive Summary<\/h2>\n\n<h3>Ist-Zustand<\/h3>\n<ul>\n<li><strong>5 MCP-Server<\/strong>: mcp-db, mcp-tasks, mcp-contracts, mcp-docs, mcp-code<\/li>\n<li><strong>91 Python-Dateien<\/strong> (ohne venv)<\/li>\n<li><strong>9.248 LOC<\/strong> gesamt<\/li>\n<li><strong>Signifikante Code-Duplikation<\/strong> (~25% redundanter Code)<\/li>\n<li><strong>Inkonsistente Patterns<\/strong> zwischen Servern<\/li>\n<\/ul>\n\n<h3>Ziel<\/h3>\n<p>Konsolidierung zu einer modularen, wartbaren Architektur unter Einhaltung von:<\/p>\n<ul>\n<li><strong>DRY<\/strong> (Don't Repeat Yourself)<\/li>\n<li><strong>SRP<\/strong> (Single Responsibility Principle)<\/li>\n<li><strong>SOLID<\/strong> Principles<\/li>\n<li><strong>Clean Architecture<\/strong><\/li>\n<li><strong>KISS<\/strong> (Keep It Simple, Stupid)<\/li>\n<li><strong>YAGNI<\/strong> (You Aren't Gonna Need It)<\/li>\n<\/ul>\n\n<h3>Erwartete Verbesserungen<\/h3>\n<ul>\n<li><strong>~30% weniger Code<\/strong> durch Elimination von Duplikaten<\/li>\n<li><strong>Einheitliche Patterns<\/strong> für alle Server<\/li>\n<li><strong>Verbesserte Wartbarkeit<\/strong> durch Modularisierung<\/li>\n<li><strong>Schnellere Feature-Entwicklung<\/strong> durch shared Components<\/li>\n<\/ul>\n\n<hr>\n\n<h2>2. Analyse der Code-Duplikation<\/h2>\n\n<h3>2.1 Kritische Duplikate (Sofort beheben)<\/h3>\n\n<h4>db_connection.py (4 Dateien, ~240 LOC dupliziert)<\/h4>\n\n<table>\n<tr><th>Server<\/th><th>Zeilen<\/th><th>Bibliothek<\/th><th>Besonderheit<\/th><\/tr>\n<tr><td>mcp-db<\/td><td>59<\/td><td>mysql.connector + <strong>Pooling<\/strong><\/td><td>Dynamisches DB-Switching via <code>USE<\/code><\/td><\/tr>\n<tr><td>mcp-tasks<\/td><td>62<\/td><td>pymysql<\/td><td>Festes <code>DB_NAME<\/code><\/td><\/tr>\n<tr><td>mcp-contracts<\/td><td>60<\/td><td>pymysql<\/td><td>Festes <code>DB_NAME<\/code><\/td><\/tr>\n<tr><td>mcp-docs<\/td><td>60<\/td><td>pymysql<\/td><td>Festes <code>DB_NAME<\/code><\/td><\/tr>\n<\/table>\n\n<p><strong>Problem:<\/strong> 3 von 4 Dateien sind nahezu identisch (mcp-tasks, mcp-contracts, mcp-docs).<\/p>\n\n<p><strong>Lösung:<\/strong> Zentralisieren in <code>shared\/infrastructure\/simple_db_connection.py<\/code><\/p>\n\n<blockquote>\n<p><strong>WICHTIG:<\/strong> Diese Klasse heißt bewusst <code>SimpleDbConnection<\/code>, nicht <code>DatabaseConnection<\/code>. Sie bietet <strong>kein Pooling<\/strong> und ist <strong>nicht für High-Throughput<\/strong> geeignet. Für mcp-db (100+ Queries\/Minute) bleibt die eigene Pooling-Implementierung.<\/p>\n<\/blockquote>\n\n<pre><code class=\"language-python\"># shared\/infrastructure\/simple_db_connection.py\n\"\"\"\nEinfache DB-Verbindung ohne Pooling.\n\nNICHT geeignet für:\n- High-Throughput (&gt; 50 Queries\/Minute)\n- Connection Pooling Requirements\n- mcp-db Server\n\nFür diese Fälle: Eigene Implementierung mit mysql.connector.pooling\n\"\"\"\nfrom contextlib import contextmanager\nfrom typing import Generator\n\nimport pymysql\nfrom pymysql.connections import Connection\n\nfrom shared.config_base import AppDatabaseConfig, LogDatabaseConfig\n\n\nclass SimpleDbConnection:\n    \"\"\"\n    Einfache Datenbankverbindung ohne Pooling.\n    \n    Für Server mit geringem Query-Volumen (&lt; 50\/Minute).\n    \"\"\"\n    \n    @classmethod\n    @contextmanager\n    def get_connection(\n        cls, \n        config: AppDatabaseConfig,\n        database: str | None = None,\n        autocommit: bool = False\n    ) -&gt; Generator[Connection, None, None]:\n        \"\"\"\n        Context Manager für App-DB Connection.\n        \n        ACHTUNG: Keine weiteren Parameter hinzufügen!\n        Bei Bedarf für mehr Logik: Neue Methode erstellen.\n        \n        Args:\n            config: Server-Konfiguration mit DB-Credentials\n            database: Optional - überschreibt config.DB_NAME\n            autocommit: True für Logging, False für Transaktionen\n        \"\"\"\n        conn = None\n        db_name = database or getattr(config, 'DB_NAME', None)\n        \n        try:\n            conn = pymysql.connect(\n                host=config.DB_HOST,\n                port=getattr(config, 'DB_PORT', 3306),\n                user=config.DB_USER,\n                password=config.DB_PASSWORD,\n                database=db_name,\n                charset=\"utf8mb4\",\n                cursorclass=pymysql.cursors.DictCursor,\n                autocommit=autocommit,\n            )\n            yield conn\n            if not autocommit:\n                conn.commit()\n        except Exception:\n            if conn and not autocommit:\n                conn.rollback()\n            raise\n        finally:\n            if conn:\n                conn.close()\n    \n    @classmethod\n    @contextmanager\n    def get_log_connection(\n        cls, \n        config: LogDatabaseConfig\n    ) -&gt; Generator[Connection, None, None]:\n        \"\"\"Separate Verbindung für Logging (autocommit=True).\"\"\"\n        conn = None\n        try:\n            conn = pymysql.connect(\n                host=config.LOG_DB_HOST,\n                user=config.LOG_DB_USER,\n                password=config.LOG_DB_PASSWORD,\n                database=config.LOG_DB_NAME,\n                charset=\"utf8mb4\",\n                cursorclass=pymysql.cursors.DictCursor,\n                autocommit=True,\n            )\n            yield conn\n        finally:\n            if conn:\n                conn.close()<\/code><\/pre>\n\n<h4>protokoll_logger.py (4 Dateien, ~240 LOC dupliziert)<\/h4>\n\n<p><strong>Lösung:<\/strong> Zentralisieren mit strikter Clean Architecture Trennung<\/p>\n\n<pre><code class=\"language-python\"># shared\/domain\/log_entry.py\n\"\"\"\nDomain Entity für Log-Einträge.\n\nREINE DOMAIN - keine Infrastructure-Abhängigkeiten!\n\"\"\"\nfrom dataclasses import dataclass\nfrom datetime import datetime\nfrom typing import Optional\n\n\n@dataclass(frozen=True)\nclass LogEntry:\n    \"\"\"Standardisierter Log-Eintrag für alle MCP-Server.\"\"\"\n    timestamp: datetime\n    client_name: str\n    request: str\n    status: str\n    duration_ms: int\n    error_message: Optional[str] = None\n    tool_name: Optional[str] = None\n    context_id: Optional[int] = None  # task_id, contract_id, etc.<\/code><\/pre>\n\n<pre><code class=\"language-python\"># shared\/infrastructure\/protokoll_logger.py\n\"\"\"\nInfrastructure Logger für mcp_log Tabelle.\n\nImportiert LogEntry aus Domain - definiert ihn NICHT selbst.\n\"\"\"\nimport logging\nimport sys\nfrom typing import TYPE_CHECKING\n\nfrom shared.domain.log_entry import LogEntry  # Import aus Domain!\nfrom shared.infrastructure.simple_db_connection import SimpleDbConnection\n\nif TYPE_CHECKING:\n    from shared.config_base import LogDatabaseConfig\n\n\nclass ProtokollLogger:\n    \"\"\"Fail-Safe Logger für mcp_log Tabelle.\"\"\"\n    \n    def __init__(self, client_name: str, config: \"LogDatabaseConfig\"):\n        self.client_name = client_name\n        self.config = config\n        self._logger = logging.getLogger(f\"mcp.{client_name}\")\n    \n    def log(self, entry: LogEntry) -&gt; None:\n        \"\"\"Schreibt Log-Eintrag. Fehler gehen nur zu stderr.\"\"\"\n        try:\n            with SimpleDbConnection.get_log_connection(self.config) as conn:\n                with conn.cursor() as cursor:\n                    request_str = self._format_request(entry)\n                    cursor.execute(\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                            entry.timestamp,\n                            self.client_name,\n                            request_str[: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            print(f\"CRITICAL: {self.client_name} log failed: {e}\", file=sys.stderr)\n    \n    def _format_request(self, entry: LogEntry) -&gt; str:\n        parts = []\n        if entry.tool_name:\n            parts.append(f\"[{entry.tool_name}]\")\n        if entry.context_id:\n            parts.append(f\"id={entry.context_id}\")\n        parts.append(entry.request[:400] if entry.request else \"\")\n        return \" \".join(parts)\n\n\n# === Registry mit Test-Support ===\n\n_logger_instances: dict[str, ProtokollLogger] = {}\n\n\ndef get_logger(client_name: str, config: \"LogDatabaseConfig\") -&gt; ProtokollLogger:\n    \"\"\"Singleton-Factory für Logger.\"\"\"\n    if client_name not in _logger_instances:\n        _logger_instances[client_name] = ProtokollLogger(client_name, config)\n    return _logger_instances[client_name]\n\n\ndef clear_logger_registry() -&gt; None:\n    \"\"\"\n    Setzt die Logger-Registry zurück.\n    \n    NUR FÜR TESTS! Ermöglicht isolierte Test-Ausführung.\n    \"\"\"\n    _logger_instances.clear()<\/code><\/pre>\n\n<h4>config.py - Strikte Statische Konfiguration<\/h4>\n\n<pre><code class=\"language-python\"># shared\/config_base.py\n\"\"\"\nBasis-Konfiguration für alle MCP-Server.\n\nWICHTIG: Diese Klasse wird NICHT instanziiert!\nAlle Zugriffe erfolgen über Klassenattribute.\n\nFalsch: config = BaseConfig()\nRichtig: host = BaseConfig.DB_HOST\n\"\"\"\nimport os\nfrom typing import ClassVar, Protocol, runtime_checkable\n\n\n@runtime_checkable\nclass AppDatabaseConfig(Protocol):\n    \"\"\"Protocol für App-Datenbank Konfiguration.\"\"\"\n    DB_HOST: str\n    DB_PORT: int\n    DB_USER: str\n    DB_PASSWORD: str\n    DB_NAME: str\n\n\n@runtime_checkable\nclass LogDatabaseConfig(Protocol):\n    \"\"\"Protocol für Log-Datenbank Konfiguration.\"\"\"\n    LOG_DB_HOST: str\n    LOG_DB_NAME: str\n    LOG_DB_USER: str\n    LOG_DB_PASSWORD: str\n\n\nclass BaseConfig:\n    \"\"\"\n    Statische Konfiguration - NICHT INSTANZIIEREN!\n    \n    Verwendung:\n        from shared.config_base import BaseConfig\n        host = BaseConfig.DB_HOST  # Korrekt\n        \n        config = BaseConfig()  # FALSCH!\n    \"\"\"\n    \n    # App-Datenbank\n    DB_HO... [TRUNCATED-cfce12bba038f7c0]"
    }
}

Response

{
    "tool_response": [
        {
            "type": "text",
            "text": "{\n  \"success\": true,\n  \"doc\": {\n    \"id\": 156,\n    \"parent_id\": 35,\n    \"slug\": \"mcp-server-refactoring-plan\",\n    \"path\": \"\/mcp\/mcp-server-refactoring-plan\",\n    \"title\": \"MCP Server Refactoring Plan\",\n    \"description\": \"Vollständiger Refactoring-Plan für alle 5 MCP-Server nach DRY, SRP, SOLID, Clean Architecture\",\n    \"content\": \"<h1>MCP Server Refactoring Plan<\/h1>\\n\\n<p><strong>Version:<\/strong> 1.2<br>\\n<strong>Erstellt:<\/strong> 2025-12-28<br>\\n<strong>Aktualisiert:<\/strong> 2025-12-28 (nach Supervision Runde 2)<br>\\n<strong>Status:<\/strong> Final<br>\\n<strong>Task:<\/strong> #507<\/p>\\n\\n<hr>\\n\\n<h2>1. Executive Summary<\/h2>\\n\\n<h3>Ist-Zustand<\/h3>\\n<ul>\\n<li><strong>5 MCP-Server<\/strong>: mcp-db, mcp-tasks, mcp-contracts, mcp-docs, mcp-code<\/li>\\n<li><strong>91 Python-Dateien<\/strong> (ohne venv)<\/li>\\n<li><strong>9.248 LOC<\/strong> gesamt<\/li>\\n<li><strong>Signifikante Code-Duplikation<\/strong> (~25% redundanter Code)<\/li>\\n<li><strong>Inkonsistente Patterns<\/strong> zwischen Servern<\/li>\\n<\/ul>\\n\\n<h3>Ziel<\/h3>\\n<p>Konsolidierung zu einer modularen, wartbaren Architektur unter Einhaltung von:<\/p>\\n<ul>\\n<li><strong>DRY<\/strong> (Don't Repeat Yourself)<\/li>\\n<li><strong>SRP<\/strong> (Single Responsibility Principle)<\/li>\\n<li><strong>SOLID<\/strong> Principles<\/li>\\n<li><strong>Clean Architecture<\/strong><\/li>\\n<li><strong>KISS<\/strong> (Keep It Simple, Stupid)<\/li>\\n<li><strong>YAGNI<\/strong> (You Aren't Gonna Need It)<\/li>\\n<\/ul>\\n\\n<h3>Erwartete Verbesserungen<\/h3>\\n<ul>\\n<li><strong>~30% weniger Code<\/strong> durch Elimination von Duplikaten<\/li>\\n<li><strong>Einheitliche Patterns<\/strong> für alle Server<\/li>\\n<li><strong>Verbesserte Wartbarkeit<\/strong> durch Modularisierung<\/li>\\n<li><strong>Schnellere Feature-Entwicklung<\/strong> durch shared Components<\/li>\\n<\/ul>\\n\\n<hr>\\n\\n<h2>2. Analyse der Code-Duplikation<\/h2>\\n\\n<h3>2.1 Kritische Duplikate (Sofort beheben)<\/h3>\\n\\n<h4>db_connection.py (4 Dateien, ~240 LOC dupliziert)<\/h4>\\n\\n<table>\\n<tr><th>Server<\/th><th>Zeilen<\/th><th>Bibliothek<\/th><th>Besonderheit<\/th><\/tr>\\n<tr><td>mcp-db<\/td><td>59<\/td><td>mysql.connector + <strong>Pooling<\/strong><\/td><td>Dynamisches DB-Switching via <code>USE<\/code><\/td><\/tr>\\n<tr><td>mcp-tasks<\/td><td>62<\/td><td>pymysql<\/td><td>Festes <code>DB_NAME<\/code><\/td><\/tr>\\n<tr><td>mcp-contracts<\/td><td>60<\/td><td>pymysql<\/td><td>Festes <code>DB_NAME<\/code><\/td><\/tr>\\n<tr><td>mcp-docs<\/td><td>60<\/td><td>pymysql<\/td><td>Festes <code>DB_NAME<\/code><\/td><\/tr>\\n<\/table>\\n\\n<p><strong>Problem:<\/strong> 3 von 4 Dateien sind nahezu identisch (mcp-tasks, mcp-contracts, mcp-docs).<\/p>\\n\\n<p><strong>Lösung:<\/strong> Zentralisieren in <code>shared\/infrastructure\/simple_db_connection.py<\/code><\/p>\\n\\n<blockquote>\\n<p><strong>WICHTIG:<\/strong> Diese Klasse heißt bewusst <code>SimpleDbConnection<\/code>, nicht <code>DatabaseConnection<\/code>. Sie bietet <strong>kein Pooling<\/strong> und ist <strong>nicht für High-Throughput<\/strong> geeignet. Für mcp-db (100+ Queries\/Minute) bleibt die eigene Pooling-Implementierung.<\/p>\\n<\/blockquote>\\n\\n<pre><code class=\\\"language-python\\\"># shared\/infrastructure\/simple_db_connection.py\\n\\\"\\\"\\\"\\nEinfache DB-Verbindung ohne Pooling.\\n\\nNICHT geeignet für:\\n- High-Throughput (&gt; 50 Queries\/Minute)\\n- Connection Pooling Requirements\\n- mcp-db Server\\n\\nFür diese Fälle: Eigene Implementierung mit mysql.connector.pooling\\n\\\"\\\"\\\"\\nfrom contextlib import contextmanager\\nfrom typing import Generator\\n\\nimport pymysql\\nfrom pymysql.connections import Connection\\n\\nfrom shared.config_base import AppDatabaseConfig, LogDatabaseConfig\\n\\n\\nclass SimpleDbConnection:\\n    \\\"\\\"\\\"\\n    Einfache Datenbankverbindung ohne Pooling.\\n    \\n    Für Server mit geringem Query-Volumen (&lt; 50\/Minute).\\n    \\\"\\\"\\\"\\n    \\n    @classmethod\\n    @contextmanager\\n    def get_connection(\\n        cls, \\n        config: AppDatabaseConfig,\\n        database: str | None = None,\\n        autocommit: bool = False\\n    ) -&gt; Generator[Connection, None, None]:\\n        \\\"\\\"\\\"\\n        Context Manager für App-DB Connection.\\n        \\n        ACHTUNG: Keine weiteren Parameter hinzufügen!\\n        Bei Bedarf für mehr Logik: Neue Methode erstellen.\\n        \\n        Args:\\n            config: Server-Konfiguration mit DB-Credentials\\n            database: Optional - überschreibt config.DB_NAME\\n            autocommit: True für Logging, False für Transaktionen\\n        \\\"\\\"\\\"\\n        conn = None\\n        db_name = database or getattr(config, 'DB_NAME', None)\\n        \\n        try:\\n            conn = pymysql.connect(\\n                host=config.DB_HOST,\\n                port=getattr(config, 'DB_PORT', 3306),\\n                user=config.DB_USER,\\n                password=config.DB_PASSWORD,\\n                database=db_name,\\n                charset=\\\"utf8mb4\\\",\\n                cursorclass=pymysql.cursors.DictCursor,\\n                autocommit=autocommit,\\n            )\\n            yield conn\\n            if not autocommit:\\n                conn.commit()\\n        except Exception:\\n            if conn and not autocommit:\\n                conn.rollback()\\n            raise\\n        finally:\\n            if conn:\\n                conn.close()\\n    \\n    @classmethod\\n    @contextmanager\\n    def get_log_connection(\\n        cls, \\n        config: LogDatabaseConfig\\n    ) -&gt; Generator[Connection, None, None]:\\n        \\\"\\\"\\\"Separate Verbindung für Logging (autocommit=True).\\\"\\\"\\\"\\n        conn = None\\n        try:\\n            conn = pymysql.connect(\\n                host=config.LOG_DB_HOST,\\n                user=config.LOG_DB_USER,\\n                password=config.LOG_DB_PASSWORD,\\n                database=config.LOG_DB_NAME,\\n                charset=\\\"utf8mb4\\\",\\n                cursorclass=pymysql.cursors.DictCursor,\\n                autocommit=True,\\n            )\\n            yield conn\\n        finally:\\n            if conn:\\n                conn.close()<\/code><\/pre>\\n\\n<h4>protokoll_logger.py (4 Dateien, ~240 LOC dupliziert)<\/h4>\\n\\n<p><strong>Lösung:<\/strong> Zentralisieren mit strikter Clean Architecture Trennung<\/p>\\n\\n<pre><code class=\\\"language-python\\\"># shared\/domain\/log_entry.py\\n\\\"\\\"\\\"\\nDomain Entity für Log-Einträge.\\n\\nREINE DOMAIN - keine Infrastructure-Abhängigkeiten!\\n\\\"\\\"\\\"\\nfrom dataclasses import dataclass\\nfrom datetime import datetime\\nfrom typing import Optional\\n\\n\\n@dataclass(frozen=True)\\nclass LogEntry:\\n    \\\"\\\"\\\"Standardisierter Log-Eintrag für alle MCP-Server.\\\"\\\"\\\"\\n    timestamp: datetime\\n    client_name: str\\n    request: str\\n    status: str\\n    duration_ms: int\\n    error_message: Optional[str] = None\\n    tool_name: Optional[str] = None\\n    context_id: Optional[int] = None  # task_id, contract_id, etc.<\/code><\/pre>\\n\\n<pre><code class=\\\"language-python\\\"># shared\/infrastructure\/protokoll_logger.py\\n\\\"\\\"\\\"\\nInfrastructure Logger für mcp_log Tabelle.\\n\\nImportiert LogEntry aus Domain - definiert ihn NICHT selbst.\\n\\\"\\\"\\\"\\nimport logging\\nimport sys\\nfrom typing import TYPE_CHECKING\\n\\nfrom shared.domain.log_entry import LogEntry  # Import aus Domain!\\nfrom shared.infrastructure.simple_db_connection import SimpleDbConnection\\n\\nif TYPE_CHECKING:\\n    from shared.config_base import LogDatabaseConfig\\n\\n\\nclass ProtokollLogger:\\n    \\\"\\\"\\\"Fail-Safe Logger für mcp_log Tabelle.\\\"\\\"\\\"\\n    \\n    def __init__(self, client_name: str, config: \\\"LogDatabaseConfig\\\"):\\n        self.client_name = client_name\\n        self.config = config\\n        self._logger = logging.getLogger(f\\\"mcp.{client_name}\\\")\\n    \\n    def log(self, entry: LogEntry) -&gt; None:\\n        \\\"\\\"\\\"Schreibt Log-Eintrag. Fehler gehen nur zu stderr.\\\"\\\"\\\"\\n        try:\\n            with SimpleDbConnection.get_log_connection(self.config) as conn:\\n                with conn.cursor() as cursor:\\n                    request_str = self._format_request(entry)\\n                    cursor.execute(\\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                            entry.timestamp,\\n                            self.client_name,\\n                            request_str[: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            print(f\\\"CRITICAL: {self.client_name} log failed: {e}\\\", file=sys.stderr)\\n    \\n    def _format_request(self, entry: LogEntry) -&gt; str:\\n        parts = []\\n        if entry.tool_name:\\n            parts.append(f\\\"[{entry.tool_name}]\\\")\\n        if entry.context_id:\\n            parts.append(f\\\"id={entry.context_id}\\\")\\n        parts.append(entry.request[:400] if entry.request else \\\"\\\")\\n        return \\\" \\\".join(parts)\\n\\n\\n# === Registry mit Test-Support ===\\n\\n_logger_instances: dict[str, ProtokollLogger] = {}\\n\\n\\ndef get_logger(client_name: str, config: \\\"LogDatabaseConfig\\\") -&gt; ProtokollLogger:\\n    \\\"\\\"\\\"Singleton-Factory für Logger.\\\"\\\"\\\"\\n    if client_name not in _logger_instances:\\n        _logger_instances[client_name] = ProtokollLogger(client_name, config)\\n    return _logger_instances[client_name]\\n\\n\\ndef clear_logger_registry() -&gt; None:\\n    \\\"\\\"\\\"\\n    Setzt die Logger-Registry zurück.\\n    \\n    NUR FÜR TESTS! Ermöglicht isolierte Test-Ausführung.\\n    \\\"\\\"\\\"\\n    _logger_instances.clear()<\/code><\/pre>\\n\\n<h4>config.py - Strikte Statische Konfiguration<\/h4>\\n\\n<pre><code class=\\\"language-python\\\"># shared\/config_base.py\\n\\\"\\\"\\\"\\nBasis-Konfiguration für alle MCP-Server.\\n\\nWICHTIG: Diese Klasse wird NICHT instanziiert!\\nAlle Zugriffe erfolgen über Klassenattribute.\\n\\nFalsch: config = BaseConfig()\\nRichtig: host = BaseConfig.DB_HOST\\n\\\"\\\"\\\"\\nimport os\\nfrom typing import Cl... [TRUNCATED-03d0c3f769f130e2]"
        }
    ]
}
← Vorheriger Zur Liste Nächster →