Hmbown/CodeWhale · error

Failed to call MCP method

Error message

Failed to call MCP method '{}': connection '{}' is not ready

What it means

Requests can only be sent to an MCP connection whose state is ConnectionState::Ready (initialization handshake completed). Calling a method on a connection still connecting, failed, or already torn down bails with this error naming the method and connection. It is a state-machine guard, not a network failure.

Solutions

  1. Ensure the MCP server finished initializing before issuing calls (await the ready signal)
  2. Reconnect/restart the MCP server if its state left Ready
  3. Check the server's stderr/logs for a crash that moved the connection out of Ready
  4. Increase startup timeout or reduce server cold-start time (e.g. pre-install npx packages)
Defensive patterns

Strategy: type-guard

Validate before calling

// only issue calls after the ready signal
connection.ready().await?; // awaits ConnectionState::Ready
let value = connection.call("tools/call", params, timeout).await?;

Type guard

fn is_ready(c: &McpConnection) -> bool { c.state() == ConnectionState::Ready }

Try / catch

match conn.call(method, params, timeout).await {
    Err(e) if e.to_string().contains("is not ready") => {
        conn.reconnect().await?; // then retry once
        conn.call(method, params, timeout).await
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling any MCP method (tools/call, tools/list, ping, etc.) before initialization completes, after a connection error transitioned state away from Ready, or after the transport was shut down/cancelled.

Common situations: A race where a tool invocation fires while the server is still starting (slow npx/npm cold start); the server crashed earlier and the stale connection object is reused; shutdown/cancel racing a pending call.

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/39a4ad7f74cfeb70. Report an issue: GitHub.

Appendix: source

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

            "prompts/get",
            serde_json::json!({
                "name": prompt_name,
                "arguments": arguments
            }),
            timeout_secs,
        )
        .await
    }

    /// Generic method to call an MCP method
    async fn call_method(
        &mut self,
        method: &str,
        params: serde_json::Value,
        timeout_secs: u64,
    ) -> Result<serde_json::Value> {
        if self.state != ConnectionState::Ready {
            anyhow::bail!(
                "Failed to call MCP method '{}': connection '{}' is not ready",
                method,
                self.name
            );
        }
        if let Some(source) = self.config.reviewed_plugin.as_ref() {
            source.validate_before_use(&self.name, method)?;
        }

        let call_id = self.next_id();
        if let Err(error) = self
            .send(serde_json::json!({
                "jsonrpc": "2.0",
                "id": &call_id,
                "method": method,
                "params": params
            }))
            .await

View on GitHub (pinned to 73e0f67d83)