fix(mcp): use Effect.timeoutOrElse for transport connect timeout

Replace withTimeout (Promise.race) with Effect.timeoutOrElse so that
fiber interruption properly triggers acquireUseRelease cleanup. The
Promise.race approach left the underlying connect promise dangling,
which prevented the release function from running on some platforms.
worktree-agent-a682f34a
Kit Langton 2026-03-26 11:16:11 -04:00
parent 3439521ef0
commit e4fbf5c657
1 changed files with 11 additions and 7 deletions

View File

@ -209,14 +209,18 @@ export namespace MCP {
const connectTransport = (transport: Transport, timeout: number) => const connectTransport = (transport: Transport, timeout: number) =>
Effect.acquireUseRelease( Effect.acquireUseRelease(
Effect.succeed(transport), Effect.succeed(transport),
(t) => (t) => {
Effect.tryPromise({
try: () => {
const client = new Client({ name: "opencode", version: Installation.VERSION }) const client = new Client({ name: "opencode", version: Installation.VERSION })
return withTimeout(client.connect(t), timeout).then(() => client) return Effect.tryPromise({
}, try: () => client.connect(t).then(() => client),
catch: (e) => (e instanceof Error ? e : new Error(String(e))), catch: (e) => (e instanceof Error ? e : new Error(String(e))),
}).pipe(
Effect.timeoutOrElse({
duration: `${timeout} millis`,
onTimeout: () => Effect.fail(new Error(`Operation timed out after ${timeout}ms`)),
}), }),
)
},
(t, exit) => (t, exit) =>
Exit.isFailure(exit) Exit.isFailure(exit)
? Effect.tryPromise(() => t.close()).pipe(Effect.ignore) ? Effect.tryPromise(() => t.close()).pipe(Effect.ignore)