Capture why agents call each tool - #134
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
dcruzeneil2
left a comment
There was a problem hiding this comment.
Approving.
Traced the full path — schema injection on tools/list, context extraction on tools/call, the beforeSend allow-list — and it does exactly what it says:
contextis required only in the advertised schema, so clients that omit it run unchanged.- Privacy boundary stays fail-closed: only
$mcp_intentand$mcp_intent_sourceadded to the allow-list, payloads and error text still excluded, 300-char truncation bounds non-compliant clients. contextcan't reach the Kernel API — the SDK strips it before the handler, and the strictz.objectschemas drop unknown keys as a second layer.
One thing before deploy: update the rollout-monitoring jobs so $mcp_intent on tool calls reads as expected instead of paging as a leak — ideally flipping the check so missing intent becomes the anomaly.
|
Thanks — monitoring is already updated, and one correction on the second point. Monitoring: done before this review landed. The t+72h rollout check no longer treats Correction: the SDK does not strip The conclusion holds, but on one layer rather than two: the tool schemas are plain Practical consequence: if anyone later adds a |
Summary
Turns on intent capture, which was deliberately left off when analytics landed. Every advertised tool now carries a required
contextargument the agent fills with why it is making the call, recorded as$mcp_intent.This is the one signal the existing data can't produce. Today we know
manage_browsersfails 10% of the time; we don't know what agents were trying to do when it did. Same for the two toolsets that are advertised and never called — no way to tell whether agents don't want them or don't understand them.What changes on the tool surface
tools/listgains one string property per tool, inrequired. Verified against the running route: all 17 tools get it, no tool is skipped, andmanage_browserscomes back withrequired: ["action", "context"].A client that ignores it is not broken. The argument is injected into the advertised schema only, so a call with no
contextvalidates and runs exactly as before — it just records no intent. Confirmed with the same tool called both ways.The description is ours, not the SDK's
The default is ~600 characters and repeats per tool, which is ~9 KB added to every
tools/listresponse on a server that answers thousands a day. The replacement is roughly half that, and names the things agents must not copy in:Privacy
Intent is the only free-form text this integration captures, and a model writes it rather than it being user data copied verbatim. Two guards:
$mcp_intentand$mcp_intent_sourceare added to the send allow-list explicitly. Everything else stays excluded — arguments, results, and error text are still dropped.beforeSend. 15-25 words fits comfortably; a client that ignores the instruction can't stream a payload or a prompt into an event property.Verification
Ran the route locally against the staging project and checked the captured events:
$mcp_intent_sourcemanage_profileswithcontextcontext_parametermanage_profileswith nocontextmanage_browserswith a 2,000-charcontextcontext_parameterNo
$exceptionevents, and no property outside the allow-list.tsc --noEmitandprettier --checkpass.Note for whoever is watching the rollout
The rollout checks currently treat any
$mcp_intentas a leak and page RED on it, since capture was off. That threshold needs to flip to expecting intent on tool calls when this deploys.Note
Medium Risk
Adds agent-written free-form text to analytics and changes every tool schema in
tools/list; rollout alerts must expect$mcp_intentinstead of treating it as a leak.Overview
Enables MCP tool-call intent analytics so product can see why agents invoke tools, not only which tools fail or go unused.
PostHog instrumentation turns on SDK context capture with a custom, shorter
contextargument description (replaces the default that bloats everytools/list). Each advertised tool gains a requiredcontextfield in the schema; values flow to$mcp_intentand$mcp_intent_sourceafter those properties are added to the send allow-list. Calls withoutcontextstill run; they simply omit intent.Privacy guardrails stay tight: call payloads and error text remain excluded.
beforeSendnow truncates intent strings to 300 characters so oversized agent text cannot flood event properties.Reviewed by Cursor Bugbot for commit 866f1b4. Bugbot is set up for automated code reviews on this repo. Configure here.
One discrepancy with PostHog's docs
The docs say the SDK "strips that argument before your handler runs, so your tool implementation never sees it." In
0.10.1it doesn't —contextis excluded from the captured parameters, but it's still on the request handed to the tool. Our handlers are unaffected because every tool parses arguments through a plainz.object, which drops unknown keys, and no tool forwards raw arguments to the Kernel API. Worth knowing before anyone adds a.passthrough()schema or a tool that spreads its arguments into a request.