Skip to content

Commit 4cd6ee1

Browse files
sanchitrkclaude
andcommitted
fix(harness): keep MCP startup logs and forget failed commands on time
- Write server log messages on the service's fibers, so a failed handshake closing the connection no longer drops the messages that explain it. - Forget a failed !command as soon as it fails, so the next connect runs it again even when every caller waiting on it gave up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 2237d9e commit 4cd6ee1

2 files changed

Lines changed: 11 additions & 7 deletions

File tree

‎packages/harness/src/mcp/mcp.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,9 @@ export const layer = (options: { readonly hostCwd: string; readonly home: string
233233
endpoint: target,
234234
...(server.roots === undefined ? {} : { roots: server.roots }),
235235
timeout: { request: Duration.seconds(config.timeout ?? DEFAULT_TIMEOUT_SECONDS) },
236-
onLog: (entry) => log.write(server.name, entry),
236+
// Written on the service's fibers: a failed handshake closes the connection's, and
237+
// its last messages usually say why.
238+
onLog: (entry) => Effect.sync(() => fork(log.write(server.name, entry))),
237239
}).pipe(Scope.provide(scope));
238240
const tools = yield* connection.tools();
239241
return { connection, tools };

‎packages/harness/src/mcp/value.ts‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,17 @@ const run = (command: string) =>
101101
const command = Effect.fnUntraced(function* (line: string, what: string) {
102102
let running = commands.get(line);
103103
if (running === undefined) {
104-
// Detached, so a caller giving up does not stop it for the others waiting on it.
105-
running = yield* Effect.forkDetach(run(line));
104+
// Detached, so a caller giving up does not stop it for the others waiting on it. A failure is
105+
// forgotten when it happens, whether or not anyone still waits.
106+
const forget = (output: string | undefined) =>
107+
Effect.sync(() => {
108+
if (output === undefined && commands.get(line) === running) commands.delete(line);
109+
});
110+
running = yield* Effect.forkDetach(Effect.andThen(Effect.yieldNow, run(line).pipe(Effect.tap(forget))));
106111
commands.set(line, running);
107112
}
108113
const output = yield* Fiber.join(running);
109-
if (output === undefined) {
110-
if (commands.get(line) === running) commands.delete(line);
111-
return yield* Effect.fail(`Failed to resolve ${what} from shell command: ${line}`);
112-
}
114+
if (output === undefined) return yield* Effect.fail(`Failed to resolve ${what} from shell command: ${line}`);
113115
return output;
114116
});
115117

0 commit comments

Comments
 (0)