MCP: hardcoded 30s timeout on every request makes long-running tools impossible (same root cause as #617)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 19.9k
- Forks
- 2.3k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 30
Description
Summary
Every MCP JSON-RPC request shares one hardcoded 30s timeout, including tools/call. There is no flag, config key, or mcp.json field to raise it, so any tool that legitimately takes longer than 30s can never succeed.
crates/jcode-base/src/mcp/client.rs:46 (at 02439b4):
let response = tokio::time::timeout(std::time::Duration::from_secs(30), rx)
.await
.context("Request timeout")?
request() is the single path used by initialize (client.rs:301), tools/list (client.rs:103) and tools/call (client.rs:71), so the same 30s covers server startup and long-running tool work alike.
I believe this is also the root cause of #617 — a slow-starting server blows the same budget during initialize.
Reproduction
Minimal MCP server (slow_mcp.py, needs pip install mcp):
import time
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("slowsrv")
@mcp.tool()
def slow_ping(seconds: int = 45) -> str:
"""Sleep then return a token."""
time.sleep(seconds)
return "SLOW-TOKEN-OK"
mcp.run()
.jcode/mcp.json:
{"mcpServers": {"slow": {"command": "python", "args": ["/abs/path/slow_mcp.py"], "env": {}}}}
jcode run 'Call slow_ping with seconds=45 exactly once, then report what it returned.'
Expected: the tool returns SLOW-TOKEN-OK after 45s.
Actual (0.68.0): the call fails at exactly 30s with Error: Request timeout, and the model reports the timeout instead of the result. I also tried timeout, timeout_ms, timeout_secs and tool_timeout_ms keys on the server entry in mcp.json — none are read.
Impact
I maintain a benchmark harness that drives Microsoft Word through an MCP server, where a single document edit routinely runs longer than 30s (the first call on a busy pool especially). Under jcode those calls come back as Request timeout and the model retries them; the work still completes, but every run burns turns and tokens on retries, and a slow enough backend can never finish at all. Anything else with real I/O behind it — builds, test suites, deploys, browser automation, remote APIs — has the same ceiling.
Suggestion
Two things would fix it, in rough priority order:
- Make the timeout configurable, and use a longer default for
tools/callthan forinitialize/tools/list. Comparable clients all expose this: Claude Code hasMCP_TIMEOUT/MCP_TOOL_TIMEOUT, VS Code and Cursor take a per-servertimeoutinmcp.json, goose and kimi-cli both have their own knobs. A per-server field inmcp.jsonplus a global default inconfig.tomlwould match what people already expect. - Optionally, reset the deadline on MCP progress notifications — the spec allows implementations to do this so well-behaved long-running tools stay alive.
Happy to test a patch against the real workload if that helps. Environment: jcode 0.68.0 (installed via jcode.sh/install), Linux x86_64.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in crates/jcode-base/src/mcp/client.rs:46 and trace request() to initialize, tools/list, and tools/call at the referenced locations. Review how MCP server settings are loaded before choosing the configuration surface. Done means long-running tools can exceed the current 30-second limit while initialization and listing retain an appropriate timeout, with the existing reproduction succeeding.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100