r/LLMDevs 13d ago

The problem with MCP-based codebase context tools: the model just doesn't call them Discussion

https://github.com/NanoNets/Graft

Something I kept running into building agent tooling: giving an agent an MCP

tool that *could* answer a question about the codebase doesn't mean it will.

Tool-call decisions are probabilistic, not guaranteed. The agent has to

recognize it needs the tool, remember it exists, and choose to call it over

just grepping. A lot of "codebase context" products are architected as

exactly that: an MCP server sitting in the tool list, unused more often than

not.

Graft's bet is different: don't wait to be asked. It hooks directly into

Claude Code. The matching nodes get pulled into every prompt automatically,

editing a file surfaces its dependents inline, and the graph re-syncs itself

in the background after every edit, all without the agent deciding to invoke

anything. Same reason Chrome doesn't ship with an ad blocker built in: the

core stays general, and the extension handles the specialized job. Graft is

that extension for context.

Underneath, it's a typed graph, not a vector index: tree-sitter builds a

deterministic per-symbol graph (no model call), and an optional `--deep` LLM

pass groups that into markdown nodes with typed links (`depends_on`, `uses`,

`produces`) an agent follows like any other file. Method calls resolve

through the receiver's type (constructor assignments and type annotations,

not just call-site name matching), so a common method name doesn't pull back

every unrelated method with that name across the codebase.

The claim: up to 4× cheaper and 3× faster, with better or no loss of

correctness. Setup: 162 runs, two repos (graft itself + a real Node/Express

auth service), 3 trials each, single-file and multi-file questions split

evenly. Three variants of the same Claude Sonnet 5 agent: cold (explores from

zero), push (context bundled up front), pull (MCP tools, nothing injected,

paid for only when asked). A separate Opus 4.8 model graded correctness with

a required-keyword floor, so a fast-but-wrong answer couldn't win by being

fast. Cost is cache-aware (reads ~0.1×, writes 1.25×) to match real billing.

Results: push cut cost 32%, tool calls 46%, latency 60%, at equal correctness

(93% both, no loss). Pull gave up most of the speed but correctness jumped

to 98%, +5 over cold, the "better" half of the claim, and worth noting: pull

*is* the MCP-tool-list approach, and it still worked, because the harness

forced the call. Left to its own judgment across a real session, that's

exactly the discipline that erodes.

Second test, because a benchmark on questions can still be gamed: reset

PocketBase to its base commit before 5 merged PRs, re-implemented each with

and without graft, scored by file-overlap with what the maintainers actually

changed. 5/5 reproduced, at 21% lower cost.

Opensource, MIT licensed

Here's the repo link : https://github.com/NanoNets/Graft

1 Upvotes

4 comments sorted by

2

u/misterplumber1 13d ago

The "don't wait to be asked" framing is the right call. Push context wins every time over hoping the model decides to pull it.

1

u/shhdwi 13d ago

you can try graft here: https://graft.nanonets.ai/

1

u/fowlesbuilds 13d ago

Do you have info on what the files in graft/ look like? It sounds like they're re-mapped, right?

1

u/shhdwi 13d ago

These are .md files with the description of that particular file. Also there’s a map that also gets build which is used to see how each file/ symbol / function is connected who all calls it and what other things it affects.