Skip to content

feat: propagate per-server MCP timeout to tool executors#3254

Open
billbtbillb-ui wants to merge 1 commit into
OpenHands:mainfrom
billbtbillb-ui:feat/mcp-tool-timeout
Open

feat: propagate per-server MCP timeout to tool executors#3254
billbtbillb-ui wants to merge 1 commit into
OpenHands:mainfrom
billbtbillb-ui:feat/mcp-tool-timeout

Conversation

@billbtbillb-ui
Copy link
Copy Markdown

Summary

This PR implements per-server MCP tool execution timeout propagation, allowing users to configure tool timeouts in their .mcp.json config and have them automatically applied to tool executors.

Changes

openhands-sdk/openhands/sdk/mcp/utils.py

  • Added _extract_timeout_from_config() — reads per-server timeout fields (milliseconds) from MCPConfig, converts to seconds, and returns the maximum across all servers (or None if none configured)
  • Updated _connect_and_list_tools() to accept and forward tool_timeout to MCPToolDefinition.create()
  • Updated create_mcp_tools() to extract the timeout from config and pass it through

openhands-sdk/openhands/sdk/mcp/tool.py

  • Added timeout: float | None = None parameter to MCPToolDefinition.create()
  • When timeout is None, falls back to MCP_TOOL_TIMEOUT_SECONDS (300s)
  • Passes the resolved timeout to MCPToolExecutor

tests/sdk/mcp/test_mcp_timeout.py (new)

  • 13 tests covering:
    • _extract_timeout_from_config(): empty config, single server, multiple servers, no timeout, missing attribute
    • MCPToolDefinition.create(): custom timeout propagation, None fallback, omitted fallback
    • MCPToolExecutor: timeout error observation, default value
    • End-to-end: config → executor timeout propagation

How it works

Users can now configure per-server timeouts in their MCP config:

{
  "mcpServers": {
    "my_server": {
      "url": "http://localhost:3000/mcp",
      "timeout": 60000
    }
  }
}

The timeout value (in milliseconds, matching FastMCP convention) is converted to seconds and applied to tool execution. When multiple servers are configured, the maximum timeout is used. When no timeout is specified, the existing default of 300 seconds applies.

- Add _extract_timeout_from_config() to read per-server timeout (ms→s)
  from MCPConfig, using max when multiple servers are configured
- Add timeout parameter to MCPToolDefinition.create(), falling back to
  MCP_TOOL_TIMEOUT_SECONDS (300s) when not specified
- Thread tool_timeout through create_mcp_tools() → _connect_and_list_tools()
  → MCPToolDefinition.create() → MCPToolExecutor
- Add comprehensive tests covering config extraction, timeout propagation,
  default fallback, and timeout error observation handling
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant