can1357/oh-my-pi · error · Error

Legacy SSE response did not include a body

Error message

Legacy SSE response did not include a body

What it means

The legacy SSE transport's connect() received a 2xx response but with a null body, so there is no event stream to read the 'endpoint' event from. A valid legacy SSE handshake requires a readable stream whose first event names the POST message endpoint; without a body the transport cannot complete initialization and throws. This runs after the !response.ok check, so the server did return success — just with nothing in it.

Source

Thrown at packages/coding-agent/src/mcp/transports/sse.ts:90

		const connection = new AbortController();
		const timeout = resolveMCPTimeoutMs(this.#config.timeout);
		const operation = createMCPTimeout(timeout, connection.signal);
		const endpointReady = Promise.withResolvers<void>();
		this.#sseConnection = connection;

		try {
			const response = await this.#fetch(
				this.#config.url,
				{ method: "GET", signal: operation.signal },
				{ Accept: "text/event-stream" },
			);

			if (!response.ok) {
				const text = await response.text();
				throw new Error(`HTTP ${response.status}: ${text}`);
			}
			if (!response.body) {
				throw new Error("Legacy SSE response did not include a body");
			}

			void this.#readSSEStream(response.body, operation, endpointReady).finally(() => {
				const wasConnected = this.#connected;
				if (this.#sseConnection === connection) this.#sseConnection = null;
				if (wasConnected) this.onClose?.();
			});
			await endpointReady.promise;
		} catch (error) {
			operation.clear();
			if (this.#sseConnection === connection) this.#sseConnection = null;
			connection.abort();
			if (operation.isTimeoutAbort(error)) {
				throw new Error(`Legacy SSE endpoint timeout after ${timeout}ms`);
			}
			throw error;
		}
	}

View on GitHub (pinned to 9690622007)

Solutions

  1. Confirm with curl -N -H 'Accept: text/event-stream' <url> whether the server actually streams an 'endpoint' event or closes immediately.
  2. Disable proxy response buffering for the SSE route (e.g. proxy_buffering off in nginx).
  3. If the server runs on a platform without streaming support (some serverless runtimes), move it to a streaming-capable host.
  4. Update or fix the MCP server so a 200 SSE response always carries the stream.
  5. Migrate to the Streamable HTTP transport, which this client prefers and most current servers support.

Example fix

// server (before)
res.writeHead(200, { 'Content-Type': 'text/event-stream' });
res.end();
// after: send the required endpoint event and keep alive
res.writeHead(200, { 'Content-Type': 'text/event-stream' });
res.write(`event: endpoint\ndata: ${messageEndpointUrl}\n\n`);
Defensive patterns

Strategy: validation

Validate before calling

const res = await fetch(sseUrl, { headers: { Accept: 'text/event-stream' } });
if (res.ok && !res.body) throw new Error('Server returns 200 SSE with empty body — cannot run legacy SSE here');
await res.body?.cancel();

Type guard

function hasStreamingBody(res: Response): res is Response & { body: ReadableStream<Uint8Array> } {
  return res.body !== null;
}

Try / catch

try {
  const transport = await createSseTransport(config);
} catch (e) {
  if (e instanceof Error && e.message.includes('did not include a body')) {
    logger.error('Legacy SSE server/proxy returns empty streams; switch transport');
    return useStreamableHttp(config);
  }
  throw e;
}

Prevention

When it happens

Trigger: Server (or intermediary) returns 200 with Content-Type: text/event-stream but an empty/immediately-closed body; a proxy that buffers and truncates the stream; server handler that sets SSE headers then ends the response.

Common situations: Misconfigured nginx/gateway buffering an SSE stream into an empty body; buggy or outdated MCP server SSE implementations; serverless platforms that don't support streaming responses hosting the MCP server.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/2d64e1eaa6cdc52c. Report an issue: GitHub.