# code-atlas **Multi-language code intelligence MCP server** — gives Claude Code (and any MCP client) a structured view of your codebase instead of raw text: symbol search, file outlines, AST pattern queries, cross-file references, call/type hierarchies, import graphs, change-impact analysis with affected-test detection, web-framework route maps (Express/NestJS/Fastify/FastAPI/Flask/Django), Mermaid diagrams, precise LSP-backed answers, local-embedding semantic search, and game-engine asset understanding (Godot, Unity, Unreal). 25 languages indexed. Instead of grepping and reading whole files, the model asks questions like *"map this repo"*, *"outline this file"*, *"who calls `parseConfig`?"*, *"how does the request handler reach the DB layer?"*, *"what changes whenever this file changes?"* — and gets compact, token-efficient answers backed by a persistent tree-sitter index. Every answer is budgeted: tools take a `max_tokens` cap, and a clamped response returns a cursor you can pass back to continue rather than re-asking with a bigger budget. > **Status: released** (npm `@lusiem/code-atlas`, MCP registry `io.github.lusiem/code-atlas`). 25 languages, 32 tools, LSP-exact answers with a structural floor, engine adapters, and an agent-workflow layer (`repo_map`, `context_pack`, `verify_changes`) built for token economy. Validated at 19k files / 6.3M LOC. ## How it works ``` your repo ──scan (gitignore-aware)──> tree-sitter parse ──> SQLite index (symbols, imports, occurrences, call/type edges, FTS5) │ Claude Code ◄──────────── MCP tools over stdio ────────────────────┘ ``` - **Persistent index** at `/.code-atlas/index.db` (self-gitignored), incrementally refreshed by content hash. - **Live** — a gitignore-aware file watcher reindexes saves within a debounce beat and re-resolves only the affected files (`--no-watch` or `"watch": false` to disable). - **Zero config** — point it at a repo root and it works. Optional `code-atlas.json` for include/exclude tweaks. - **Everything local** — your code never leaves your machine. ## Install & use with Claude Code ```sh claude mcp add code-atlas -- npx -y @lusiem/code-atlas serve ``` Or from a clone: ```sh git clone https://github.com/lusiem/code-atlas && cd code-atlas npm install && npm run build claude mcp add code-atlas -- node /path/to/code-atlas/dist/index.js serve ``` The server indexes the current working directory; pass `--root ` to override. ### CLI ```sh node dist/index.js index [--root ] # one-shot index build (debugging / warm-up) node dist/index.js serve [--root ] [--no-watch] [--no-lsp] [--no-embeddings] [--no-download] # MCP server on stdio ``` ## Tools Full reference with example outputs: [docs/tools.md](docs/tools.md). | Tool | What it answers | |---|---| | `repo_map` | **What is this repo and where do I start?** Annotated directory tree with import fan-in/fan-out (layering at a glance), entry points, importance-ranked key symbols with the reason each ranks, and the third-party dependency inventory — one budgeted call instead of a grep sweep. `path_prefix`/`depth` to zoom. | | `project_overview` | The cheap version: languages, sizes, layout, index freshness. | | `search_symbols` | Where is *X* defined? FTS + fuzzy over names and doc comments, filterable by kind/language/path. | | `search_content` | Where does this *text* appear? String literals, error messages, env vars, config keys, TODOs — and the only tool that sees non-code files (md/json/yaml/toml/sql/Dockerfile/CI). The index proposes candidates, the disk verifies them, so a hit is never stale. | | `semantic_search` | *"Where is retry backoff implemented?"* — natural-language search, hybrid keyword+embedding ranking, fully local. | | `get_file_outline` | What's in this file? Hierarchical signatures without reading source — over budget it sheds nesting depth rather than tail lines, so every top-level symbol survives. Pass a **directory** for a package's public API surface in one call. | | `get_symbol_info` | Everything about one symbol (by id, position, or name) incl. docs and source. | | `context_pack` | One-call, token-budgeted briefing on a symbol: source, outline, callers/callees, types, route, related tests — instead of six lookups. Sections that don't fit the budget are named. | | `batch_symbols` | Up to 50 `#id`s resolved to compact one-liners in a single call. | | `ast_query` | Raw tree-sitter S-expression queries — structural search regex can't do. | | `find_references` | Who uses this symbol? Exact (LSP) when available, else resolved usages first, name-matches as candidates. | | `go_to_definition` | Definition of the identifier at a position. LSP-exact with index fallback. | | `call_hierarchy` | Who calls this / what does it call, as a tree. `[lsp 1.00]` edges when a language server is running. | | `type_hierarchy` | Supertypes and subtypes over extends/implements edges. | | `get_dependencies` | File import graph, both directions (imports / imported-by). | | `trace_path` | Shortest call chain between two symbols. | | `change_impact` | Blast radius of a change: transitive callers + import reachability, affected **test files** first. Target a symbol, a file list, or nothing — no args analyzes the uncommitted git diff (hunk-level: only symbols you actually touched seed the traversal). Affected route handlers are tagged `[ROUTE GET /users/:id]`. | | `verify_changes` | Post-edit structural check against git HEAD: imports that stopped resolving, removed exports other files still reference, signature changes with live callers. `change_impact` predicts; this confirms. | | `tests_for_symbol` | Which tests exercise this symbol? Reverse graph walk to test files, naming the test case; import-chain-only hits reported as a weaker signal. | | `find_similar_code` | *"Does a helper for this already exist?"* — near-duplicate search over the local embedding vectors, with a text-similarity fallback while coverage builds. | | `find_dead_code` | Zero-reference symbols after entry-point/route/lifecycle exclusions, confidence-hedged (`possibly dead` when a same-name usage exists anywhere); unused exports listed separately. | | `hotspots` | Churn × size risk ranking, answered from the cached commit history. | | `change_coupling` | Which files historically change together with this one — **the coupling a structural index cannot see** (config, fixtures, docs, string-keyed dispatch). Directional confidence, and files with no import edge are flagged. | | `symbol_history` | Why does this look like this, and who do I ask? `git log -L` over the symbol's line span: sha, date, author, subject. | | `list_routes` | Web-framework routes across the workspace — Express, Fastify, NestJS, FastAPI, Flask, Django, plus file-based routing for Next.js, SvelteKit, Nuxt, and Remix — each linked to its handler symbol. | | `find_route` | *"Which code serves `GET /api/users/7`?"* — matches a concrete URL against indexed route patterns (`:id`, `{id}`, `` are wildcards) and returns the handler. | | `generate_diagram` | Mermaid diagrams of the above graphs: import graph (file or directory level), call graph around a symbol, type hierarchy, call path — paste straight into GitHub markdown or docs. | | `get_scene_structure` | Godot scene node tree with attached scripts, instanced sub-scenes, and signal connections (handlers resolved to symbols). | | `find_asset_references` | Which scenes/prefabs/Blueprints use this script, asset, or handler? Reverse lookup across Godot res:// paths, Unity GUIDs (via .meta), and Unreal modules + /Game/ Blueprint paths. | | `search_reflection` | All `UPROPERTY(Replicated)`, `[SerializeField]`, `@export` vars, signals — engine reflection markers across the workspace. | | `index_status` / `reindex` | Index health and manual refresh. | Cross-file answers are **LSP-first with a structural floor**: when a language server is available (found on PATH or auto-acquired into a per-user cache), references/definitions/hover/call hierarchies are exact and tagged `lsp`; everywhere else, heuristic import/name resolution answers with a confidence score per edge. Servers: typescript-language-server + pyright (npm), gopls (go install), rust-analyzer + clangd (pinned, SHA-256-verified release binaries), Eclipse JDT LS for Java (needs a Java 21+ runtime — detected via PATH/JAVA_HOME), kotlin-language-server (needs any JRE), and csharp-ls for C# (needs the .NET SDK; installed as a dotnet tool — deliberately not Microsoft's Roslyn LSP, whose license is VS-only). GDScript attaches to the Godot editor's built-in language server (TCP 127.0.0.1:6005, override with `CODE_ATLAS_GODOT_LSP_PORT`) whenever the editor has the project open — close the editor and answers fall back to structural, reopen it and the next query reattaches. Missing runtimes degrade that language to structural, reported honestly in `index_status`. A first-time acquisition (download + boot) never blocks a query: tools wait up to 8 s, then answer structurally while the server finishes starting. Disable with `--no-lsp`; disable auto-download with `--no-download`. **Semantic search** embeds every function/class (signature + doc + body) with a code-tuned local model — `jinaai/jina-embeddings-v2-base-code`, quantized ONNX — and fuses cosine similarity with BM25 keyword rank. Everything stays on your machine. The ONNX runtime (~220 MB) and model (~150 MB) are **not** part of this package: they download to the per-user cache the first time you call `semantic_search`, never at install, and structural tools never wait on them. Until coverage completes, results are keyword-weighted and say so. Embedding a 60k-symbol repo takes ~15 minutes of background time, once; after that only edited symbols re-embed. `"embeddings": {"model": "fast"}` swaps in a 4× faster general-purpose model; `--no-embeddings` turns the layer off. ## Languages **Indexing today (25):** TypeScript, TSX, JavaScript, Python, C, C++, Rust, Go, Java, Kotlin, C#, GDScript, PHP, Ruby, Lua, Solidity, Zig, Nix, Swift, Scala, Dart, Terraform/HCL, Pascal/Delphi, Vue, Svelte. Vue and Svelte single-file components index the `