Hmbown/CodeWhale · error
MCP SSE rejected (transport=http url={} status={}): {}
Error message
MCP SSE rejected (transport=http url={} status={}): {} What it means
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.
Source
Thrown at crates/tui/src/mcp/sse.rs:124
&headers,
);
let response = tokio::select! {
biased;
_ = cancel_token.cancelled() => {
anyhow::bail!("MCP SSE connect cancelled before the request completed")
}
response = request.send() => response.with_context(|| {
format!(
"MCP SSE connect failed (transport=http url={})",
mask_url_secrets(&url),
)
})?,
};
let status = response.status();
if !status.is_success() {
let body_excerpt = bounded_body_excerpt(response, ERROR_BODY_PREVIEW_BYTES).await;
let body_excerpt = auth.server_error_preview(&body_excerpt);
anyhow::bail!(
"MCP SSE rejected (transport=http url={} status={}): {}",
mask_url_secrets(&url),
status,
body_excerpt,
);
}
let mut stream = response.bytes_stream();
use futures_util::StreamExt;
// Raw byte buffer so a multi-byte UTF-8 char split across reads is not
// corrupted, and bounded so a separator-less server cannot OOM us.
let mut buffer: Vec<u8> = Vec::new();
loop {
if cancel_token.is_cancelled() {
tracing::debug!("SSE loop cancelled");
break;
}View on GitHub (pinned to 8880682c63)
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
Example fix
// before: streamable endpoint used with transport=sse let url = "https://mcp.example.com/mcp"; // after: the server's SSE endpoint let url = "https://mcp.example.com/sse";
Defensive patterns
Strategy: retry
Validate before calling
```rust
async fn probe_sse_connect(client: &reqwest::Client, url: &str) -> anyhow::Result<()> {
let resp = client.get(url).send().await?;
anyhow::ensure!(resp.status().is_success(), "SSE probe status {}", resp.status());
Ok(())
}
``` Try / catch
```rust
let mut attempt = 0;
loop {
match connect_sse(&url, &auth).await {
Err(e) if e.to_string().contains("MCP SSE rejected") => {
if status_is_server_error(&e) && attempt < 2 { attempt += 1; backoff(attempt).await; continue; }
reauth_or_fix_config(&e); // 4xx: re-login or correct URL/transport
return Err(e);
}
other => return other.map(|_| ()),
}
}
``` Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- MCP SSE POST rejected (transport=sse endpoint={} status={}):
- Runtime API request failed (${status}): ${message}
- Anthropic API error (HTTP {status} {error_type}): {message}
- SSE stream request failed: HTTP {status}: {error_text}
- MCP session expired: {error}
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/53484eaec5fe2a15.
Report an issue: GitHub.