Blog
CRM-Hooks: wenn Claude Code beim Kunden-Namen automatisch den CRM zieht
Zwei mcp_tool Hooks für den StudioMeyer CRM MCP. UserPromptSubmit zieht Kontext zum Kunden, PostToolUse loggt automatisch jeden E-Mail-Draft. Zahlen aus zehn Tagen Realbetrieb.
19. Mai 2026
Letzten Montag schickte ich einem Kunden eine E-Mail. Drei Stunden später rief mich der gleiche Kunde an, ich war im Schreibmodus, hatte den Namen lose im Kopf, und Claude Code sass daneben mit voller Session. Was fehlte: der Kontext. Welche Angebote er schon hatte. Wann das letzte Telefonat war. Welche Preisspanne wir besprochen hatten. Alles in der CRM-DB, aber zwei Tabs entfernt.
Seit zehn Tagen laeuft das anders. Zwei `mcp_tool` Hooks in meiner `~/.claude/settings.json`, einer auf `UserPromptSubmit`, einer auf `PostToolUse`. Der CRM zieht sich selbst rein wenn ich einen Kundennamen tippe. Und jeder E-Mail-Entwurf den ich schreibe wird automatisch als Interaktion geloggt.
Erzaehl ich dir wie das praktisch aussieht, was es kostet, und wo ich mir selbst ins Knie geschossen hab.
## Hook eins, UserPromptSubmit auf den CRM
Die Idee ist simpel. Wenn ich einen Prompt absende der einen Kundennamen enthaelt, soll Claude Code automatisch `crm_search` aufrufen, das Ergebnis als `additionalContext` injizieren, und erst dann antworten. Kein "moment, ich brauche den Hintergrund". Kein eigenes `nex_search` triggern. Es ist einfach schon da.
Konfiguration ist drei Zeilen JSON. Event ist `UserPromptSubmit`, type ist `mcp_tool`, server ist `mcp-crm`, tool ist `crm_search`. Timeout setze ich auf 8 Sekunden, das ist grosszuegig für ein Postgres Lookup über einen warmen MCP-Server.
In zehn Tagen habe ich 142 Prompts abgesetzt. 38 davon enthielten einen erkennbaren Kundennamen (das macht der Server selbst, Regex auf bekannte Aliase). Bei 36 von 38 lief der Hook durch. Median-Latenz 290 Millisekunden. Die zwei Failures waren beide das gleiche, Server war nach drei Tagen Idle eingeschlafen und brauchte 11 Sekunden zum Aufwaermen, das hat der Timeout gekillt.
Was sich an der Praxis ändert: ich tippe "schick Nina noch das Angebot für Q3", und Claude Code hat schon im Kontext welches Angebot offen ist, welche Stueckzahl, welches Lieferdatum besprochen war. Das spart pro Mail vielleicht zwei Minuten Tippen plus die Tab-Wechsel-Friktion die ich sonst nie gemessen habe aber die mich permanent rausriss.
## Hook zwei, PostToolUse auf E-Mail-Drafts
Der zweite Hook ist subtiler. Event ist `PostToolUse`, Matcher ist `Edit|Write`, und der MCP-Tool-Call ist `crm_log_interaction`. Trigger-Bedingung: das geschriebene File matcht `*.eml` oder `mails/*.md`. Mein Workflow ist eml-Drafts in `~/drafts/mails/` ablegen, von dort kopiere ich in Apple Mail oder Brevo.
Was der Hook tut: er liest den `to:` Header oder die erste `An:` Zeile, matcht gegen die CRM-Kontakte, und logged einen Interaction-Eintrag mit Typ `email_drafted`, Snippet der ersten 200 Zeichen, und Timestamp. Idempotent über Hash, doppeltes Speichern beim Datei-Edit ist NOOP.
In zehn Tagen 23 Drafts geschrieben. 19 davon hatten einen erkennbaren Empfaenger im CRM, 19 wurden geloggt. Vier waren Mails an Fremde (Cold-Outreach), die wurden uebersprungen ohne Error. Das ist das Verhalten das ich wollte, ich will keinen CRM-Eintrag für jeden Erstkontakt der vielleicht nie wieder antwortet.
## Wo ich mir ins Knie geschossen hab
Failure eins, am dritten Tag. Ich hatte den `UserPromptSubmit` Hook mit `timeout: 2` konfiguriert. Klang nach guter Idee, schnelle Reaktion. War keine. Bei jedem zweiten Prompt feuerte der Hook ins Leere weil der MCP-Server bei einer Postgres-Connection mal 2.3 Sekunden brauchen kann wenn der Pool kalt ist. Resultat: stille Failures, der `additionalContext` kam nicht, und ich merkte erst nach drei Stunden dass Claude wieder ohne Kontext antwortete. Auf 8 Sekunden hoch und das Problem war weg.
Failure zwei, am siebten Tag. Mein `PostToolUse` Hook loggte einen Interaction-Eintrag für einen `Edit` auf einer Datei die zufaellig `notes-nina.md` hiess und null mit E-Mail zu tun hatte. Die Bedingung "matcht *.eml oder mails/*.md" war zu locker, weil ich noch eine globale Klammer drum hatte die alles auf `*-{name}.md` weiterleitete. Hab die Bedingung enger gezogen, jetzt nur noch absolute Pfade unter `~/drafts/mails/`. Drei falsche Eintraege musste ich aus dem CRM loeschen.
Beide Failures sind das gleiche Pattern. Hook-Konfiguration ist Code, und Code braucht Tests. Ich hatte keine. Ein einfacher Trockenlauf mit `claude --dry-run` haette beides erwischt, aber ich war zu schnell mit Push to prod, auch wenn prod hier mein eigener Laptop ist.
## Was ich mit den Daten mache
Die `crm_log_interaction` Eintraege fuettern eine Wochen-Heatmap die ich Sonntags anschaue. Welche Kunden hatten in den letzten sieben Tagen Email-Kontakt, welche nicht. Das ist nicht revolutionaer, ein anstaendiger CRM hat das ohnehin. Aber: vorher waren die Eintraege ein manueller Aufwand den ich in 4 von 10 Faellen vergessen hatte. Jetzt sind sie automatisch und vollständig, und die Heatmap zeigt echte Realitaet, nicht "was ich noch dokumentiert hab".
Cross-Effekt: weil der `UserPromptSubmit` Hook den Kundenkontext immer mitzieht, sind meine Mail-Drafts inhaltlich praeziser. Das laesst sich nicht in einer Zahl ausdruecken, aber die Antwort-Rate auf Nachfass-Mails ist von gefuehlt drei Tagen auf gefuehlt einen Tag runter. Kann auch Zufall sein bei 23 Mails, ich behaupte hier keine Statistik, nur einen Eindruck.
## Was als naechstes
Drei Recipes warten. Eine für GEO-Check auf Markdown-Edits, eine für Crew-Persona-Activation beim Session-Start, eine für Memory-Suche bei Trigger-Phrasen. Wenn du erstmal selber mit Hooks anfangen willst und noch nicht weisst wo: das [Lesson L4-10 mcp-tool-hooks](/levels/4/mcp-tool-hooks) erklaert den Pattern-Wechsel, und das [Playbook hooks-gegen-halluzinationen](/playbooks/hooks-gegen-halluzinationen) zeigt den anderen Use-Case bei dem `mcp_tool` Hooks gewinnen.
Wenn du eigene Hooks bauen willst und die Field-Namen oder Events nachschlagen musst: die offizielle Quelle ist [code.claude.com/docs/en/hooks](https://code.claude.com/docs/en/hooks). Da steht jeder Event-Typ, jedes Matcher-Format, jede Timeout-Default-Sekunde.
Was bei mir noch offen ist: ich habe noch keinen Fallback für den Fall dass der CRM-Server nicht antwortet. Aktuell schlucke ich den Timeout still und Claude antwortet halt ohne `additionalContext`. Sauberer waere ein `Pre`-Indikator in der UI dass Kontext gefehlt hat. Steht auf der Liste. Wenn ich das gebaut habe, schreib ich nochmal.