Kuberwastaken/claurst · error

MCP server ' ': legacy SSE POST request failed

Error message

MCP server '{}': legacy SSE POST request failed: {}

What it means

This error wraps a reqwest transport failure that occurred while POSTing a JSON-RPC message to a legacy (HTTP+SSE) MCP server's message endpoint. It is raised in the `send` implementation of `LegacySseRmcpTransport`, which serializes the outgoing rmcp message as JSON and sends it to the previously discovered post endpoint. Any error at the HTTP layer (DNS, connect, TLS, timeout, body encode, request build) is wrapped with the MCP server name so the operator can identify which configured server is unreachable. The inner reqwest error is preserved in the message, so the actual root cause (e.g. 'connection refused', 'timed out') appears after the colon.

Solutions

  1. Verify the MCP server is running and reachable: `curl -v <post-endpoint-URL>` from the same host.
  2. Check the mcpServers config entry (command/args or url) for a wrong host, port, or path.
  3. If the server was restarted, reconnect — the discovered post endpoint may be stale.
  4. Inspect the inner reqwest error text in the message (connection refused / timed out / dns error) to pick the right fix.
  5. If timeouts are the cause, increase the reqwest client timeout or check server load/proxy settings.

Example fix

// before: transport constructed with a hardcoded port that nothing listens on
let backend = RmcpClientBackend::connect_legacy_sse("http://127.0.0.1:9999/sse", ...).await?;
// after: start the MCP server first and derive the port/URL from its startup log
let server = spawn_mcp_server(port_file)?;
let port = read_port(port_file).await?;
let backend = RmcpClientBackend::connect_legacy_sse(&format!("http://127.0.0.1:{port}/sse"), ...).await?;
Defensive patterns

Strategy: retry

Validate before calling

async fn mcp_server_reachable(sse_url: &str) -> bool {
    reqwest::get(sse_url).await.map(|r| r.status().is_success()).unwrap_or(false)
}

Try / catch

match backend.list_tools().await {
    Ok(t) => t,
    Err(e) if e.to_string().contains("legacy SSE POST request failed") => {
        eprintln!("MCP server unreachable, check config/process: {e}");
        Vec::new()
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling any MCP operation through a backend configured with the legacy SSE transport when `request.send().await` fails: server process is down, wrong host/port in the MCP server config, the SSE-post endpoint URL is stale after a server restart, TLS certificate problems, or the network drops mid-request.

Common situations: MCP server binary not running or crashed; `mcpServers` entry points at a port nothing listens on; server restarted and returned a different message endpoint; corporate proxy or firewall blocking the connection; request timeout because the server is overloaded and slow to accept POSTs.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10). Data as JSON: /api/errors/68ac458f3313dcf8. Report an issue: GitHub.

Appendix: source

Thrown at src-rust/crates/mcp/src/rmcp_backend.rs:388

                anyhow::anyhow!(
                    "MCP server '{}': legacy SSE POST endpoint has not been discovered",
                    server_name
                )
            })?;

            let mut request = client
                .post(endpoint)
                .header(reqwest::header::CONTENT_TYPE, "application/json")
                .json(&item);
            if let Some(token) = &auth_token {
                request = request.header(
                    reqwest::header::AUTHORIZATION,
                    transport::bearer_header_value(token)?,
                );
            }

            let response = request.send().await.map_err(|e| {
                anyhow::anyhow!(
                    "MCP server '{}': legacy SSE POST request failed: {}",
                    server_name,
                    e
                )
            })?;

            handle_legacy_sse_http_response(server_name, response, incoming_tx, background_tasks)
                .await
                .map_err(Into::into)
        }
    }

    fn receive(
        &mut self,
    ) -> impl std::future::Future<Output = Option<rmcp::service::RxJsonRpcMessage<RoleClient>>> + Send {
        let incoming_rx = Arc::clone(&self.incoming_rx);
        async move {
            let mut rx = incoming_rx.lock().await;

View on GitHub (pinned to b0637c97ec)