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
- Rename one of the colliding servers so sanitized names are unique (see the register_server collision error).
- Unregister the redundant server before listing.
- 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
- Keep sanitized server names globally unique across all config sources.
- Run a startup lint that registers servers and lists tools before exposing them to the model.
- Remove legacy servers when their renamed replacements land.
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
- MCP server ' ' collides with already-registered server ' '…
- qualified MCP tool name
- qualified MCP tool name
- qualified MCP tool name
- A managed, project or plugin connector already uses this…
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)