codebase-cartographer
Maps a local Python repository into an AST-backed symbol graph and performs verified multi-file refactors, enabling scope-aware renaming, moving, and deletion of symbols with safety checks.
README
Codebase Cartographer
An MCP server that maps a local Python repository into an AST-backed symbol graph and performs verified multi-file refactors on it.
Most coding agents refactor by grepping for a string and rewriting what they find. That
approach cannot tell a call to compute() apart from a local variable that happens to be
named compute, and it has no idea which twelve files break when you rename it. This server
gives the model a real index instead: scope-resolved references, an import graph, and a
two-phase edit protocol that refuses to write anything it cannot verify.
What it does
Maps. Walks the repository (honouring .gitignore), parses every module, and builds a
symbol table of functions, classes, methods, and module-level variables, plus the import
graph between modules.
Resolves. Finds references using real scope analysis — the LEGB chain, global and
nonlocal declarations, comprehension scopes, walrus bindings, and the rule that class
bodies are invisible to nested functions. A local variable that shadows a module-level
symbol is not a reference to it, and the tool knows the difference.
Refactors. Renames, moves, and deletes symbols across every file that touches them —
rewriting from x import y, import x + x.y attribute access, as aliases, and __all__
entries. Nothing is written until you apply a plan you have seen the diff for.
Safety model
Refactoring is two-phase, and the first phase never touches disk.
plan_rename_symbol/plan_move_symbol/plan_delete_symbolreturn a plan id, a unified diff, and a list of warnings. Every touched file's content hash is recorded.apply_planre-checks those hashes (aborting if anything changed on disk since planning), builds the new content for every file, re-parses each one, and refuses to write if any file would end up unparseable. Originals are copied to.cartographer-backups/<plan_id>/. A failure mid-write rolls every file back.
Further guardrails: paths outside the mapped root are rejected; renaming a method requires
an explicit allow_heuristic=true because attribute matching cannot be resolved without type
inference; deleting a symbol that still has references is refused unless forced.
What it cannot see
Static analysis has a hard edge, and the tool is built to say where that edge is rather than to pretend it isn't there.
find_dynamic_references reports string literals matching a symbol name — getattr(mod, "compute"),
plugin registries, dotted settings strings, entry-point tables — and detects imports of
underscore-prefixed native modules. Those warnings are attached to every refactor plan.
This matters concretely. Renaming JSONDecodeError in a copy of the stdlib json package
rewrites all 19 Python references correctly and still breaks the package, because the _json
C accelerator resolves that name at runtime through the C API. No pure-Python analysis can
follow that. The tool flags the native accelerator import and tells you to check by hand.
Also invisible: from x import * re-exports (reported as a warning), runtime monkey-patching,
and references from other languages or config files.
Tools
| Tool | Purpose |
|---|---|
map_repository |
Scan a directory and build the index. Call this first, and again after applying. |
repository_overview |
Stats, packages, import cycles, most-depended-on modules. |
list_modules |
Indexed modules, filterable by dotted prefix. |
file_outline |
One file's imports and definitions. |
search_symbols |
Find definitions by substring, kind, or module prefix. |
get_symbol_source |
Full source of one definition, with docstring and decorators. |
find_references |
Every scope-resolved use of a symbol. |
find_dynamic_references |
String literals and native imports that static analysis can't follow. |
dependency_graph |
Internal import edges, whole-graph or one module's neighbourhood. |
impact_of_change |
Transitive dependents — the blast radius of editing a module. |
find_dead_code |
Module-level definitions with no discoverable references. |
plan_rename_symbol |
Plan a repository-wide rename. Writes nothing. |
plan_move_symbol |
Plan moving a definition to another module. Writes nothing. |
plan_delete_symbol |
Plan removing a definition and its __all__ entry. Writes nothing. |
preview_plan |
Re-render a pending plan's diff. |
list_plans / discard_plan |
Inspect or drop pending plans. |
apply_plan |
Commit a plan, with hash checks, syntax validation, and backups. |
Install
pip install -e .
Register it with an MCP client:
{
"mcpServers": {
"codebase-cartographer": {
"command": "python",
"args": ["-m", "cartographer"],
"env": { "CARTOGRAPHER_ROOT": "/path/to/your/repo" }
}
}
}
CARTOGRAPHER_ROOT is only the default for map_repository; the tool takes an explicit
root argument too.
A typical session
map_repository(root="~/work/service")
-> 412 files, 1 import cycle, 38k LOC
impact_of_change(module="service.auth.tokens")
-> 23 transitive dependents
find_references(qualname="service.auth.tokens.decode_jwt")
-> 31 references across 12 files
find_dynamic_references(name="decode_jwt")
-> 1 string literal in service/registry.py:44 <- read this before proceeding
plan_rename_symbol(qualname="service.auth.tokens.decode_jwt", new_name="decode_access_token")
-> plan 9f2a1c: 31 edits across 12 files, with diff
apply_plan(plan_id="9f2a1c")
-> written, backed up to .cartographer-backups/9f2a1c/
Development
pip install -e ".[dev]"
pytest
65 tests cover scope resolution (shadowing, global, comprehensions, class-body visibility),
reference finding across every import style, rename/move/delete correctness, generated-import
style, and the apply-phase guarantees: stale-file detection, syntax validation, and rollback.
The suite's strongest check is that the tool refactors its own source — renaming a function across the implementation and the tests, and moving one between modules — after which the full suite still passes against the rewritten copy.
Requirements
Python 3.10+ (uses ast.alias position attributes). Python source only.
License
MIT
Recommended Servers
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.
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.
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.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
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.
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.
Neon Database
MCP server for interacting with Neon Management API and databases
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.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.
E2B
Using MCP to run code via e2b.