{"record":{"id":"53484eaec5fe2a15","repo":"Hmbown/CodeWhale","slug":"mcp-sse-rejected-transport-http-url-status","errorCode":null,"errorMessage":"MCP SSE rejected (transport=http url={} status={}): {}","messagePattern":"MCP SSE rejected \\(transport=http url=(.+?) status=(.+?)\\): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp/sse.rs","lineNumber":124,"sourceCode":"            &headers,\n        );\n        let response = tokio::select! {\n            biased;\n            _ = cancel_token.cancelled() => {\n                anyhow::bail!(\"MCP SSE connect cancelled before the request completed\")\n            }\n            response = request.send() => response.with_context(|| {\n                format!(\n                    \"MCP SSE connect failed (transport=http url={})\",\n                    mask_url_secrets(&url),\n                )\n            })?,\n        };\n        let status = response.status();\n        if !status.is_success() {\n            let body_excerpt = bounded_body_excerpt(response, ERROR_BODY_PREVIEW_BYTES).await;\n            let body_excerpt = auth.server_error_preview(&body_excerpt);\n            anyhow::bail!(\n                \"MCP SSE rejected (transport=http url={} status={}): {}\",\n                mask_url_secrets(&url),\n                status,\n                body_excerpt,\n            );\n        }\n\n        let mut stream = response.bytes_stream();\n        use futures_util::StreamExt;\n        // Raw byte buffer so a multi-byte UTF-8 char split across reads is not\n        // corrupted, and bounded so a separator-less server cannot OOM us.\n        let mut buffer: Vec<u8> = Vec::new();\n\n        loop {\n            if cancel_token.is_cancelled() {\n                tracing::debug!(\"SSE loop cancelled\");\n                break;\n            }","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/mcp/sse.rs#L106-L142","documentation":"The initial GET to the SSE connect URL returned a non-2xx status. The message embeds the secret-masked URL, the HTTP status, and a bounded, auth-scrubbed body excerpt (server_error_preview) so the server's stated reason is visible without leaking tokens.","triggerScenarios":"GET on the SSE URL answers 401/403 (missing, expired, or unrefreshed auth headers), 404 (wrong path — e.g. the streamable /mcp endpoint used with transport=sse), 405, or a 5xx from the server or gateway.","commonSituations":"Transport/URL mismatch (sse vs streamable-http routes); OAuth token revoked or refresh failed; reverse proxy or gateway rejecting the request; server down mid-deploy.","solutions":["Read the status and body excerpt in the message — they identify the server-side reason directly","On 401/403: re-run the MCP OAuth login to refresh credentials","Verify the URL is the server's SSE endpoint (commonly /sse) and the transport is sse, not http","On 5xx: check server health and retry after recovery"],"exampleFix":"// before: streamable endpoint used with transport=sse\nlet url = \"https://mcp.example.com/mcp\";\n\n// after: the server's SSE endpoint\nlet url = \"https://mcp.example.com/sse\";","handlingStrategy":"retry","validationCode":"```rust\nasync fn probe_sse_connect(client: &reqwest::Client, url: &str) -> anyhow::Result<()> {\n    let resp = client.get(url).send().await?;\n    anyhow::ensure!(resp.status().is_success(), \"SSE probe status {}\", resp.status());\n    Ok(())\n}\n```","typeGuard":null,"tryCatchPattern":"```rust\nlet mut attempt = 0;\nloop {\n    match connect_sse(&url, &auth).await {\n        Err(e) if e.to_string().contains(\"MCP SSE rejected\") => {\n            if status_is_server_error(&e) && attempt < 2 { attempt += 1; backoff(attempt).await; continue; }\n            reauth_or_fix_config(&e); // 4xx: re-login or correct URL/transport\n            return Err(e);\n        }\n        other => return other.map(|_| ()),\n    }\n}\n```","preventionTips":["Point transport=sse at the /sse route and transport=http at /mcp; never mix them","Re-run MCP OAuth login after revoking or rotating tokens","Probe new server URLs once with curl -i before enabling them"],"tags":["mcp","sse","http","authentication"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}