The number every MCP server needs to know: 64
6 min read
#mcp #ai-platform #outage #production
In late April 2026, an MCP-backed workflow on our platform stopped responding for the better part of a day.
The chat would route a user message through the model, the model would emit a tool call, and the call would fail before the tool ran. By the time we had the incident bundle and the runtime fix in place, a single number had been burned into the platform: 64.
This is the story of that number — what the Model Context Protocol spec said about it at the time (nothing), what every major LLM provider had quietly agreed on (64), and the runtime pattern that now keeps MCP server names compatible with the entire ecosystem.
The symptom
Tool names in the MCP ecosystem follow the canonical mcp__<server>__<tool> shape — straight out of Claude Code's plugin convention. With descriptive server and tool segments, a real tool name can comfortably run past 80 characters: an mcp__<some_business_app_connector>__<some_descriptive_action> is almost guaranteed to overflow once the server team picks names a human can read.
The model emits a tools array containing one such name, the provider receives it, and the provider rejects the request:
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "tools.0.name: String should have at most 64 characters"
}
}Same error from AWS Bedrock. Same error from native Anthropic. The OpenAI API rejected with a slightly different shape but the same outcome — 64 characters, no more.
The MCP specification at the time was silent on tool name length. The Anthropic SDK schema documented a length but did not enforce it client-side. The tools/list endpoint accepted whatever the server returned. The mismatch lived at the provider boundary, and the provider was unforgiving.
How three providers agreed without speaking
I ran the same payload against all three majors to confirm the cap was real and consistent. Every one of them rejected at > 64:
| Provider | Error |
|---|---|
| AWS Bedrock (Anthropic) | ValidationException: tool name length must be less than or equal to 64 |
| Native Anthropic Messages | invalid_request_error: tools.0.name: String should have at most 64 characters |
| OpenAI Chat Completions | BadRequestError: tools[0].function.name should be at most 64 characters |
Three companies, three independent SDK teams, one shared decision: roughly ^[a-zA-Z0-9_-]{1,64}$ for tool identifiers. None of them documented the choice prominently in their getting-started guides; none of them deviated from it.
The MCP ecosystem had been bumping into the limit for months. The issue tracker on anthropics/claude-code alone carries several variants of the same bug:
- #19882 — Tool search fails when MCP tool names exceed 64 chars
- #20983 — MCP plugin tool names exceed 64-character API limit
- #21050 — MCP tool name exceeds 64 character limit with UUID-based server IDs
- #21136 — API Error 400: MCP tool names exceeding 64 character limit
- #23149 — Plugin MCP tool names can exceed API's 64-character limit
From the other side of the contract, github/github-mcp-server opened issue #520 — 64-Character Limit on Tool Names Conflicts with MCP Spec — Should Be Removed or Configurable. Same number, different angle. The spec said one thing (or rather, said nothing); the implementations all said another.
The shape of the fix
Two patterns proved enough to close the gap. I'll describe them in the abstract rather than copy-paste production code, but the shape is straightforward enough to implement from the description.
A runtime alias sanitiser. When the MCP client builds its tool registry, every name that exceeds 64 characters is rewritten to a stable, deterministic alias that fits. The two non-obvious bits:
- The shortened name must preserve the
mcp__<server>__<tool>shape so existing routing logic keeps working. Hashing the server segment to a short, stable prefix (a 12-char digest of a cryptographic hash works fine) and keeping the tool segment human-readable hits both goals — the alias survives a router restart, identical servers map to identical aliases, and the tool stays recognisable in traces and logs. - The mapping must be bidirectional. The model emits an alias on turn N, the provider returns it on the tool-call response, and the router needs to translate it back to the underlying MCP tool to actually invoke anything.
A pre-flight validator at the server-registration boundary. Servers that publish tool names with no plausible 64-char shortening — names that lack the mcp__server__tool structure, or names so long the shortened form still overflows — are refused at registration time. Failing fast at the registration boundary is cheaper than triaging an outage at the provider boundary.
The combined effect is that any MCP server can publish whatever name it likes, the router quietly normalises it to a provider-safe form, and the model never sees a name it can't actually call.
What SEP-986 changes
Shortly after our outage, SEP-986 — Specify Format for Tool Names opened against the MCP specification. The proposal: tool names are 1–64 characters, alphanumeric plus _, -, ., case-sensitive. It is the exact set every major provider had been enforcing in private.
The SEP is not yet ratified, but the discussion thread reads like a public ratification of what was already true. The 64 the providers agreed on is becoming the 64 the spec endorses. Servers that already conform — including MCP servers shipped after the alias-sanitiser pattern landed — will have nothing to change.
What this teaches
Three patterns that compound across the MCP ecosystem:
A silent spec leaves implementers free to converge. They will converge on the most restrictive option, because that's the one that protects everyone downstream. The MCP spec did not say "64" — the SDK teams at Anthropic, AWS, and OpenAI each picked 64 anyway, because permitting longer names meant either dropping support somewhere or paying for it at deserialisation. The cautious answer is usually the right answer.
Provider boundaries are spec boundaries. Anything that ships through the LLM API contract — tool names, JSON schemas, system prompts, message ordering — is constrained by the strictest provider you target. If you support Bedrock, Anthropic and OpenAI, you live in the intersection of three private specs that no document captures.
Aliasing is healthier than truncation. Truncating an 80-character tool name to its first 64 characters loses information and collides under load — two distinct tools that happen to share a long common prefix both end up at the same alias. A deterministic alias derived from a stable hash preserves the call-graph integrity, and an alias-to-real map keeps the human-readable form available where it's helpful — logging, traces, tool catalogues.
Production AI platforms run on more constraints than the documentation admits. Living in the intersection is a job in itself.
References
- SEP-986 — Specify Format for Tool Names
- Anthropic — Tool use API reference
- AWS Bedrock — Anthropic Messages on Bedrock
- OpenAI — Function calling guide
anthropics/claude-codeissues: #19882, #20983, #21050, #21136, #23149github/github-mcp-server— Issue #520