{"record":{"id":"96b1a4778eb3273b","repo":"vercel/ai","slug":"mcp-sse-transport-error-connection-closed-unexpec","errorCode":null,"errorMessage":"MCP SSE Transport Error: Connection closed unexpectedly","messagePattern":"MCP SSE Transport Error: Connection closed unexpectedly","errorType":"exception","errorClass":"MCPClientError","httpStatus":null,"severity":"error","filePath":"packages/mcp/src/tool/mcp-sse-transport.ts","lineNumber":161,"sourceCode":"            this.onerror?.(error);\n            return reject(error);\n          }\n\n          const stream = response.body\n            .pipeThrough(new TextDecoderStream())\n            .pipeThrough(new EventSourceParserStream());\n\n          const reader = stream.getReader();\n\n          const processEvents = async () => {\n            try {\n              while (true) {\n                const { done, value } = await reader.read();\n\n                if (done) {\n                  if (this.connected) {\n                    this.connected = false;\n                    throw new MCPClientError({\n                      message:\n                        'MCP SSE Transport Error: Connection closed unexpectedly',\n                    });\n                  }\n                  return;\n                }\n\n                const { event, data } = value;\n\n                if (event === 'endpoint') {\n                  if (this.endpoint) {\n                    continue;\n                  }\n\n                  const endpoint = new URL(data, this.url);\n\n                  if (endpoint.origin !== this.url.origin) {\n                    this.connected = false;","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/mcp/src/tool/mcp-sse-transport.ts#L143-L179","documentation":"The SSE stream ended (reader returned done) while the transport still considered itself connected, i.e. the server closed the connection without a proper shutdown. processEvents throws MCPClientError so callers of establishConnection/send learn the session died instead of hanging.","triggerScenarios":"SSE server closes the response stream (crash, deploy, idle timeout, proxy terminating long-lived connections) while this.connected is still true; network interruption causing the body stream to end early.","commonSituations":"Long-running sessions behind reverse proxies (nginx/ALB) with aggressive idle timeouts; serverless or autoscaling platforms recycling connections; MCP server restart during an active session.","solutions":["Wrap client operations in retry logic that recreates the client/transport and re-calls tools() after this error","Increase/proxy keep-alive and idle timeouts (e.g. nginx proxy_read_timeout) or send periodic traffic to keep the SSE stream alive","Verify the MCP server is not crashing or being redeployed mid-session; check server logs at the disconnect time","Reconnect and re-list tools before continuing, since session state is lost"],"exampleFix":"// before\nconst client = await createMCPClient({ transport });\nconst tools = await client.tools(); // throws if server dropped\n// after\nasync function withRetry(fn) {\n  try { return await fn(); }\n  catch (e) {\n    if (MCPClientError.isInstance(e)) { client = await createMCPClient({ transport: newTransport() }); return fn(); }\n    throw e;\n  }\n}","handlingStrategy":"retry","validationCode":"// check connection state before issuing requests\nif (!clientIsHealthy()) { client = await createMCPClient({ transport: newTransport() }); }","typeGuard":"function isConnectionClosedError(e: unknown): boolean {\n  return MCPClientError.isInstance(e) && e.message.includes('Connection closed unexpectedly');\n}","tryCatchPattern":"try {\n  result = await client.tools();\n} catch (error) {\n  if (isConnectionClosedError(error)) {\n    await delay(backoff++ * 1000);\n    client = await createMCPClient({ transport: newTransport() });\n    result = await client.tools();\n  } else throw error;\n}","preventionTips":["Configure generous keep-alive/idle timeouts on proxies fronting the SSE server","Implement reconnect-with-backoff around all client calls","Monitor server deploys/crashes; expect session loss on restart and re-fetch tools after reconnect"],"tags":["network","sse","connection-closed"],"backgroundTag":"connection-closed-unexpectedly","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}