Build This Now
Build This Now
TastenkürzelStatus Line Guide
Hooks-LeitfadenPlattformübergreifende Hooks für Claude CodeClaude Code Setup-HooksStop HooksSelbstvalidierende Claude Code AgentenClaude Code Session-HooksKontext-Backup-Hooks für Claude CodeSkill-Aktivierungs-HookClaude Code Permission-HookMCP Tool Hooks in Claude CodeCommands to Skills
Skills, Subagents, HooksSubagent Sweet SpotClaude Code vs CursorCLAUDE.md Best PracticesFix Context LimitSpec-Driven DevRules Into Patterns
speedy_devvkoen_salo
Blog/Toolkit/Hooks/MCP Tool Hooks

MCP Tool Hooks in Claude Code

Wie du MCP-Server-Tools direkt aus Claude Code Hooks aufrufst mit type: mcp_tool — Schema, Substitutions-Syntax, Anwendungsfälle und Produktionsmuster.

Sie möchten das Framework hinter diesen Projekten?

Holen Sie sich das Claude Code System, mit dem wir produktionsreife Software planen, bauen, testen und ausliefern.

Sehen Sie, was wir für Unternehmen bauen →
speedy_devvkoen_salo
speedy_devvWritten by speedy_devvPublished Apr 24, 20269 min readToolkit hubHooks index

Problem: Deine Hooks laufen als Shell-Skripte. Jedes Mal, wenn ein Hook einen MCP-Server aufrufen muss, startet er einen Subprozess, richtet den Transport ein, handhabt Auth, parsed die Antwort und formatiert JSON-Output zurück an stdout. Für einen Formatter oder einen Security-Check, der bei jedem File-Write feuert, summiert sich das.

Quick Win: Ab v2.1.118 haben Hooks einen neuen Typ, der MCP-Tools direkt aufruft. Füge das zu .claude/settings.json hinzu, um nach jedem File-Write einen Security-Scan zu starten, ganz ohne Subprozess:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "mcp_tool",
            "server": "semgrep",
            "tool": "scan_file",
            "input": { "path": "${tool_input.file_path}" }
          }
        ]
      }
    ]
  }
}

Der MCP-Server läuft bereits. Der Hook überspringt die Shell komplett und ruft direkt die RPC-Verbindung des Servers auf. Der Text-Output des Tools läuft durch denselben JSON-Decision-Parser wie jeder Command-Hook.

Was type: "mcp_tool" eigentlich ist

Vor v2.1.118 gab es vier Handler-Typen für Hooks: command, http, prompt und agent. Jetzt sind es fünf:

TypWas läuft
commandShell-Subprozess (stdin/stdout)
httpPOST an einen URL-Endpunkt
mcp_toolDirekter RPC-Call an einen verbundenen MCP-Server
promptSingle-Turn LLM-Auswertung (Haiku als Standard)
agentMulti-Turn-Subagent mit Read/Grep/Glob-Zugriff

mcp_tool funktioniert bei jedem Hook-Event, genau wie command und http. Ein praktischer Vorbehalt: SessionStart und Setup feuern, während Server noch verbinden, daher kann es beim ersten Lauf zu einem "server not connected"-Fehler kommen. Folgeläufe funktionieren problemlos.

Das vollständige Schema

Drei Felder sind spezifisch für mcp_tool-Hooks. Der Rest wird mit allen Hook-Typen geteilt:

{
  "type": "mcp_tool",
  "server": "my-mcp-server",
  "tool": "tool_name",
  "input": {
    "arg1": "${tool_input.file_path}",
    "arg2": "${session_id}"
  },
  "timeout": 30,
  "statusMessage": "Checking...",
  "if": "Edit(*.ts|*.tsx)"
}
FeldPflichtBeschreibung
serverJAExakter Name des MCP-Servers, wie in den Settings konfiguriert
toolJATool-Name auf diesem Server
inputneinArgumente, die an das Tool übergeben werden. Unterstützt ${path}-Substitution
timeoutneinSekunden, bevor der Hook abgebrochen wird
statusMessageneinSpinner-Text, der während der Hook läuft angezeigt wird
ifneinPermission-Rule-Syntax-Filter. Hook feuert nur, wenn der vollständige Call übereinstimmt

