Repository navigation
BUG-001: MCP tool call missing progressToken injection causing timeout on long reviews (-32001) #14499
Description
Bug Description
OpenCode experiences -32001 timeout errors during long-running code reviews (10~20 minutes) when calling MCP tools (like review-mcp), even though:
- The MCP server has implemented progress notifications with 12-second heartbeat
- OpenCode client has
resetTimeoutOnProgress: trueset
The timeout errors still occur, indicating a broken link between "server heartbeat exists" and "client timeout renewal works".
Root Cause Analysis
The issue is NOT whether the server sends heartbeat, but whether the client establishes a complete timeout renewal chain: progressToken + progress handler + resetTimeoutOnProgress.
Current Data Flow (Broken Link)
| Step | Input | Process | Output | File |
|---|---|---|---|---|
| 1. Tool wrapper | MCP tool definition | convertMcpTool generates dynamic tool |
execute(args) |
packages/opencode/src/mcp/index.ts:120 |
| 2. Tool call | args |
calls client.callTool |
MCP request | packages/opencode/src/mcp/index.ts:135 |
| 3. Request options | resetTimeoutOnProgress=true + timeout |
Missing onprogress callback |
No progress handler | packages/opencode/src/mcp/index.ts:142 |
| 4. SDK request construction | call options | Only injects _meta.progressToken when options.onprogress exists |
No token carried | MCP SDK protocol.ts |
| 5. Server reads token | MCP request | getProgressToken(request.params._meta.progressToken) |
token / undefined | MCP server |
| 6. Server heartbeat | token + interval | startProgressHeartbeat sends progress |
progress / no-op | MCP server |
| 7. Client timeout renewal | progress notification | SDK executes _resetTimeout() when progress handler exists |
Request renewed | MCP SDK protocol.ts |
Break point: Step 3 -> 4 (OpenCode doesn't provide onprogress, so SDK doesn't inject progressToken)
Consequence: Server can't see token, heartbeat degrades to no-op; client timer never resets, long request hits -32001.
Proposed Solution
Add onprogress callback in OpenCode's MCP call options at packages/opencode/src/mcp/index.ts:142:
return client.callTool(
{
name: mcpTool.name,
arguments: (args || {}) as Record<string, unknown>,
},
CallToolResultSchema,
{
onprogress: (event) => {
log.debug("mcp progress", {
tool: mcpTool.name,
progress: event.progress,
total: event.total,
})
},
resetTimeoutOnProgress: true,
timeout,
},
)This allows the SDK to:
- Inject
progressTokenin request_meta - Trigger
_resetTimeout()on progress notifications
Acceptance Criteria
- Both
designandimplementationreview types no longer experience-32001timeout - Works reliably without relying on "fixed long timeout" as primary strategy
- Unit tests verify
onprogresscallback is included in call options - Integration tests verify progress notifications renew timeout
- E2E tests pass for long-running tool scenarios
Constraints
- Must maintain existing MCP tool protocol compatibility
- Should work with any MCP server that supports progress notifications
- Progress callback should be lightweight (debug logging only for now)
Activity
fix: add onprogress callback to MCP tool calls for timeout renewal
flood-runner commentedon Mar 14, 2026
thanks @jaried for raising this
we run MCP servers with long-running container and infrastructure operations, this is blocking us
hhoughgg commentedon Mar 20, 2026
@jaried are you planning to follow up on your PR? It looks like there are build failures. I also would really like to see this merged as the default timeouts are painful for long running calls.
claui commentedon May 5, 2026
I think this is now being addressed in #24964.