◉CLAUDE LABJP
●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…
Articles/API & SDK
⬡ API & SDK/2026-05-20Advanced

Resolving Tool Name Collisions When Bundling Multiple MCP Servers in the Claude Agent SDK

When the GitHub MCP and Linear MCP both expose create_issue, Sonnet 4.6 cannot tell them apart. This article covers the structure of MCP tool name collisions, a TypeScript reconciler implementation, and a measured correction: the schemaHash I originally published missed all five schema drifts I tested it against.

Claude Agent SDK13MCP54TypeScript24Production23Namespacing

✦ Premium Article

The day I plugged the GitHub MCP and the Linear MCP into the same Claude Agent SDK app, Sonnet 4.6 received a user instruction to "open a ticket on Linear" and confidently created a GitHub issue instead. Both servers exposed a tool named create_issue, and the GitHub schema had silently overwritten the Linear one when the second server registered. I only found the cause after dumping the SDK's tool list to the debug log.

Back when I wired REST APIs together by hand, the endpoint URL settled the routing question for me. MCP removes that handle. All the model gets is a tool name and a description, and overlapping verbs across servers turn out to be far more common than they were in the pre-MCP era.

What follows is the namespace design and the TypeScript reconciler I now use. It also corrects something: the schemaHash I originally published here was broken, and I only noticed months later. The correction comes with measurements.

How tool name collisions actually happen

The Claude Agent SDK hands off the tool list from each MCP server straight into the tools array of the Anthropic Messages API and leaves collision detection to the caller. The API itself only allows alphanumerics, underscores, and hyphens in name. If the same name appears twice, the SDK implementations I've inspected push them through a Map that ends up keeping the last entry, which makes the earlier server's tool vanish silently.

From the model's perspective, a tool is a triple of name, description, and input_schema. Two tools with the same name get collapsed before the request leaves your process, so the model never sees the duplicate. If the descriptions differ, the model is choosing based on whichever description survived the merge. That mismatch is exactly what produced the GitHub-vs-Linear mistake above.

Typical collision-prone verbs include:

VerbLikely MCP servers
create_issueGitHub MCP / Linear MCP / Jira MCP
searchNotion MCP / Slack MCP / Web Search MCP
uploadS3 MCP / Cloudflare R2 MCP / Stripe Files MCP
send_messageSlack MCP / Discord MCP / SendGrid MCP

In my own setup, having three or more of these servers alive in a single agent session is the default rather than the exception. A workflow that pulls AdMob revenue numbers into Slack, opens a fix PR on GitHub, and closes the related Linear ticket walks straight into this minefield.

Comparing three namespacing strategies

There are several ways to resolve collisions. After running a few in production I kept the "prefix with server identifier" approach. Here is how the three candidates compare.

The first candidate is dot notation. Names like github.create_issue read well to humans, but the Anthropic Messages API rejects . in name and you have to escape or substitute it. That forces you to maintain a bidirectional mapping back to the original name on every dispatch.

The second is slash notation, which runs into the same character restriction and the same escape cost.

The third is double underscore separation: github__create_issue, linear__create_issue. It uses only API-legal characters and the model parses it as "the GitHub side's create_issue" without prompting. I ran the same prompt 50 times each across Sonnet 4.6 and Haiku 4.5 with temperature: 0.0, comparing strategies. Double underscore had the lowest misfire rate and beat a 2-character prefix like gh_ by about 7 points. Short prefixes also get confused with other meanings ("gh" vs "ghp"), so I do not recommend them.

I also keep the following rules around prefixing:

  1. Prefixes are lowercase ASCII, between 3 and 10 characters
  2. Original tool names stay untouched; the prefix is additive
  3. Prefixes are applied only when there is an actual collision; never blanket-prefix everything

Rule 3 matters. Renaming every tool unconditionally hides the "idiomatic" names the model already knows (web_search, for instance) and degrades selection accuracy. Limiting prefixes to the servers that actually collide is the most model-friendly setting.

It is worth saying a word about the benchmark setup. Fifty samples is just enough to see the differences, but only if you pin the temperature to zero and replay the exact same system prompt and user message. I also kept the working set close to production, with four AdMob-related MCP servers, two GitHub-side servers, and one Slack server in the bundle — about 60 tools in total. Toy benchmarks with five tools always look rosier than reality.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Observed misfire patterns when GitHub MCP and Linear MCP both ship create_issue, and whether the model relies more on name or description
✦A TypeScript Reconciler that prefixes only colliding tool names with double underscores and returns a bidirectional alias map
✦A measured correction: the schemaHash originally published here misused the JSON.stringify replacer and reported all five tested schema drifts as identical, plus a recursive canonicalization that fixes it
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⬡ API & SDK2026-05-04
Claude API on Bun in Production: Migration Decisions and Implementation Patterns That Actually Survive Real Traffic
A practical guide to running Claude API services on Bun in production. Covers migration triggers from Node.js, built-in SQLite/WebSocket usage, streaming optimization, and the pitfalls that only surface after deployment — with working code and measured numbers.
⬡ API & SDK2026-04-25
Claude API × Convex: Reactive AI Apps — Data Flow, Streaming, and Agent Patterns
How to combine Convex's reactive database with the Claude API to build chat and agent applications that hold up in production. Covers schema design, the Action/Mutation/Query boundary, streaming, tool-call state, and the cold-start pitfalls nobody warns you about.
⬡ API & SDK2026-04-22
Building Fault-Tolerant Long-Running AI Workflows with Claude Agent SDK × Temporal.io — A Production Design Guide to Durable Execution and Saga Patterns
A complete production guide to combining Claude Agent SDK with Temporal.io to build AI workflows that survive crashes, restarts, and multi-day human approval gates. Durable Execution, retry policies, saga compensation, and signal integration patterns.