Wichtig: server muss exakt mit dem Server-Namen in deiner MCP-Konfiguration übereinstimmen. Ein einziges falsches Zeichen und der Hook schlägt lautlos mit einem nicht-blockierenden Fehler fehl.

Input-Substitution

String-Werte in input unterstützen ${field.path}-Dot-Notation in das vollständige Event-JSON des Hooks. Für einen PostToolUse-Hook bei einem Write-Call sieht das Event-JSON so aus:

{
  "session_id": "abc123",
  "cwd": "/your/project",
  "hook_event_name": "PostToolUse",
  "tool_name": "Write",
  "tool_use_id": "toolu_01...",
  "tool_input": {
    "file_path": "/your/project/src/api.ts",
    "content": "..."
  },
  "tool_response": { "filePath": "/your/project/src/api.ts", "success": true },
  "duration_ms": 142
}

"${tool_input.file_path}" löst sich also zu /your/project/src/api.ts auf. Jedes Feld in diesem Objekt ist erreichbar. Das duration_ms-Feld wurde in v2.1.119 hinzugefügt, eine Version nach mcp_tool.

Wie der Output verarbeitet wird

Der Text-Content des MCP-Tools wird genauso behandelt wie der stdout eines Command-Hooks. Wenn er als valides JSON geparst werden kann, handelt Claude Code entsprechend der Decision-Felder. Wenn nicht, wird der Text zu Kontext für Claude.

Die Decision-Felder funktionieren genauso wie bei jedem anderen Hook:

{
  "decision": "block",
  "reason": "Security issue found in src/api.ts: SQL injection risk on line 42."
}

Gibt ein PostToolUse-MCP-Tool-Hook das zurück, bekommt Claude die Meldung und korrigiert die Datei. Das Tool hat schon ausgeführt, daher ist das beratend, nicht präventiv. Für echtes Blockieren vor einem Tool-Run nutze PreToolUse und gib permissionDecision: "deny" zurück.

Ein Feld ist exklusiv für mcp_tool-Hooks bei PostToolUse: updatedMCPToolOutput. Es ersetzt, was Claude als Output des Tools sieht, bevor es in die Konversation eingeht. Ein laufender MCP-Server kann das Ergebnis eines anderen Tools nachbearbeiten, bevor Claude es liest.

Warum das besser ist als Shell-Command-Hooks

Zwei konkrete Unterschiede, nicht nur Geschwindigkeit.

Stateful Server. Ein Shell-Subprozess startet jedes Mal neu. Ein MCP-Server ist ein lebendiger Prozess mit eigenem Zustand: geladene Configs, offene Verbindungen, Caches, akkumulierter Session-Kontext. Ein Linting-MCP, das dein tsconfig.json beim Start geparst hat, parst es nicht bei jedem File-Write neu. Ein Command-Hook schon.

Keine Shell-Umgebungs-Abhängigkeit. Command-Hooks schlagen lautlos fehl, wenn PATH falsch ist, wenn jq nicht installiert ist, wenn ~/.zshrc etwas nach stdout ausgibt bei nicht-interaktiven Shells. MCP-Tool-Hooks umgehen das alles. Der Call geht direkt von Claude Code zum Server über die bestehende RPC-Verbindung.

Das if-Feld: Hooks eingrenzen

Ohne if feuert ein Hook bei jedem Event, das zum matcher passt. Mit if startet der Hook-Prozess nur, wenn der vollständige Tool-Call (Name und Argumente) der Permission-Rule-Syntax entspricht:

{
  "type": "mcp_tool",
  "server": "semgrep",
  "tool": "scan_file",
  "if": "Edit(*.py|*.ts|*.js)",
  "input": { "path": "${tool_input.file_path}" }
}

Dieser Hook läuft nie auf .md- oder .json-Dateien. Bei einem Projekt mit vielen Doku-Edits macht das einen echten Performance-Unterschied.

Muster 1: Security-Scan bei jedem Write

