Hmbown/CodeWhale · error · anyhow::Error
Invalid MCP tool name: {prefixed_name}
Error message
Invalid MCP tool name: {prefixed_name} What it means
parse_prefixed_name strips the literal prefix 'mcp_' from a tool name and returns (server, tool) for the unique advertised catalog match. A name that does not start with mcp_ — including empty strings, bare tool names, or names with a different prefix — fails here before any catalog lookup. This is the entry validation for the model-facing tool naming scheme where every MCP tool is exposed as mcp_{server}_{tool}.
Source
Thrown at crates/tui/src/mcp.rs:3017
let global_timeouts = self.config.timeouts;
let conn = self.get_or_connect(server_name).await?;
if !conn
.prompts()
.iter()
.any(|prompt| prompt.name == prompt_name)
{
anyhow::bail!(
"MCP prompt '{prompt_name}' was not advertised by server '{server_name}'"
);
}
let timeout = conn.config().effective_execute_timeout(&global_timeouts);
conn.get_prompt(prompt_name, arguments, timeout).await
}
/// 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"
);
}View on GitHub (pinned to 8880682c63)
Solutions
- Prefix the name: use mcp_{server}_{tool} exactly as advertised by the tool catalog (all_tools/to_api_tools).
- Route non-mcp_ names to the local tool dispatcher instead of the MCP resolver.
- Validate names at the boundary (before dispatch) with a simple starts_with check.
- Regenerate or re-read the advertised tool list to copy exact names.
Example fix
// before
let (server, tool) = pool.parse_prefixed_name("github_create_issue")?; // Err
// after
let (server, tool) = pool.parse_prefixed_name("mcp_github_create_issue")?; Defensive patterns
Strategy: validation
Validate before calling
// Rust: check the prefix before resolution
ensure!(name.starts_with("mcp_"), "'{name}' is not an MCP tool (missing mcp_ prefix)");
let (server, tool) = pool.parse_prefixed_name(name)?; Type guard
// Rust
fn is_mcp_tool_name(name: &str) -> bool {
name.strip_prefix("mcp_").is_some_and(|rest| !rest.is_empty() && rest.contains('_'))
} Try / catch
// Rust: route non-MCP names elsewhere
match pool.parse_prefixed_name(name) {
Err(e) if e.to_string().contains("Invalid MCP tool name") => dispatch_local_tool(name).await,
r => r,
} Prevention
- Validate the mcp_ prefix at the dispatch boundary, not deep in the resolver.
- Build tool names from the advertised catalog (mcp_{server}_{tool}) rather than by string concatenation at call sites.
- Keep local (non-MCP) tool dispatch separate so prefixless names never reach this code.
When it happens
Trigger: Calling a tool-resolution or dispatch API with a name like 'github_create_issue' (missing the mcp_ prefix), 'mcp' with nothing after, or a non-MCP tool name routed into the MCP resolver by mistake.
Common situations: The model omits the prefix when composing tool calls; callers forward user-typed tool names unvalidated; refactors that rename tools and drop the prefix; mixing up local tool names with MCP-prefixed ones.
Related errors
- MCP prompt '{prompt_name}' was not advertised by server '{se
- Ambiguous MCP tool name '{prefixed_name}' matches more than
- disabled_tools must use Codewhale catalog identifiers: ${",
- Moonshot function parameters failed safe compatibility valid
- MCP config path cannot be empty
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/2c095c9738e784d3.
Report an issue: GitHub.