{"record":{"id":"efc0422bda0187e2","repo":"Kuberwastaken/claurst","slug":"mcp-server-failed-to-parse-legacy-sse-json-p","errorCode":null,"errorMessage":"MCP server '{}': failed to parse legacy SSE JSON payload: {}","messagePattern":"MCP server '(.+?)': failed to parse legacy SSE JSON payload: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-rust/crates/mcp/src/rmcp_backend.rs","lineNumber":428,"sourceCode":"\n    fn close(&mut self) -> impl std::future::Future<Output = Result<(), Self::Error>> + Send {\n        let background_tasks = Arc::clone(&self.background_tasks);\n        async move {\n            let mut tasks = lock_recover(&background_tasks);\n            for handle in tasks.drain(..) {\n                handle.abort();\n            }\n            Ok(())\n        }\n    }\n}\n\nfn parse_server_message(\n    server_name: &str,\n    data: &str,\n) -> anyhow::Result<rmcp::service::RxJsonRpcMessage<RoleClient>> {\n    serde_json::from_str(data).map_err(|e| {\n        anyhow::anyhow!(\n            \"MCP server '{}': failed to parse legacy SSE JSON payload: {}\",\n            server_name,\n            e\n        )\n    })\n}\n\nasync fn handle_legacy_sse_http_response(\n    server_name: String,\n    response: reqwest::Response,\n    incoming_tx: mpsc::UnboundedSender<rmcp::service::RxJsonRpcMessage<RoleClient>>,\n    background_tasks: Arc<StdMutex<Vec<JoinHandle<()>>>>,\n) -> anyhow::Result<()> {\n    let status = response.status();\n    if !status.is_success() && status != reqwest::StatusCode::ACCEPTED {\n        let body = response.text().await.unwrap_or_default();\n        anyhow::bail!(\n            \"MCP server '{}': HTTP {} from legacy SSE transport: {}\",","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/Kuberwastaken/claurst/blob/b0637c97ec34144387cbf2f74f65df6d16a6cef1/src-rust/crates/mcp/src/rmcp_backend.rs#L410-L446","documentation":"Raised by `parse_server_message` when a JSON payload arriving from a legacy SSE MCP server (either from the long-lived SSE stream or from a POST response body) cannot be deserialized into an rmcp `RxJsonRpcMessage<RoleClient>`. The library expects every server-sent event data block to be a valid JSON-RPC 2.0 message conforming to the MCP schema. If the payload is malformed JSON, empty-but-not-blank, or structurally not a JSON-RPC message, serde deserialization fails and the server name plus serde error are wrapped into this anyhow error.","triggerScenarios":"`parse_server_message` called from `start_sse_listener` or `handle_legacy_sse_http_response` with `data` that is not valid JSON-RPC: server sends HTML error pages over SSE, sends JSON that lacks required JSON-RPC fields (e.g. no `jsonrpc: \"2.0\"`), sends a JSON array, or truncates a message.","commonSituations":"Connecting the legacy SSE transport to a non-MCP HTTP endpoint that streams HTML or plain text; an old MCP server implementing a pre-standard protocol revision whose message shapes no longer deserialize; a proxy mangling the SSE stream; server bug emitting comments/keepalives as data payloads.","solutions":["Inspect the raw SSE payload (log `data` before parsing) to see what the server actually sent.","Confirm the endpoint is a real MCP server speaking the SSE transport (GET /sse), not a generic HTTP route.","Upgrade the MCP server to a protocol version compatible with the rmcp client schema.","If the server sends non-JSON keepalive frames, configure it to use SSE comments (`: ping`) instead of data events."],"exampleFix":"// before: pointing the SSE transport at the messages endpoint instead of the SSE endpoint\nlet backend = connect_legacy_sse(\"http://host:3000/message\").await?;\n// after: use the server's advertised SSE endpoint\nlet backend = connect_legacy_sse(\"http://host:3000/sse\").await?;","handlingStrategy":"validation","validationCode":"fn looks_like_jsonrpc(data: &str) -> bool {\n    serde_json::from_str::<serde_json::Value>(data)\n        .map(|v| v.get(\"jsonrpc\").is_some() && v.get(\"method\").is_some() || v.get(\"id\").is_some())\n        .unwrap_or(false)\n}","typeGuard":"fn as_jsonrpc_message(data: &str) -> Option<serde_json::Value> {\n    serde_json::from_str(data).ok().filter(|v| v.is_object())\n}","tryCatchPattern":"match parse_server_message(&server_name, data) {\n    Ok(msg) => incoming_tx.send(msg).ok(),\n    Err(e) => {\n        tracing::warn!(%server_name, raw = %data, \"dropping unparseable SSE payload: {e}\");\n        Ok(())\n    }\n}","preventionTips":["Confirm the SSE endpoint is the MCP server's SSE route, not a generic HTTP path.","Pin and test the MCP protocol version supported by both client and server.","Log raw SSE data frames at debug level so malformed payloads are diagnosable in the field.","Keep the MCP server updated to a revision whose message schema matches the rmcp client."],"tags":["mcp","sse","json","deserialization","protocol"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"b0637c97ec34144387cbf2f74f65df6d16a6cef1","analyzedAt":"2026-09-10T00:24:58.650Z","contentChangedAt":"2026-09-10T00:24:58.650Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}