{"record":{"id":"d7dd4c93591beddc","repo":"koala73/worldmonitor","slug":"no-result-found-in-sse-response","errorCode":null,"errorMessage":"No result found in SSE response","messagePattern":"No result found in SSE response","errorType":"exception","errorClass":null,"httpStatus":422,"severity":"error","filePath":"api/mcp-proxy.ts","lineNumber":291,"sourceCode":"    signal: AbortSignal.timeout(TIMEOUT_MS),\n  });\n  return resp;\n}\n\nasync function parseJsonRpcResponse(resp) {\n  const ct = resp.headers.get('content-type') || '';\n  if (ct.includes('text/event-stream')) {\n    const text = await resp.text();\n    const lines = text.split('\\n');\n    for (const line of lines) {\n      if (line.startsWith('data: ')) {\n        try {\n          const parsed = JSON.parse(line.slice(6));\n          if (parsed.result !== undefined || parsed.error !== undefined) return parsed;\n        } catch { /* skip */ }\n      }\n    }\n    throw new Error('No result found in SSE response');\n  }\n  return resp.json();\n}\n\nasync function sendInitialized(serverUrl, headers, sessionId) {\n  try {\n    await postJson(serverUrl, {\n      jsonrpc: '2.0',\n      method: 'notifications/initialized',\n      params: {},\n    }, headers, sessionId);\n  } catch (error) {\n    if (error instanceof McpProxySsrfError) throw error;\n    /* non-fatal */\n  }\n}\n\nasync function mcpListTools(serverUrl, customHeaders) {","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/koala73/worldmonitor/blob/ffec79ac339946fd2d24e85845da5755dcaa534b/api/mcp-proxy.ts#L273-L309","documentation":"Thrown by parseJsonRpcResponse when the upstream MCP server answered with Content-Type text/event-stream but none of the `data:` lines parsed as JSON containing a top-level `result` or `error` field. The Streamable HTTP transport (MCP 2025-03-26) expects the RPC response — initialize, tools/list, etc. — to be carried in an SSE data frame; if the stream only carries progress/keepalive events or is malformed, this fires.","triggerScenarios":"POST /api/mcp-proxy completes the initialize handshake, then issues an RPC; the upstream returns text/event-stream whose data lines are either non-JSON (skipped silently), JSON without `result`/`error`, or empty. Common with a misbehaving MCP server that streams comments/heartbeats but never delivers the actual response within the parsed buffer.","commonSituations":"Upstream MCP server uses a non-standard SSE framing; the response got truncated mid-stream; the server sent only `:keepalive` comments; a protocol-version mismatch (server speaks an older MCP transport); the upstream server errored but wrote the error outside a `data:` line.","solutions":["Confirm the upstream MCP server implements the Streamable HTTP transport (MCP 2025-03-26) and emits the JSON-RPC response in a `data:` frame.","Check the upstream server logs for an exception during the RPC that prevented it from writing the result frame.","Verify MCP_PROTOCOL_VERSION matches what the upstream server expects.","If the server only supports the older HTTP POST+JSON transport, point the proxy at the JSON endpoint rather than the SSE one (or upgrade the server)."],"exampleFix":"// before — upstream returns SSE with no result/error data line\n//   -> parseJsonRpcResponse throws 'No result found in SSE response'\n// after — upstream emits a proper JSON-RPC response in a data frame\n//   data: {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{...}}\n//\n// (server-side fix; no client-side change beyond confirming protocol compliance)","handlingStrategy":"validation","validationCode":"function looksLikeSseJsonRpcResponse(text: string): boolean {\n  for (const line of text.split('\\n')) {\n    if (!line.startsWith('data: ')) continue;\n    try {\n      const p = JSON.parse(line.slice(6));\n      if (p && (p.result !== undefined || p.error !== undefined)) return true;\n    } catch { /* skip */ }\n  }\n  return false;\n}","typeGuard":"function isJsonRpcResultOrError(parsed: unknown): boolean {\n  return typeof parsed === 'object' && parsed !== null\n    && ('result' in parsed || 'error' in parsed);\n}","tryCatchPattern":"try {\n  const rpc = await parseJsonRpcResponse(resp);\n  // proceed\n} catch (err) {\n  if (err.message === 'No result found in SSE response') {\n    // Upstream did not emit a JSON-RPC frame; surface as a 502 with the\n    // serverUrl so the operator can debug the upstream MCP server.\n    return res.status(502).json({ error: 'Upstream MCP server returned no JSON-RPC result.' });\n  }\n  throw err;\n}","preventionTips":["Ensure upstream MCP servers implement the Streamable HTTP transport (MCP 2025-03-26) and emit the JSON-RPC response in a `data:` frame.","Keep MCP_PROTOCOL_VERSION aligned with what the upstream server expects.","Capture the raw SSE body for debugging when this fires — it usually reveals a malformed/empty stream or a protocol mismatch."],"tags":["mcp","sse","json-rpc","proxy","upstream"],"backgroundTag":null,"analyzedSha":"ffec79ac339946fd2d24e85845da5755dcaa534b","analyzedAt":"2026-08-12T11:24:56.012Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}