summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDax Raad <[email protected]>2025-12-30 23:06:07 -0500
committerDax Raad <[email protected]>2025-12-30 23:06:07 -0500
commited4ce67cdc24e4e9324a00cf176a45ccd267a584 (patch)
tree79645363948d66ded086b602d9972f0f1973bf54
parent94dca309e93dc85b22eb3fc2b2ea9481580269d5 (diff)
downloadopencode-ed4ce67cdc24e4e9324a00cf176a45ccd267a584.tar.gz
opencode-ed4ce67cdc24e4e9324a00cf176a45ccd267a584.zip
core: add configurable timeout for MCP tool calls to prevent hanging requests
-rw-r--r--packages/opencode/src/config/config.ts6
-rw-r--r--packages/opencode/src/mcp/index.ts26
2 files changed, 25 insertions, 7 deletions
diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts
index f7c55d6f0..86576667b 100644
--- a/packages/opencode/src/config/config.ts
+++ b/packages/opencode/src/config/config.ts
@@ -844,6 +844,12 @@ export namespace Config {
.optional()
.describe("Tools that should only be available to primary agents."),
continue_loop_on_deny: z.boolean().optional().describe("Continue the agent loop when a tool call is denied"),
+ mcp_timeout: z
+ .number()
+ .int()
+ .positive()
+ .optional()
+ .describe("Timeout in milliseconds for model context protocol (MCP) requests"),
})
.optional(),
})
diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts
index 8ee54a4bf..bb25d7d1c 100644
--- a/packages/opencode/src/mcp/index.ts
+++ b/packages/opencode/src/mcp/index.ts
@@ -4,7 +4,11 @@ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"
import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js"
-import { type Tool as MCPToolDef, ToolListChangedNotificationSchema } from "@modelcontextprotocol/sdk/types.js"
+import {
+ CallToolResultSchema,
+ type Tool as MCPToolDef,
+ ToolListChangedNotificationSchema,
+} from "@modelcontextprotocol/sdk/types.js"
import { Config } from "../config/config"
import { Log } from "../util/log"
import { NamedError } from "@opencode-ai/util/error"
@@ -93,7 +97,7 @@ export namespace MCP {
}
// Convert MCP tool definition to AI SDK Tool type
- function convertMcpTool(mcpTool: MCPToolDef, client: MCPClient): Tool {
+ async function convertMcpTool(mcpTool: MCPToolDef, client: MCPClient): Promise<Tool> {
const inputSchema = mcpTool.inputSchema
// Spread first, then override type to ensure it's always "object"
@@ -103,15 +107,23 @@ export namespace MCP {
properties: (inputSchema.properties ?? {}) as JSONSchema7["properties"],
additionalProperties: false,
}
+ const config = await Config.get()
return dynamicTool({
description: mcpTool.description ?? "",
inputSchema: jsonSchema(schema),
execute: async (args: unknown) => {
- return client.callTool({
- name: mcpTool.name,
- arguments: args as Record<string, unknown>,
- })
+ return client.callTool(
+ {
+ name: mcpTool.name,
+ arguments: args as Record<string, unknown>,
+ },
+ CallToolResultSchema,
+ {
+ resetTimeoutOnProgress: true,
+ timeout: config.experimental?.mcp_timeout,
+ },
+ )
},
})
}
@@ -474,7 +486,7 @@ export namespace MCP {
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] = convertMcpTool(mcpTool, client)
+ result[sanitizedClientName + "_" + sanitizedToolName] = await convertMcpTool(mcpTool, client)
}
}
return result