Hmbown/CodeWhale · error · anyhow::Error

missing mcp__ prefix

Error message

missing mcp__ prefix

What it means

parse_qualified_tool_name() requires the string to start with the literal prefix 'mcp__'; the qualified format is mcp__<server>__<tool>. This bail (and the sibling 'missing server segment'/'missing tool segment' errors) means the caller passed a bare tool name, a server__tool pair without the prefix, or a name built by hand with the wrong shape.

Source

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

        let remaining = component_budget - server_len - tool_len;
        if remaining > 0 {
            let server_extra = (server.len() - server_len).min(remaining);
            server_len += server_extra;
            tool_len += (tool.len() - tool_len).min(remaining - server_extra);
        }
        name = format!(
            "mcp__{}__{}{}",
            &server[..server_len],
            &tool[..tool_len],
            suffix
        );
    }
    name
}

fn parse_qualified_tool_name(value: &str) -> Result<(String, String)> {
    let Some(stripped) = value.strip_prefix("mcp__") else {
        bail!("missing mcp__ prefix");
    };
    let mut split = stripped.splitn(2, "__");
    let server = split
        .next()
        .filter(|s| !s.is_empty())
        .map(ToOwned::to_owned)
        .context("missing server segment")?;
    let tool = split
        .next()
        .filter(|s| !s.is_empty())
        .map(ToOwned::to_owned)
        .context("missing tool segment")?;
    Ok((server, tool))
}

#[derive(Debug, Deserialize)]
struct JsonRpcRequest {
    #[serde(default)]

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Prefix the name: pass mcp__<server>__<tool> with non-empty server and tool segments
  2. Build qualified names with the crate's formatting helper rather than manual concatenation
  3. For bare names, call call_tool(server, tool, args) directly instead of the qualified API

Example fix

// before
let v = registry.call_qualified_tool("github__search_code", args)?; // missing prefix

// after
let v = registry.call_qualified_tool("mcp__github__search_code", args)?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_qualified_tool_name(s: &str) -> bool {
    let Some(rest) = s.strip_prefix("mcp__") else { return false };
    match rest.split_once("__") {
        Some((server, tool)) => !server.is_empty() && !tool.is_empty(),
        None => false,
    }
}

if !is_qualified_tool_name(&name) { bail!("expected mcp__<server>__<tool>, got {name}"); }

Type guard

fn split_qualified(s: &str) -> Option<(&str, &str)> {
    s.strip_prefix("mcp__")?.split_once("__")
        .filter(|(srv, tool)| !srv.is_empty() && !tool.is_empty())
}

Prevention

When it happens

Trigger: Passing a bare tool name ('search_code') or 'github__search_code' to call_qualified_tool(); constructing qualified names by string concatenation instead of using the crate's qualify helper; stripping or lowercasing the prefix during logging/round-tripping so 'MCP__' or 'mcp_' no longer matches.

Common situations: Tool names round-tripped through user input, logs, or prompts where the prefix was trimmed; LLM-emitted tool calls missing the prefix; copy-paste between systems that use different qualification conventions.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/b88e78b906749484. Report an issue: GitHub.