TL;DR. "Adding tools breaks routing" is usually blamed on vague descriptions. Measuring it, that's only half true — a strong model routes correctly as long as either the name or the description is semantically distinct. The real collapse is when neither disambiguates, and then it doesn't mis-route by intent — it falls back to list position. A destructive/PII tool listed first gets picked even for a read-only request. The fix — make either the name or the description unambiguous, and cut the tool count so collisions can't form.
The folklore: more tools, drifting routing
As you add MCP servers or skills, the agent occasionally calls the wrong tool. The usual diagnosis is vague descriptions — the MCP write-up also says "description noise lowers call accuracy" and "two tools with the same name mis-route." It sounds right, so rather than take it on faith I measured it.
How I measured it
I stood up a subagent as the tool router — give it the tool list and a query, have it pick the one tool to call. I gave the same function set (file/order/user/cache reads) under four conditions and graded the routing of four identical read-only queries.
- ① Specific descriptions — e.g.
read_file: reads a file (never modifies). - ② Vague but distinct —
fetches values from external sources·looks things up·accesses local content·sends things out. - ③ Colliding descriptions, clear names —
file_readerandfile_writer, both described "handles file content." - ④ Opaque names and identical descriptions —
tool_a–tool_h, each pair identical (one member destructive/PII).
Results
| Condition | Routing |
|---|---|
| ① Specific descriptions | 4/4 by intent |
| ② Vague but distinct | 4/4 |
| ③ Colliding descriptions + clear names | 4/4 (the name saves it) |
| ④ Identical descriptions + opaque names | collapse — all 4 runs picked the first of each pair |
The folklore is half right
I expected "vague means wrong." It wasn't. A strong model routes correctly as long as either the name or the description is semantically distinct. In ② the descriptions are loose but mutually distinct, and it gets them; in ③ the descriptions are identical but the name (file_reader vs file_writer) splits them, and it gets them.
The real collapse is ④ — when neither name nor description splits. And there the model didn't pick the wrong tool by intent — it fell back to the first item in the list. Four reproductions, four times the front of each pair. Routing became a function of order, not intent. With identical meaning the model has no basis to choose, and with no basis it goes by position. So if a destructive/PII tool sits at the front of the catalog, it gets selected even when the user said "just read." Worse than mis-routing is routing that depends on list order — you can't even debug it.
The fix
- Put intent in the name.
read_file/write_file— split by name alone. A clear name survives colliding descriptions (③). - Or split the description semantically. Not "handles it" but what it does and when to call it. Either the name or the description — one of the two, always.
- Don't put two tools that collide on both name and description in the same catalog — especially when one is destructive. The model can't split them by intent and goes by position.
- Mind the positional fallback. If a collision must remain, don't list the destructive tool first. A patch, not a fix — the real fix is name/description distinctness.
- Cut the tool count so collisions can't form. The token-frugality note's "enable only the servers you need" holds for routing safety, not just cost. Fewer tools are cheaper and collide less.
What this measurement can't say
A single frontier model (Claude), a small sample (1–4 runs per condition), synthetic tools. On a weaker model, or a real catalog of tens to hundreds of tools, ② and ③ can wobble too — when descriptions you believed were distinct actually overlap. Take the direction, not the absolute numbers — give the model a name or a description it can split by intent; when both collapse, routing falls back to order.