fix(mcp): await failed transport cleanup on Windows

Wait for failed MCP transport cleanup before command exit so targeted live checks do not crash on Windows.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
gnanam1990
2026-04-02 14:55:05 +05:30
parent ad1f328672
commit fb27164ddf
2 changed files with 68 additions and 5 deletions

View File

@@ -0,0 +1,48 @@
import assert from 'node:assert/strict'
import test from 'node:test'
import { cleanupFailedConnection } from './client.js'
test('cleanupFailedConnection awaits transport close before resolving', async () => {
let closed = false
let resolveClose: (() => void) | undefined
const transport = {
close: async () =>
await new Promise<void>(resolve => {
resolveClose = () => {
closed = true
resolve()
}
}),
}
const cleanupPromise = cleanupFailedConnection(transport)
assert.equal(closed, false)
resolveClose?.()
await cleanupPromise
assert.equal(closed, true)
})
test('cleanupFailedConnection closes in-process server and transport', async () => {
let inProcessClosed = false
let transportClosed = false
const inProcessServer = {
close: async () => {
inProcessClosed = true
},
}
const transport = {
close: async () => {
transportClosed = true
},
}
await cleanupFailedConnection(transport, inProcessServer)
assert.equal(inProcessClosed, true)
assert.equal(transportClosed, true)
})

View File

@@ -560,6 +560,22 @@ function getRemoteMcpServerConnectionBatchSize(): number {
) )
} }
type InProcessMcpServer = {
connect(t: Transport): Promise<void>
close(): Promise<void>
}
export async function cleanupFailedConnection(
transport: Pick<Transport, 'close'>,
inProcessServer?: Pick<InProcessMcpServer, 'close'>,
): Promise<void> {
if (inProcessServer) {
await inProcessServer.close().catch(() => {})
}
await transport.close().catch(() => {})
}
function isLocalMcpServer(config: ScopedMcpServerConfig): boolean { function isLocalMcpServer(config: ScopedMcpServerConfig): boolean {
return !config.type || config.type === 'stdio' || config.type === 'sdk' return !config.type || config.type === 'stdio' || config.type === 'sdk'
} }
@@ -606,9 +622,7 @@ export const connectToServer = memoize(
}, },
): Promise<MCPServerConnection> => { ): Promise<MCPServerConnection> => {
const connectStartTime = Date.now() const connectStartTime = Date.now()
let inProcessServer: let inProcessServer: InProcessMcpServer | undefined
| { connect(t: Transport): Promise<void>; close(): Promise<void> }
| undefined
try { try {
let transport let transport
@@ -1145,9 +1159,10 @@ export const connectToServer = memoize(
}) })
} }
if (inProcessServer) { if (inProcessServer) {
inProcessServer.close().catch(() => { }) await cleanupFailedConnection(transport, inProcessServer)
} else {
await cleanupFailedConnection(transport)
} }
transport.close().catch(() => { })
if (stderrOutput) { if (stderrOutput) {
logMCPError(name, `Server stderr: ${stderrOutput}`) logMCPError(name, `Server stderr: ${stderrOutput}`)
} }