From f34150e8e89dc8981a3e8c1e48da0c80ca990886 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Thu, 21 May 2026 09:06:02 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=B5=20chore:=20Raise=20MCP=20SSE=20Lin?= =?UTF-8?q?e=20Default=20(#13224)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 4 +-- .../mcp/__tests__/MCPConnectionSSRF.test.ts | 27 +++++++++++++++++++ packages/api/src/mcp/connection.ts | 2 +- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index 1aa95fd5be..bf992b67cc 100644 --- a/.env.example +++ b/.env.example @@ -898,8 +898,8 @@ OPENWEATHER_API_KEY= # MCP_STREAMABLE_HTTP_MAX_RESPONSE_BYTES=16777216 # Max bytes allowed in a single SSE line for non-GET streamable HTTP MCP responses. -# Set to 0 to disable. Default: 1048576 (1 MiB) -# MCP_STREAMABLE_HTTP_MAX_LINE_BYTES=1048576 +# Set to 0 to disable. Default: 5242880 (5 MiB) +# MCP_STREAMABLE_HTTP_MAX_LINE_BYTES=5242880 # Skip code challenge method validation (e.g., for AWS Cognito that supports S256 but doesn't advertise it) # When set to true, forces S256 code challenge even if not advertised in .well-known/openid-configuration diff --git a/packages/api/src/mcp/__tests__/MCPConnectionSSRF.test.ts b/packages/api/src/mcp/__tests__/MCPConnectionSSRF.test.ts index fcc6b72dcf..60de0db5e4 100644 --- a/packages/api/src/mcp/__tests__/MCPConnectionSSRF.test.ts +++ b/packages/api/src/mcp/__tests__/MCPConnectionSSRF.test.ts @@ -1185,6 +1185,33 @@ describe('MCP SSRF protection – customFetch input shapes', () => { } }); + it('should allow SSE lines above the old 1 MiB default when no line override is set', async () => { + delete process.env.MCP_STREAMABLE_HTTP_MAX_LINE_BYTES; + const payload = 'x'.repeat(2 * 1024 * 1024); + const server = await createRawResponseServer((_req, res) => { + res.writeHead(200, { 'Content-Type': 'text/event-stream' }); + res.end(`data: ${payload}\n\n`); + }); + try { + conn = new MCPConnection({ + serverName: 'customfetch-sse-default-line-limit', + serverConfig: { type: 'streamable-http', url: server.url }, + useSSRFProtection: false, + }); + + const customFetch = getGuardedStreamableHTTPCustomFetch(conn); + const response = await customFetch(server.url, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ jsonrpc: '2.0', method: 'notifications/cancelled' }), + }); + + await expect(response.text()).resolves.toContain(payload.slice(0, 128)); + } finally { + await server.close(); + } + }); + it('should fail an actual streamable HTTP tool call promptly with a clear oversized SSE line error', async () => { process.env.MCP_STREAMABLE_HTTP_MAX_LINE_BYTES = '512'; target = await createOversizedToolResultStreamableServer(2048); diff --git a/packages/api/src/mcp/connection.ts b/packages/api/src/mcp/connection.ts index 3eddf26a91..0bb4c033d4 100644 --- a/packages/api/src/mcp/connection.ts +++ b/packages/api/src/mcp/connection.ts @@ -75,7 +75,7 @@ const DEFAULT_INIT_TIMEOUT = 30000; /** Max 307/308 redirects to follow per request (prevents redirect loops) */ const MAX_REDIRECTS = 5; const DEFAULT_MCP_STREAMABLE_HTTP_MAX_RESPONSE_BYTES = 16 * 1024 * 1024; -const DEFAULT_MCP_STREAMABLE_HTTP_MAX_LINE_BYTES = 1024 * 1024; +const DEFAULT_MCP_STREAMABLE_HTTP_MAX_LINE_BYTES = 5 * 1024 * 1024; function getNonNegativeIntegerEnv(name: string, defaultValue: number): number { const raw = process.env[name];