{
"tool_response": [
{
"type": "text",
"text": "{\n \"success\": true,\n \"doc\": {\n \"id\": 44,\n \"parent_id\": 36,\n \"slug\": \"mcp-db-infrastructure\",\n \"path\": \"\/mcp\/mcp-db\/mcp-db-infrastructure\",\n \"title\": \"Infrastructure\",\n \"description\": \"Connection Pool und Protokoll Logger.\",\n \"content\": \"<nav class=\\\"breadcrumb\\\">\\n <a href=\\\"\/docs\\\">Dokumentation<\/a> » <a href=\\\"\/docs\/mcp\/mcp-db\\\">MCP-DB<\/a> » Infrastructure\\n<\/nav>\\n\\n<h1>MCP-DB Infrastructure<\/h1>\\n<p>Connection Pool und Protokoll Logger.<\/p>\\n\\n<h2>DatabaseConnection<\/h2>\\n<p>Singleton Connection Pool für Datenbankzugriffe.<\/p>\\n\\n<pre><code>\\\"\\\"\\\"Database Connection Pool\\\"\\\"\\\"\\nimport os\\nfrom contextlib import contextmanager\\nimport mysql.connector\\nfrom mysql.connector import pooling\\nfrom config import Config\\n\\nclass DatabaseConnection:\\n \\\"\\\"\\\"Singleton Connection Pool - SRP: Nur Verbindungsmanagement\\\"\\\"\\\"\\n\\n _pool = None\\n\\n @classmethod\\n def get_pool(cls):\\n if cls._pool is None:\\n cls._pool = pooling.MySQLConnectionPool(\\n pool_name=\\\"mcp_pool\\\",\\n pool_size=5,\\n host=Config.DB_HOST,\\n user=Config.DB_USER,\\n password=Config.DB_PASSWORD,\\n charset=\\\"utf8mb4\\\",\\n connection_timeout=10,\\n autocommit=True\\n )\\n return cls._pool\\n\\n @classmethod\\n @contextmanager\\n def get_connection(cls, database: str):\\n \\\"\\\"\\\"Context Manager für DB Connection.\\\"\\\"\\\"\\n conn = cls.get_pool().get_connection()\\n try:\\n # Datenbank wechseln (USE statement statt property)\\n cursor = conn.cursor()\\n cursor.execute(f\\\"USE {database}\\\")\\n\\n # Query Timeout setzen (MariaDB verwendet max_statement_time in Sekunden)\\n try:\\n cursor.execute(\\n f\\\"SET SESSION max_statement_time = {Config.QUERY_TIMEOUT_SEC}\\\"\\n )\\n except Exception:\\n pass # Falls Variable nicht unterstützt wird\\n cursor.close()\\n\\n yield conn\\n finally:\\n conn.close()<\/code><\/pre>\\n\\n<h3>Pool-Konfiguration<\/h3>\\n<table>\\n <tr><th>Parameter<\/th><th>Wert<\/th><th>Beschreibung<\/th><\/tr>\\n <tr><td>pool_size<\/td><td>5<\/td><td>Maximale Verbindungen<\/td><\/tr>\\n <tr><td>connection_timeout<\/td><td>10<\/td><td>Verbindungs-Timeout in Sekunden<\/td><\/tr>\\n <tr><td>autocommit<\/td><td>True<\/td><td>Automatisches Commit (nur SELECT)<\/td><\/tr>\\n <tr><td>charset<\/td><td>utf8mb4<\/td><td>Unicode-Support<\/td><\/tr>\\n<\/table>\\n\\n<h3>Query Timeout<\/h3>\\n<p>Bei jeder Verbindung wird <code>max_statement_time<\/code> gesetzt (MariaDB-spezifisch):<\/p>\\n<pre><code>SET SESSION max_statement_time = 30 # 30 Sekunden (in Sekunden, nicht ms)<\/code><\/pre>\\n<p><strong>Hinweis:<\/strong> MySQL verwendet <code>max_execution_time<\/code> in Millisekunden, MariaDB verwendet <code>max_statement_time<\/code> in Sekunden.<\/p>\\n\\n<h2>ProtokollLogger<\/h2>\\n<p>Logging aller Operationen nach ki_protokoll.mcp_log.<\/p>\\n\\n<pre><code>\\\"\\\"\\\"Logging in ki_protokoll\\\"\\\"\\\"\\nimport sys\\nimport mysql.connector.pooling as pooling\\nfrom domain.log_contract import LogEntry\\nfrom config import Config\\n\\nclass ProtokollLogger:\\n \\\"\\\"\\\"Schreibt in ki_protokoll.mcp_log - SRP: Nur Logging\\\"\\\"\\\"\\n\\n def __init__(self):\\n self._pool = None\\n\\n def _get_pool(self):\\n if self._pool is None:\\n self._pool = pooling.MySQLConnectionPool(\\n pool_name=\\\"log_pool\\\",\\n pool_size=2,\\n host=Config.LOG_DB_HOST,\\n database=Config.LOG_DB_NAME,\\n user=Config.LOG_DB_USER,\\n password=Config.LOG_DB_PASSWORD,\\n charset=\\\"utf8mb4\\\"\\n )\\n return self._pool\\n\\n def log(self, entry: LogEntry) -> None:\\n \\\"\\\"\\\"Schreibt LogEntry in Datenbank.\\\"\\\"\\\"\\n try:\\n conn = self._get_pool().get_connection()\\n cursor = conn.cursor()\\n cursor.execute(\\n \\\"\\\"\\\"INSERT INTO mcp_log\\n (timestamp, client_name, request, status,\\n duration_ms, error_message)\\n VALUES (%s, %s, %s, %s, %s, %s)\\\"\\\"\\\",\\n (entry.timestamp, entry.client_name, entry.request,\\n entry.status, entry.duration_ms, entry.error_message)\\n )\\n conn.commit()\\n cursor.close()\\n conn.close()\\n except Exception as e:\\n # Fail-Safe: Exception werfen statt silent failure\\n error_msg = f\\\"CRITICAL: Failed to write to mcp_log: {str(e)}\\\"\\n print(error_msg, file=sys.stderr)\\n raise RuntimeError(error_msg) from e<\/code><\/pre>\\n\\n<h3>Logger-Pool<\/h3>\\n<table>\\n <tr><th>Parameter<\/th><th>Wert<\/th><th>Beschreibung<\/th><\/tr>\\n <tr><td>pool_size<\/td><td>2<\/td><td>Kleinerer Pool für Logging<\/td><\/tr>\\n <tr><td>database<\/td><td>ki_protokoll<\/td><td>Aus Config.LOG_DB_NAME<\/td><\/tr>\\n <tr><td>user<\/td><td>mcp_logger<\/td><td>Nur INSERT-Rechte<\/td><\/tr>\\n<\/table>\\n\\n<h3>Fail-Safe Verhalten<\/h3>\\n<p>Bei Logging-Fehlern:<\/p>\\n<ul>\\n <li>Fehlermeldung nach stderr<\/li>\\n <li>RuntimeError wird geworfen<\/li>\\n <li>Kein silent failure<\/li>\\n<\/ul>\\n\\n<h2>mcp_log Tabelle<\/h2>\\n<pre><code>CREATE TABLE IF NOT EXISTS mcp_log (\\n id INT AUTO_INCREMENT PRIMARY KEY,\\n timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,\\n client_name VARCHAR(50) NOT NULL DEFAULT 'mcp-db',\\n request TEXT,\\n status ENUM('success', 'error', 'denied') NOT NULL,\\n duration_ms INT DEFAULT 0,\\n error_message TEXT,\\n INDEX idx_timestamp (timestamp),\\n INDEX idx_status (status)\\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;<\/code><\/pre>\\n\\n<h2>Nutzung<\/h2>\\n<pre><code># DatabaseConnection\\nwith DatabaseConnection.get_connection(\\\"ki_protokoll\\\") as conn:\\n cursor = conn.cursor(dictionary=True)\\n cursor.execute(\\\"SELECT * FROM mcp_log LIMIT 10\\\")\\n rows = cursor.fetchall()\\n cursor.close()\\n\\n# ProtokollLogger\\nlogger = ProtokollLogger()\\nlogger.log(LogEntry(\\n request=\\\"SELECT * FROM mcp_log\\\",\\n status=\\\"success\\\",\\n duration_ms=45\\n))<\/code><\/pre>\\n\\n<h2>Verwandte Kapitel<\/h2>\\n<ul>\\n <li><a href=\\\"\/docs\/mcp\/mcp-db-security\\\">Sicherheit<\/a> - Separate DB-User<\/li>\\n <li><a href=\\\"\/docs\/mcp\/mcp-db-contracts\\\">Contracts<\/a> - LogEntry<\/li>\\n<\/ul>\",\n \"status\": \"published\",\n \"sort_order\": 8,\n \"depth\": 2,\n \"created_at\": \"2025-12-20T11:13:58\",\n \"updated_at\": \"2025-12-20T11:13:58\"\n }\n}"
}
]
}