Skip to content

fix(mcp): exit promptly on stdin EOF while a tool call is in flight - #125

Merged
amondnet merged 3 commits into
mainfrom
amondnet/116-mcp-exit-on-eof
Oct 14, 2026
Merged

amondnet merged 3 commits into
mainfrom
amondnet/116-mcp-exit-on-eof

Conversation

@amondnet

@amondnet amondnet commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

After stdin EOF, csp mcp stayed alive until a tool call that was mid index-build finished. The search / find_related handlers run synchronous index/model code inline on a tokio worker, and dropping the Runtime at the end of run_mcp joins that worker.

run_mcp now goes through block_then_abandon, which calls Runtime::shutdown_background() instead of dropping the runtime, so the process exits as soon as waiting() returns. Mirrors upstream semble MinishLab/semble#282.

Remaining bound: rmcp 1.7 drains in-flight handler responses for up to 5 s on QuitReason::Closed before waiting() returns. That is internal to rmcp and left as is.

Known trade-off of abandoning workers: an in-flight index save or git clone is cut off when the process exits, as with any SIGKILL-style exit. Not addressed here.

Test: block_then_abandon_does_not_join_a_blocked_worker parks a worker in a 30 s sleep (synchronised via a oneshot) and asserts the helper returns in under 5 s. With drop(rt) it fails after 30 s; with the fix it passes in about 0 s.

E2E (debug build, about 4000-file / 120k-line scratch tree, scratch HOME with no index cache, HF model cache warmed beforehand; initialize, search tool call, stdin closed after 1 s):

  • main: 90.1 s total (waits for the whole index build)
  • this PR: 6.0 s total (1 s pre-EOF sleep, plus about 5 s rmcp drain)

Related issue

Closes #116

Checklist

  • PR title follows Conventional Commits
  • Tests added or updated, and the suite passes (cargo test --workspace: 340 + 28 passed)
  • Lint/format pass (cargo fmt, cargo clippy -D warnings)
  • Documentation updated if behavior changed (no user-facing docs affected)
  • No breaking change, or a BREAKING CHANGE: note is included

Summary by cubic

Fixes csp mcp hanging after stdin EOF when a tool call's index build is still in flight. The process now abandons the tokio runtime with shutdown_background instead of dropping it, so it exits without joining the blocked worker. Closes #116.

  • A drop guard abandons the runtime on panic too, so a failing serve loop never joins blocked workers during unwinding.
  • In-flight index saves or git clones may be cut off on exit.
  • rmcp still drains in-flight handlers for up to 5s before the process exits.
  • Adds unit tests asserting teardown doesn't wait for a worker blocked in a 30s sleep, both normally and on panic.

Written for commit 364c2d2. Summary will update on new commits.

Turn on auto-fix

…116)

Abandon the tokio runtime with shutdown_background instead of dropping it, so a worker blocked in a synchronous index build is not joined after the client disconnects.
@codacy-production

codacy-production Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 8 complexity · 4 duplication

Metric Results
Complexity 8
Duplication 4

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@codecov

codecov Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.23077% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/csp/src/bin/csp/mcp_server.rs 94.23% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a block_then_abandon helper function in mcp_server.rs to run a future to completion and then immediately shut down the Tokio runtime in the background without waiting for worker threads to join, preventing the process from hanging on stdin EOF. It also adds a corresponding unit test. The review feedback suggests wrapping the runtime in a custom drop guard within block_then_abandon to ensure shutdown_background is called even if the future panics, preventing a potential hang during panic unwinding.

Comment thread crates/csp/src/bin/csp/mcp_server.rs
@codspeed

codspeed Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 5 untouched benchmarks


Comparing amondnet/116-mcp-exit-on-eof (364c2d2) with main (dfa7193)

Open in CodSpeed

@amondnet
amondnet marked this pull request as ready for review October 14, 2026 16:17

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cubic analysis

No issues found across 1 file

Linked issue analysis

Linked issue: pleaseai/code-search#116: parity(#282): csp mcp should exit promptly on stdin EOF while an index build is in flight

Status Acceptance criteria Notes
⚠️ Exit promptly after stdin EOF during an in-flight build The helper abandons blocked workers, but the E2E run took about six seconds and no integration test asserts the one-second target.
Architecture diagram
sequenceDiagram
    participant Client as MCP Client (stdin)
    participant RMCP as rmcp Server
    participant Handler as Tool Handler
    participant Worker as Tokio Worker
    participant Runtime as Tokio Runtime
    participant Helper as block_then_abandon

    Note over Client,Runtime: MCP Server Lifecycle with fix

    Client->>RMCP: stdin data (initialize, search tool call)
    RMCP->>Handler: dispatch search / find_related
    
    Note over Handler,Worker: Tool call blocks worker synchronously
    Handler->>Worker: index build / model inference
    
    Client->>RMCP: CHANGED: stdin EOF detected
    RMCP->>RMCP: Initiate shutdown (QuitReason::Closed)
    
    Note over RMCP,Runtime: Up to 5s drain of in-flight handler responses
    RMCP->>Helper: waiting() returns
    Helper->>Runtime: CHANGED: shutdown_background() (abandon worker)
    
    alt Worker still running (index build in flight)
        Runtime->>Runtime: CHANGED: Abandon worker (no join)
        Runtime-->>Helper: process exits immediately (~0s)
    else Worker already finished
        Runtime->>Runtime: Normal shutdown
        Runtime-->>Helper: process exits
    end
    
    Note over Client,Helper: Old behavior: drop(runtime) joined worker,<br/>waited up to 90s for index build

    Note over Helper,Worker: Known trade-off: in-flight index save /<br/>git clone may be cut off on exit
Loading

Turn on auto-fix | Re-trigger cubic

@greptile-apps

greptile-apps Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium impact] The PR appears safe to merge.

Summary

run_mcp now uses shutdown_background() to avoid waiting for blocked workers after the client disconnects. A drop guard also covers panic paths.

  • The MCP server exits without waiting for a busy worker.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Client closes stdin] --> B[Service waiting returns]
  B --> C[Drop guard runs]
  D[Serve loop panics] --> C
  C --> E[shutdown_background]
  E --> F[Return without joining blocked workers]
Loading

Reviews (3) · Last reviewed commit: "test(mcp): run the blocking stand-in thr..." · Reviewed by Greptile

@amondnet

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new helper function block_then_abandon in mcp_server.rs to drive a future to completion on a Tokio runtime and then abandon the runtime without joining its workers. This prevents the csp mcp process from hanging on stdin EOF if there are active synchronous tasks running on runtime workers. The change includes a custom Drop guard to handle both normal execution and panics, along with corresponding unit tests to verify the behavior. There are no review comments, so no feedback is provided.

@sonarqubecloud

Copy link
Copy Markdown

@amondnet
amondnet merged commit 339349b into main Oct 14, 2026
14 checks passed
@amondnet
amondnet deleted the amondnet/116-mcp-exit-on-eof branch October 14, 2026 16:49
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.

parity(#282): csp mcp should exit promptly on stdin EOF while an index build is in flight

1 participant