Skip to content

feat(mcp): surface when a newer CodeGraph release exists (non-blocking update check)#1253

Merged
colbymchenry merged 1 commit into
mainfrom
feat/update-check-1243
Jul 10, 2026
Merged

feat(mcp): surface when a newer CodeGraph release exists (non-blocking update check)#1253
colbymchenry merged 1 commit into
mainfrom
feat/update-check-1243

Conversation

@colbymchenry

Copy link
Copy Markdown
Owner

Closes #1243.

Problem

The recommended MCP config launches the local codegraph binary, so the server (and the prompt hook beside it) silently stays on whatever version was last manually upgraded. Users discover the drift only when something breaks. The reporter's preferred fix (their option 1): check on serve start, surface a notice, change nothing.

What this does

On MCP server start (proxy, daemon, and direct modes share the hook), refresh a machine-shared update-check cache in the background and — when a newer release exists — surface one sentence on three surfaces:

  • stderr at startup (lands in the MCP host's server log; never stdout, the protocol channel)
  • the initialize instructions, with explicit "mention it to the user when convenient; do not run the upgrade yourself" guidance — the primary user-visible channel, since codegraph_status is unlisted by default
  • codegraph_status

Nothing auto-updates.

Design notes

  • Version resolution reuses resolveLatestVersion() (the GitHub release-redirect trick, linux install? how? #325-safe), so what the check reports and what codegraph upgrade installs can't drift.
  • Cache: ~/.codegraph/update-check.json, shared by every server process — 24h TTL on success, 1h backoff on failure; an outage never hides an already-known update; a stale cache re-kicks a background refresh so long-lived daemons keep noticing.
  • The initialize path is a memoized synchronous cache read (the MCP server fails to connect with Claude Code: Content-Length framing vs newline-delimited JSON transport mismatch #172 respond-fast contract holds), and both handshake answerers — session and proxy — share one initializeInstructions() helper so they can't diverge.
  • Hardening: the latest tag arrives from a network redirect via an on-disk cache and ends up inside agent-visible instructions — only a canonical vX.Y.Z rebuilt from parsed semver fields is ever interpolated. A tag with trailing text (parseSemver isn't end-anchored) renders without it; a non-version tag renders nothing and counts as a failed attempt.
  • Off is off: CODEGRAPH_NO_UPDATE_CHECK=1 (dedicated) or DO_NOT_TRACK=1 (broad convention) suppresses the network call and the notice entirely. Documented in TELEMETRY.md with the honest note that only a version number is fetched.

Validation

  • 20 unit tests: TTL/backoff discipline, opt-outs, torn-cache resilience, dev-sentinel guard, injection canonicalization, the instructions suffix.
  • End-to-end smoke against the spawned dist server: fake-HOME cache claiming v9.9.9 → notice in initialize instructions + stderr; current-version control run → byte-identical clean instructions, silent log.
  • Full suite green (2344+ tests).

🤖 Generated with Claude Code

…ging anything (#1243)

The recommended MCP config launches the local binary, so a server left
running drifts behind releases silently — users discover the version gap
only when something breaks. Per the reporter's preferred option 1, the
server now checks the latest GitHub release in the background on startup
(never blocking; reuses the upgrade command's release-redirect resolution
so the two can't drift) and surfaces a one-line notice on three surfaces:
one stderr line (the MCP host's server log), the initialize instructions
(with do-not-run-it-yourself guidance for the agent), and codegraph_status.

Discipline: results cache in ~/.codegraph/update-check.json shared across
every proxy/daemon on the machine — 24h TTL on success, 1h backoff after
failure, an outage never hides an already-known update, and a stale cache
re-kicks a background refresh so long-lived daemons keep noticing. The
initialize path is a memoized synchronous cache read (the respond-fast
contract holds), and both handshake answerers (session + proxy) share one
helper so they can't diverge. Never stdout.

Hardening: the latest tag arrives from a network redirect via an on-disk
cache and ends up inside agent-visible instructions, so only a canonical
vX.Y.Z rebuilt from PARSED semver fields is ever interpolated — a tag
carrying trailing text (parseSemver is not end-anchored) renders without
it, and a non-version tag renders nothing and counts as a failed attempt.

Off is off: CODEGRAPH_NO_UPDATE_CHECK=1 (dedicated) or DO_NOT_TRACK=1
(broad convention — already set by data-plane deployments) suppresses the
network call and the notice entirely. Documented in TELEMETRY.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

codegraph upgrade should run automatically on MCP server start (or offer a check)

1 participant