Kuberwastaken/claurst · error · anyhow::Error
MCP server ' ' connection failed
Error message
MCP server '{}' connection failed: {} What it means
After a failed MCP client connection attempt, connect marks the server Disconnected with the underlying error message stored as last_error, then returns this wrapped error including the server name and root cause. The state machine is updated before the error propagates so callers and the reconnect loop can inspect what failed.
Solutions
- Inspect the embedded root cause (last_error / inner message) — fix that underlying failure first.
- Verify the server command, args, and env in the MCP config; run the command manually to test.
- For remote servers, check the URL/port is reachable.
- Rely on restart/reconnect after fixing config, since state is already Disconnected.
Example fix
// before
manager.connect("filesystem").await?;
// after
if let Err(e) = manager.connect("filesystem").await {
eprintln!("filesystem MCP unavailable, continuing without it: {}", e);
// check server command: npx -y @modelcontextprotocol/server-filesystem
} Defensive patterns
Strategy: try-catch
Try / catch
match manager.connect(name).await {
Ok(()) => {},
Err(e) => {
// error embeds root cause after "connection failed: ..."
tracing::warn!("MCP '{}' unavailable: {}", name, e);
// proceed degraded; inspect McpServerStatus::Disconnected.last_error for detail
}
} Prevention
- Run the server command manually to verify it starts before wiring it up.
- Pin MCP server versions to avoid protocol handshake breakage.
- Check last_error in Disconnected status for the root cause.
- Use connect_all and tolerate partial failures rather than hard-failing.
When it happens
Trigger: connect(name) on a registered server whose client handshake/transport fails: server process not installed/unlaunchable, wrong command or URL in config, server crashed during MCP handshake, or network failure for HTTP/SSE servers.
Common situations: MCP server command not on PATH; bad args/env in the server config; protocol version mismatch during initialize handshake; server port closed; server binary panics on startup.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- MCP server ' ': legacy SSE POST request failed
- MCP server ' ': legacy SSE stream returned HTTP
- WebSocket connect to
- failed to resolve legacy SSE endpoint
- MCP server ' ': failed to read legacy SSE HTTP response body
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/c1cb89a8c82ee35c.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/mcp/src/connection_manager.rs:179
match Self::connect_expanded_config(name, &config).await {
Ok(client) => {
let tool_count = client.tools.len();
let client_arc = Arc::new(client);
let mut st = state_arc.lock().await;
st.client = Some(client_arc);
st.status = McpServerStatus::Connected { tool_count };
info!(server = %name, transport = %config.server_type, tools = tool_count, "MCP server connected");
Ok(())
}
Err(e) => {
let msg = e.to_string();
let mut st = state_arc.lock().await;
st.client = None;
st.status = McpServerStatus::Disconnected {
last_error: Some(msg.clone()),
};
Err(anyhow::anyhow!("MCP server '{}' connection failed: {}", name, msg))
}
}
}
/// Disconnect a server and cancel its reconnect loop.
pub async fn disconnect(&self, name: &str) {
{
let mut handles = self.reconnect_handles.lock().await;
if let Some(handle) = handles.remove(name) {
handle.abort();
}
}
if let Some(entry) = self.state.get(name) {
let mut st = entry.value().lock().await;
st.client = None;
st.status = McpServerStatus::Disconnected { last_error: None };
}
View on GitHub (pinned to b0637c97ec)