Hmbown/CodeWhale · error · anyhow::Error
Failed to call MCP method '{}': connection '{}' is not ready
Error message
Failed to call MCP method '{}': connection '{}' is not ready What it means
call_method is the shared path behind call_tool / read_resource / get_prompt and refuses to send when the connection state is anything but Ready (crates/tui/src/mcp.rs:2065-2071). State is Connecting until initialize and discover_all finish inside connect_with_policy, and any send/recv error flips it to Disconnected via finish_guarded_error (or explicit shutdown), after which every further call fails fast with this message instead of hanging.
Source
Thrown at crates/tui/src/mcp.rs:2066
"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
}))
.awaitView on GitHub (pinned to 8880682c63)
Solutions
- Gate calls on the public accessors: conn.is_ready() or conn.state() == ConnectionState::Ready (mcp.rs:2149/2160).
- On Disconnected, drop the connection and reconnect via connect_with_policy rather than retrying calls on it.
- For one-shot flows, construct the connection and let connect_with_policy return (it only returns Ready connections) before issuing calls.
Example fix
// before: may hit "connection is not ready" after an earlier error
let resp = conn.call_tool("search", args, 30).await?;
// after: check readiness and reconnect when the connection dropped
if !conn.is_ready() {
conn = McpConnection::connect_with_policy(name, cfg, &timeouts, policy).await?;
}
let resp = conn.call_tool("search", args, 30).await?; Defensive patterns
Strategy: type-guard
Validate before calling
if !conn.is_ready() {
// Connecting: wait for connect_with_policy to return Ready.
// Disconnected: rebuild the connection instead of calling.
} Type guard
use crate::mcp::ConnectionState;
fn connection_ready(conn: &McpConnection) -> bool {
matches!(conn.state(), ConnectionState::Ready)
} Try / catch
match conn.call_tool(tool, args, timeout).await {
Ok(value) => value,
Err(err) if err.to_string().contains("is not ready") => {
// State moved to Connecting/Disconnected: reconnect, do not re-call blindly.
*conn = McpConnection::connect_with_policy(name, cfg, &timeouts, policy).await?;
conn.call_tool(tool, args, timeout).await?
}
Err(err) => return Err(err),
} Prevention
- Gate every call_tool/read_resource/get_prompt on is_ready().
- Treat Disconnected as terminal for that handle: reconnect, never re-call.
- Let connect_with_policy fully return before dispatching calls at startup.
When it happens
Trigger: Invoking tools during the connect window; reusing a connection after a prior call errored (state already Disconnected, see mcp.rs:2173-2264); calling after shutdown_all.
Common situations: Embedding code missing an is_ready() gate; retry loops hammering a dead connection instead of reconnecting; startup races where calls are dispatched before connect returns.
Related errors
- MCP SSE connect cancelled before authentication completed
- SSE transport cancelled before endpoint was discovered
- invalid JSON payload at key {MCP_SERVER_DEFINITIONS_KEY}; co
- invalid MCP server definition list in key {MCP_SERVER_DEFINI
- tracked SSH Fleet worker {worker_id} has no host adapter
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/39a4ad7f74cfeb70.
Report an issue: GitHub.