From a55280bb869e08381a1454fcf5e57dab55f05e9f Mon Sep 17 00:00:00 2001 From: Guilherme Rodrigues Date: Sat, 24 Jan 2026 13:01:07 -0300 Subject: [PATCH] fix(gateway): reject GET requests to prevent SSE reconnection loop Virtual MCPs are stateless aggregators that create a new transport per request. For GET requests (SSE streaming), handleRequest returns after setting up the stream, but our finally block immediately closes the transport, terminating the connection. Clients then reconnect, creating an infinite loop. By rejecting GET requests with a 405 and JSON-RPC error, clients fall back to POST-only mode which works correctly with our stateless model. --- apps/mesh/src/api/routes/gateway.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/apps/mesh/src/api/routes/gateway.ts b/apps/mesh/src/api/routes/gateway.ts index 2a63890974..f6f937f5d9 100644 --- a/apps/mesh/src/api/routes/gateway.ts +++ b/apps/mesh/src/api/routes/gateway.ts @@ -63,6 +63,26 @@ export async function handleVirtualMcpRequest( }, virtualMcpId: string | undefined, ) { + // Reject GET requests to prevent SSE reconnection loops. + // Virtual MCPs are aggregators that respond to client requests - they don't + // need server-initiated messages (SSE). When clients send GET requests for + // SSE streaming, our stateless transport setup closes immediately after + // handleRequest returns, causing an infinite reconnection loop. + // By rejecting GET, clients fall back to POST-only mode which works correctly. + if (c.req.raw.method === "GET") { + return c.json( + { + jsonrpc: "2.0", + error: { + code: -32000, + message: "SSE streaming not supported. Use POST requests only.", + }, + id: null, + }, + 405, + ); + } + const ctx = c.get("meshContext"); try {