{"record":{"id":"2ba5a0bef99a2264","repo":"Hmbown/CodeWhale","slug":"mcp-tool-tool-name-is-disabled-for-server-se","errorCode":null,"errorMessage":"MCP tool '{tool_name}' is disabled for server '{server_name}'","messagePattern":"MCP tool '(.+?)' is disabled for server '(.+?)'","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp.rs","lineNumber":3325,"sourceCode":"        let route = self.resolve_advertised_tool(prefixed_name).await?;\n        let server_name = route.server_name.clone();\n        let tool_name = route.tool_name.clone();\n        // Copy the global timeouts to avoid borrow conflict\n        let global_timeouts = self.config.timeouts;\n        let conn = self.get_or_connect(&server_name).await?;\n        if conn.catalog_generation != route.catalog_generation {\n            anyhow::bail!(\"MCP catalog changed after tool resolution; retry the call\");\n        }\n        if conn\n            .config()\n            .reviewed_plugin\n            .as_ref()\n            .map(|source| &source.authority)\n            != route.plugin_authority.as_ref()\n            || !conn.config().is_tool_enabled(&tool_name)\n            || !conn.tools().iter().any(|tool| tool.name == tool_name)\n        {\n            anyhow::bail!(\"MCP tool '{tool_name}' is disabled for server '{server_name}'\");\n        }\n        let timeout = conn.config().effective_execute_timeout(&global_timeouts);\n        match conn.call_tool(&tool_name, arguments.clone(), timeout).await {\n            Ok(result) => Ok(result),\n            Err(err) if is_mcp_stale_session_error(&err) => {\n                tracing::debug!(\n                    target: \"mcp\",\n                    server = server_name,\n                    tool = tool_name,\n                    error = %err,\n                    \"retrying MCP tool call after stale session\"\n                );\n                self.drop_connection(&server_name, \"stale session retry\");\n                let conn = self.get_or_connect(&server_name).await?;\n                if conn.catalog_generation != route.catalog_generation\n                    || conn\n                        .config()\n                        .reviewed_plugin","sourceCodeStart":3307,"sourceCodeEnd":3343,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/mcp.rs#L3307-L3343","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check enabled_tools/disabled_tools for the server in mcp.json and add (or remove) the tool name accordingly","Refresh the tool catalog and confirm the tool still appears in the server's tools/list","If a reviewed plugin is involved, re-review/re-approve it so its authority matches, then reconnect","If the server renamed the tool, update the calling code to the new name"],"exampleFix":"// before (.codewhale/mcp.json)\n\"my-server\": { \"command\": \"npx\", \"args\": [\"-y\", \"some-server\"], \"enabled_tools\": [\"old_tool\"] }\n\n// after\n\"my-server\": { \"command\": \"npx\", \"args\": [\"-y\", \"some-server\"], \"enabled_tools\": [\"old_tool\", \"new_tool\"] }","handlingStrategy":"validation","validationCode":"// Before calling, confirm the tool is still enabled and advertised on the live connection:\nif let Some(conn) = manager.connection(server_name) {\n    let cfg = conn.config();\n    if !cfg.is_tool_enabled(&tool_name) || !conn.tools().iter().any(|t| t.name == tool_name) {\n        anyhow::bail!(\"tool '{tool_name}' is not currently enabled/advertised; fix config first\");\n    }\n}\nmanager.call_tool(prefixed_name, args).await?;","typeGuard":null,"tryCatchPattern":"match manager.call_tool(prefixed_name, args).await {\n    Err(e) if e.to_string().contains(\"is disabled for server\") => {\n        // inspect enabled_tools/disabled_tools and the refreshed catalog, then surface a config error\n    }\n    other => other,\n}","preventionTips":["Keep enabled_tools in mcp.json explicit and in sync with the tools your prompts actually call","After upgrading or restarting an MCP server, refresh the catalog and verify tool names before invoking them","Re-review plugins after re-staging so their authority matches the advertised routes"],"tags":["mcp","config","tools","authorization"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}