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 Code
speedy_devvkoen_salo
Blog/Toolkit/Hooks/MCP Tool Hooks in Claude Code

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.

Hören Sie auf zu konfigurieren. Fangen Sie an zu bauen.

SaaS-Builder-Vorlagen mit KI-Orchestrierung.

Published 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

  • 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.
  • Selbstvalidierende Claude Code Agenten
    Selbstvalidierende Claude Code Agenten: PostToolUse-Lint-Hooks, Stop-Hooks und schreibgeschützte Reviewer-Subagenten in Agentendefinitionen verdrahten, damit fehlerhafte Ausgaben nie ausgeliefert werden.

More from Toolkit

  • Tastenkürzel
    Claude Code keybindings.json konfigurieren: 17 Kontexte, Tastenkombinations-Syntax, Chord-Sequenzen, Modifier-Kombinationen und wie du jeden Standard-Shortcut sofort deaktivierst.
  • Status Line Guide
    Richte eine Claude Code Status Line ein, die Modellname, Git-Branch, Sitzungskosten und Kontextnutzung anzeigt. settings.json-Konfiguration, JSON-Eingabe, Bash-, Python- und Node.js-Skripte.
  • KI-SEO und GEO-Optimierung
    Ein Überblick über Generative Engine Optimization: Wie du dafür sorgst, dass deine Inhalte in ChatGPT-, Claude- und Perplexity-Antworten zitiert werden, statt nur bei Google zu ranken.
  • Claude Code vs Cursor in 2026
    Ein direkter Vergleich von Claude Code und Cursor in 2026: Agentenmodelle, Kontextfenster, Preisstufen und welches Tool zu welchem Entwickler-Workflow passt.

Hören Sie auf zu konfigurieren. Fangen Sie an zu bauen.

SaaS-Builder-Vorlagen mit KI-Orchestrierung.

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

Hören Sie auf zu konfigurieren. Fangen Sie an zu bauen.

SaaS-Builder-Vorlagen mit KI-Orchestrierung.