Hmbown/CodeWhale · error

qualified MCP tool name

Error message

qualified MCP tool name '{qualified_name}' is ambiguous between {}

What it means

Raised by `list_tools_with_input_schemas` (crates/mcp/src/lib.rs) while building the cross-server tool listing: two different servers each expose a tool that qualifies to the same `mcp__<server-segment>__<tool>` name (their sanitized server components collide), so one qualified name maps to two origins. The library sorts both origins ('prior_server:prior_tool' and 'server:tool') and reports the ambiguity instead of picking one.

Solutions

  1. Rename one of the colliding servers so sanitized names are unique (see the register_server collision error).
  2. Unregister the redundant server before listing.
  3. Apply a ToolFilter scoped to one server so the ambiguous qualified name has a single origin.

Example fix

// before: 'fs-local' and 'fs.local' both sanitize to 'fs'
{"fs-local": {...}, "fs.local": {...}}
// after
{"fs-local": {...}, "fs-remote": {...}}
Defensive patterns

Strategy: validation

Validate before calling

// Rust: detect cross-server qualified collisions before list_tools
let mut seen = std::collections::HashMap::new();
for t in manager.list_tools()? {
    anyhow::ensure!(seen.insert(qualify_tool_name(&t.server, &t.tool_name), t.server.clone()).is_none(),
        "cross-server collision on {}", t.tool_name);
}

Type guard

fn no_cross_server_collision(tools: &[McpToolDescriptor]) -> bool {
    let mut q = std::collections::HashSet::new();
    tools.iter().all(|t| q.insert(qualify_tool_name(&t.server, &t.tool_name)))
}

Try / catch

match manager.list_tools() {
    Err(e) if e.to_string().contains("is ambiguous between") => {
        // parse both origins from the message; unregister or rename one server
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `list_tools` when two registered server names sanitize to the same component (e.g. 'fs-local' and 'fs.local') and both expose same-named tools, or when duplicate servers with colliding sanitized names are registered through separate paths.

Common situations: Multiple config sources each registering similarly named filesystem/server MCP instances; case or punctuation variants of a server name across environments; a renamed legacy server left registered alongside its replacement.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/4bd289978af6db05. Report an issue: GitHub.

Appendix: source

Thrown at crates/mcp/src/lib.rs:416

        for (server_name, (_, filter)) in &self.configs {
            let Some(client) = self.clients.get(server_name) else {
                continue;
            };
            let tools = client.list_tools_with_input_schemas()?;
            for (tool, input_schema) in tools {
                if !allowed_by_filter(&tool.tool_name, filter) {
                    continue;
                }
                let qualified_name = qualify_tool_name(server_name, &tool.tool_name);
                if let Some((prior_server, prior_tool)) = qualified_origins.get(&qualified_name)
                    && (prior_server != server_name || prior_tool != &tool.tool_name)
                {
                    let mut origins = [
                        format!("{prior_server}:{prior_tool}"),
                        format!("{server_name}:{}", tool.tool_name),
                    ];
                    origins.sort();
                    bail!(
                        "qualified MCP tool name '{qualified_name}' is ambiguous between {}",
                        origins.join(" and ")
                    );
                }
                qualified_origins.insert(
                    qualified_name.clone(),
                    (server_name.clone(), tool.tool_name.clone()),
                );
                out.push((
                    McpToolDescriptor {
                        server_name: server_name.clone(),
                        tool_name: tool.tool_name,
                        qualified_name,
                        description: tool.description,
                    },
                    input_schema,
                ));
            }

View on GitHub (pinned to 73e0f67d83)