From cbb378265eb31ad50a40deb7e861bbc3a58c5995 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 12 Mar 2026 02:24:29 +0900 Subject: [PATCH] fix(skill-mcp-manager): drop superseded stale clients Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../skill-mcp-manager/connection-race.test.ts | 18 ++++++++++++++++++ src/features/skill-mcp-manager/connection.ts | 1 + 2 files changed, 19 insertions(+) diff --git a/src/features/skill-mcp-manager/connection-race.test.ts b/src/features/skill-mcp-manager/connection-race.test.ts index 2b188c180..784a3e189 100644 --- a/src/features/skill-mcp-manager/connection-race.test.ts +++ b/src/features/skill-mcp-manager/connection-race.test.ts @@ -230,4 +230,22 @@ describe("getOrCreateClient multi-key disconnect race", () => { expect(state.clients.has(clientKey2)).toBe(false) expect(state.disconnectedSessions.has("session-a")).toBe(false) }) + + it("#given a superseded pending connection #when the old connection completes #then the stale client is removed from state.clients", async () => { + const state = createState() + const info = createClientInfo("session-a") + const clientKey = createClientKey(info) + const pendingConnect = createDeferred() + const supersedingConnection = createDeferred>>() + pendingConnects.push(pendingConnect) + + const clientPromise = getOrCreateClient({ state, clientKey, info, config: stdioConfig }) + state.pendingConnections.set(clientKey, supersedingConnection.promise) + + pendingConnect.resolve(undefined) + + await expect(clientPromise).rejects.toThrow(/superseded by a newer connection attempt/) + expect(state.clients.has(clientKey)).toBe(false) + expect(createdClients[0]?.close).toHaveBeenCalledTimes(1) + }) }) diff --git a/src/features/skill-mcp-manager/connection.ts b/src/features/skill-mcp-manager/connection.ts index fabc8924f..3be07d853 100644 --- a/src/features/skill-mcp-manager/connection.ts +++ b/src/features/skill-mcp-manager/connection.ts @@ -42,6 +42,7 @@ export async function getOrCreateClient(params: { const isStale = state.pendingConnections.has(clientKey) && state.pendingConnections.get(clientKey) !== currentConnectionPromise if (isStale) { + state.clients.delete(clientKey) try { await client.close() } catch {} throw new Error(`Connection for "${info.sessionID}" was superseded by a newer connection attempt.`) }