Files
worldmonitor/api/mcp-proxy.js
Elie Habib 5ba0d8db83 fix(mcp): SSE transport support for /sse MCP servers (#1848)
* fix(mcp): add SSE transport support for /sse MCP servers (Cloudflare Radar etc.)

Servers like radar.mcp.cloudflare.com/sse use the HTTP+SSE transport, not the
newer streamable HTTP transport. The proxy was POSTing JSON-RPC directly to the
/sse endpoint (which only accepts GET), causing a hang/502.

SseSession opens the SSE GET stream, waits for the `endpoint` event to get the
POST URL, then dispatches JSON-RPC requests there while reading responses from
the same stream.

Also: return 422 instead of 502 for upstream MCP errors so Cloudflare proxy
does not replace the JSON error body with its own HTML error page.

* fix(mcp): harden SSE transport against SSRF, early stream close, and path over-match

P1: re-validate the endpoint URL from the SSE stream against BLOCKED_HOST_PATTERNS
and protocol allowlist before assigning _endpointUrl, preventing a malicious MCP
server from redirecting the proxy to RFC1918 / metadata addresses.

P2 (stream close): when reader.read() returns done=true before an endpoint event
arrives, reject _endpointDeferred so connect() throws a descriptive error instead
of hanging forever (hits misconfigured servers, auth failures wrapped in SSE, etc).

P2 (path match): narrow isSseTransport() to suffix-only match; removing the
p.includes('/sse/') arm prevents misclassifying valid streamable HTTP endpoints
such as https://host/mcp/sse/proxy as legacy SSE transport.
2026-03-19 03:42:48 +04:00

14 KiB