Skip to content

feat(mcp): query same-repository worktrees per tool call - #561

Draft
Frankie-Xu wants to merge 5 commits into
trailhq:mainfrom
Frankie-Xu:frankie/mcp-worktree-root-515
Draft

Frankie-Xu wants to merge 5 commits into
trailhq:mainfrom
Frankie-Xu:frankie/mcp-worktree-root-515

Conversation

@Frankie-Xu

@Frankie-Xu Frankie-Xu commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

A shared MCP server currently answers every tool call from its startup root, so an agent reviewing a linked worktree can receive code and spans from the parent checkout. This adds an optional root to all six tools and routes refresh/query/cache access through the selected checkout. Results include the root and current full HEAD, including calls that omit root.

Fixes #515.

This is a proposed interface in Draft; no upstream agreement on root semantics is assumed. Relative paths resolve against the server root, checkout subdirectories normalize to their Git top-level, and the canonical Git common directory defines the access boundary. Linked worktrees are accepted; separate clones, submodules and unrelated/non-Git roots are refused before graph access. A pinned --dir retains both the server's source scope and graph directory, and refuses another checkout. Existing no-root/workspace dispatch and old tool aliases remain supported.

Graph and ask-index caches already use graph paths as keys; distinct checkout roots now select distinct paths and reuse those caches. HEAD is read on each response, and represents checkout identity rather than a content snapshot: uncommitted source edits still participate in freshness. Shared Git probes/enumeration receive a copied environment without inherited repository overrides, and session pricing is assigned after asynchronous freshness before query formatting.

Validation:

  • Original MCP dispatcher reproduced the wrong-checkout answer: explicit review root returned the parent's current-checkout source.
  • Seven new two-worktree regressions passed: all tools, seed/refresh from graphless older checkout, graph + ask-index cache reuse, source/HEAD changes, main graph preservation, relative/subdirectory/symlink aliases, clone/submodule/foreign refusals without writes, custom --dir source scope, non-Git defaults and target-only files under inherited Git overrides.
  • Additional concurrent stdio MCP regression checks serialized schemas and independent source/HEAD responses.
  • npm run build passed (core + viewer TypeScript compilation and viewer/query bundles).
  • Full suite: 1,365 passed, 0 failed/skipped on Node 26.5.0, using the repository runner settings with test concurrency capped at 2. This includes the concurrent stdio regression and all existing default/workspace/ingestion/cache tests.
  • Node 24: test/generic-node24.test.ts passed (all breadth grammars).
  • Independent code/spec review completed; actionable source-scope, inherited Git environment and concurrent-pricing findings were fixed and rechecked.

Cross-platform fixtures expand Windows DOS 8.3 temporary paths with realpathSync.native while checking the complete resolved root and full HEAD. The shared CodeQL workflow initializes and analyzes with the same officially verified v4.38.1 commit.

