code-map-mcp
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
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 the 20 most recent files kept in your browser; in a private window, or with site storage blocked, they last only until the page reloads), 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: clew
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. For better text, an agent or a person writes the descriptions into a template (see Writing the descriptions).
Usage
The CLI is the source of truth: every command is defined once in src/commands.ts, and the MCP server exposes the same commands as tools (see MCP server). code-map <command> --help lists a command's options; --json prints its result as JSON.
Command | MCP tool | |
|
| Build the map and write |
|
| Trace the path and write the fill-in template ( |
|
| Likely entry points: functions nothing calls, ranked by how much code they reach |
|
| What a spec or glob matches, with caller and callee counts |
|
| The plain-English checker |
|
| The |
|
| The agent guides in |
| Serve the viewer on localhost (CLI only) |
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 entries ../game-manager -i src
# 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#*"Options for build (trace, entries and symbols share the scope options):
Option | |
|
|
| Map only these symbols (repeatable). Takes a selection file or an inline comma-separated list; see below. |
| Where to write the map (repeatable). |
| Analyze only this sub-path (repeatable) |
| Include |
| With |
| Use a filled-in template's |
| Page title, when the descriptions file has none |
| With |
| Also write the raw analysis (every symbol, call and import) and walkthrough as JSON; the viewer opens this too. CLI only |
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). 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. Any existing file that isn't a source file (.ts, .tsx, .js, …) is read as a selection file; a source file path selects everything in it.
# 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 trace ../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": ["build", "../game-manager", "--include", "src", "--entry", "…"] }, // 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 also opens raw --raw dumps. Version-1 files are refused; build them again.
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. Each tool is a CLI command (see Usage): its input schema is built from the command's options, and a call runs the CLI with --json, so a tool and its command can't drift apart. Options keep their CLI meaning under camelCase names (dirs, include, tests, entry, select, maxHops, templatePath for --template, descriptionsPath for --descriptions); CLI-only options like --strict aren't exposed.
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. They are the drafts that written descriptions replace. |
| 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 steps from folders to document and output files, used by the commands. |
| The React viewer: the start page (upload, recent files in IndexedDB, |
| The command definitions (one per command: options, types, help, MCP tool name) and the machinery that turns them into the CLI parser, the MCP input schemas and the recorded |
| The MCP server: one tool per command with a |
| 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 and CI
Workflows
Workflow | Starts on | What it does |
CI ( | Push to | Type check and tests |
Publish ( | Run by hand on | Raises the version, runs the type check and tests, publishes to npm, then deploys the hosted viewer from the same commit |
Pages ( | Run by hand on | Deploys only the hosted viewer, for a viewer fix between releases |
The hosted viewer deploys with each release, not on every push. That way it always matches the latest version on npm, and a change on main can't stop it from opening maps that the released CLI writes. A viewer fix shipped with Pages between releases must still open those maps.
Making a release
Never edit the version in package.json by hand. Run Publish from the Actions tab on main and pick patch, minor or major, or:
gh workflow run publish.yml -f bump=minorThe workflow:
sets the next version in
package.json, and stops if that version is already on npm;runs the type check and tests;
commits
chore(release): vX.Y.Zand tags itvX.Y.Z, in the job's copy of the repo only;publishes to npm with a provenance statement, only if that commit succeeded;
pushes the commit and the tag to
maintogether, only if npm accepted the package;builds the viewer from the release commit and deploys it to GitHub Pages.
If a step fails, nothing after it runs. Nothing leaves the job until step 4, so a failure before that leaves npm and main unchanged; fix the cause and run it again. The one gap is a failed push after a successful publish, for example when main moved during the run. Then npm has the version but main doesn't: pull, set package.json to that version, commit chore(release): vX.Y.Z, tag it and push both. Pushing a tag yourself doesn't start a release.
One-time setup
npm trusted publishing. Publish has no npm token. npm trusts the workflow itself: GitHub gives the job a short-lived identity token (OpenID Connect, OIDC), and npm accepts it because the package names this workflow as its trusted publisher. On npmjs.com, open the package's Settings → Trusted Publisher → GitHub Actions and enter:
Field | Value |
Organization or user |
|
Repository |
|
Workflow filename |
|
Environment | leave it empty; the publish job uses none |
Or run this from a terminal; npm opens the browser for a two-factor check:
npm trust github @eronsalling23/code-map --file publish.yml --repo esalling23/code-map --allow-publish
npm trust list @eronsalling23/code-map # check itThe entry belongs to one package name. Renaming the package, or the workflow file, means adding it again. Trusted publishing needs npm 11.5.1 or later, which the workflow installs.
GitHub Pages. In the repo's Settings → Pages, the source is GitHub Actions. The github-pages environment only allows deployments from main. Both workflows that deploy run on main, so it needs no change.
Troubleshooting Publish
npm error 404 Not Found - PUT https://registry.npmjs.org/@eronsalling23%2fcode-mapafter the tests pass: npm found no trusted publisher that matches this run. Check the entry above, especially the owner and the workflow filename, then run Publish again."X.Y.Z is already on npm": that version exists. Pick a larger bump.
The deploy step is rejected by the environment: the run wasn't on
main. Start it frommain.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
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 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 gradedqualityBmaintenanceEnables 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.514 npm2MIT
- AlicenseNot gradedqualityBmaintenanceEnables coding agents to explore TypeScript, JavaScript, and Prisma projects through local symbol, call, and model-usage graphs, while recalling persistent project-scoped decisions and returning focused source context.1MIT