Cartograph
Cartograph
エージェントネイティブなコードインテリジェンス。 あらゆるリポジトリをクエリ可能なコードグラフに変換し、MCP を通じてコーディングエージェントに提供します。これにより、エージェントは*「これを変更したら何が壊れる?」*と尋ねることができ、grepして推測する代わりに済みます。
tree-sitter + SQLite。埋め込みなし、ベクターストアなし、APIキーなし、サーバーなし、コストなし。
→ ライブデモ — このリポジトリの実インデックスからプッシュのたびに生成されています。
問題
コーディングエージェントに、見慣れない大きなリポジトリを与えて、その行動を観察してみてください:grepをし、ファイルを読み、またgrepをし、別のファイルを読む。パーサーなら一度の呼び出しで教えてくれる構造を再構築するためにコンテキストを消費し、それでも、変更が壊す3モジュール先の呼び出し元を見逃してしまいます。
通常の解決策はRAGです:コードベースを埋め込み、「類似」チャンクを取得します。しかし*「この関数を呼んでいるのは誰?」*は類似性の問題ではありません。それには正確な答えがあり、その答えはコールグラフにあります。
Cartographはグラフを構築し、エージェントが実際に動作する方法に合わせた10のツールを提供します。
$ cartograph blast src/cartograph/graph/store.py
## Blast radius — file `src/cartograph/graph/store.py`
17 dependent file(s), 31 affected symbol(s), 7 test file(s).
**Tests to run first**
- `tests/test_cli.py`
- `tests/test_docs.py`
- `tests/test_incremental.py`
- `tests/test_mcp.py`
- `tests/test_resolver.py`
- `tests/test_traversal.py`
- `tests/test_views.py`
**Dependent files** (by import distance)
- `src/cartograph/graph/resolver.py` · d1
- `src/cartograph/indexer/pipeline.py` · d1
- `src/cartograph/service.py` · d1
- `src/cartograph/cli.py` · d2
…編集前の1回の呼び出し。テストスイートが赤くなった後の7回のgrepではありません。
クイックスタート
uv tool install cartograph-mcp # or: pipx install cartograph-mcp
cartograph index ~/code/my-repo # builds .cartograph/cartograph.db
cartograph arch # modules, layers, cycles, hotspots
cartograph blast src/auth/token.py # what a change here could break
cartograph callers validate_token # reverse call treeエージェントに組み込む
Claude Code:
claude mcp add cartograph -- cartograph serve /path/to/repoまたは任意のMCPクライアントから、mcp.jsonを使用:
{
"mcpServers": {
"cartograph": {
"command": "cartograph",
"args": ["serve", "/path/to/repo"]
}
}
}serveは初回実行時にインデックスが存在しなければインデックスを作成します。その後、エージェントに*「トークンバリデータを変更したら何が壊れる?」*と尋ねると、推測する代わりにblast_radiusを呼び出します。
10のツール
ツール | 回答 |
| Xはどこで定義されているか?(構造的重要度でランク付け) |
| 名前、シグネチャ、docstringに対する全文検索(BM25) |
| 1つのシンボル:シグネチャ、ドキュメント、メンバー、呼び出し元、呼び出し先、ソース |
| 逆コールツリー — シグネチャを変更する前に |
| 順方向コールツリー — すべてのファイルを読まずにコードを理解する |
| 変更が壊す可能性があるもの、そして実行すべきテスト |
| 「他に何を読むべきか?」をパーソナライズされたPageRankで |
| ファイルが定義しているもの、インポートしているもの、そして誰がそれをインポートしているか |
| モジュール、レイヤリング、インポートサイクル、ホットスポット、エントリポイント |
| インデックスの健全性とルール別のエッジ解決の内訳 |
さらに、MCPリソース(cartograph://architecture、cartograph://stats)と、馴染みのないリポジトリに対するグラフ優先の最初のパスのためのorientプロンプトがあります。
対応言語: Python、TypeScript、TSX、JavaScript、Go。
議論に値する設計判断
1. 信頼度は第一級のカラム
型チェッカーがなければ、store.who_calls()がGraphStore.who_callsを意味することを知ることはできません。仮説をランク付けすることしかできません。だから、そのふりをする代わりに、すべてのエッジはそれを生成したルールと信頼度を記録します:
ルール | 信頼度 | 直感 |
| 0.95 | 定義が同じスコープ内にある |
| 0.90 | ファイルがこの名前を明示的にインポートしている |
| 0.85 |
|
| 0.75 | 同じパッケージ内の兄弟ファイル |
| 0.60 | リポジトリ内でこの名前を持つシンボルがただ1つあり、修飾なしの呼び出し |
| 0.45 | 1件マッチするが、型付けされていないレシーバに対するもの |
| ≤0.40 | N個の候補があり、それぞれ1/Nの重みでN個のエッジとして保持 |
| 0.00 | サードパーティまたは標準ライブラリのインポートに由来 |
| 0.00 | 本当に不明(動的、または型付きメソッド) |
呼び出し元(ツールの利用者)は、自分自身の運用ポイントを選びます。who_callsのデフォルトは≥0.5 — 精度優先。エージェントは答えに基づいて行動するからです。blast_radiusは0.3まで下げます — 再現率優先。影響を受けるテストを見逃すことが高くつくミスであり、誤検知はレビュアーが一目見るだけのコストだからです。
name-only層は実際のバグが理由で存在します。組み込みsetに対するseen.add(...)が、単に名前がたまたま一意だったというだけの理由で、リポジトリ内のクラスのaddメソッドに解決され、それが自信ありの呼び出し元として表示されました。型を付けられないレシーバ上のメソッド名は証拠にならないため、現在は精度ラインの下に置かれています。(テスト)
external層は、メトリクスに関する正直さのために存在します。ほとんどのリポジトリでは、「unresolved」バケットはtyper.Optionとsqlite3.executeが大半を占めます。これらをまとめると、カバレッジが実際よりもはるかに悪く見えるため、Cartographは内部解決率を報告します — リポジトリのシンボルに到達し得る呼び出しサイトのうち、実際に到達した割合です。
2. パースはインクリメンタル、解決は決してインクリメンタルではない
ファイルのsha256が変わったときだけ再パースされます。しかし、生の参照はrefsテーブルに事実として保存され、edgesは何かが変更されるたびに(refs × symbols)の純粋関数として再計算されます。
これこそが「編集のたびに再インデックス」を信頼できるものにしています。解決もインクリメンタルだったら、1つのファイルを編集したときに、別のファイルのエッジが移動したシンボルを指したままになる可能性があります。グローバルな再解決は、それを構造的に不可能にします。(テスト)
コストは現実のものなので、安全なショートカットは正確に1つだけあります。ファイルが追加・再パース・削除されていない場合、両方の入力テーブルは不変であり、解決は証明可能なほど同一であるため、スキップされます。これにより、Djangoのno-op再インデックスが、バイト単位で同一のグラフで7.5秒から0.67秒に短縮されました。
3. 埋め込みの代わりにPageRank
「どのgetのこと?」は構造的な質問です。40の呼び出しサイトが依存しているgetこそがエージェントが望むものであり、コールグラフはすでにそれを知っています。したがって、シンボルのランキングはコールグラフ上の重み付きPageRankです — 安定していて、説明可能で、無料です。モデルも、インデックス構築も、ベクターストアもありません。
related_symbolsは同じ考え方を拡張します。1つのシンボルをシードにしたパーソナライズドPageRankで、グラフを無向として扱います。関数を変更しようとしているとき、その呼び出し元と呼び出し先の両方が関連するコンテキストだからです。これはセマンティック検索の構造的類似物であり、埋め込みは不要です。
4. ツールはJSONではなくMarkdownを、トークン予算の下で返す
消費者はコンテキストウィンドウです。40シンボルのJSON配列は、ブラケットや繰り返されるキーに何千ものトークンを費やし、モデルはそれを結局再フォーマットします。ここにあるすべてのビューは、ハードなトークン予算を持つコンパクトなMarkdownです。
重要なのは、すべての切り詰めが明示されることです。87件の呼び出し元のうち20件だけをマーカーなしで渡されたエージェントは、残りの67件は存在しないと自信を持って結論づけ、何かを削除してしまいます。
5. トラバーサルはPythonではなくSQLiteで実行される
深さ4のwho_callsは再帰CTEなので、トラバーサル全体がSQLiteのCループ内に留まります。Djangoの252kエッジのグラフでは約5msです。エッジテーブルをPythonに読み込んで走査するのでは、そうはいきません。
ベンチマーク
実際のリポジトリ、Mシリーズのラップトップ、シングルプロセス。Cold = ゼロからの完全インデックス、Warm = no-op再インデックス。
リポジトリ | ファイル数 | KLOC | シンボル数 | エッジ数 | Cold | Warm | DB | 内部解決率 |
2,973 | 534 | 45,394 | 252,441 | 11.9s | 0.67s | 80 MB | 83.2% | |
gin (Go) | 98 | 24 | 1,610 | 9,179 | 0.32s | 0.03s | 2.5 MB | 88.1% |
83 | 18 | 1,624 | 4,271 | 0.21s | 0.03s | 1.7 MB | 87.4% |
クエリレイテンシ(中央値、5回、ウォーム):
リポジトリ |
|
|
|
|
django | 12.3ms | 5.1ms | 5.6ms | 68.5ms |
gin | 0.4ms | 0.4ms | 0.5ms | 1.2ms |
flask | 0.5ms | 1.1ms | 1.3ms | 1.8ms |
scripts/bench.pyで再現できます。
アーキテクチャ
flowchart LR
subgraph index["cartograph index"]
W[walker<br/>git ls-files] --> P[tree-sitter<br/>+ .scm queries]
P --> X[extract<br/>defs · refs · imports]
end
X --> DB[(SQLite<br/>symbols · refs<br/>edges · FTS5)]
DB --> R[resolver<br/>rule cascade]
R --> DB
DB --> RK[PageRank<br/>Tarjan SCC]
RK --> DB
DB --> S[service facade]
S --> V[views<br/>token-budgeted MD]
V --> M[MCP server<br/>10 tools]
V --> C[CLI]
M --> A((coding agent))モジュール | 責務 |
| ファイル検出 — 正しい |
| 言語ごとに1つのアダプタ:拡張子、クエリ、docstring、モジュールキー、インポート解決 |
| AST → シンボル/参照/インポート、言語非依存 |
| tree-sitterのキャプチャパターン — 言語ごとの知識をデータとして |
| グラフ: |
| 信頼度カスケード |
| PageRank、パーソナライズドPageRank、反復的Tarjan SCC、レイヤリング |
| 再帰CTEトラバーサル、ランク付きルックアップ、集計 |
| CLIとMCPサーバーが乖離しないための単一ファサード |
| トークン予算付きMarkdown |
組み合わせ爆発するクエリを使わないスコープ解決
queries/*.scmを小さく保つ秘訣は、スコープをクエリに一切エンコードしないことです。キャプチャされたすべての定義は、そのtree-sitterノードIDでインデックス化され、参照の囲むシンボルはparentチェーンを辿ってシンボルに当たるまで探索することで見つかります。これは参照ごとにO(ツリー深さ)であり、クロージャ、メソッド、内部クラス、アロー関数を追加のパターンなしで自然に処理します。
言語の追加
LanguageAdapterをサブクラス化し(約40行)、.scmファイルを置きます。GoAdapterが最短の完全な例です。tests/test_queries.pyが、あなたのクエリを文法に対して自動的にコンパイルし、何かをキャプチャすることを検証します。
開発
git clone https://github.com/GokulRaj2210/cartograph-mcp && cd cartograph-mcp
uv sync
uv run pytest -q # 209 tests
uv run ruff check .
uv run mypy # strictCIはPython 3.11/3.12/3.13(さらにmacOS)でスイートを実行し、その後ドッグフーディングします。つまり、このリポジトリをインデックス化し、インポートサイクルで失敗し、no-op再インデックスが何も再パースしないことを検証し、実際のstdio経由でMCPサーバーを駆動します。また、ビルドしたwheelをクリーンなvenvにインストールしてインデックス化します。パッケージ化された.scmファイルはwheelから漏れやすいが、ローカルでは気づきにくいからです。
サイクルゲートはすでにその価値を証明しています。このリポジトリで私が導入したstore → resolver → storeサイクルを検出し、ゲートを緩めるのではなく、問題のヘルパーを移動することで修正されました。
注目すべきテスト
tests/test_queries.py— すべての.scmが、それを読み込むすべての文法に対してコンパイルされ、何かをキャプチャすることを検証します。JavaScriptでは有効なパターン ((class_heritage (identifier))) は、TypeScriptではスーパータイプをextends_clauseでラップするため、不可能なパターンです。その1行は、TypeScriptのシンボルを黙ってゼロ生成していました。tests/test_incremental.py— 編集、削除、またはシンボルがファイル間を移動した後も、古いエッジが残らないことを検証します。tests/test_resolver.py— すべてのルールが発動し、どのルールも信頼度を過大に主張しないことを検証します。tests/test_cli.py— リーダーとインデクサーが同時にデータベースを保持できることを検証します。tests/test_docs.py— 生成されたデモページがタグの釣り合いが取れた整形式HTMLであることを検証します。これにより、Markdownレンダラーのmin_confidenceに関するタグ交差バグが発見されました。
制限事項
率直に言えば、精度を過大に宣伝するコードインテリジェンスツールは、役に立たないどころか有害だからです:
型推論なし。
self.conn.execute(...)はconnの型を知らなければリポジトリのシンボルに解決できません。これらはunresolvedに入り、内部解決率~85%で残る大部分を占めます。動的ディスパッチは見えない。
getattr(obj, name)()、デコレータレジストリ、DIコンテナはエッジとして現れません。言語間エッジは追跡されない。 TypeScriptフロントエンドがPythonエンドポイントを呼び出す場合、それらは2つの独立したサブグラフになります。
定義のみであり、すべての参照ではない。 値として使用されるシンボル(コールバックとして渡される)は、呼び出されるシンボルよりもグラフ内で弱い存在です。
ロードマップ:RustおよびJavaアダプター、言語サーバーが利用可能な場合に正確な解決を可能にするオプションのLSP拡張、およびPR規模の影響範囲を対象とした --changed-since <ref> モード。
なぜこれが存在するのか
大規模リポジトリにおけるコーディングエージェントの最大の弱点—コードの構造モデルが無いこと—が、より大きなモデルやベクターデータベースではなく、静的解析と適切に設計されたツールサーフェスで修正できるかどうかを知りたかったのです。ほとんど、それは可能です。
ライセンス
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Give your AI agent a persistent map of your project's structure, dependencies, and bugs.
Driflyte MCP server which lets AI assistants query topic-specific knowledge from web and GitHub.
AI Agent with Architectural Memory. Impact analysis (free), tests and code from the graph (pro).
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/GokulRaj2210/cartograph-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server