diff --git a/src/main/transport.ts b/src/main/transport.ts index eb7b157d75..4846bedd9d 100644 --- a/src/main/transport.ts +++ b/src/main/transport.ts @@ -115,12 +115,17 @@ export const startMcpTransport = async ( }, ); } catch (cause: unknown) { - const [binaryCleanup, androidCleanup, serverCleanup] = - await Promise.allSettled([ - session.close(), - closeAndroid(), - closeServers(), - ]); + const [ + binaryCleanup, + androidCleanup, + serverCleanup, + optionalProviderCleanup, + ] = await Promise.allSettled([ + session.close(), + closeAndroid(), + closeServers(), + closeOptionalProviders(), + ]); serverLogger.error( { error: cause instanceof Error ? cause.message : String(cause), @@ -136,7 +141,12 @@ export const startMcpTransport = async ( ); dependencies.writeStderr(`${cleanupError.message}\n`); } - for (const cleanup of [binaryCleanup, androidCleanup, serverCleanup]) { + for (const cleanup of [ + binaryCleanup, + androidCleanup, + serverCleanup, + optionalProviderCleanup, + ]) { if (cleanup.status === "rejected") { const reason = cleanup.reason instanceof Error diff --git a/tests/boundary/process/browserScenarioProbeLifecycle.test.ts b/tests/boundary/process/browserScenarioProbeLifecycle.test.ts index 42871d13aa..66dc09d6f0 100644 --- a/tests/boundary/process/browserScenarioProbeLifecycle.test.ts +++ b/tests/boundary/process/browserScenarioProbeLifecycle.test.ts @@ -59,3 +59,44 @@ it("keeps the shared browser scenario provider open when the SDK discards its di await session.close(); } }); + +it("closes optional providers when MCP server startup throws", async () => { + const session = createTestBinarySession(() => { + throw new Error("Unexpected deep provider"); + }); + const close = vi.fn(async () => undefined); + const browserScenarioCapture: BrowserScenarioCapturePort = { + identity: () => ({ + id: "fake-browser", + name: "Fake browser", + version: "1", + }), + captureScenario: async () => { + throw new Error("Unexpected scenario capture"); + }, + close, + }; + const runtime: RuntimeDependencies = { + env: {}, + serve: () => { + throw new Error("Server startup failed"); + }, + writeStderr: () => undefined, + setExitCode: () => undefined, + registerShutdown: () => () => undefined, + }; + try { + const transport = await startMcpTransport(runtime, session, { + logger: silentLogger, + serverLogger: silentLogger, + environment: runtime.env, + delivery: new ToolResultDelivery(STDIO_DEFAULT_MAX_BUFFER_SIZE), + loadOptionalProviders: async () => ({ browserScenarioCapture }), + }); + + expect(transport).toEqual({ ok: false }); + expect(close).toHaveBeenCalledTimes(1); + } finally { + await session.close(); + } +});