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

  1. Read the status and body excerpt in the message — they identify the server-side reason directly
  2. On 401/403: re-run the MCP OAuth login to refresh credentials
  3. Verify the URL is the server's SSE endpoint (commonly /sse) and the transport is sse, not http
  4. 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

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


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/53484eaec5fe2a15. Report an issue: GitHub.