客户端: StdioConnector 在失败的握手后重试时,在前驱进程退出之前就可以创建子进程
作者: rohith500创建于 2026年9月8日更新于 2026年9月8日
标签buginvalidserverclientprotocolmcp-use/mcp-use
重现
正如 @Elioooon 在 https://GitHub.com/mcp-use/mcp-use/pull/2458#issuecomment-5587664551 中所述:
当初始化失败时,Client._legacyHandshake() 会立即调用 this.close() 而不等待,而 StdioClientTransport.close() 会在不等待子进程退出的情况下将其进程句柄置为空:
import assert from "node:assert/strict";
import { Client } from "@modelcontextprotocol/client";
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
// Child server that fails initialize
const transport = new StdioClientTransport({
command: process.execPath,
args: ["-e", `/* keep open until SIGUSR2 */`],
});
await assert.rejects(client.connect(transport), /initialization failure/);
await client.close();
// Child process is still alive when client.close() resolves:
process.kill(transportPid, 0); // succeeds (ESRCH is not thrown)生产影响
- 独占锁竞争:如果一个 MCP 服务器在启动时获取了一个独占锁(例如嵌入式 SQLite / DuckDB 数据库锁,
.mcp/中的文件锁或 leveldb),那么立即重试可能会失败,因为退出的前驱进程还没有完成刷新和释放操作系统锁。 - 端口/套接字冲突:如果本地 stdio 服务器为辅助服务绑定到固定的循环回环端口或 IPC 套接字,那么快速重启可能会与
EADDRINUSE相冲突。 - 资源峰值:在崩溃-重启循环期间,多个同时运行的相同服务器的并发实例会产生临时的 CPU/内存峰值。
内容来源: mcp-use/mcp-use