From e58c80440b658af719d601926d38999563aa45a8 Mon Sep 17 00:00:00 2001 From: cliffhall Date: Mon, 17 Aug 2026 14:41:24 -0400 Subject: [PATCH] fix: guard the abort listener against a double invocation Copilot review round 1. The helper's contract is exactly-once teardown and the test asserted it must not lean on Hono's own re-entry guard, but neither the implementation nor the test actually enforced that: the listener had no local guard and the test aborted only once. Signed-off-by: cliffhall --- .../test/integration/mcp/remote/sse-abort-cleanup.test.ts | 5 ++++- core/mcp/remote/node/server.ts | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/clients/web/src/test/integration/mcp/remote/sse-abort-cleanup.test.ts b/clients/web/src/test/integration/mcp/remote/sse-abort-cleanup.test.ts index a5fd5229..a41c9a3d 100644 --- a/clients/web/src/test/integration/mcp/remote/sse-abort-cleanup.test.ts +++ b/clients/web/src/test/integration/mcp/remote/sse-abort-cleanup.test.ts @@ -138,9 +138,12 @@ describe("primeAndHoldSseStream (#1999)", () => { s.finishWrite(); s.abort(); + // Hono guards re-entry itself, but the helper must not depend on that — + // so drive the listener a second time directly. + s.abort(); await withinTick(held); - // Hono guards re-entry itself, but the helper must not depend on that. expect(cleanups).toBe(1); + expect(s.closes).toBe(1); }); it("does not reject when cleanup's own close loses the race", async () => { diff --git a/core/mcp/remote/node/server.ts b/core/mcp/remote/node/server.ts index b837eac1..5bc58f5e 100644 --- a/core/mcp/remote/node/server.ts +++ b/core/mcp/remote/node/server.ts @@ -147,8 +147,15 @@ export async function primeAndHoldSseStream( stream: PrimableSseStream, cleanup: () => void, ): Promise { + let done = false; const aborted = new Promise((resolve) => { stream.onAbort(() => { + // Hono's `abort()` guards its own re-entry, but the guard belongs here + // too: this helper's contract is exactly-once teardown, and running a + // caller's cleanup twice would double-delete a subscriber that has + // since been re-added by a reconnect. + if (done) return; + done = true; cleanup(); closeAbortedStream(stream); resolve();