Skip to content

Commit 84e21d0

Browse files
sanchitrkclaude
andcommitted
test(harness): check MCP stderr grandchildren die before scope close
The process spawner kills the group when the connection's scope closes, which hid a missing kill. Assert instead that a grandchild holding only stderr is gone once the connection reports the server's exit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent a1b8ad1 commit 84e21d0

1 file changed

Lines changed: 9 additions & 6 deletions

File tree

‎packages/harness/test/mcp.client.test.ts‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -230,22 +230,25 @@ describe("mcp client", () => {
230230
);
231231

232232
it(
233-
"stdio: a grandchild holding only stderr is killed after the server exits",
233+
"stdio: a grandchild holding only stderr is killed when the server exits, before scope close",
234234
Effect.gen(function* () {
235235
const outer = yield* Effect.scope;
236-
const pids = yield* Effect.gen(function* () {
236+
const killed = yield* Effect.gen(function* () {
237237
const connection = yield* McpClient.connect({ server: "fixture", endpoint: stdio("server.mjs") });
238+
const closed = yield* Deferred.make<void>();
239+
connection.onClose(() => Deferred.succeed(closed, undefined).pipe(Effect.asVoid));
238240
const spawned = JSON.parse(text(yield* connection.callTool({ name: "stderr-child" }))) as {
239241
readonly server: number;
240242
readonly grandchild: number;
241243
};
242244
yield* Scope.addFinalizer(outer, reap([spawned.server, spawned.grandchild]));
243-
// The server exits on its own; its grandchild keeps the stderr pipe open.
245+
// The server exits on its own; its grandchild keeps the stderr pipe open. The group is killed
246+
// as soon as the connection notices the exit, while the connection's scope is still open: the
247+
// spawner's own release at scope close would hide a missing kill.
244248
yield* gone([spawned.server]);
245-
expect(alive(spawned.grandchild)).toBe(true);
246-
return [spawned.server, spawned.grandchild];
249+
yield* Deferred.await(closed).pipe(Effect.timeout("5 seconds"));
250+
return yield* gone([spawned.grandchild]);
247251
}).pipe(Effect.scoped);
248-
const killed = yield* gone(pids);
249252
summary.stderrGrandchild = { killed };
250253
expect(killed).toBe(true);
251254
}),

0 commit comments

Comments
 (0)