Skip to content

fix(mcp): keep an explicit projectPath project in sync (#1835) - #1886

Open
danusha2345 wants to merge 1 commit into
colbymchenry:mainfrom
danusha2345:fix/1835-projectpath-lifecycle
Open

danusha2345 wants to merge 1 commit into
colbymchenry:mainfrom
danusha2345:fix/1835-projectpath-lifecycle

Conversation

@danusha2345

Copy link
Copy Markdown
Contributor

Symptom

A single MCP server started in an un-indexed workspace whose children each have their own .codegraph/ (the multiple-indexed-children case from #1606/#1607) can query each child through projectPath, but those projects were opened read-only: no catch-up sync on open and no file watcher. Renaming or adding an exported function in a child and querying it again after the debounce window returned the old index until someone ran codegraph sync by hand. The same applied to any projectPath other than the server's default project.

Fix

The engine now owns the lifecycle of every project the ToolHandler opens for an explicit projectPath, mirroring what the default project already gets:

Nothing changes for un-indexed paths: they still get the success-shaped "not indexed" guidance, never isError, and are never indexed.

Bounds

  • The cache is keyed by the canonical (realpath) root, so a symlinked spelling or a sub-path of a project shares one connection, one watcher and one lock.
  • LRU, MAX_CACHED_PROJECTS = 8. Opening a ninth distinct project closes the least recently used one: watcher stopped, writer lock released, DB closed. Many projectPath values leak nothing; a re-visit pays a reopen plus a catch-up.
  • MCPEngine.stop() closes every cached project and releases every lock it took.
  • The CLI's and the worker-thread handlers set no lifecycle, so they behave as before (read-only, no watcher).

Verification

  • npx tsc --noEmit -p tsconfig.json — exit 0.
  • New __tests__/mcp-projectpath-lifecycle.test.ts (3 tests, engine at an un-indexed workspace with two indexed children, driven through MCPEngine.getToolHandler().execute): a pre-start edit is caught up on the first projectPath call and a later edit is picked up by the watcher; three spellings of one root (direct, symlink, sub-path) open one watched instance whose writer.pid exists and is gone after stop(); a project whose lock a foreign live PID holds is served read-only and its lock is left in place.
  • Targeted suites, all green: mcp-unindexed (8), mcp-stale-slice (6), mcp-roots (3), watcher (36), mcp-catchup-gate (7), mcp-staleness-banner (7), writer-lock (6), mcp-writer-lock (2).

Fixes #1835

🤖 Generated with Claude Code

…1835)

A project opened through a tool call's `projectPath` (a repository other
than the server's default — e.g. an indexed child of an un-indexed
workspace) was opened read-only: no catch-up sync on open and no file
watcher, so its answers went stale until someone ran `codegraph sync`.

The engine now owns the lifecycle of every project the ToolHandler opens
for an explicit path, mirroring the default project:
- the project's writer lock is acquired (colbymchenry#1740 single-writer rule); if
  another live process holds it, that process keeps syncing and we only
  read;
- a catch-up `sync()` runs on open and the first call against that
  project awaits it, time-boxed like the default gate (colbymchenry#905);
- a file watcher runs for as long as the project stays cached.

Bounds: the cache is keyed by the canonical (realpath) root, so a
symlinked spelling shares one connection and one watcher; it is LRU with
`MAX_CACHED_PROJECTS = 8` — opening a ninth closes the least recently
used (watcher stopped, writer lock released, DB closed); `stop()` closes
them all. Un-indexed paths still get the success-shaped guidance.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

MCP: projectPath queries leave non-default repository indexes without auto-sync

1 participant