repo-atlas-mcp

repo-atlas-mcp

Provides a graph-based code analysis to coding agents, enabling tools to trace call dependencies, assess change impact, and identify hotspots using tree-sitter and Neo4j.

Category
Visit Server

README

repo-atlas-mcp

An MCP server that gives coding agents a graph of your codebase instead of a text search over it.

Grep finds a name. It cannot tell you who calls that function, what breaks if you change it, or whether any test reaches it. Those are relationship questions, so repo-atlas-mcp parses your repository with tree-sitter, loads the call and import structure into Neo4j, and exposes it to your agent as MCP tools.

▸ hotspots
  17 callers  stock_analyzer/base.py:54        is_num
  10 callers  stock_analyzer/data/market.py:144  get_row
   9 callers  stock_analyzer/base.py:12        Finding

▸ impact_of is_num
  21 production caller(s) across 11 file(s).
  ⚠ No test reaches this symbol on any call path — changes here are unguarded.

Why a graph

Reachability is transitive, and transitive questions are exactly what a graph database answers in one query and a text search cannot answer at all. impact_of walks every call path upstream of a symbol, partitions the callers into production code and tests, and tells you when nothing guards the change. That is the query that stops an agent from confidently editing shared code.

Requirements

  • Node.js 18+
  • A Neo4j instance. AuraDB Free is enough for repositories in the hundreds-of-thousands-of-lines range and costs nothing.

Setup

Create a free AuraDB instance, then note the connection URI and password it gives you.

Add the server to your MCP client:

{
  "mcpServers": {
    "repo-atlas": {
      "command": "npx",
      "args": ["-y", "repo-atlas-mcp"],
      "env": {
        "NEO4J_URI": "neo4j+s://xxxxxxxx.databases.neo4j.io",
        "NEO4J_USER": "neo4j",
        "NEO4J_PASSWORD": "your-password"
      }
    }
  }
}

For Claude Code that goes in .mcp.json at your project root, or run:

claude mcp add repo-atlas -- npx -y repo-atlas-mcp

Then ask your agent to index the project once:

index this repo at /path/to/project

Re-indexing is incremental — unchanged files are skipped by content hash, so running it again after a few edits takes about as long as parsing the files you touched.

Tools

Tool Question it answers
index_repo Build or refresh the graph for a repository
find_symbol Where is this function/class/method defined?
who_calls What reaches this symbol, transitively?
what_it_calls What does this symbol depend on, transitively?
impact_of What breaks if I change this — and do any tests cover it?
path_between How does control flow from A to B?
hotspots Which symbols have the most distinct callers?
module_map What does the top-level package structure depend on?
list_repos What is indexed?
drop_repo Remove a repository from the graph

Languages

Python, TypeScript, TSX, and JavaScript, via tree-sitter WASM grammars — no native compilation, so npx works on a clean machine without build tools.

How call resolution works, and where it is wrong

Resolving a call to a definition properly requires full type inference. This does something cheaper and tells you when it is guessing. What the call looks like decides how it is resolved:

self.foo() / this.foo() — resolves to foo on the enclosing class, else to a definition in the same file. This is the one method form that resolves precisely. Tier: local.

foo() — a bare call, very likely a repo-level function. Resolved against a definition in the same file (local), then in a file this one imports (imported), then repo-wide if three or fewer candidates exist (global).

something.foo() — the receiver's type is unknown. Accepted only when foo is defined exactly once in the whole repository and is not a well-known builtin name. Tier: receiver.

That last rule matters more than it looks. Without it, one repo method named get absorbs every dict.get() and response.get() in the codebase; on a real 26-file project it produced a phantom symbol with 59 callers, ranked as the most-called code in the project. The denylist in COMMON_METHOD_NAMES (get, add, update, join, map, read, …) is a heuristic, and it is consulted only for this weakest case — a bare get() still resolves normally.

Every CALLS edge stores which tier produced it, and the tools surface anything above local.

Known limitations, stated plainly:

  • Dynamic dispatch is invisible. getattr(obj, name)(), reflection, and dependency-injection wiring produce no edges.
  • Polymorphism is not modelled. Two classes with a run() method cannot be told apart, so calls on a non-self receiver to a name defined more than once are dropped rather than guessed.
  • Calls into third-party packages are dropped. Only symbols defined inside the repository become nodes.
  • Top-level code is attributed to a synthetic <module> symbol per file, so route registration and CLI wiring still appear in the graph rather than being discarded.
  • Repeated calls between the same pair collapse to one edge, which keeps the last line number seen.

The practical effect: the graph under-reports rather than over-reports. impact_of can miss a caller that goes through dynamic dispatch, so treat its output as a strong lead, not a proof — but a symbol it names really is a caller.

Graph model

(:Repo)-[:HAS_FILE]->(:File)-[:DEFINES]->(:Symbol)
(:File)-[:IMPORTS]->(:File)
(:Symbol)-[:CALLS {line, confidence}]->(:Symbol)

Symbol.isTest is set from the defining file's path, which is what lets impact_of separate covering tests from production callers.

Ranking in hotspots uses caller in-degree rather than PageRank, so it runs on AuraDB Free, which does not include the Graph Data Science library.

Development

npm install
npm run build
node scripts/smoke.mjs                 # parser check, no database needed
node scripts/bulk-parse.mjs /some/repo  # parse a real repo and report totals

License

MIT

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured