Skip to content

Commit 134a3eb

Browse files
authored
Merge pull request #15 from pro-vi/fix/configurable-mcp-timeout
fix(mcp): use configured timeout instead of hardcoded 15s
2 parents 069a277 + 9a3a7a5 commit 134a3eb

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 ${timeoutMs / 1000}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 ${timeoutMs / 1000}s.`)), timeoutMs))]);
190192
}
191-
193+
192194
throw e;
193195
}
194196
}

0 commit comments

Comments
 (0)