From f77f037225399063518d1d85501fd26f1ee951bb Mon Sep 17 00:00:00 2001 From: OpenCode Date: Sat, 13 Jun 2026 01:37:24 +0000 Subject: [PATCH] fix(mcp): invalidate replaced prompt catalogs --- packages/opencode/src/mcp/index.ts | 2 +- packages/opencode/test/mcp/lifecycle.test.ts | 34 ++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index fd4067933a..d24c858e30 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -555,7 +555,7 @@ export const layer = Layer.effect( s.defs[name] = listed watch(s, name, client, bridge, timeout) if (previous) yield* Effect.tryPromise(() => previous.close()).pipe(Effect.ignore) - if (client.getServerCapabilities()?.prompts) { + if (previous || client.getServerCapabilities()?.prompts) { yield* events.publish(CatalogChanged, { server: name, kinds: ["prompts"] }).pipe(Effect.ignore) } return s.status[name] diff --git a/packages/opencode/test/mcp/lifecycle.test.ts b/packages/opencode/test/mcp/lifecycle.test.ts index 090882dd95..8ec0fbfb5b 100644 --- a/packages/opencode/test/mcp/lifecycle.test.ts +++ b/packages/opencode/test/mcp/lifecycle.test.ts @@ -458,6 +458,40 @@ it.instance( { config: { mcp: {} } }, ) +it.instance( + "replacing a prompt-capable server publishes catalog invalidation", + () => + Effect.gen(function* () { + const mcp = yield* MCP.Service + lastCreatedClientName = "prompt-replace-server" + const serverState = getOrCreateClientState("prompt-replace-server") + serverState.prompts = [{ name: "original" }] + + yield* mcp.add("prompt-replace-server", { + type: "local", + command: ["echo", "test"], + }) + + serverState.capabilities = { tools: {} } + + let changed = 0 + const listener = (event: GlobalEvent) => { + if (event.payload.type !== MCP.CatalogChanged.type) return + changed += 1 + } + GlobalBus.on("event", listener) + + yield* mcp.add("prompt-replace-server", { + type: "local", + command: ["echo", "test"], + }) + GlobalBus.off("event", listener) + + expect(changed).toBe(1) + }), + { config: { mcp: {} } }, +) + // ======================================================================== // Test: connect() / disconnect() lifecycle // ========================================================================