Hmbown/CodeWhale · error

MCP server ' ' is disabled

Error message

MCP server '{server_name}' is disabled

What it means

During the OAuth/login ready-check flow for an MCP server, the server's current config is fetched and found to be disabled. The flow refuses to proceed (e.g. restarting a browser login) because authentication for a disabled server is pointless and would silently diverge from config intent.

Solutions

  1. Enable the MCP server in config first, then run the login/authorize flow again.
  2. If the server was intentionally disabled, cancel the login instead of authenticating it.
  3. Confirm the server name matches an enabled entry in the active MCP config file.

Example fix

// before
[mcp.servers.github]
enabled = false
# then: codewhale mcp login github  -> fails
// after
[mcp.servers.github]
enabled = true
# then: codewhale mcp login github
Defensive patterns

Strategy: validation

Validate before calling

if let Some(cfg) = pool.server_config(name) {
    if !cfg.is_enabled() {
        return Err(format!("enable server '{name}' before running login"));
    }
} else {
    return Err(format!("server '{name}' is no longer configured"));
}

Try / catch

match pool.start_login(name).await {
    Err(e) if e.to_string().ends_with("is disabled") => {
        // prompt user to enable the server; do not open the browser flow
    }
    r => r?,
}

Prevention

When it happens

Trigger: Invoking the login/authorize path for `server_name` when `server_config(server_name)` resolves but `is_enabled()` is false. Note the distinct 'no longer configured' error when the server is missing entirely.

Common situations: Running `codewhale mcp login` (or triggering login from the catalog) for a server that was disabled in config; disabling a server between catalog build and login.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/767e8b174eba39cd. Report an issue: GitHub.

Appendix: source

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

    /// release it before the (up to five minute) browser wait in
    /// [`oauth::McpOAuthToolLogin::finish`]. Holding the lock across that wait
    /// would freeze every other MCP call, the `/mcp` manager, and the
    /// Extensions view for the whole sign-in.
    pub(crate) async fn begin_authenticate_tool(
        &self,
        server_name: &str,
    ) -> Result<AuthenticateToolStart> {
        self.require_server(server_name)?;
        Self::authorize_call(
            &self.disallowed_tools,
            &Self::mcp_model_tool_name(server_name, AUTHENTICATE_TOOL_NAME),
            &serde_json::json!({}),
        )?;
        let server = self
            .server_config(server_name)
            .ok_or_else(|| anyhow::anyhow!("MCP server '{server_name}' is no longer configured"))?;
        if !server.is_enabled() {
            anyhow::bail!("MCP server '{server_name}' is disabled");
        }

        // Already-authorized branch: a login that completed since the catalog
        // was built (e.g. `codewhale mcp login` in another window) must not
        // restart the browser flow — adopt the stored tokens by reconnecting.
        let ready = self
            .connections
            .get(server_name)
            .is_some_and(McpConnection::is_ready);
        if ready || oauth::has_usable_stored_tokens(server_name, &server) {
            return Ok(AuthenticateToolStart::AlreadyAuthorized);
        }
        let login = oauth::begin_oauth_login_for_server_tool(
            server_name,
            &server,
            None,
            self.oauth_callback_port,
            self.oauth_callback_url.as_deref(),

View on GitHub (pinned to 73e0f67d83)