Ein Security-MCP-Server, der einen Dateipfad akzeptiert und Findings zurückgibt. Claude blockieren, wenn er etwas findet:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "mcp_tool",
            "server": "semgrep",
            "tool": "scan_file",
            "if": "Write(*.ts|*.py|*.js|*.go)",
            "input": { "path": "${tool_input.file_path}" },
            "statusMessage": "Scanning..."
          }
        ]
      }
    ]
  }
}

Wenn das MCP-Tool ein Finding zurückgibt, strukturiere die Antwort so:

{
  "decision": "block",
  "reason": "Semgrep finding: [description of issue at line N]"
}

Claude bekommt die Block-Meldung und überarbeitet die Datei. Der Scan läuft auf dem gecachten Ruleset des Servers, nicht auf einem frisch gestarteten Subprozess-Parse.

Muster 2: Stop-Hook mit externer Verifizierung

Ein Stop-Hook, der ein Linear- oder Jira-MCP aufruft, um zu prüfen, ob das zugehörige Ticket wirklich geschlossen ist, bevor Claude "fertig" meldet:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "mcp_tool",
            "server": "linear",
            "tool": "get_issue_status",
            "input": { "issue_id": "${tool_input.issue_id}" }
          }
        ]
      }
    ]
  }
}

Das MCP-Tool gibt den Ticket-Status zurück. Kommt In Progress zurück, sollte das Response-JSON decision: "block" und einen Grund tragen. Claude arbeitet weiter.

Überprüfe immer stop_hook_active in deiner Stop-Hook-Logik. Das Event-JSON enthält dieses Feld als "true", wenn Claude bereits aus einem vorherigen Stop-Hook-Aufruf heraus weiterläuft. Ein Server, der das nicht prüft, erzeugt eine Endlosschleife. Baue die Absicherung direkt ins MCP-Tool ein: Wenn stop_hook_active im Input "true" ist, leere Ausgabe zurückgeben und sauber beenden.

Muster 3: Production-Error-Check vor dem Stoppen

Nachdem Claude ein Feature fertiggestellt hat, prüfen, ob in Staging etwas Neues kaputt gegangen ist, bevor die Session als abgeschlossen gilt. Ein Sentry-MCP übernimmt die Abfrage:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "mcp_tool",
            "server": "sentry",
            "tool": "get_new_errors_since",
            "input": { "minutes": "5", "skip_if_active": "${stop_hook_active}" }
          }
        ]
      }
    ]
  }
}

Wenn in den letzten fünf Minuten neue Fehler aufgetaucht sind, gibt das MCP-Tool sie zusammen mit decision: "block" zurück. Claude liest die Fehlerdetails und behebt die Regression, bevor es stoppt.

Muster 4: Docs automatisch vor jedem Prompt laden

Ein UserPromptSubmit-Hook mit einem Context7-MCP holt aktuelle Dokumentation für jede im Prompt erwähnte Library, bevor Claude ihn verarbeitet:

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "mcp_tool",
            "server": "context7",
            "tool": "get_library_docs",
            "input": { "prompt": "${prompt}" },
            "timeout": 15
          }
        ]
      }
    ]
  }
}

Früher musste Claude das MCP-Tool explizit aufrufen. Jetzt passiert es bei jedem Prompt automatisch. Claude startet mit aktuellen Docs statt mit Trainingsdaten.

Muster 5: Policy-Enforcement für Agent-Teams

Bei Multi-Agent-Workflows kann ein gemeinsamer Policy-MCP-Server durchsetzen, welcher Agent in welche Verzeichnisse schreiben darf. Die Umgebungsvariable CLAUDE_AGENT_NAME identifiziert den aktuellen Agenten. Ein PreToolUse-Hook ruft den Policy-Server auf:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "mcp_tool",
            "server": "policy-server",
            "tool": "check_write_permission",
            "input": {
              "agent": "${agent_name}",
              "path": "${tool_input.file_path}"
            }
          }
        ]
      }
    ]
  }
}

Der Policy-Server hält die vollständige Autorisierungs-Map. Den Server einmal aktualisieren und jeder Agent in jedem Projekt erbt die neuen Regeln, ohne eine einzige settings.json anzufassen.

Muster 6: MCP-Tool-Hooks im Agent-Frontmatter

Hooks müssen nicht in settings.json leben. Sie können im YAML-Frontmatter eines Agenten stehen, auf den Lebenszyklus dieses Agenten beschränkt:

