Repository navigation
stdio MCP projectPath silently queries an ancestor index from a nested Git repository #2110
Description
Summary
When codegraph_explore is called over stdio with projectPath inside an independent nested Git repository, CodeGraph walks past that Git boundary to the nearest ancestor .codegraph index. If the parent index excludes the nested repository, the call succeeds with symbols from the parent project and gives no ownership or "not indexed" warning.
Environment
- @colbymchenry/codegraph 1.6.0 (Windows, stdio MCP)
- Reproduced on main at f4ddf50 (1.6.1)
Minimal reproduction
T="$(mktemp -d)"
mkdir -p "$T/parent/nested"
printf 'nested/\n' > "$T/parent/.gitignore"
printf "export function parentOnly() { return 'parent'; }\n" > "$T/parent/parent-only.ts"
printf "export function nestedOnly() { return 'nested'; }\n" > "$T/parent/nested/nested-only.ts"
git -C "$T/parent" init
git -C "$T/parent" add .gitignore parent-only.ts
git -C "$T/parent" commit -m repro-parent
git -C "$T/parent/nested" init
git -C "$T/parent/nested" add nested-only.ts
git -C "$T/parent/nested" commit -m repro-nested
# Initialize only the parent repository.
codegraph init --yes "$T/parent"Start codegraph serve --mcp with the current directory set to $T/parent, complete the MCP initialize handshake, then send this JSON-RPC tool call:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "codegraph_explore",
"arguments": {
"query": "parentOnly nestedOnly",
"projectPath": "$T/parent/nested",
"maxFiles": 10
}
}
}Actual result
The response is success-shaped and contains parent-only.ts / parentOnly. It does not contain nested-only.ts, and it does not say that the requested nested Git repository is unindexed.
For comparison, the same call against a standalone repository with no .codegraph at or above it returns the expected "isn't indexed with codegraph" guidance.
Expected result
When the ancestor index excludes an independent nested Git repository (here through the parent's .gitignore), an explicit projectPath inside that repository should not silently borrow the ancestor's index. If the nested repository has no .codegraph of its own, return the normal not-indexed guidance, or require an explicit opt-in before using the ancestor index. Nested repositories that the parent index does include, and ordinary subdirectories of the same Git worktree, can keep the current nearest-index behavior.
Root cause
ToolHandler.getCodeGraph(projectPath) calls findNearestCodeGraphRoot(projectPath), and findNearestCodeGraphRoot walks parent directories until the filesystem root without checking Git ownership. The extraction side correctly respects the parent's .gitignore, so the parent index can omit the nested repository while MCP still selects that parent index.
Suggested fix
Add a regression test with two independent Git roots, a parent .gitignore entry for the nested root, and an MCP stdio projectPath call. Then, when the resolved index does not include projectPath's Git repository, either stop resolution at that Git boundary or fail closed instead of answering from the ancestor. Preserve an explicit, documented opt-in if maintainers want ancestor indexes to serve such repositories anyway.
Activity
wstczyw commentedon Sep 30, 2026
Related: #1524, the same ancestor-index lookup for
codegraph index <path>, fixed only forindexin #1797. Onmain,detectWorktreeIndexMismatch(src/sync/worktree.ts) returns null when the nested repo's git common dir differs, so no borrowed-index warning appears for this case either.fix(mcp): a projectPath in a nested repo the ancestor index leaves ou…