Hmbown/CodeWhale · error

qualified MCP tool name

Error message

qualified MCP tool name '{}' is ambiguous across servers: {}

What it means

call_qualified_tool resolves an mcp__<server>__<tool> name to (server, tool). When the server segment is missing or resolves to multiple running servers exposing the same tool, the qualified name is ambiguous and the call fails closed listing the candidate servers.

Solutions

  1. Use the fully qualified mcp__<specific-server>__<tool> name
  2. Rename the tool on one server to remove the collision
  3. Apply a tool filter on one server so only one match remains

Example fix

// before
manager.call_qualified_tool("mcp__search__find")?
// after
manager.call_qualified_tool("mcp__docs__search__find")?
Defensive patterns

Strategy: validation

Validate before calling

if !name.starts_with("mcp__") || name.matches("__").count() < 2 { return Err("need fully qualified name"); }

Try / catch

match manager.call_qualified_tool(name) { Err(e) if e.to_string().contains("ambiguous across servers") => /* retry with explicit server segment */, other => other }

Prevention

When it happens

Trigger: Calling call_qualified_tool with a qualified name whose tool name matches tools on multiple running servers, or a truncated/partial name that matches more than one server.

Common situations: Two servers ship a tool with the same name and the caller used a short/unqualified form; a legacy caller building names without the server segment; name truncation in UI-generated tool calls.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/74c482570c8167d7. Report an issue: GitHub.

Appendix: source

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

            }
        }
        match matches.len() {
            0 => {}
            1 => {
                let (server_name, tool_name) = &matches[0];
                let client = self
                    .clients
                    .get(*server_name)
                    .with_context(|| format!("MCP server '{server_name}' not available"))?;
                return client.call_tool(tool_name, arguments);
            }
            _ => {
                matches.sort();
                let servers: Vec<&str> = matches
                    .iter()
                    .map(|(server_name, _)| server_name.as_str())
                    .collect();
                bail!(
                    "qualified MCP tool name '{qualified_tool_name}' is ambiguous across servers: \
                     {}",
                    servers.join(", ")
                );
            }
        }

        let (server_name, tool_name) = parsed?;
        self.call_tool(&server_name, &tool_name, arguments)
    }

    /// List all resources from all running servers.
    pub fn list_resources(&self) -> Result<Vec<McpResourceDescriptor>> {
        Ok(self
            .list_resources_with_metadata()?
            .into_iter()
            .map(|(resource, _)| resource)
            .collect())

View on GitHub (pinned to 433685b202)