---
name: backend-developer
description: Builds API endpoints and database logic
hooks:
  PostToolUse:
    - matcher: "Write"
      hooks:
        - type: mcp_tool
          server: semgrep
          tool: scan_file
          input: { "path": "${tool_input.file_path}" }
  Stop:
    - hooks:
        - type: agent
          prompt: "Verify all API endpoints have corresponding tests. Block if any are missing."
---

Jeder Spezialist-Agent in einem orchestrierten Team trägt seine eigene Validierungslogik. Der Backend-Agent scannt auf Security-Probleme. Der Frontend-Agent prüft Accessibility. Keiner braucht einen globalen Hook, der für alle gilt.

Elicitation-Steuerung

Das Elicitation-Event feuert, wenn ein MCP-Server während einer Aufgabe Nutzereingaben anfordert. Ein mcp_tool-Hook kann bekannte Prompts automatisch beantworten, indem er einen Secrets-Manager aufruft:

{
  "hooks": {
    "Elicitation": [
      {
        "matcher": "my-db-server",
        "hooks": [
          {
            "type": "mcp_tool",
            "server": "secrets-manager",
            "tool": "get_credential",
            "input": { "key": "${elicitation.field_name}" }
          }
        ]
      }
    ]
  }
}

Vorhersehbare Credential-Prompts lösen sich automatisch auf. Die Aufgabe läuft ohne Unterbrechung durch.

MCP-Server, die gut zu Hooks passen

Nicht jeder MCP-Server eignet sich als Hook-Ziel. Am besten geeignet sind Tools, die bei bestimmten Events ohne User-Eingriff feuern müssen:

ServerEventWas er tut
SemgrepPostToolUse: WriteSecurity-Scan bei jedem Write
SentryStopNeue Staging-Fehler prüfen vor dem Abschluss
Linear / JiraStop, TaskCompletedTicket-Status prüfen, bei Abschluss aktualisieren
Context7UserPromptSubmitAktuelle Docs für erwähnte Libraries automatisch laden
ElevenLabsStop, NotificationTTS-Audio bei Aufgabenabschluss
SlackNotification, StopTeam-Alerts ohne curl-Boilerplate
E2BStopGenerierte Skripte in einer Sandbox ausführen vor dem Abschluss
claude-memPostCompact, SessionStartSession-Kontext nach Compaction wiederherstellen
n8nTaskCompletedExternen Workflow bei Abschluss triggern

Bekanntes Problem: PostToolUse + MCP-Events + additionalContext

