shareAI-lab/learn-claude-code · error · ValueError

MCP tool name is longer than 64 characters

Error message

MCP tool name is longer than 64 characters: {prefixed}

What it means

When the host harness merges MCP client tools into its tool table it prefixes each name as mcp__<server>__<tool> and enforces a 64-character limit matching the model's tool-name alphabet. A longer name is rejected with ValueError at wiring time because the upstream model API would reject or truncate it later.

Solutions

  1. Shorten the server alias used as the dict key when registering mcp_clients (e.g. 'docs' instead of 'documentation-service-prod')
  2. Shorten the tool name in the MCP server's tool_defs
  3. Compute the prefixed length in a pre-flight check before starting the harness

Example fix

# before
mcp_clients = {
    "internal_documentation_services": docs_client,  # tool 'search_all_namespaces' -> 5+29+2+20 = too long
}

# after
mcp_clients = {
    "docs": docs_client,  # mcp__docs__search_all_namespaces fits in 64
}
Defensive patterns

Strategy: validation

Validate before calling

def fits_tool_name_budget(server: str, tool: str) -> bool:
    return len(f"mcp__{server}__{tool}") <= 64

for server_name, client in mcp_clients.items():
    for tool in client.tools:
        assert fits_tool_name_budget(server_name, tool), f"{server_name}/{tool} too long"

Type guard

def is_within_mcp_name_limit(server: str, tool: str) -> bool:
    return isinstance(server, str) and isinstance(tool, str) and len(f"mcp__{server}__{tool}") <= 64

Try / catch

try:
    harness = build_harness(mcp_clients)
except ValueError as exc:
    if "longer than 64 characters" in str(exc):
        # shorten the server alias or tool name, then rebuild
        raise SystemExit(str(exc)) from exc
    raise

Prevention

When it happens

Trigger: Registering a server with a long name (e.g. 'internal-documentation-services') plus a long tool name (e.g. 'search_across_all_namespaces') so that 5 + len(server) + 2 + len(tool) > 64. Note normalization can grow names: each disallowed character becomes '_' (1:1), but names near the limit tip over once prefixed.

Common situations: Connecting enterprise MCP servers whose names mirror hostnames or service FQDNs. Teams renaming tools descriptively (verb_object_qualifier) over time until the budget is exceeded.

Related errors


AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14). Data as JSON: /api/errors/72b9ba92b62cf7af. Report an issue: GitHub.

Appendix: source

Thrown at s15_integrated_harness/code.py:2552

            f"Discovered {len(mcp_client.tools)} tools: {', '.join(tool_names)}")


def assemble_tool_pool() -> tuple[list[dict], dict]:
    """Merge builtin tools + all MCP tools into one pool."""
    global mcp_tool_policies
    tools = list(BUILTIN_TOOLS)
    handlers = dict(BUILTIN_HANDLERS)
    policies: dict[str, str] = {}
    origins = {tool["name"]: f"built-in tool {tool['name']!r}"
               for tool in tools}
    for server_name, mcp_client in mcp_clients.items():
        safe_server = normalize_mcp_name(server_name)
        for tool_def in mcp_client.tools:
            raw_name = tool_def["name"]
            safe_tool = normalize_mcp_name(raw_name)
            prefixed = f"mcp__{safe_server}__{safe_tool}"
            if len(prefixed) > 64:
                raise ValueError(
                    f"MCP tool name is longer than 64 characters: {prefixed}"
                )
            origin = f"MCP tool {server_name!r}/{raw_name!r}"
            if prefixed in origins:
                raise ValueError(
                    "MCP tool name collision after normalization: "
                    f"{prefixed!r} maps both {origins[prefixed]} and {origin}"
                )
            schema = tool_def.get("inputSchema", {})
            if not isinstance(schema, dict) or schema.get("type", "object") != "object":
                raise ValueError(f"Invalid input schema for {origin}")
            origins[prefixed] = origin
            tools.append({
                "name": prefixed,
                "description": tool_def.get("description", ""),
                "input_schema": schema,
            })
            handlers[prefixed] = (

View on GitHub (pinned to 985456f4ad)