mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 03:02:56 +00:00
fix(mcp): release optional providers when transport startup fails
Close the browser scenario owner alongside session, Android and servers when transport startup throws. Preserve cleanup failures in the existing diagnostics. Reviewed-PR: #3230 Co-authored-by: qorvr <330186599+qorvr@users.noreply.github.com>
This commit is contained in:
1 parent
69b8509602
commit
c482ddd6ad
2 files changed
+58
-7
No files matched your search
+17
-7
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user