diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index bf4a6035bd8..77916e878db 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -395,9 +395,7 @@ export namespace Config { .int() .positive() .optional() - .describe( - "Timeout in ms for fetching tools from the MCP server. Defaults to 5000 (5 seconds) if not specified.", - ), + .describe("Timeout in ms for MCP server requests. Defaults to 5000 (5 seconds) if not specified."), }) .strict() .meta({ @@ -436,9 +434,7 @@ export namespace Config { .int() .positive() .optional() - .describe( - "Timeout in ms for fetching tools from the MCP server. Defaults to 5000 (5 seconds) if not specified.", - ), + .describe("Timeout in ms for MCP server requests. Defaults to 5000 (5 seconds) if not specified."), }) .strict() .meta({ diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index 4e0968391f3..b0790d93e27 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -109,7 +109,7 @@ export namespace MCP { } // Convert MCP tool definition to AI SDK Tool type - async function convertMcpTool(mcpTool: MCPToolDef, client: MCPClient): Promise { + async function convertMcpTool(mcpTool: MCPToolDef, client: MCPClient, timeout?: number): Promise { const inputSchema = mcpTool.inputSchema // Spread first, then override type to ensure it's always "object" @@ -119,7 +119,6 @@ export namespace MCP { properties: (inputSchema.properties ?? {}) as JSONSchema7["properties"], additionalProperties: false, } - const config = await Config.get() return dynamicTool({ description: mcpTool.description ?? "", @@ -133,7 +132,7 @@ export namespace MCP { CallToolResultSchema, { resetTimeoutOnProgress: true, - timeout: config.experimental?.mcp_timeout, + timeout, }, ) }, @@ -556,7 +555,10 @@ export namespace MCP { export async function tools() { const result: Record = {} const s = await state() + const cfg = await Config.get() + const config = cfg.mcp ?? {} const clientsSnapshot = await clients() + const defaultTimeout = cfg.experimental?.mcp_timeout for (const [clientName, client] of Object.entries(clientsSnapshot)) { // Only include tools from connected MCPs (skip disabled ones) @@ -577,10 +579,13 @@ export namespace MCP { if (!toolsResult) { continue } + const mcpConfig = config[clientName] + const entry = isMcpConfigured(mcpConfig) ? mcpConfig : undefined + const timeout = entry?.timeout ?? defaultTimeout for (const mcpTool of toolsResult.tools) { const sanitizedClientName = clientName.replace(/[^a-zA-Z0-9_-]/g, "_") const sanitizedToolName = mcpTool.name.replace(/[^a-zA-Z0-9_-]/g, "_") - result[sanitizedClientName + "_" + sanitizedToolName] = await convertMcpTool(mcpTool, client) + result[sanitizedClientName + "_" + sanitizedToolName] = await convertMcpTool(mcpTool, client, timeout) } } return result