Hmbown/CodeWhale · error · anyhow::Error

MCP tool '{tool_name}' is disabled for server '{server_name}

Error message

MCP tool '{tool_name}' is disabled for server '{server_name}'

What it means

Before executing a tool, call_tool re-validates the live connection against the resolved route: the reviewed plugin's authority must match route.plugin_authority, is_tool_enabled must allow the tool (if enabled_tools is non-empty the tool must be listed, and disabled_tools must not list it), and the tool must still appear in the server's advertised tools list (mcp.rs:1053-1063). If any check fails, the call is refused as 'disabled' even though the tool name resolved earlier.

Source

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

        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",
                    server = server_name,
                    tool = tool_name,
                    error = %err,
                    "retrying MCP tool call after stale session"
                );
                self.drop_connection(&server_name, "stale session retry");
                let conn = self.get_or_connect(&server_name).await?;
                if conn.catalog_generation != route.catalog_generation
                    || conn
                        .config()
                        .reviewed_plugin

View on GitHub (pinned to 8880682c63)

Solutions

  1. Check enabled_tools/disabled_tools for the server in mcp.json and add (or remove) the tool name accordingly
  2. Refresh the tool catalog and confirm the tool still appears in the server's tools/list
  3. If a reviewed plugin is involved, re-review/re-approve it so its authority matches, then reconnect
  4. If the server renamed the tool, update the calling code to the new name

Example fix

// before (.codewhale/mcp.json)
"my-server": { "command": "npx", "args": ["-y", "some-server"], "enabled_tools": ["old_tool"] }

// after
"my-server": { "command": "npx", "args": ["-y", "some-server"], "enabled_tools": ["old_tool", "new_tool"] }
Defensive patterns

Strategy: validation

Validate before calling

// Before calling, confirm the tool is still enabled and advertised on the live connection:
if let Some(conn) = manager.connection(server_name) {
    let cfg = conn.config();
    if !cfg.is_tool_enabled(&tool_name) || !conn.tools().iter().any(|t| t.name == tool_name) {
        anyhow::bail!("tool '{tool_name}' is not currently enabled/advertised; fix config first");
    }
}
manager.call_tool(prefixed_name, args).await?;

Try / catch

match manager.call_tool(prefixed_name, args).await {
    Err(e) if e.to_string().contains("is disabled for server") => {
        // inspect enabled_tools/disabled_tools and the refreshed catalog, then surface a config error
    }
    other => other,
}

Prevention

When it happens

Trigger: enabled_tools is set for the server and the tool is not in it; the tool is listed in disabled_tools; the server no longer advertises the tool after a restart; the reviewed_plugin authority changed (plugin re-reviewed/re-staged) so it no longer equals the authority captured when the tool was advertised.

Common situations: Editing mcp.json to add enabled_tools filtering; a server upgrade that renamed or removed a tool; a reviewed plugin re-staged so its authority digest differs from the advertised route.

Related errors


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