Skip to content

fix(cli): serve MCP handshake immediately on cold start - #129

Merged
sunerpy merged 1 commit into
mainfrom
fix/cli-cold-start-handshake-race
Jul 10, 2026
Merged

sunerpy merged 1 commit into
mainfrom
fix/cli-cold-start-handshake-race

Conversation

@sunerpy

@sunerpy sunerpy commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Summary

Cold serve --mcp previously ran a spawn→poll(≤400ms)→proxy-attach→heal prelude BEFORE answering the MCP initialize/tools/list handshake. Under load that prelude exceeded the MCP client init timeout, so opencode (and other clients) marked the codegraph MCP server failed and its codegraph_* tools never registered.

This splits the SpawnOrProxy decision into a pure cold_start_action(daemon_running):

  • WARM (live daemon): attach via proxy_to_running_daemon (old spawn_or_proxy semantics unchanged), falling back to serve_direct on attach failure.
  • COLD (no live daemon): fire-and-forget spawn_shared_daemon_best_effort for the NEXT session, then serve_direct THIS session immediately — no poll, no blocking proxy. The daemon pid lock guarantees N concurrent cold starts converge on ≤1 daemon.

Serve-path only — no extraction/resolve/store change, golden .schema byte-stability and the no-AI/vector/LLM guardrail untouched.

Verification

  • make ci green locally (fmt + clippy + test + guardrail).
  • New integration test cold_start_serve_answers_handshake_within_bound: cold serve --mcp answers initialize + tools/list in <2s and exposes codegraph_search/codegraph_explore; reaps the fire-and-forget daemon in teardown; passes 3× (~0.2s each), no orphan process.
  • New unit test cold_start_action_warm_proxies_cold_spawns_then_serves_direct.
  • Independent oracle review: APPROVE (warm path preserved, cold path converges on ≤1 daemon, invariants intact).

Note

In production cold start the direct session runs a transient second watcher alongside the just-spawned daemon until the session exits; safe (WAL + busy_timeout serialize writes, idempotent upserts) and bounded, but noted for reviewers.

Cold `serve --mcp` previously ran a spawn->poll->proxy-attach->heal
prelude before answering the MCP initialize/tools/list handshake. Under
load that prelude exceeded the client init timeout, so opencode (and
other MCP clients) marked the codegraph server failed and its
codegraph_* tools never registered.

Split the SpawnOrProxy decision into a pure `cold_start_action`: a WARM
start (live daemon) attaches via the proxy as before; a COLD start now
fire-and-forgets the shared daemon for the NEXT session and serves THIS
session direct immediately, so the handshake is answered without
blocking on daemon socket readiness. Warm proxy semantics and
serve_direct are unchanged.

Add a cold-start integration test asserting initialize + tools/list
return within a strict bound and expose codegraph_search/codegraph_explore,
plus a unit test for the cold/warm decision.
@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 29.72973% with 26 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/codegraph-cli/src/main.rs 29.72% 26 Missing ⚠️

❌ Your patch check has failed because the patch coverage (29.72%) is below the target coverage (95.00%). You can increase the patch coverage or adjust the target coverage.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #129      +/-   ##
==========================================
- Coverage   95.64%   95.63%   -0.01%     
==========================================
  Files         115      115              
  Lines       55334    55348      +14     
==========================================
+ Hits        52923    52934      +11     
- Misses       2411     2414       +3     
Files with missing lines Coverage Δ
crates/codegraph-cli/src/main.rs 89.03% <29.72%> (-0.05%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@sunerpy
sunerpy merged commit d0d7298 into main Jul 10, 2026
7 checks passed
@sunerpy
sunerpy deleted the fix/cli-cold-start-handshake-race branch July 10, 2026 06:22
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