mcp over stdio typescript and javascript no network
DaiVELOPER
An MCP server that gives a coding model a code-structure-aware view of a repository instead of a generic filesystem.
Ask for a symbol, get the symbol. Ask for a repo map, get signatures rather than bodies. Read returns whole files and Grep returns unstructured lines, so a structural question is answered by pulling thousands of tokens of file text into context and having the model do the parsing. The parsing is cheap and deterministic; paying for it in model context is the waste.
Five runs, one proof of concept. Not a product. On twelve questions of its own choosing, over a fixture of its own construction, it delivered the same evidence as a scripted native-tool agent for 21% of the approximate tokens — reproducibly, and with no model in the loop.
That is not evidence that it generalises, and nothing here claims it is.
what is here
Six things, and the last one argues with the fourth
The filesystem interface is structure-blind
Readreturns whole files andGrepreturns unstructured lines, so 'where ishandleAuthdefined and who calls it' is answered by pulling thousands of tokens of file text into context and having the model do the parsing.Eight tools, each replacing a specific native move
Six retrieval tools and two symbol-scoped edits. Every one of them names the native call it is meant to be reached for instead of, because a tool a model does not reach for is a tool that costs its description and returns nothing.
Every response says what it did not see
A response states how many files it scanned and how many it could not index, scoped to the path searched, so a gap never reads as a confident 'not found'. On an unfamiliar repository that line read
120 files scanned, 127 unindexed.Twelve questions, 3,486 tokens, and one scenario carrying it
Against a scripted native-tool agent's 16,495 approximate tokens, the treatment arm answered all twelve on 3,486 — a 78.9% reduction with answer derivability held at 12/12 in both arms.
A write that would not parse is refused, not repaired
replace_symbolandinsert_symbolre-parse the prospective file in memory first and refuse if it does not parse, naming the line. Validation happens before the write, never after.What it is not
Five runs, one proof of concept. Not a product. No editor integration, no LSP, no remote service, no semantic search, no embeddings, and no network at runtime.
01 · structure-blind
The filesystem interface is structure-blind
Read returns whole files and Grep returns unstructured lines, so 'where is handleAuth defined and who calls it' is answered by pulling thousands of tokens of file text into context and having the model do the parsing.
The parsing is cheap and deterministic. Paying for it in model context is the waste, and it is the only thing this project is about.
Read charges for all twelve; the question was which three declarations the file contains.02 · eight-tools
Eight tools, each replacing a specific native move
Six retrieval tools and two symbol-scoped edits. Every one of them names the native call it is meant to be reached for instead of, because a tool a model does not reach for is a tool that costs its description and returns nothing.
The eight descriptions and schemas cost 2,000 approximate tokens, paid once per session — run 5 cut them 18% by tightening the wording and the schemas, merging and removing nothing. At the median per-scenario saving of 405 tokens, a session has to ask about five structural questions before that introduction has paid for itself.
claude mcp add -s user daiveloper -- \ node /abs/path/to/daiveloper/dist/server/main.js
- outline
- find_symbol
- read_symbol
- search_code
- find_callers
- find_references
- replace_symbol — write
- insert_symbol — write
03 · audit
Every response says what it did not see
A response states how many files it scanned and how many it could not index, scoped to the path searched, so a gap never reads as a confident 'not found'. On an unfamiliar repository that line read 120 files scanned, 127 unindexed.
That second number is Markdown, JSON, CSS and everything else the grammars do not cover. It is also the reminder that 'not found' from these tools means 'not found in TypeScript and JavaScript'. A bounded response says how many results exist and what offset fetches the rest; nothing truncates silently.
04 · measured
Twelve questions, 3,486 tokens, and one scenario carrying it
Against a scripted native-tool agent's 16,495 approximate tokens, the treatment arm answered all twelve on 3,486 — a 78.9% reduction with answer derivability held at 12/12 in both arms.
And 95.2% of the margin over the cheapest possible native sequence comes from one scenario of the twelve. Remove it and the remaining eleven total 2,529 approximate tokens against that floor's 2,826: under it before the session preamble, and above it once the preamble is charged. The aggregate is real and it hides its own composition.
05 · writes
A write that would not parse is refused, not repaired
replace_symbol and insert_symbol re-parse the prospective file in memory first and refuse if it does not parse, naming the line. Validation happens before the write, never after.
The write boundary is checked both lexically and against realpath, so neither a .. nor a symlink escapes the served root. All three refusal paths were exercised from a cold start and all three refused without writing.
Still no refactoring and no formatting. A write tool that reshapes code it was not asked to reshape is a tool nobody can review the output of, and neither of these two moves a line it was not pointed at.
06 · not
What it is not
Five runs, one proof of concept. Not a product. No editor integration, no LSP, no remote service, no semantic search, no embeddings, and no network at runtime.
TypeScript and JavaScript only. Twelve scenarios written by the same project they measure, over a fixture built by it, with no held-out set and no model in the loop — RESULTS.md names that as the largest threat to its own result and does not resolve it.
Twelve questions, written by the people building the thing that answers them, against a fixture written by the same people and built to be hard to grep. There is no held-out set and no third party wrote a single question. RESULTS.md calls that its own largest threat and does not resolve it.
start here
Clone it, build it, register it
git clone <this repo> daiveloper && cd daivelopernpm install --include=devnpm run build
Node 22 or later. --include=dev matters if NODE_ENV=production is set, and the build is optional — the server also runs from source under node --import tsx.
npm run typechecknpm testnpm run bench
npm test includes a real stdio round trip against the server, and npm run bench prints the table on this site and writes the run to bench/results/.
claude mcp add -s user daiveloper -- \ node /abs/path/to/daiveloper/dist/server/main.js
Use an absolute path: Claude Code launches the command from the project directory, not from the checkout. -s project writes a .mcp.json shared with anyone who clones the repository instead. Confirm with claude mcp list, then /mcp inside a session.
stdout belongs to the JSON-RPC transport. Every diagnostic goes to stderr — including the one line the server prints when it cannot create its cache directory and falls back to the OS temp directory — or the transport breaks.
The startup line on stderr also names the root the server resolved and why: --root if one was passed, otherwise the git repository above the directory it was launched in. Since run 5, root is optional on every tool — a call that names one still wins.