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
- Fix the server URL in the MCP config (verify the /sse path with curl)
- Run the MCP auth flow if the response is 401/403 — the server needs OAuth tokens
- If the server migrated to streamable HTTP, change the config type from 'sse' to 'http'
- 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
- Curl the /sse endpoint before wiring it into the MCP config
- Run the OAuth flow first for servers that require authentication
- Switch to the http (streamable) transport when the server supports it
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
- MCP server ' ': HTTP from legacy SSE transport
- MCP server ' ': legacy SSE POST request failed
- legacy SSE endpoint event did not include a POST endpoint
- MCP server ' ' connection failed
- invalid legacy SSE base URL
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)