diff --git a/packages/core/src/mcp/index.ts b/packages/core/src/mcp/index.ts index 8271102880..7586f26272 100644 --- a/packages/core/src/mcp/index.ts +++ b/packages/core/src/mcp/index.ts @@ -210,7 +210,12 @@ export const layer = Layer.effect( entry.integrationID = integrationID owned.add(integrationID) const methodID = Integration.MethodID.make(suffix) - entry.registration = yield* integration + // Each registration gets its own child scope so disposal detaches it from the root scope + // entirely; registering directly on root would accumulate a dead finalizer per replaced or + // removed server for the lifetime of the layer. + const scope = yield* Scope.fork(root) + entry.registration = { dispose: Scope.close(scope, Exit.void) } + yield* integration .transform((draft) => { draft.update(integrationID, (ref) => { ref.name = name @@ -221,7 +226,7 @@ export const layer = Layer.effect( authorize: () => MCPOAuth.authorize({ name, config: remote, methodID }), }) }) - .pipe(Scope.provide(root)) + .pipe(Scope.provide(scope)) }) yield* Effect.forEach(runtime, ([name, entry]) => register(name, entry), { discard: true })