Skip to content

context_server: Reset MCP request idle timer on inbound activity#57360

Open
beardfaceguy wants to merge 1 commit into
zed-industries:mainfrom
beardfaceguy:resubmit/mcp-progress-timeout-reset
Open

context_server: Reset MCP request idle timer on inbound activity#57360
beardfaceguy wants to merge 1 commit into
zed-industries:mainfrom
beardfaceguy:resubmit/mcp-progress-timeout-reset

Conversation

@beardfaceguy
Copy link
Copy Markdown

Closes #56774.

Summary

  • Fixes request cancellation during long-running MCP calls when the server is still sending inbound frames (including notifications/progress).
  • Changes timeout behavior from fixed wall-clock since request start to inactivity-based timeout (last_inbound_activity + timeout).
  • Keeps protection against genuinely silent servers.

Changes

  • Tracked latest inbound activity timestamp on the context server client.
  • Updated request timeout loop to re-arm against inactivity rather than request start time.
  • Added regression tests for silent timeout, keep-alive via progress notifications, and timeout after progress stops.

Test plan

  • cargo test -p context_server request_times_out_when_server_is_silent -- --nocapture
  • cargo test -p context_server progress_notifications_keep_request_alive_past_timeout -- --nocapture
  • cargo test -p context_server request_times_out_after_progress_stops -- --nocapture

Release Notes:

  • Fixed long-running MCP context server requests being cancelled despite inbound progress notifications; timeout is now based on true server inactivity.

The per-request timeout in `Client::request_with` was a fixed
`executor.timer(timeout)` armed at request time, with no way for the
server to signal "still alive, just busy." Long-running MCP tool calls
(`cargo test`, large refactors, codebase reviews — anything that runs
beyond `context_server_timeout`) get cancelled at the boundary even when
the server is actively working and emitting `notifications/progress`.

Track the timestamp of the most recent inbound JSON-RPC frame on the
shared `Client` and consult it inside the request loop. Any frame the
server sends — response, request, OR notification — bumps the timestamp.
The request future computes a per-iteration deadline of
`last_activity + timeout` and re-arms the timer; when activity arrives
during a sleep, the next iteration extends the deadline. A genuinely
silent server still bails after `timeout` of true silence, so the
protective behavior is unchanged for misbehaving servers.

Uses `BackgroundExecutor::now()` so the timer participates correctly in
GPUI test executor's fake clock.

Tests: request_times_out_when_server_is_silent
  progress_notifications_keep_request_alive_past_timeout
  request_times_out_after_progress_stops
Co-authored-by: Cursor <cursoragent@cursor.com>
@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label May 21, 2026
@zed-community-bot zed-community-bot Bot added the first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions label May 21, 2026
@MrSubidubi MrSubidubi added the area:ai/mcp Model Context Protocol label May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:ai/mcp Model Context Protocol cla-signed The user has signed the Contributor License Agreement first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP context server requests cancelled mid-flight despite progress notifications

2 participants