Hmbown/CodeWhale · error · anyhow::Error
Ambiguous MCP tool name '{prefixed_name}' matches more than
Error message
Ambiguous MCP tool name '{prefixed_name}' matches more than one server/tool authority What it means
parse_prefixed_name iterates every catalog-authorized connection and collects every (server, tool) pair whose composed name format!("{server}_{tool}") equals the suffix after mcp_. If more than one pair matches, the name is ambiguous and resolution aborts rather than silently picking one — e.g. server 'a' with tool 'b_c' and server 'a_b' with tool 'c' both produce mcp_a_b_c.
Source
Thrown at crates/tui/src/mcp.rs:3032
/// Parse a prefixed name into (server_name, tool_name)
pub(crate) fn parse_prefixed_name(&self, prefixed_name: &str) -> Result<(String, String)> {
let Some(rest) = prefixed_name.strip_prefix("mcp_") else {
anyhow::bail!("Invalid MCP tool name: {prefixed_name}");
};
let mut matched: Option<(String, String)> = None;
for (server, connection) in &self.connections {
if !connection.catalog_authorized() {
continue;
}
for tool in connection.tools() {
if !connection.config().is_tool_enabled(&tool.name)
|| format!("{server}_{}", tool.name) != rest
{
continue;
}
if matched.is_some() {
anyhow::bail!(
"Ambiguous MCP tool name '{prefixed_name}' matches more than one server/tool authority"
);
}
matched = Some((server.clone(), tool.name.clone()));
}
}
if let Some(matched) = matched {
return Ok(matched);
}
Err(anyhow::anyhow!("Unknown MCP tool name: {prefixed_name}"))
}
/// Resolve an MCP tool through an exact advertised catalog. A configured
/// but lazy server may be connected and asked for `tools/list`; the
/// requested suffix is never treated as authority on its own.
async fn resolve_advertised_tool(&mut self, prefixed_name: &str) -> Result<McpToolRoute> {
if let Ok((server_name, tool_name)) = self.parse_prefixed_name(prefixed_name) {View on GitHub (pinned to 8880682c63)
Solutions
- Rename one of the colliding servers (or the colliding tool on the server side) so the composed mcp_{server}_{tool} strings differ.
- Remove duplicate registrations — check both static config and dynamic_servers for the same underlying server/tool.
- After renaming, refresh the model-facing catalog so stale names disappear.
- Avoid server names that are prefixes of other server names plus underscore boundaries when tools share suffixes.
Example fix
# before (.mcp.json) — both produce mcp_db_backup_list
{"servers": {"db": {"command": "m1"}, "db_backup": {"command": "m2"}}}
# db exposes tool 'backup_list'; db_backup exposes tool 'list'
# after
{"servers": {"db": {"command": "m1"}, "backup": {"command": "m2"}}}
# composed names: mcp_db_backup_list vs mcp_backup_list — unambiguous Defensive patterns
Strategy: validation
Validate before calling
// Rust: detect ambiguity before dispatching
fn unique_owner(pool: &McpPool, rest: &str) -> Option<(String, String)> {
let mut hits = pool.connections().iter()
.filter(|(_, c)| c.catalog_authorized())
.flat_map(|(s, c)| c.tools().iter().filter(move |t| format!("{s}_{}", t.name) == rest).map(move |t| (s.clone(), t.name.clone())))
.collect::<Vec<_>>();
(hits.len() == 1).then(|| hits.pop().unwrap())
}
ensure!(unique_owner(&pool, rest).is_some(), "ambiguous or unknown tool"); Try / catch
// Rust: surface both colliding owners to the operator
match pool.parse_prefixed_name(name) {
Err(e) if e.to_string().contains("Ambiguous MCP tool name") => {
// report the colliding (server, tool) pairs so one can be renamed
bail!("{e:#}; rename a server or tool so names differ")
}
r => r,
} Prevention
- Don't register the same server twice (check both static config and dynamic registrations).
- Avoid server names that are prefixes of other server names when tools share name tails.
- When renaming servers, re-check composed mcp_{server}_{tool} uniqueness across the whole catalog.
When it happens
Trigger: Two servers whose names/tool names concatenate to the same string (server 'db' + tool 'backup_list' vs server 'db_backup' + tool 'list'); duplicate server registrations in static and dynamic registries exposing the same tool; a dynamic server registered under a name that prefixes another server's name.
Common situations: Registering the same MCP server twice under different names (one static, one dynamic); renaming servers without checking composed-name collisions; plugin bundles that add servers whose names collide with user-configured ones.
Related errors
- Invalid MCP tool name: {prefixed_name}
- {} exceeded the {}-page catalogue limit
- {} exceeded the {}-item catalogue limit
- Failed to find MCP server: {server_name}
- MCP prompt '{prompt_name}' was not advertised by server '{se
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/4ce222924f345e41.
Report an issue: GitHub.