Hosted CI passed on exact head 8d906bbb338427948a53b75193004d7012b65843: Ubuntu, Windows, Node 24 WASM, CodeQL analysis/aggregate, blast radius and blast viewer. The cleanup job is intentionally skipped. Local validation uses macOS arm64. This does not change implicit startup root discovery (#454) or implement the separate custom graph refresh guard (#443).

@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

🌱 graft blast radius

3 areas changed → 4 areas can be affected. 6 dependent symbols, depth 2.
Tests: no test reaches Git File Enumeration, Git Environment Setup; 1 area updated its tests.
Tag: @anirudhkumar-nanonets — 6 of 7 areas · @shhdwi — 4 of 7 areas · @yescine — Git File Enumeration

flowchart TB
  A0(("Dependency Graph Building<br/>3 symbols"))
  A1(("CLI Entry Point<br/>1 symbol"))
  A2(("Context File Discovery<br/>1 symbol"))
  A3(("MCP Server<br/>1 symbol"))
  classDef reached fill:#D9EDF3,stroke:#3AA7C9,stroke-width:1.5px,color:#0E313C;
  class A0,A1,A2,A3 reached;
Loading
Can be affected Symbols Nearest hop Reached from
Dependency Graph Building 3 src/graph/build.ts:L204-L472 buildGraph — calls, depth 2 Git File Enumeration
CLI Entry Point 1 src/cli.ts:L1-L2380 cli.ts — calls, depth 2 MCP Tool Execution
Context File Discovery 1 src/context/build.ts:L109-L122 listContextFiles — calls, depth 2 Git File Enumeration
MCP Server 1 src/mcp/server.ts:L73-L155 startMcpServer — calls, depth 1 MCP Tool Execution
Who knows this code — 4 people across 7 areas
Area Who knows it
MCP Tool Execution · changed @shhdwi — 15 commits, last yesterday · @anirudhkumar-nanonets — 7 commits, last 1mo ago
Git File Enumeration · changed @anirudhkumar-nanonets — 3 commits, last 2mo ago · @yescine — 2 commits, last 2mo ago
Dependency Graph Building · affected @anirudhkumar-nanonets — 17 commits, last 2mo ago · @shhdwi — 10 commits, last yesterday
CLI Entry Point · affected @anirudhkumar-nanonets — 58 commits, last today · @shhdwi — 26 commits, last today
Context File Discovery · affected @anirudhkumar-nanonets — 4 commits, last 2mo ago · @qoole — 2 commits, last 3mo ago
MCP Server · affected @anirudhkumar-nanonets — 6 commits, last 2d ago · @shhdwi — 2 commits, last 3mo ago
Git Environment Setup · changed only you — nobody else has touched these files

Ownership is git history over each area's own files, weighted towards recent work (120-day half-life). Merge commits and bots are dropped, and you are dropped from your own PR. A name with no @ has no GitHub handle in its commit email — tag them by hand, or add a .mailmap entry. A suggestion from history, not a CODEOWNERS rule.

All 6 dependent symbols, grouped by area

Dependency Graph Building — 3 symbols in 3 files

  • src/graph/build.ts:L204-L472 — buildGraph (calls, depth 2)
    210: // Enumerate once: source extraction, scope discovery, and Go module
  • src/graph/scopes.ts:L133-L272 — discoverScopes (calls, depth 2)
  • src/graph/source-files.ts:L64-L85 — listSourceFiles (calls, depth 2)
    73: // A file is a source file if a depth-tier grammar (languageOf), a breadth-tier

CLI Entry Point — 1 symbol in 1 file

  • src/cli.ts:L1-L2380 — cli.ts (calls, depth 2)
    5: * graft/ and a clone has the graph. A workspace parent (≥2 git children)

Context File Discovery — 1 symbol in 1 file

  • src/context/build.ts:L109-L122 — listContextFiles (calls, depth 2)

MCP Server — 1 symbol in 1 file

  • src/mcp/server.ts:L73-L155 — startMcpServer (calls, depth 1)
    131: // graph/refresh.ts). `callTool` absorbs its own errors, so the only thing
Test signal per changed area — 1 ✓ · 2 ✗

Reached = a node under a test path has a resolved edge into the changed symbol. It undercounts anything called indirectly — through a CLI, a spawned process or a dynamic import — so read a low ratio as “look here”, never as a coverage gate.

  • ✓ MCP Tool Execution — 1 of 5 reached · 1 test file changed here: test/mcp-worktree-root.test.ts
    • not reached: checkout, git, resolveToolRoot, rootNote
  • ✗ Git File Enumeration — 0 of 2 reached · no test file reaches it
    • not reached: gitVisibleFiles, gitVisibleFilesShallow
  • ✗ Git Environment Setup — 0 of 1 reached · no test file reaches it
    • not reached: gitEnvForDirectory
6 test suites also reference this code

7 symbols, kept out of the diagram and the table so they cannot crowd out the areas a reviewer has to look at.

  • test/graph-follow-submodules.test.ts
  • test/graph-load.test.ts
  • test/graph-refresh.test.ts
  • test/graph-seed.test.ts
  • test/ingest-fs.test.ts
  • test/mcp-tools.test.ts

⚠️ 1 changed file not in the graph (README.md) — no parser claims the extension, or the index predates the file.

graft blast · origin/main...HEAD · depth 2 · 7 changed files

Open the interactive graph → — click an area to see its dependent symbols at file:line.

github-actions Bot added a commit that referenced this pull request Oct 7, 2026
github-actions Bot added a commit that referenced this pull request Oct 7, 2026
github-actions Bot added a commit that referenced this pull request Oct 15, 2026

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 tools can't target another checkout: the server root is fixed at spawn, so subagents reviewing a worktree get the parent session's graph

1 participant