Skip to content

Commit c966bcb

Browse files
committed
fix(mcp): use configured timeout instead of hardcoded 15s
The `timeout` field was defined in `McpHttpServerSchema` but never used. `_withSession()` had a hardcoded 15000ms timeout which caused issues with slow MCP servers (e.g., LLM providers via OpenRouter). Changes: - Add `timeout` field to `McpStdioServerSchema` for consistency - Use `serverConfig.timeout` in `_withSession()` instead of hardcoded 15s - Default timeout increased from 15s to 30s to match schema default Fixes #20 in code-mode repo
1 parent 1840f28 commit c966bcb

File tree

2 files changed

+9
-5
lines changed

2 files changed

+9
-5
lines changed

packages/mcp/src/mcp_call_template.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export interface McpStdioServer {
2222
args: string[];
2323
cwd?: string;
2424
env: Record<string, string>;
25+
timeout: number;
2526
}
2627

2728
/**
@@ -33,6 +34,7 @@ export const McpStdioServerSchema: z.ZodType<McpStdioServer> = z.object({
3334
args: z.array(z.string()).optional().default([]).describe('Arguments to pass to the command.'),
3435
cwd: z.string().optional().describe('Working directory for the command.'),
3536
env: z.record(z.string(), z.string()).optional().default({}).describe('Environment variables for the command.'),
37+
timeout: z.number().optional().default(30).describe('Timeout for MCP operations in seconds.'),
3638
}) as z.ZodType<McpStdioServer>;
3739

3840

packages/mcp/src/mcp_communication_protocol.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,26 +169,28 @@ export class McpCommunicationProtocol implements CommunicationProtocol {
169169
operation: (client: McpClient) => Promise<T>
170170
): Promise<T> {
171171
const sessionKey = `${serverName}:${serverConfig.transport}`;
172+
// Use configured timeout (in seconds) or default to 30s
173+
const timeoutMs = (serverConfig.timeout ?? 30) * 1000;
172174
try {
173175
const client = await this._getOrCreateSession(serverName, serverConfig, auth);
174176
return await Promise.race([
175177
operation(client),
176-
new Promise<T>((_, reject) => setTimeout(() => reject(new Error(`MCP operation on '${sessionKey}' timed out after 15s.`)), 15000))
178+
new Promise<T>((_, reject) => setTimeout(() => reject(new Error(`MCP operation on '${sessionKey}' timed out after ${serverConfig.timeout ?? 30}s.`)), timeoutMs))
177179
]);
178180
} catch (e: any) {
179181
this._logError(`MCP operation on '${sessionKey}' failed:`, e.message);
180-
182+
181183
const errorMsg = String((e as any)?.message ?? e).toLowerCase();
182184
// Check for connection errors or "already initialized" errors
183-
if (errorMsg.includes('closed') || errorMsg.includes('disconnected') ||
185+
if (errorMsg.includes('closed') || errorMsg.includes('disconnected') ||
184186
errorMsg.includes('econnreset') || errorMsg.includes('etimedout') ||
185187
errorMsg.includes('already initialized')) {
186188
this._logInfo(`Connection/initialization error detected on '${sessionKey}'. Cleaning up and retrying once...`);
187189
await this._cleanupSession(sessionKey);
188190
const newClient = await this._getOrCreateSession(serverName, serverConfig, auth);
189-
return await Promise.race([operation(newClient), new Promise<T>((_, reject) => setTimeout(() => reject(new Error(`MCP operation on '${sessionKey}' timed out after 15s.`)), 15000))]);
191+
return await Promise.race([operation(newClient), new Promise<T>((_, reject) => setTimeout(() => reject(new Error(`MCP operation on '${sessionKey}' timed out after ${serverConfig.timeout ?? 30}s.`)), timeoutMs))]);
190192
}
191-
193+
192194
throw e;
193195
}
194196
}

0 commit comments

Comments
 (0)