{"record":{"id":"8b644e9e5d965ada","repo":"Hmbown/CodeWhale","slug":"mcp-response-body-exceeds-max-bytes-bytes-abor","errorCode":null,"errorMessage":"MCP response body exceeds {max_bytes} bytes — aborting","messagePattern":"MCP response body exceeds (.+?) bytes — aborting","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp/streamable_http.rs","lineNumber":228,"sourceCode":"}\n\n/// Read a response body through the byte stream, failing as soon as it\n/// exceeds `max_bytes`. This bounds chunked and missing-Content-Length\n/// responses exactly like declared ones (the declared-length fast path in\n/// `send` only covers servers honest enough to announce their size).\n/// MCP bodies are JSON or SSE, so lossy UTF-8 matches `.text()` behavior.\npub(super) async fn read_body_capped(\n    response: reqwest::Response,\n    max_bytes: usize,\n) -> Result<String> {\n    use futures_util::StreamExt;\n\n    let mut stream = response.bytes_stream();\n    let mut buf: Vec<u8> = Vec::new();\n    while let Some(chunk) = stream.next().await {\n        let chunk = chunk.context(\"failed to read MCP response body\")?;\n        if buf.len().saturating_add(chunk.len()) > max_bytes {\n            anyhow::bail!(\"MCP response body exceeds {max_bytes} bytes — aborting\");\n        }\n        buf.extend_from_slice(&chunk);\n    }\n    Ok(String::from_utf8_lossy(&buf).into_owned())\n}\n\n/// TUI recovery for a rejected OAuth session. Settings recovery and the\n/// Streamable HTTP path share the oauth helpers so `/mcp login <name>` stays\n/// the only advertised command; `/mcp auth` is not a command.\nfn oauth_refresh_failed_hint() -> &'static str {\n    super::oauth::tui_reauth_refresh_failed_hint()\n}\n\n/// TUI recovery for a rejected OAuth session. `oauth_configured` is the\n/// server's configured auth path ([`McpHttpAuth::oauth_configured`]), not the\n/// presence of a cached token, so a first-run OAuth server — a 401 with\n/// nothing stored yet — is still pointed at `/mcp login <name>` rather than at\n/// a bearer token it never had (#6030). Servers where a bearer credential is","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/mcp/streamable_http.rs#L210-L246","documentation":"The streamable-HTTP MCP transport caps response body reads at max_bytes. While streaming the response body, if accumulating another chunk would exceed the cap the read is aborted with this error, protecting the client from unbounded or malicious responses.","triggerScenarios":"An MCP server returns a response body larger than the configured cap while send() drains the bytes_stream — e.g. a huge tool result, a server bug returning an error page as a giant body, or a compromised/hostile endpoint.","commonSituations":"Tool returning enormous output (large file dumps, log spew); misconfigured cap set below the server's legitimate response size; server streaming an error document without a proper HTTP error status.","solutions":["Increase the MCP response body size cap in configuration if legitimate responses are large.","Reduce the size of tool outputs on the server side (paginate, truncate).","Check the server for a bug that returns oversized non-JSON bodies.","If the endpoint is untrusted, treat this as the size guard working as intended and investigate the server."],"exampleFix":"// before: cap too small for large tool outputs\nlet max_bytes = 64 * 1024;\n\n// after\nlet max_bytes = 4 * 1024 * 1024;","handlingStrategy":"validation","validationCode":"if expected_max_response > configured_max_bytes {\n    raise ConfigError(\"response cap smaller than expected tool outputs; raise the cap\")\n}","typeGuard":null,"tryCatchPattern":"Err(e) if e.to_string().contains(\"body exceeds\") => {\n    // treat as untrusted/oversized response: do not retry blindly;\n    // raise cap only if the server is trusted and outputs are legitimately large\n    return Err(anyhow!(\"oversized MCP response; cap={}, check server output size\", e));\n}","preventionTips":["Size the cap above your largest legitimate tool output but well below memory limits.","Cap tool outputs server-side (paginate/truncate) so responses stay bounded.","Treat repeated breaches from one endpoint as a server bug or compromise signal."],"tags":["mcp","http","payload-size","streaming"],"backgroundTag":"payload-too-large","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}