From 94d37c4b8b9a8674bc0b52195e4b88edfe31eab4 Mon Sep 17 00:00:00 2001 From: vjymisal0 Date: Thu, 10 Sep 2026 16:05:43 +0530 Subject: [PATCH] fix(server): restore onclose after modern exchanges --- .../server/src/server/createMcpHandler.ts | 1 + .../test/server/createMcpHandler.test.ts | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/packages/server/src/server/createMcpHandler.ts b/packages/server/src/server/createMcpHandler.ts index 9adbe54fb8..f1267690d1 100644 --- a/packages/server/src/server/createMcpHandler.ts +++ b/packages/server/src/server/createMcpHandler.ts @@ -848,6 +848,7 @@ export function createMcpHandler(factory: McpServerFactory, options: CreateMcpHa inflight.add(server); server.onclose = () => { inflight.delete(server); + server.onclose = previousOnClose; previousOnClose?.(); }; diff --git a/packages/server/test/server/createMcpHandler.test.ts b/packages/server/test/server/createMcpHandler.test.ts index 4dae5c0ad7..e1175db22f 100644 --- a/packages/server/test/server/createMcpHandler.test.ts +++ b/packages/server/test/server/createMcpHandler.test.ts @@ -274,6 +274,27 @@ describe('createMcpHandler — modern path', () => { expect(onerror).toHaveBeenCalledWith(expect.objectContaining({ message: 'factory exploded' })); }); + it('restores a reused server onclose handler after each modern exchange', async () => { + const reused = new McpServer({ name: 'entry-test-server', version: '1.0.0' }); + reused.registerTool('echo', { inputSchema: z.object({ text: z.string() }) }, async ({ text }) => ({ + content: [{ type: 'text', text }] + })); + + const originalOnClose = vi.fn(); + reused.server.onclose = originalOnClose; + + const handler = createMcpHandler(() => reused); + + for (let i = 0; i < 3; i++) { + const response = await handler.fetch(postRequest(modernToolsCall('echo', { text: `hello-${i}` }))); + expect(response.status).toBe(200); + await response.text(); + expect(reused.server.onclose).toBe(originalOnClose); + } + + expect(originalOnClose).toHaveBeenCalledTimes(3); + }); + it('closes and releases the per-request instance when a modern exchange fails internally', async () => { const { factory, state } = testFactory(); const onerror = vi.fn();