Protokoll #23880
| ID | 23880 |
|---|---|
| Zeitstempel | 2025-12-27 15:29:08.177886 |
| Client | root |
| IP | Warning: Undefined array key "request_ip" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13 Deprecated: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13 |
| Modell | claude-sonnet-4-20250514 |
| Status | completed |
| Tokens | 2,695 (Input: 0, Output: 0) |
| Dauer | 103 ms |
| Request-Zeit | Warning: Undefined array key "request_timestamp" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 18 |
| Response-Zeit | - |
Warning: Undefined array key "error_message" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 22
Request
{
"event": "PreToolUse",
"tool_name": "mcp__mcp-docs__docs_get",
"tool_input": {
"id": 141
}
}
Response
{
"tool_response": [
{
"type": "text",
"text": "{\n \"success\": true,\n \"doc\": {\n \"id\": 141,\n \"parent_id\": 92,\n \"slug\": \"task-completion-guard\",\n \"path\": \"\/prozesse\/claude-hooks-prozess\/task-completion-guard\",\n \"title\": \"Task-Completion Guard Hook\",\n \"description\": \"Pre-Hook zur Validierung von Task-Completion - verhindert tasks_status(completed) ohne vorheriges tasks_result()\",\n \"content\": \"<h2>Task-Completion Guard Hook<\/h2>\\n\\n<p>Pre-Hook der verhindert, dass Tasks als \\\"completed\\\" markiert werden, ohne dass vorher ein Ergebnis via <code>tasks_result()<\/code> geschrieben wurde.<\/p>\\n\\n<h3>Problem<\/h3>\\n<p>Claude ruft <code>tasks_status(id, \\\"completed\\\")<\/code> auf, ohne vorher <code>tasks_result()<\/code> zu rufen. Dies führt zu 77+ Fehlern pro Woche mit der Meldung:<\/p>\\n<pre><code>Task kann nicht abgeschlossen werden. Fehlend: Ergebnis (tasks_result)<\/code><\/pre>\\n\\n<h3>Lösung<\/h3>\\n<p>Ein PreToolUse-Hook der VOR dem MCP-Call prüft, ob ein Result existiert und bei Fehlen die Aktion blockiert.<\/p>\\n\\n<table>\\n <tr><th>Datei<\/th><td><code>\/var\/www\/tools\/ki-protokoll\/claude-hook\/task_completion_guard.py<\/code><\/td><\/tr>\\n <tr><th>Trigger<\/th><td><code>PreToolUse<\/code> mit Matcher <code>mcp__mcp-tasks__tasks_status<\/code><\/td><\/tr>\\n <tr><th>Exit-Codes<\/th><td>0 = allow, 2 = block<\/td><\/tr>\\n<\/table>\\n\\n<h3>Technische Details<\/h3>\\n\\n<h4>1. Input-Format (stdin)<\/h4>\\n<pre><code>{\\n \\\"tool_name\\\": \\\"mcp__mcp-tasks__tasks_status\\\",\\n \\\"tool_input\\\": {\\n \\\"id\\\": 425,\\n \\\"status\\\": \\\"completed\\\"\\n }\\n}<\/code><\/pre>\\n\\n<h4>2. Prüflogik<\/h4>\\n<ol>\\n <li>Parse JSON von stdin<\/li>\\n <li>Prüfe: <code>tool_name == \\\"mcp__mcp-tasks__tasks_status\\\"<\/code><\/li>\\n <li>Prüfe: <code>status == \\\"completed\\\"<\/code><\/li>\\n <li>Wenn ja: DB-Abfrage <code>SELECT COUNT(*) FROM task_results WHERE task_id = ?<\/code><\/li>\\n <li>Wenn count == 0: Block mit Exit-Code 2 + stderr-Nachricht<\/li>\\n<\/ol>\\n\\n<h4>3. Block-Nachricht<\/h4>\\n<pre><code>BLOCKIERT: Task kann nicht als 'completed' markiert werden!\\n\\nGRUND: Kein Ergebnis vorhanden (tasks_result fehlt).\\n\\nLÖSUNG: Vor tasks_status(id, \\\"completed\\\") MUSS tasks_result() aufgerufen werden:\\n\\n tasks_result(\\n id=TASK_ID,\\n response=\\\"Zusammenfassung der erledigten Arbeit...\\\",\\n executor=\\\"claude\\\",\\n executor_type=\\\"claude\\\"\\n )\\n\\nErst danach: tasks_status(id, \\\"completed\\\")<\/code><\/pre>\\n\\n<h4>4. Konfiguration in settings.json<\/h4>\\n<pre><code>{\\n \\\"PreToolUse\\\": [\\n {\\n \\\"matcher\\\": \\\"mcp__mcp-tasks__tasks_status\\\",\\n \\\"hooks\\\": [\\n {\\n \\\"type\\\": \\\"command\\\",\\n \\\"command\\\": \\\"\/var\/www\/tools\/ki-protokoll\/claude-hook\/task_completion_guard.py\\\",\\n \\\"timeout\\\": 5\\n }\\n ]\\n }\\n ]\\n}<\/code><\/pre>\\n\\n<h3>Ablauf<\/h3>\\n<pre>\\n┌─────────────────────────────┐\\n│ Claude: tasks_status( │\\n│ id=425, status=\\\"completed\\\"│\\n│ ) │\\n└─────────────┬───────────────┘\\n │\\n ▼\\n┌─────────────────────────────┐\\n│ PreToolUse Hook auslösen │\\n│ Matcher: mcp__mcp-tasks__ │\\n│ tasks_status │\\n└─────────────┬───────────────┘\\n │\\n ▼\\n┌─────────────────────────────┐\\n│ task_completion_guard.py │\\n│ - Parse Input │\\n│ - Check: status==\\\"completed\\\"│\\n└─────────────┬───────────────┘\\n │\\n ┌──────┴──────┐\\n │ │\\n ▼ ▼\\n┌─────────────┐ ┌─────────────┐\\n│ status != │ │ status == │\\n│ \\\"completed\\\" │ │ \\\"completed\\\" │\\n└──────┬──────┘ └──────┬──────┘\\n │ │\\n ▼ ▼\\n┌─────────────┐ ┌─────────────────┐\\n│ exit(0) │ │ DB-Check: │\\n│ → Allow │ │ task_results │\\n└─────────────┘ │ WHERE task_id=? │\\n └────────┬────────┘\\n │\\n ┌──────┴──────┐\\n │ │\\n ▼ ▼\\n ┌──────────┐ ┌──────────┐\\n │ count > 0│ │ count = 0│\\n └────┬─────┘ └────┬─────┘\\n │ │\\n ▼ ▼\\n ┌─────────┐ ┌─────────────┐\\n │ exit(0) │ │ stderr: │\\n │ → Allow │ │ BLOCKIERT │\\n └─────────┘ │ exit(2) │\\n │ → Block │\\n └─────────────┘\\n<\/pre>\\n\\n<h3>Implementierungsplan<\/h3>\\n\\n<h4>Schritt 1: Hook-Script erstellen<\/h4>\\n<p>Datei: <code>\/var\/www\/tools\/ki-protokoll\/claude-hook\/task_completion_guard.py<\/code><\/p>\\n<pre><code>#!\/usr\/bin\/env python3\\n\\\"\\\"\\\"\\nTask Completion Guard Hook\\n\\nBlockiert tasks_status(completed) wenn kein Result existiert.\\nErzwingt korrekten Workflow: tasks_result() vor tasks_status(completed).\\n\\nTrigger: PreToolUse (mcp__mcp-tasks__tasks_status)\\n\\\"\\\"\\\"\\n\\nimport json\\nimport sys\\nimport os\\nfrom pathlib import Path\\nfrom dotenv import load_dotenv\\nimport pymysql\\n\\n# Lade Environment aus .env im Hook-Verzeichnis\\nload_dotenv(Path(__file__).parent \/ '.env')\\n\\nDB_CONFIG = {\\n 'host': os.environ.get('CLAUDE_DB_HOST', 'localhost'),\\n 'port': int(os.environ.get('CLAUDE_DB_PORT', '3306')),\\n 'user': os.environ.get('CLAUDE_DB_USER', 'root'),\\n 'password': os.environ.get('CLAUDE_DB_PASSWORD', ''),\\n 'database': 'ki_dev',\\n 'charset': 'utf8mb4'\\n}\\n\\nBLOCK_MESSAGE = \\\"\\\"\\\"BLOCKIERT: Task kann nicht als 'completed' markiert werden!\\n\\nGRUND: Kein Ergebnis vorhanden (tasks_result fehlt).\\n\\nLÖSUNG: Vor tasks_status(id, \\\"completed\\\") MUSS tasks_result() aufgerufen werden:\\n\\n tasks_result(\\n id={task_id},\\n response=\\\"Zusammenfassung der erledigten Arbeit...\\\",\\n executor=\\\"claude\\\",\\n executor_type=\\\"claude\\\"\\n )\\n\\nErst danach: tasks_status({task_id}, \\\"completed\\\")\\\"\\\"\\\"\\n\\n\\ndef check_result_exists(task_id: int) -> bool:\\n \\\"\\\"\\\"Prüft ob ein Result für den Task existiert.\\\"\\\"\\\"\\n try:\\n conn = pymysql.connect(**DB_CONFIG)\\n cursor = conn.cursor()\\n cursor.execute(\\n \\\"SELECT COUNT(*) FROM task_results WHERE task_id = %s\\\",\\n (task_id,)\\n )\\n count = cursor.fetchone()[0]\\n conn.close()\\n return count > 0\\n except Exception as e:\\n # Bei DB-Fehler durchlassen (fail-open)\\n print(f\\\"DB-Check fehlgeschlagen: {e}\\\", file=sys.stderr)\\n return True\\n\\n\\ndef main():\\n try:\\n input_data = json.load(sys.stdin)\\n except json.JSONDecodeError:\\n sys.exit(0)\\n \\n # Nur mcp__mcp-tasks__tasks_status prüfen\\n tool_name = input_data.get(\\\"tool_name\\\", \\\"\\\")\\n if tool_name != \\\"mcp__mcp-tasks__tasks_status\\\":\\n sys.exit(0)\\n \\n # Prüfe ob Status auf \\\"completed\\\" gesetzt wird\\n tool_input = input_data.get(\\\"tool_input\\\", {})\\n status = tool_input.get(\\\"status\\\", \\\"\\\")\\n task_id = tool_input.get(\\\"id\\\")\\n \\n if status.lower() != \\\"completed\\\":\\n sys.exit(0)\\n \\n if not task_id:\\n sys.exit(0)\\n \\n # Prüfe ob Result existiert\\n if not check_result_exists(task_id):\\n print(BLOCK_MESSAGE.format(task_id=task_id), file=sys.stderr)\\n sys.exit(2)\\n \\n sys.exit(0)\\n\\n\\nif __name__ == \\\"__main__\\\":\\n main()\\n<\/code><\/pre>\\n\\n<h4>Schritt 2: Script ausführbar machen<\/h4>\\n<pre><code>chmod +x \/var\/www\/tools\/ki-protokoll\/claude-hook\/task_completion_guard.py<\/code><\/pre>\\n\\n<h4>Schritt 3: settings.json erweitern<\/h4>\\n<p>Datei: <code>\/root\/.claude\/settings.json<\/code><\/p>\\n<p>Füge folgenden Eintrag in \\\"PreToolUse\\\" Array hinzu:<\/p>\\n<pre><code>{\\n \\\"matcher\\\": \\\"mcp__mcp-tasks__tasks_status\\\",\\n \\\"hooks\\\": [\\n {\\n \\\"type\\\": \\\"command\\\",\\n \\\"command\\\": \\\"\/var\/www\/tools\/ki-protokoll\/claude-hook\/task_completion_guard.py\\\",\\n \\\"timeout\\\": 5\\n }\\n ]\\n}<\/code><\/pre>\\n\\n<h4>Schritt 4: Testen<\/h4>\\n<pre><code># Test 1: Task ohne Result → sollte blockiert werden (Exit 2)\\necho '{\\\"tool_name\\\":\\\"mcp__mcp-tasks__tasks_status\\\",\\\"tool_input\\\":{\\\"id\\\":999,\\\"status\\\":\\\"completed\\\"}}' | \\\\\\n \/var\/www\/tools\/ki-protokoll\/claude-hook\/task_completion_guard.py\\necho \\\"Exit code: $?\\\"\\n\\n# Test 2: Anderer Status → sollte durchgelassen werden (Exit 0)\\necho '{\\\"tool_name\\\":\\\"mcp__mcp-tasks__tasks_status\\\",\\\"tool_input\\\":{\\\"id\\\":999,\\\"status\\\":\\\"in_progress\\\"}}' | \\\\\\n \/var\/www\/tools\/ki-protokoll\/claude-hook\/task_completion_guard.py\\necho \\\"Exit code: $?\\\"\\n\\n# Test 3: Anderes Tool → sollte durchgelassen werden (Exit 0)\\necho '{\\\"tool_name\\\":\\\"Bash\\\",\\\"tool_input\\\":{\\\"command\\\":\\\"ls\\\"}}' | \\\\\\n \/var\/www\/tools\/ki-protokoll\/claude-hook\/task_completion_guard.py\\necho \\\"Exit code: $?\\\"\\n<\/code><\/pre>\\n\\n<h3>Voraussetzungen<\/h3>\\n<ul>\\n <li>Python 3.x<\/li>\\n <li>PyMySQL (bereits installiert: <code>pip3 install pymysql<\/code>)<\/li>\\n <li>python-dotenv (bereits installiert)<\/li>\\n <li>Zugriff auf ki_dev.task_results<\/li>\\n <li>.env Datei im Hook-Verzeichnis mit DB-Credentials<\/li>\\n<\/ul>\\n\\n<h3>Fail-Safe Verhalten<\/h3>\\n<p>Bei DB-Verbindungsfehlern wird der Hook \\\"fail-open\\\" - d.h. die Aktion wird durchgelassen, um Claude nicht zu blockieren. Die Server-seitige Validierung in MCP-Tasks greift dann als zweite Verteidigung.<\/p>\\n\\n<h3>Validierung<\/h3>\\n<table>\\n <tr><th>Prüfpunkt<\/th><th>Status<\/th><\/tr>\\n <tr><td>PyMySQL verfügbar<\/td><td>✓ PyMySQL 1.1.2 installiert<\/td><\/tr>\\n <tr><td>python-dotenv Pattern<\/td><td>✓ Konsistent mit log_storage.py<\/td><\/tr>\\n <tr><td>DB_CONFIG Pattern<\/td><td>✓ Identisch zu bestehenden Hooks<\/td><\/tr>\\n <tr><td>Exit-Code Pattern<\/td><td>✓ 0=allow, 2=block (wie block_direct_db.py)<\/td><\/tr>\\n <tr><td>Matcher-Syntax<\/td><td>✓ Regex-kompatibel für MCP-Tools<\/td><\/tr>\\n <tr><td>Fail-Open Design<\/td><td>✓ Bei Fehler durchlassen<\/td><\/tr>\\n<\/table>\\n\",\n \"status\": \"published\",\n \"sort_order\": 6,\n \"depth\": 2,\n \"created_at\": \"2025-12-27T10:08:47\",\n \"updated_at\": \"2025-12-27T15:19:06\"\n }\n}"
}
]
}