Skip to content

Commit 8f47476

Browse files
refactor: 为每个会话管理独立的 transport 实例
Co-authored-by: aider (vertex_ai/gemini-2.5-pro) <aider@aider.chat>
1 parent 32d0688 commit 8f47476

File tree

1 file changed

+68
-22
lines changed

1 file changed

+68
-22
lines changed

packages/mcp-server/src/bridge/bridge.ts

Lines changed: 68 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import {
88
type ToolResult,
99
GeminiChat,
1010
} from '@google/gemini-cli-core';
11-
// isInitializeRequest 在这种模式下不再需要
1211
import {
1312
type CallToolResult,
13+
isInitializeRequest,
1414
} from '@modelcontextprotocol/sdk/types.js';
1515
import {
1616
type PartUnion,
@@ -34,8 +34,8 @@ export class GcliMcpBridge {
3434
private readonly cliVersion: string;
3535
private readonly mcpServer: McpServer;
3636
private readonly debugMode: boolean;
37-
// transport 提升为类的成员
38-
private transport: StreamableHTTPServerTransport | undefined;
37+
// **修改 1: 创建一个 Map 来存储每个会话的 transport 实例**
38+
private readonly transports: Record<string, StreamableHTTPServerTransport> = {};
3939

4040
constructor(config: Config, cliVersion: string, debugMode = false) {
4141
this.config = config;
@@ -56,29 +56,75 @@ export class GcliMcpBridge {
5656
if (this.debugMode) {
5757
app.use(requestLogger(this.debugMode));
5858
}
59-
60-
// 1. 在 start 方法中只创建一次 transport
61-
this.transport = new StreamableHTTPServerTransport({
62-
// sessionIdGenerator 仍然是需要的,SDK 会用它来处理会话
63-
sessionIdGenerator: () => randomUUID(),
64-
});
65-
66-
// 2. 在 start 方法中只连接一次
67-
await this.mcpServer.connect(this.transport);
68-
69-
console.log(`${LOG_PREFIX} McpServer connected to the transport.`);
7059

71-
// 3. 修改路由处理器,始终使用同一个 transport 实例
60+
// **修改 2: 更新路由处理器以管理多个 transport**
7261
app.all('/mcp', async (req: Request, res: Response) => {
73-
if (!this.transport) {
74-
console.error(`${LOG_PREFIX} Transport is not initialized.`);
75-
res.status(500).json({ error: 'Server transport not available' });
76-
return;
62+
const sessionId = req.headers['mcp-session-id'] as string | undefined;
63+
let transport: StreamableHTTPServerTransport | undefined = sessionId ? this.transports[sessionId] : undefined;
64+
65+
if (!transport) {
66+
// 如果没有找到 transport,并且这是一个新的 initialize 请求,则创建一个新的
67+
if (isInitializeRequest(req.body)) {
68+
if (this.debugMode) {
69+
console.log(
70+
`${LOG_PREFIX} Creating new transport for initialize request`,
71+
);
72+
}
73+
74+
transport = new StreamableHTTPServerTransport({
75+
sessionIdGenerator: () => randomUUID(),
76+
onsessioninitialized: newSessionId => {
77+
if (this.debugMode) {
78+
console.log(
79+
`${LOG_PREFIX} Session initialized: ${newSessionId}`,
80+
);
81+
}
82+
// 将新的 transport 实例存储在 Map 中
83+
if (transport) {
84+
this.transports[newSessionId] = transport;
85+
}
86+
},
87+
});
88+
89+
// 当连接关闭时,从 Map 中移除 transport
90+
transport.onclose = () => {
91+
const sid = transport!.sessionId;
92+
if (sid && this.transports[sid]) {
93+
if (this.debugMode) {
94+
console.log(
95+
`${LOG_PREFIX} Session ${sid} closed, removing transport.`,
96+
);
97+
}
98+
delete this.transports[sid];
99+
}
100+
};
101+
102+
// 将新的 transport 连接到我们唯一的 McpServer 实例
103+
await this.mcpServer.connect(transport);
104+
} else {
105+
// 如果请求没有 session ID 但又不是 initialize 请求,则为错误请求
106+
console.error(
107+
`${LOG_PREFIX} Bad Request: Missing session ID for non-initialize request.`,
108+
);
109+
res.status(400).json({
110+
jsonrpc: '2.0',
111+
error: {
112+
code: -32000,
113+
message: 'Bad Request: Mcp-Session-Id header is required',
114+
},
115+
id: null,
116+
});
117+
return;
118+
}
119+
} else if (this.debugMode) {
120+
console.log(
121+
`${LOG_PREFIX} Reusing transport for session: ${sessionId}`,
122+
);
77123
}
78-
124+
125+
// 使用找到的或新创建的 transport 处理请求
79126
try {
80-
// handleRequest 方法能够处理并发请求
81-
await this.transport.handleRequest(req, res, req.body);
127+
await transport.handleRequest(req, res, req.body);
82128
} catch (e) {
83129
console.error(`${LOG_PREFIX} Error handling request:`, e);
84130
if (!res.headersSent) {

0 commit comments

Comments
 (0)