code-map-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@code-map-mcpmap how a request flows through the API, starting from src/index.ts"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
code-map
Generates a code-map for a TypeScript/JavaScript codebase: a JSON document that describes how one path through the code runs. It is built for agents first:
Agents read the document's
systemsection: a plain-language sitemap of the code (summary, areas, every step with its file, lines, description, calls and data, and the links between services). CI can rebuild it to keep system docs current.People open the same file in the viewer, which draws it as one page.
Make maps with the CLI or the MCP server (code-map-mcp); both write the same file. Open them in the hosted viewer (file upload, with recent files kept in your browser), locally with code-map view, or as a standalone .html.
Install
code-map runs on Bun (1.1 or later); it is TypeScript run directly, with no build step.
# The MCP server, for Claude Code in every project
claude mcp add --scope user code-map -- bunx --package @eronsalling23/code-map code-map-mcp
# The CLI, without installing
bunx @eronsalling23/code-map <repo> -e <entry> -o map.json
# Or install both commands (code-map, code-map-mcp)
bun add -g @eronsalling23/code-mapThe viewer shows
What you're looking at. What the code does overall and where it sits in the system, from the repo's README and package description. Then the areas the path runs through, in order (e.g.
deploy → gcs → client). Each area quotes what the repo's own docs say about it and names the source. The hand-offs between areas are listed under that.A system diagram. The Call path tab shows every function and method on an execution path, numbered by step and grouped into boxes per file. Data types (interfaces, type aliases, enums, classes) appear as cylinders. Solid arrows are calls. Dotted arrows show data a step takes (
param),returns,createsoruses. The Files tab shows how the files on the path import each other.A walkthrough. The path the code takes when it runs: a depth-first walk of the call graph from the entry point, in source order. It follows every call it can reach within the scope you choose, so the map is complete and the same code gives the same file. Each step puts a plain-language description beside the code for that step. The call lines that lead to the next steps are highlighted and linked, and long functions are cut down to the signature plus the lines around those calls.
Tabs beside each step. Code is the excerpt above. Data has one sub-tab per type the step takes, returns, creates or uses, showing its definition. Calls has one sub-tab per function it calls, showing a preview with a link to its step. Full source appears when the excerpt is cut. Clicking a data chip or a call name in the description opens the matching tab.
A data section. Every data type the path touches, as a list on the left and the definition on the right, with links back to the steps that use it.
Diagram controls: zoom with the − / + / Fit / Entry buttons, Ctrl/⌘ + scroll, a trackpad pinch or the + - 0 keys. Drag to move around; ⤢ goes full screen, where a plain scroll pans. Hover a box to highlight what it calls (blue) and what calls it (orange), with everything else faded. Hover an arrow to highlight both of its ends. Click a box or arrow to jump to its step. As you scroll the walkthrough, the current step's box is highlighted.
The call path has three more controls:
Compact hides the data types and their dotted arrows, leaving only the functions and the calls between them.
Full path highlights the route the walkthrough takes: each step's box and the arrow that leads into it, from step 1 to the last. Everything else fades. It works in both modes.
◀ / ▶ (or the ← / → keys) step through the functions and methods in walkthrough order. Each move highlights the arrow into the new step, keeps the arrows walked so far highlighted, and glides the view along that arrow until the box is centred. Click the step's name to read it in the walkthrough; × or Esc stops. While stepping, a panel beside the diagram shows the step's description, signature and calls, the same text as in the walkthrough; its "step N" links move the navigator there. Details or the panel's × hides it, and the page remembers that choice. The view centres each box in the space the panel leaves free.
The bar. A bar stays at the top of a map with its title, links to its sections (Overview, Map, Code, Data) and the levels control. In the hosted viewer, ← goes back to your recent files; open another file from there.
Levels. A map keeps every step, so a big one can be long. The Steps control in the bar (All, 1+, 3+, 5+, 10+, with the count shown, e.g. 14/73; hover it for an explanation) hides helper steps that have fewer than N steps beneath them, using each step's descendants. The entry and other starting points always show, and so does every step above a shown one. Step numbers stay the same, so a gap in the numbering means hidden steps. In the walkthrough, a step with hidden helpers has a "N helper steps hidden" button; in the call path, a dashed "N hidden" box. Either one shows that group. The viewer remembers the setting.
Each tab's content is built the first time the tab opens, so a type shown in ten steps doesn't make the page ten times bigger.
Related MCP server: context-ops-mcp
Where the descriptions come from
Areas and system context (src/context.ts). An area is the nearest folder above a file that has its own README.md, ARCHITECTURE.md or package.json. Without one, it's the first folder below src/, packages/, modules/ and similar. Each area's text comes from the first of these that exists:
The intro of its own
ARCHITECTURE.mdorREADME.md(text before the first##, or under an Overview/Purpose heading).The row, bullet or paragraph in the repo's
README.md,ARCHITECTURE.mdordocs/that names it, such as a module map table.Its
package.jsondescription.The doc comment on a class in it.
A file's header comment.
The first paragraph of its own docs, with the section named.
A repo is described by its README's opening paragraph, falling back to its package.json description.
Steps and summary:
By default the text is put together from what the analysis found, with no network calls (describeStep in src/describe.ts). It covers the first sentence of the doc comment (or the function name split into words), how the step is reached, the data it takes, returns, creates or uses, what it calls in order, and the outside code it calls. With --llm, the code for every step goes to Claude in one request, together with the repo and area docs above. Claude writes the summary, the "where it sits" paragraph, one sentence per area, and a 2–4 sentence description per step.
Usage
bun install
bun run src/cli.ts <dir> [<dir> ...] [options] # writes code-map.json
bun run src/cli.ts view code-map.json # opens it in the viewer on localhost# Find likely entry points (functions nothing calls that reach the most code)
bun run src/cli.ts ../game-manager -i src --list-entries
# Map one flow
bun run src/cli.ts ../game-manager -i src -e PromoteGameHandler.execute -o promote.json
# The same, plus a standalone page that opens anywhere
bun run src/cli.ts ../game-manager -i src -e PromoteGameHandler.execute -o promote.json -o promote.html
# Start from a file's top-level code
bun run src/cli.ts ./my-app -e src/server.ts
# Several repos as one system: calls into another repo's package link to its source
bun run src/cli.ts ../wolf-editor ../game-sdk -i src -i packages/editor-kit/src -e gameCommandKind
# Only an exact set of methods (file, inline list, or both)
bun run src/cli.ts ../wolf-editor ../game-sdk -s flow.txt -s "editor-kit/src/args.ts#*"
# Have Claude write the descriptions (sends the code on the path to the Anthropic API)
ANTHROPIC_API_KEY=... bun run src/cli.ts ./my-app -e handleRequest --llmOption | |
|
|
| Map only these symbols (repeatable). Takes a file or an inline comma-separated list; see below. |
| Where to write the map (repeatable). |
| Also write the raw analysis (every symbol, call and import) and walkthrough as JSON; the viewer opens this too |
| With |
| Analyze only this sub-path (repeatable) |
| Include |
| With |
| --list <spec> | Print what a spec or glob matches, with caller and callee counts, then exit |
| --template <file> | Also write a fill-in JSON with every step and area: facts, the generated draft, and an empty description |
| --descriptions <file> | Use a filled-in template's title, summary, role, overview, area and step descriptions, and links in place of generated text |
| --llm, --model | Descriptions written by Claude (default model claude-opus-5-5) |
The walk follows every call reachable from the entry or selection inside the analyzed files. It never drops steps, and there is no depth or step limit to tune (--max-depth and --max-steps were removed; passing them is an error). To focus a map, narrow the scope: -i for fewer folders, -s for an exact set of functions, or -e for a later starting point. In the viewer, people hide small helpers with the levels filter. A walk over 2000 steps fails with an error rather than writing part of a map; narrow the scope and run it again.
Several repos
Pass more than one directory and they are analyzed as one system. Files are shown under each repo's folder name (wolf-editor/src/...), and the diagrams group them inside a box per repo. -i paths apply to every repo that has them.
The TypeScript compiler resolves a call into another repo's package (e.g. @wolfgames/editor-kit) to that package's built .d.ts, not its source. code-map reads every package.json in the analyzed repos, workspace packages included. When a call lands in one of those packages' type files, it is linked to the source function or method of the same name in that package. These links are drawn as thick arrows and tagged "by name" in the walkthrough.
Selecting an exact set of methods
--select limits the map to the symbols you list. Only those become steps. A call that passes through functions you did not select becomes one arrow labelled via a → b, and the highlight stays on the line in the selected function where the chain starts. Selected functions that no other selected one leads to start their own part of the walkthrough, so every selected function appears. Selected data types (interfaces, types, enums) appear in the diagram and the Data section. --entry still works with a selection: if the entry is not selected, the first selected functions it reaches become the starting points.
A selection file has one spec per line; lines starting with # or // are comments. It can also be a JSON array of specs.
# Checkout flow, without pricing internals
src/server.ts#handlePost
OrderService.*
OrderRepo.save
src/types.ts#Order
editor-kit/src/args.ts#*
src/api/payments.tsSpec | Selects |
| One symbol; the path can be partial ( |
| One symbol by name; ambiguous names are an error that lists the candidates |
| Every match of the glob ( |
| Everything in that file |
Writing the descriptions yourself (or with an agent)
bun run src/cli.ts ../game-manager -i src -e PromoteGameHandler.execute --template promote.desc.json
# fill in the empty "description" fields (and title, summary, role, overview) in promote.desc.json
bun run src/cli.ts check promote.desc.json # plain-English check: long sentences, jargon, copied docs
bun run src/cli.ts ../game-manager -i src -e PromoteGameHandler.execute -o promote.json --descriptions promote.desc.jsonSteps are matched by function id, so the file still applies after the code changes, as long as those functions still exist. links adds connections the analysis can't see, such as an HTTP request between two services or a file one writes and another reads: {"from": 3, "to": 12, "label": "uploads bundle → CDN"}. They are drawn as dashed arrows and listed under "Connections outside the code". Any step, area or link that doesn't match prints a warning.
The MCP server runs this whole loop for any agent (see below). Its instructions and guide tool tell the agent how to pick the code (from paths, or from a system name like "dynamic data across game-manager and game-sdk"), read it, and write the descriptions in plain English.
The code-map document
{
"format": "code-map", "version": 2,
"generator": { "args": ["../game-manager", "-i", "src", "-e", "…"] }, // the CLI command that rebuilds it
"system": { // for agents: read this, stop before "render"
"title", "summary", "role", "overview", "entry", "repos",
"areas": [{ "id", "name", "description", "doc", "docSource", "steps": [1, 2] }],
"steps": [{ "step", "id", "name", "kind", "file": "src/x.ts:12-40", "area", "signature",
"description", "calledBy", "parent", "descendants",
"calls": [{ "id", "name", "step" }], "data": [{ "id", "name", "relation" }],
"outsideCalls", "docComment" }],
"data", "links", "handoffs"
},
"render": { … } // for the viewer: the walkthrough, the source of every symbol shown, diagram sources
}The file has no timestamp, so two builds from the same code and arguments are byte-identical. Each step's parent is the step number (from 1) of the step that first called it; descendants counts every step beneath it, at all levels. A step reached from several callers counts under its first caller only. The viewer still opens version-1 files and raw --raw dumps.
Viewer
One page (src/viewer/, a React app) draws any code-map document. Bun bundles it, with its CSS, into one self-contained HTML file; the only things it loads from the network are Mermaid and highlight.js from a CDN.
Hosted:
bun run build:viewerwritesdist/index.html, a single static file to put on any static host. People drop or pick a.jsonfile; it's read in the browser, never uploaded. The last 20 files are kept in the browser's IndexedDB and listed on the start page (#map=<id>links reopen one).Local:
code-map view [map.json] [--port 4173]serves the viewer on localhost and opens the file. Reload to see a rebuilt map.Standalone:
-o map.htmlwrites the viewer with the map built in.
MCP server
code-map-mcp speaks MCP over stdio. Add it to Claude Code with:
claude mcp add --scope user code-map -- bunx --package @eronsalling23/code-map code-map-mcp
# or, from a clone of this repo
claude mcp add --scope user code-map -- bun run /path/to/code-map/src/mcp.tsIts instructions tell the agent the workflow: pick the code, trace, read every step's code, write the descriptions in plain English, check, build. Tools are stateless and take the same options as the CLI (dirs, include, tests, entry, select, maxHops) each call:
Tool | |
| The workflow, the writing rules, and how to find the code for a named system ( |
| Ranked entry points; what specs and globs match |
| Runs the walk and writes the fill-in template (or returns it inline); reports the step count and the steps with the most steps beneath them |
| The plain-English checker |
| Writes |
| The |
Documenting systems in CI
Commit a selection file and a filled-in descriptions file next to the code, then rebuild the map on each change:
bun run src/cli.ts . -i src -s docs/maps/orders.selection.txt \
--descriptions docs/maps/orders.desc.json -o docs/maps/orders.json --strict--strict fails the build when a described function no longer exists or a new step has no description, so the map can't silently go stale. Agents read docs/maps/*.json (or call read_map) to learn the system; people open the same files in the viewer.
How it works
File | Role |
| Builds a TypeScript program with the compiler API and indexes functions, arrow-function consts, class methods/constructors/accessors, object-literal methods and data types. It resolves every call through the type checker, following imports, |
| Resolves the entry and the |
| Groups the steps into areas, finds each area's docs, and lists the hand-offs between areas. |
| Heuristic descriptions built from doc comments, the caller, data relations, calls in order and outside calls, so no network is needed. |
| One traced path as a model: the map and walkthrough with the lookups the other steps share (step of a symbol, data types and their users, repo of a file), plus |
| Builds the code-map document: the |
| The shared steps from folders to document and output files, used by the CLI and the MCP server. |
| The React viewer: the start page (upload, recent files in IndexedDB, |
| The MCP server, the plain-English checker, and |
Limits
tsconfig
pathsaliases (e.g.@contract/...) aren't read, so calls through them show as outside code.Linking by name picks the exported symbol with that name inside the package. If a package has two exported symbols with the same name, the link can land on the wrong one.
Calls are resolved statically. Calls through interfaces, dependency injection tokens, event buses or dynamic dispatch stop at the declaration the type checker finds. Those show up as outside code or as the interface method, not as the implementation.
Calls inside callbacks and nested functions are counted as calls made by the enclosing named function.
Only the first visit to a function becomes a step. Later visits link back to it.
Releasing
CI runs the typecheck and tests on every push. Pushing to main also deploys the hosted viewer to GitHub Pages.
To publish to npm, never edit the version by hand. Either:
run the Publish workflow from the Actions tab on
mainand pickpatch,minorormajor(orgh workflow run publish.yml -f bump=minor). It raises the version, runs the tests, publishes, then commitschore(release): vX.Y.Ztomainand pushes the tag; orpush a tag,
git tag v0.3.0 && git push origin v0.3.0. The tag is the version: it publishes, then commits that version tomain.
Publishing uses npm trusted publishing, so no npm token is stored in the repo. The package's settings on npmjs.com list this repo's publish.yml as its trusted publisher.
This server cannot be deployed
Maintenance
Related MCP Connectors
Stateless TS/JS compiler facts for agents: references, imports, impact. No repo index or OAuth.
Give your AI agent a persistent map of your project's structure, dependencies, and bugs.
Coding agents in multi-service codebases routinely rebuild existing helpers, trust stale type definitions, and modify API contracts without knowing who consumes them. Carrick solves this by indexing your entire TypeScript ecosystem across service and repository boundaries. By integrating deeply with the TypeScript compiler, Carrick traces every route, type, and cross-service call while recording function behaviour so agents search by intent rather than name. Delivered via MCP for AI agents and LSP for IDEs, Carrick ensures models see existing endpoints and utilities before generating new code. The scanner is source-available and runs from your CLI or CI pipeline.
AI Agent with Architectural Memory. Impact analysis (free), tests and code from the graph (pro).
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables LLM agents to create annotated bookmarks and narrative trails to document code exploration and decision-making. It organizes these bookmarks into a navigable knowledge graph stored in a local JSON file, helping users track the context and reasoning behind code changes.41 npmMIT
- AlicenseNot gradedqualityBmaintenanceGives your AI coding agent a bounded map of an unfamiliar TypeScript SaaS repo: where the code lives, what's risky to touch, and where the money / auth / user flows are. Provides eight MCP tools for orientation, task focus, risk assessment, and SaaS-specific observations without AST or type checking.14 npmMIT
- AlicenseNot gradedqualityAmaintenanceEnables coding agents to navigate and score brownfield multi-service flows by mapping use-case trees, tracing loadouts and consumers, and detecting drift.MIT
- AlicenseAqualityBmaintenanceProvides coding agents with a compact map of a TypeScript/TSX codebase, enabling direct answers about symbol locations, imports, dependencies, and references while reducing token usage.54 npm1MIT