Es gibt einen offenen Bug (GitHub Issue #24788), bei dem additionalContext von Hooks stillschweigend verworfen wird, wenn das auslösende Event ein MCP-Tool-Call war. Das betrifft type: "command"-Hooks, die auf MCP-Tool-Events reagieren, nicht mcp_tool-Hooks selbst.

Der Unterschied ist wichtig: Hooks, die MCP-Aufrufe SIND, funktionieren einwandfrei. Hooks, die AUF MCP-Tool-Calls REAGIEREN und additionalContext zurückgeben, tun es nicht. Der Workaround ist exit 2 plus stderr für kritische Meldungen aus PostToolUse-Hooks, die auf MCP-Tool-Calls zielen. Das Blocking-Pattern funktioniert; Advisory-Injection tut es nicht.

MCP-Tool-Hooks sind das letzte fehlende Stück

Vorher waren Hooks ein Sicherheitsnetz. Shell-Befehle, die gefährliche Dinge blockieren oder Formatter ausführen konnten. Zustandslos, prozesslokal, von allem getrennt, was deine MCP-Server bereits wissen.

Danach: Hooks sind eine deterministische Orchestrierungsschicht. Jedes Event, jedes MCP-Tool, volle Decision-Kontrolle, mit Zustand, der über Calls hinweg erhalten bleibt, und kein Subprozess-Overhead.

Die Pipeline ist jetzt vollständig. PreToolUse validiert. PostToolUse formatiert und scannt. PostToolBatch führt Tests aus. Stop verifiziert mit echten externen Daten. Jeder Schritt kann ein MCP-Tool-Aufruf sein, und keiner davon braucht ein Shell-Skript.

Continue in Hooks

  • Slash Commands Are Now Skills: Migrating Commands to Skills
    Claude Code slash commands and skills now do the same thing. Here is how to migrate .claude/commands to .claude/skills and why it pays off.
  • Claude Code Setup-Hooks
    Verknüpfe Skripte, Agenten und Docs in Claude Code Setup-Hooks. Ein Befehl führt ein deterministisches Skript aus, übergibt die Ausgabe an einen diagnostizierenden Agenten und protokolliert lebendige Dokumentation.
  • Kontext-Backup-Hooks für Claude Code
    Ein StatusLine-gesteuerter Claude Code Kontext-Backup-Hook. Schreibt strukturierte Snapshots alle 10K Tokens, damit die Auto-Komprimierung nie Fehler, Signaturen und Entscheidungen verschluckt.
  • Plattformübergreifende Hooks für Claude Code
    Plattformübergreifende Claude Code Hooks: Vermeide .cmd-, .sh- und .ps1-Wrapper und rufe node direkt auf, damit eine .mjs-Datei auf macOS, Linux und Windows im Team funktioniert.
  • Hooks-Leitfaden
    Claude Code Hooks von Grund auf: Exit-Codes, JSON-Ausgabe, asynchrone Befehle, HTTP-Endpunkte, PreToolUse- und PostToolUse-Matcher, Produktionsmuster.
  • Claude Code Permission-Hook
    Installiere einen dreistufigen Claude Code Permission-Hook: sofortiges Allow für sichere Aufrufe, sofortiges Deny für gefährliche, LLM-Check für die Grauzone. Kein Skip-Flag.

More from Toolkit

  • CLAUDE.md, Skills, Subagents, Hooks: When to Use Which
    Claude Code skills vs subagents vs hooks vs CLAUDE.md: a plain mental model for picking the right primitive, with token costs and examples.
  • Claude Code Subagents: The 3 to 5 Agent Sweet Spot
    Claude code subagents work best at 3-5 concurrent agents. Here is why that ceiling exists, how to set them up, and what to use past it.
  • Claude Code vs Cursor in 2026: Which Ships Faster?
    Claude Code vs Cursor in 2026: which ships faster? A benchmark-backed breakdown of terminal agent vs IDE, token cost, and how to ship a whole SaaS.
  • CLAUDE.md Best Practices: The File That Makes Claude Code Reliable
    CLAUDE.md best practices: keep it under 200 lines, write it by hand, and use hooks when you need real enforcement, not advice.

Sie möchten das Framework hinter diesen Projekten?

Holen Sie sich das Claude Code System, mit dem wir produktionsreife Software planen, bauen, testen und ausliefern.

Sehen Sie, was wir für Unternehmen bauen →
speedy_devvkoen_salo

Claude Code Permission-Hook

Installiere einen dreistufigen Claude Code Permission-Hook: sofortiges Allow für sichere Aufrufe, sofortiges Deny für gefährliche, LLM-Check für die Grauzone. Kein Skip-Flag.

Commands to Skills

Claude Code slash commands and skills now do the same thing. Here is how to migrate .claude/commands to .claude/skills and why it pays off.

On this page

Was type: "mcp_tool" eigentlich ist
Das vollständige Schema
Input-Substitution
Wie der Output verarbeitet wird
Warum das besser ist als Shell-Command-Hooks
Das if-Feld: Hooks eingrenzen
Muster 1: Security-Scan bei jedem Write
Muster 2: Stop-Hook mit externer Verifizierung
Muster 3: Production-Error-Check vor dem Stoppen
Muster 4: Docs automatisch vor jedem Prompt laden
Muster 5: Policy-Enforcement für Agent-Teams
Muster 6: MCP-Tool-Hooks im Agent-Frontmatter
Elicitation-Steuerung
MCP-Server, die gut zu Hooks passen
Bekanntes Problem: PostToolUse + MCP-Events + additionalContext
MCP-Tool-Hooks sind das letzte fehlende Stück

Sie möchten das Framework hinter diesen Projekten?

Holen Sie sich das Claude Code System, mit dem wir produktionsreife Software planen, bauen, testen und ausliefern.

Sehen Sie, was wir für Unternehmen bauen →