Hmbown/CodeWhale · warning · anyhow::Error

MCP catalog changed after tool resolution; retry the call

Error message

MCP catalog changed after tool resolution; retry the call

What it means

Every MCP connection carries a catalog_generation counter that the manager bumps whenever dynamic servers are registered/removed or a connection is refreshed/dropped (crates/tui/src/mcp.rs:2567,2618,3400,3410). call_tool resolves an advertised tool against a snapshot of that generation; if the live connection's generation differs by the time the call is about to execute, the resolved route may name a tool or authority that no longer exists, so the call is aborted and the caller must re-resolve before retrying.

Source

Thrown at crates/tui/src/mcp.rs:3314

            let name = arguments
                .get("name")
                .and_then(|v| v.as_str())
                .context("Missing 'name' argument")?;
            let args = arguments
                .get("arguments")
                .cloned()
                .unwrap_or(serde_json::json!({}));
            return self.get_prompt(server_name, name, args).await;
        }

        let route = self.resolve_advertised_tool(prefixed_name).await?;
        let server_name = route.server_name.clone();
        let tool_name = route.tool_name.clone();
        // Copy the global timeouts to avoid borrow conflict
        let global_timeouts = self.config.timeouts;
        let conn = self.get_or_connect(&server_name).await?;
        if conn.catalog_generation != route.catalog_generation {
            anyhow::bail!("MCP catalog changed after tool resolution; retry the call");
        }
        if conn
            .config()
            .reviewed_plugin
            .as_ref()
            .map(|source| &source.authority)
            != route.plugin_authority.as_ref()
            || !conn.config().is_tool_enabled(&tool_name)
            || !conn.tools().iter().any(|tool| tool.name == tool_name)
        {
            anyhow::bail!("MCP tool '{tool_name}' is disabled for server '{server_name}'");
        }
        let timeout = conn.config().effective_execute_timeout(&global_timeouts);
        match conn.call_tool(&tool_name, arguments.clone(), timeout).await {
            Ok(result) => Ok(result),
            Err(err) if is_mcp_stale_session_error(&err) => {
                tracing::debug!(
                    target: "mcp",

View on GitHub (pinned to 8880682c63)

Solutions

  1. Retry the call from the top (re-resolve the tool name) with a small bounded number of attempts
  2. Serialize dynamic server registration/removal with tool invocation (single writer for catalog mutations)
  3. If it persists, trace catalog_generation bumps to find which code path keeps mutating the catalog mid-call
  4. Confirm the tool still appears in the server's refreshed tools/list before retrying

Example fix

// before
let result = manager.call_tool(prefixed_name, args).await?;

// after
let mut attempt = 0;
let result = loop {
    attempt += 1;
    match manager.call_tool(prefixed_name, args.clone()).await {
        Ok(out) => break Ok(out),
        Err(e) if e.to_string().contains("catalog changed after tool resolution") && attempt < 3 => continue,
        Err(e) => break Err(e),
    }
}?;
Defensive patterns

Strategy: retry

Try / catch

let mut attempts = 0;
loop {
    attempts += 1;
    match manager.call_tool(name, args.clone()).await {
        Ok(out) => return Ok(out),
        Err(e) if e.to_string().contains("catalog changed after tool resolution") && attempts < 3 => continue,
        Err(e) => return Err(e),
    }
}

Prevention

When it happens

Trigger: Calling manager.call_tool while another task runs add_runtime_server_config/remove_runtime_server_config, refreshes a server catalog, or triggers drop_connection between resolve_advertised_tool and get_or_connect.

Common situations: An agent turn executing tools while the user adds/removes an MCP server in another pane; a background reconnect racing an in-flight tool call; a flaky server that keeps being dropped and re-added mid-call.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/b21264f53b4e4af0. Report an issue: GitHub.