| @@ -6,7 +6,7 @@ index c8fad448e8797b89690a99d93490d1363851b225..439da01e789713d217778e8bdebfa1a9 · 5 unmodified lines |
| 6 | xt as MCPClientOAuthCallbackConfig, | 6 | xt as MCPClientOAuthCallbackConfig, |
| 7 | zt as ElicitResult | 7 | zt as ElicitResult |
| 8 | } from "../agent-tool-types-CNyE1iz_.js"; | 8 | } from "../agent-tool-types-CNyE1iz_.js"; |
| 9 | +declare const MAX_SSE_AGE_MS = 300000; | 9 | +declare const MAX_SSE_AGE_MS = 1800000; |
| 10 | export { | 10 | export { |
| 11 | type ClearableEventStore, | 11 | type ClearableEventStore, |
| 12 | type CreateMcpHandlerOptions, | 12 | type CreateMcpHandlerOptions, |
| @@ -22,11 +22,14 @@ diff --git a/dist/mcp/index.js b/dist/mcp/index.js · 9 unmodified lines |
| 22 | index 1edcf0c8c9e67aa211ae515e7672cdf79912101e..0ba4f5bff8e6a968aa18c609952e576cedf13d8f 100644 | 22 | index 1edcf0c8c9e67aa211ae515e7672cdf79912101e..0ba4f5bff8e6a968aa18c609952e576cedf13d8f 100644 |
| 23 | --- a/dist/mcp/index.js | 23 | --- a/dist/mcp/index.js |
| 24 | +++ b/dist/mcp/index.js | 24 | +++ b/dist/mcp/index.js |
| 25 | @@ -28,13 +28,14 @@ import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/ | 25 | @@ -28,13 +28,17 @@ import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/ |
| 26 | const KEEPALIVE_INTERVAL_MS = 25e3; | 26 | const KEEPALIVE_INTERVAL_MS = 25e3; |
| 27 | /** SSE comment frame the parser drops before any event dispatch. */ | 27 | /** SSE comment frame the parser drops before any event dispatch. */ |
| 28 | const KEEPALIVE_FRAME = ": keepalive\n\n"; | 28 | const KEEPALIVE_FRAME = ": keepalive\n\n"; |
| 29 | +const MAX_SSE_AGE_MS = 300_000; | 29 | +// Max age is a stalled-client memory backstop, not session idleness. Keep it |
| | 30 | +// well above Executor's 5 minute session idle timeout so active clients rarely |
| | 31 | +// rotate. |
| | 32 | +const MAX_SSE_AGE_MS = 30 * 60 * 1000; |
| 30 | /** | 33 | /** |
| 31 | * Start an SSE keepalive on `writer`. Returns a `clearInterval` handle | 34 | * Start an SSE keepalive on `writer`. Returns a `clearInterval` handle |
| 32 | * that the stream cleanup must invoke when the stream closes. | 35 | * that the stream cleanup must invoke when the stream closes. |
| @@ -39,7 +42,7 @@ index 1edcf0c8c9e67aa211ae515e7672cdf79912101e..0ba4f5bff8e6a968aa18c609952e576c · 6 unmodified lines |
| 39 | }, KEEPALIVE_INTERVAL_MS); | 42 | }, KEEPALIVE_INTERVAL_MS); |
| 40 | return handle; | 43 | return handle; |
| 41 | } | 44 | } |
| 42 | @@ -180,10 +181,15 @@ const createStreamingHttpHandler = (basePath, namespace, options = {}) => { | 45 | @@ -180,10 +184,15 @@ const createStreamingHttpHandler = (basePath, namespace, options = {}) => { |
| 43 | }); | 46 | }); |
| 44 | return new Response(body, { status: 404 }); | 47 | return new Response(body, { status: 404 }); |
| 45 | } | 48 | } |
| @@ -59,7 +62,7 @@ index 1edcf0c8c9e67aa211ae515e7672cdf79912101e..0ba4f5bff8e6a968aa18c609952e576c · 13 unmodified lines |
| 59 | request.headers.forEach((value, key) => { | 62 | request.headers.forEach((value, key) => { |
| 60 | existingHeaders[key] = value; | 63 | existingHeaders[key] = value; |
| 61 | }); | 64 | }); |
| 62 | @@ -206,45 +212,71 @@ const createStreamingHttpHandler = (basePath, namespace, options = {}) => { | 65 | @@ -206,45 +215,71 @@ const createStreamingHttpHandler = (basePath, namespace, options = {}) => { |
| 63 | jsonrpc: "2.0" | 66 | jsonrpc: "2.0" |
| 64 | }); | 67 | }); |
| 65 | return new Response(body, { status: 500 }); | 68 | return new Response(body, { status: 500 }); |
| @@ -157,7 +160,7 @@ index 1edcf0c8c9e67aa211ae515e7672cdf79912101e..0ba4f5bff8e6a968aa18c609952e576c · 91 unmodified lines |
| 157 | } | 160 | } |
| 158 | onClose().catch(console.error); | 161 | onClose().catch(console.error); |
| 159 | }); | 162 | }); |
| 160 | @@ -279,10 +311,16 @@ const createStreamingHttpHandler = (basePath, namespace, options = {}) => { | 163 | @@ -279,10 +314,16 @@ const createStreamingHttpHandler = (basePath, namespace, options = {}) => { |
| 161 | id: null, | 164 | id: null, |
| 162 | jsonrpc: "2.0" | 165 | jsonrpc: "2.0" |
| 163 | }), { status: 400 }); | 166 | }), { status: 400 }); |
| @@ -178,7 +181,7 @@ index 1edcf0c8c9e67aa211ae515e7672cdf79912101e..0ba4f5bff8e6a968aa18c609952e576c · 14 unmodified lines |
| 178 | props: ctx.props, | 181 | props: ctx.props, |
| 179 | jurisdiction: options.jurisdiction | 182 | jurisdiction: options.jurisdiction |
| 180 | }); | 183 | }); |
| 181 | @@ -306,27 +344,86 @@ const createStreamingHttpHandler = (basePath, namespace, options = {}) => { | 184 | @@ -306,27 +347,86 @@ const createStreamingHttpHandler = (basePath, namespace, options = {}) => { |
| 182 | if (!ws) { | 185 | if (!ws) { |
| 183 | await writer.close(); | 186 | await writer.close(); |
| 184 | return new Response("Failed to establish WS to DO", { status: 500 }); | 187 | return new Response("Failed to establish WS to DO", { status: 500 }); |
| @@ -280,7 +283,7 @@ index 1edcf0c8c9e67aa211ae515e7672cdf79912101e..0ba4f5bff8e6a968aa18c609952e576c · 95 unmodified lines |
| 280 | return new Response(readable, { | 283 | return new Response(readable, { |
| 281 | headers: { | 284 | headers: { |
| 282 | "Cache-Control": "no-cache", | 285 | "Cache-Control": "no-cache", |
| 283 | @@ -389,10 +486,16 @@ const createLegacySseHandler = (basePath, namespace, options = {}) => { | 286 | @@ -389,10 +489,16 @@ const createLegacySseHandler = (basePath, namespace, options = {}) => { |
| 284 | const url = new URL(request.url); | 287 | const url = new URL(request.url); |
| 285 | if (request.method === "GET" && basePattern.test(url)) { | 288 | if (request.method === "GET" && basePattern.test(url)) { |
| 286 | const sessionId = url.searchParams.get("sessionId") || namespace.newUniqueId().toString(); | 289 | const sessionId = url.searchParams.get("sessionId") || namespace.newUniqueId().toString(); |
| @@ -301,7 +304,7 @@ index 1edcf0c8c9e67aa211ae515e7672cdf79912101e..0ba4f5bff8e6a968aa18c609952e576c · 14 unmodified lines |
| 301 | endpointUrl.pathname = encodeURI(`${basePath}/message`); | 304 | endpointUrl.pathname = encodeURI(`${basePath}/message`); |
| 302 | endpointUrl.searchParams.set("sessionId", sessionId); | 305 | endpointUrl.searchParams.set("sessionId", sessionId); |
| 303 | const endpointMessage = `event: endpoint\ndata: ${endpointUrl.pathname + endpointUrl.search + endpointUrl.hash}\n\n`; | 306 | const endpointMessage = `event: endpoint\ndata: ${endpointUrl.pathname + endpointUrl.search + endpointUrl.hash}\n\n`; |
| 304 | @@ -414,35 +517,94 @@ const createLegacySseHandler = (basePath, namespace, options = {}) => { | 307 | @@ -414,35 +520,94 @@ const createLegacySseHandler = (basePath, namespace, options = {}) => { |
| 305 | console.error("Failed to establish WebSocket connection"); | 308 | console.error("Failed to establish WebSocket connection"); |
| 306 | await writer.close(); | 309 | await writer.close(); |
| 307 | return new Response("Failed to establish WebSocket connection", { status: 500 }); | 310 | return new Response("Failed to establish WebSocket connection", { status: 500 }); |
| @@ -414,7 +417,7 @@ index 1edcf0c8c9e67aa211ae515e7672cdf79912101e..0ba4f5bff8e6a968aa18c609952e576c · 106 unmodified lines |
| 414 | console.error("Error closing SSE connection:", error); | 417 | console.error("Error closing SSE connection:", error); |
| 415 | } | 418 | } |
| 416 | } | 419 | } |
| 417 | @@ -1698,6 +1860,6 @@ var McpAgent = class McpAgent extends Agent { | 420 | @@ -1698,6 +1863,6 @@ var McpAgent = class McpAgent extends Agent { |
| 418 | }; | 421 | }; |
| 419 | McpAgent.STREAM_REQS_KEY_PREFIX = "__mcp_stream_reqs__:"; | 422 | McpAgent.STREAM_REQS_KEY_PREFIX = "__mcp_stream_reqs__:"; |
| 420 | //#endregion | 423 | //#endregion |