My MCP server had four tools, clean handlers, a test suite — and a user who kept asking the same exasperated question: "why didn't you use the MCP here?" The agent could see the tools. It just kept choosing grep, or a memory file, or nothing. The bug wasn't in the code. It was in four paragraphs of prose.

Thesis: A tool description is not documentation — it's a routing surface. The agent reads it in competition with every other tool in context and decides, from that text alone, whether this moment is the tool's moment. Descriptions that explain what a tool is lose that competition to tools that say when to reach for them. Rewriting mine — trigger conditions, alias map, one trap warning — took routing from 90% to 100% on a battery of real asks, with zero new over-triggering. And like any behavior you've fixed with text, it regresses silently unless a test pins it.


The False-Negative Problem

The server is a local knowledge loop: harvest → curate → retrieve, plus a readiness check. The tool descriptions were written the way engineers write them — from the inside out. They described implementation: what the handler owned, which validation gates it enforced, how the wire format was verified. Accurate, and useless for the one decision the text exists to serve: should the agent call this now?

The misses had a pattern. The user would say "memorialize this" — their own word, used constantly — and the agent would write to a personal memory file instead of curating to the shared corpus. A durable decision would emerge mid-task, unprompted, and the agent would reach for grep instead of capturing it. Each miss was invisible in the moment; nothing errored. The knowledge just silently didn't accumulate.

There was an architectural constraint worth respecting here: the server refuses to parse intent in handlers. No if (input.includes("remember")) heuristics on the server side — the agent decides what the user means; the server executes. Which leaves exactly one lever for routing behavior: the text the agent reads. Server instructions and tool descriptions. That's the whole steering wheel.

Measure It Like Routing, Not Vibes

"The agent doesn't use my MCP enough" is a feeling. To make it an eval, treat triggering as what it actually is: a classification problem.

  1. Mine real asks. I extracted 294 real requests from 23 of my own session logs — the actual vocabulary in use, not invented test phrasing. "Memorialize," "recall," "what do we know about," "do we have notes on."
  2. Build a battery under competition. 20 cases: canonical asks, alias phrasings, natural intent with no tool named, traps, and negatives that must not trigger. Each case is answered against the full competing surface — the MCP's tools plus everything else an agent realistically has: memory files, grep, shell, other knowledge tools.
  3. Grade with code, not an LLM. The executor returns a structured decision — which surface it would reach for. Grading is a string comparison against a fixed answer key. No rubric, no judge model, no drift.

The competing-surface part is the part most people skip, and it's where the signal lives. A description doesn't need to beat silence; it needs to beat memory.write and grep — the strong defaults the model already loves.

Variant Accuracy Aliases routed Over-firing
Original descriptions 90% (18/20) 6/7 0
Trigger-first rewrite 100% (20/20) 7/7 0

Ninety percent sounds fine until you look at which two cases failed: "memorialize this" routing to the personal memory file, and the unprompted-capture moment routing to grep. The battery's two misses were, verbatim, the two complaints that started the project. Real-world false negatives cluster exactly where your vocabulary and the model's defaults disagree.

What the Rewrite Actually Changed

Five moves, all text:

  • Server-level instructions. The server had none — every routing decision rode on four isolated tool descriptions. The instructions block frames the loop as a whole and states the natural-intent rule directly: the user does not have to say "harvest," "curate," or name a tool.
  • Per-tool USE WHEN. Each description now leads with its trigger conditions — the situations, not the mechanism.
  • An explicit alias map. memorialize / remember / save / capture / "write this down" → curate. recall / "what do we know" / "have we figured out" → retrieve. The user's own verbs, routed literally.
  • A proactive clause. "When a durable finding emerges mid-task, memorialize it even unprompted — offer it if unsure." Without this line, the agent treats capture as strictly reactive.
  • One trap warning. "Is the MCP running?" is a build-status question about the repo — shell territory — not a readiness query for the config tool. Disambiguating lookalike asks matters as much as attracting the right ones.
flowchart TD
    A["'memorialize this decision'"] --> B{"Routing"}
    B -->|"what-it-is description"| C["memory.write<br/>personal file, wrong tier"]
    B -->|"trigger-first + alias map"| D["curate.publish<br/>shared corpus"]

    style A fill:#5a5a8a,color:#fff
    style B fill:#5a5a8a,color:#fff
    style C fill:#9d4444,color:#fff
    style D fill:#2d6a4f,color:#fff

Same request, same tools, different text in front of the model — that's the entire delta between the two branches above. Note what this echoes from the ablation post: the text that moved behavior is dense, imperative, and trigger-shaped — when X, reach for Y — while the descriptive prose it replaced carried almost nothing. Same lesson, opposite direction: there I deleted inert text to find the load-bearing core; here I added load-bearing text where none existed.

Guidance Regresses Like Code, So Test It Like Code

The rewrite lives in prose, and prose is what refactors trample. Somebody will "clean up" a description, an update will regenerate a manifest, and the routing will quietly rot back to 90% — with no error, ever, because a false negative doesn't throw.

So the last move was a regression test that pins the behavior's preconditions: the server must expose the instructions block, and every tool description must carry its use-when cue. The test fails against the pre-rewrite server. It runs in the same suite as the type checks. Text that carries behavior earns the same guardrails as code that carries behavior — that's also the argument of Instructions That Outlive the Model, from the durability side.

One caveat the battery keeps honest: those tests pin the text, and the text's effect on routing was measured on today's models. The map from words to behavior can shift under you — which is why the battery, cheap and code-graded, is the artifact worth keeping, not any one score.

When What-It-Is Still Wins

  • After routing, the agent still needs mechanics. Trigger-first descriptions get the right tool invoked; schemas and precise parameter docs make the invocation correct. The rewrite reorders emphasis; it doesn't delete the what.
  • Single-purpose servers with no competition. If your MCP is the only surface in context and the user invokes it by name, trigger text is mostly redundant.
  • Alias maps can overreach. Routing "remember this" to a shared corpus is right for a team knowledge loop and wrong for a personal scratchpad. Negatives in the battery are what license the aliases — don't add the map without the traps.
  • Don't stuff synonyms speculatively. Every alias you add is a claim about user vocabulary. Mine came from 294 logged asks; invented ones are how over-triggering starts.

What to Do Next

  1. Mine your real asks. Pull the last few weeks of session logs and extract every request your tool should have served. That's your vocabulary; write it down before you write descriptions.
  2. Build a 20-case routing battery — canonical, alias, natural-intent, trap, negative — and grade it in code against the full competing tool surface.
  3. Rewrite descriptions trigger-first: lead with USE WHEN, add the alias map your logs justify, add a proactive clause if capture matters, disambiguate the lookalike asks.
  4. Score before and after. If you can't name which cases flipped and why, you're tuning vibes.
  5. Pin it with a regression test that fails when the trigger text disappears — and keep the battery around for the day the model underneath you changes.

Previous in this series: The Gotchas Are Load-Bearing — finding the 4% of a skill that carries its behavior. Next: Grade the Answer, Not the Shape — the eval discipline both experiments depended on. Related: MCP as a Discovery Protocol and Five Things Wrong With MCP on the protocol side of tool surfaces.