Hmbown/CodeWhale · warning

MCP configuration changed; reload it before connecting this…

Error message

MCP configuration changed; reload it before connecting this server

What it means

The MCP tools endpoint checks whether the freshly loaded MCP configuration still matches the in-memory connection pool's configuration. If it does not, it refuses to connect — even to a single named server — and returns this error in the response, telling the caller to reload the MCP configuration first.

Solutions

  1. Call the Runtime API's MCP config reload endpoint (or restart the Runtime API) so the pool snapshot matches the fresh config.
  2. Retry the MCP tools/connect request after reload succeeds.
  3. If no changes were intended, compare the fresh config against what the pool was built from to find the unexpected diff.
  4. Automate: after any mcp config write, always issue a reload before further MCP calls.

Example fix

// before
POST /mcp/tools {"server": "github"}  // -> "MCP configuration changed; reload..."

// after
POST /mcp/reload
POST /mcp/tools {"server": "github"}
Defensive patterns

Strategy: retry

Validate before calling

let fresh = fetch_mcp_config().await?;
let stale = fetch_pool_config_hash().await? != hash_of(&fresh);
if stale { call_mcp_reload().await?; }

Try / catch

match resp.error {
    Some(e) if e.contains("MCP configuration changed") => {
        client.reload_mcp_config().await?;
        client.mcp_tools(query).await?;
    }
    other => handle(other),
}

Prevention

When it happens

Trigger: POSTing to the MCP tools endpoint (with or without a specific server name in query.server) while the pool_handle's config_matches(fresh_config) check fails, i.e. the MCP config changed after the pool snapshot was loaded.

Common situations: Editing mcp config (adding/removing servers, changing commands or env) while a Runtime API client holds an old pool handle, then attempting to connect without calling the reload endpoint.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at crates/tui/src/runtime_api.rs:4329

    // best-effort reload behavior: unreadable/revoked sources fail closed.
    let fresh_config = if query.connect {
        Some(mcp_management_config(&state)?.0)
    } else {
        None
    };
    let Some(pool_handle) = mcp_pool_handle(&state, query.connect).await? else {
        return Ok(Json(McpToolsResponse {
            tools: Vec::new(),
            connections: Vec::new(),
        }));
    };
    let mut pool = pool_handle.lock().await;
    if fresh_config
        .as_ref()
        .is_some_and(|config| !pool.config_matches(config))
    {
        let error =
            anyhow::anyhow!("MCP configuration changed; reload it before connecting this server");
        let names = query
            .server
            .clone()
            .map(|name| vec![name])
            .unwrap_or_else(|| pool.server_names());
        return Ok(Json(McpToolsResponse {
            tools: Vec::new(),
            connections: names
                .iter()
                .map(|name| mcp_connection_outcome(&pool, name, Some(&error)))
                .collect(),
        }));
    }
    let errors = if query.connect {
        if let Some(server) = query.server.as_deref() {
            match pool.get_or_connect(server).await {
                Ok(_) => Vec::new(),
                Err(error) => vec![(server.to_owned(), error)],

View on GitHub (pinned to 73e0f67d83)