Kuberwastaken/claurst · error

MCP server ' ': legacy SSE stream returned HTTP

Error message

MCP server '{}': legacy SSE stream returned HTTP {}: {}

What it means

When establishing the legacy SSE transport, the client opens a long-lived GET stream to the server's /sse endpoint. If that initial request returns a non-success HTTP status, the connection cannot proceed and the error includes the status and response body for diagnosis.

Solutions

  1. Fix the server URL in the MCP config (verify the /sse path with curl)
  2. Run the MCP auth flow if the response is 401/403 — the server needs OAuth tokens
  3. If the server migrated to streamable HTTP, change the config type from 'sse' to 'http'
  4. Check proxy/load-balancer health if the body shows a 5xx gateway error

Example fix

// before
{ "mcpServers": { "x": { "type": "sse", "url": "https://host/mcp" } } }
// after
{ "mcpServers": { "x": { "type": "http", "url": "https://host/mcp" } } }
Defensive patterns

Strategy: retry

Validate before calling

let resp = reqwest::get(&sse_url).await?;
if !resp.status().is_success() {
    anyhow::bail!("precheck failed: {} {}", resp.status(), resp.text().await?);
}

Try / catch

match backend.connect().await {
    Err(e) if e.to_string().contains("legacy SSE stream returned HTTP") => {
        // inspect status: 401 -> run auth; 404 -> fix URL; 5xx -> retry with backoff
    }
    other => other?,
}

Prevention

When it happens

Trigger: start_sse_listener issues the initial GET on the legacy SSE stream for server self.server_name and receives a non-success response status.

Common situations: Wrong URL in the MCP config (404); server requires authentication (401/403); reverse proxy returns 502/503 when the backend is down; server no longer supports legacy SSE after an upgrade.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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

Appendix: source

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

            .header(reqwest::header::ACCEPT, "text/event-stream");
        if let Some(token) = &self.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 '{}': failed to open legacy SSE stream '{}': {}",
                self.server_name,
                self.sse_url,
                e
            )
        })?;
        if !response.status().is_success() {
            let status = response.status();
            let body = response.text().await.unwrap_or_default();
            anyhow::bail!(
                "MCP server '{}': legacy SSE stream returned HTTP {}: {}",
                self.server_name,
                status,
                body
            );
        }

        let server_name = self.server_name.clone();
        let sse_url = self.sse_url.clone();
        let post_endpoint = Arc::clone(&self.post_endpoint);
        let incoming_tx = self.incoming_tx.clone();
        let endpoint_tx_for_task = Arc::clone(&endpoint_tx);
        let task = tokio::spawn(async move {
            let result = transport::process_sse_response(response, |event, data| {
                if matches!(event, Some("endpoint")) {
                    let endpoint = transport::resolve_legacy_endpoint(&sse_url, data)?;
                    *lock_recover(&post_endpoint) = Some(endpoint.clone());
                    if let Some(tx) = lock_recover(&endpoint_tx_for_task).take() {

View on GitHub (pinned to b0637c97ec)