Code Crawler について
Code Crawlerは、Java、Python、TypeScript、JavaScriptのプロジェクトをSQLiteのプロパティグラフに索引化し、コーディングエージェントやLLMクライアントからコードの関係を検索できるようにします。静的な呼び出しに加え、動的ディスパッチやフレームワークの配線も扱い、増分索引に対応します。
主な機能
- 014言語を単一のコードグラフに索引化
- 02呼び出し元・呼び出し先・経路の検索
- 03動的ディスパッチとリフレクションの追跡
- 04依存性注入とHTTPルートの索引化
- 05解析結果をキャッシュする増分索引
- 06ホットスポット・デッドコード候補・シンボルの検索
活用シーン
- 01メソッドを推移的に呼び出す箇所の追跡
- 02メソッド変更の影響範囲の評価
- 03フレームワークのルートと注入依存関係の分析
- 04ホットスポットと潜在的なデッドコードの特定
MCP 対応
stdioで動作するMCPサーバーとして、シンボル検索、呼び出し追跡、実装の検索、ホットスポット分析などのコードグラフツールを公開します。索引はSQLiteデータベースに保存されます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
npx -y @nithin554/code-crawlerCODECRAWLER_DBPath to the SQLite graph database (default ~/.code-crawler/index.db)CODECRAWLER_EXCLUDE_DIRSComma-separated directories to skip during crawlCODECRAWLER_DEFAULT_LIMITDefault result cap for list queries (default 50)CODECRAWLER_MAX_DEPTHTraversal depth cap (default 10)CODECRAWLER_HELPFUL_ERRORSFuzzy suggestions on unknown symbols (default true)ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
27掲載時のツール一覧 · 1 日前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| path | string | はい | インデックスを作成するプロジェクトのルートディレクトリの絶対パス。 |
| force | boolean | いいえ | マニフェストのサイズ、mtime、コンテンツハッシュによるショートカットを無視し、検出したすべてのファイルを再解析します。メタデータが一致していてもインデックスが古い可能性がある場合に使用します。同じサイズの編集後に mtime を復元した場合(git checkout、rsync -t、unzip)、指定しないとキャッシュから再利用されます。 |
| language | string | いいえ | インデックス対象を 1 つのパーサー言語に限定します:'java'、'python'、'typescript'、'javascript'。該当言語に属さない拡張子のファイルはスキップされます。既定ではファイル拡張子から判定します。 |
| fileFilter | string | いいえ | 任意の部分文字列フィルターです。この文字列をパスに含むファイルのみをインデックスします。 |
詳細
Code-Crawler
コードベースの永続的なプロパティグラフを基盤とする、静的・動的コールトレーシング MCP サーバーです。
Code-Crawler は、プロジェクトを SQLite ベースのプロパティグラフにインデックス化します。ファイル、パッケージ、モジュール、クラス、インターフェース、メソッド、フィールド、インポート、アノテーション/デコレーター、呼び出しエッジ、仮想ディスパッチ、アスペクトアドバイス、そしてフレームワークが追加する配線情報(エントリーポイント、ルート、注入された依存関係、リフレクティブな検索)を含みます。その後、このグラフを MCP ツールとして LLM クライアントに公開し、呼び出し元の検索、呼び出し経路のトレース、近傍の探索、実行時ディスパッチの追跡、コードベース全体にわたるシンボル検索を可能にします。
Java、Python、TypeScript、JavaScript のプロジェクトに対応し、すべてを同じグラフにインデックス化できます。
📖 ドキュメントサイト: https://nithin554.github.io/code-crawler/
📘 タスク別ガイド: USAGE.md
🗺️ ロードマップ: ROADMAP.md
┌─────────────────────── MCP (stdio) ───────────────────────┐
│ crawl_project search_symbols get_callers get_callees │
│ trace_path trace_execution find_aspects get_decorators│
│ find_implementations find_hotspots find_dead_code ... │
└───────────────┬──────────────────────────────┬───────────────┘
│ │
┌──────▼───────┐ ┌────────▼────────┐
│ crawler │ │ graph queries │
│ parse+resolve│ │ recursive CTEs │
└──────┬───────┘ └────────┬────────┘
│ │
┌──────▼──────────────────────────────▼──────┐
│ SQLite property graph (WAL) │
│ nodes (kind, fqn, props) + edges (kind) │
└─────────────────────────────────────────────┘
なぜグラフなのか?
プレーンテキストの grep では、次のような質問に答えられません。
- 「
OrderRepository#createを間接的に呼び出しているのは誰ですか?」 - 「
Main#mainからTracking#dispatchへの静的な経路はありますか?」 - 「
OrderService#placeを変更した場合の影響範囲はどれくらいですか?」
これらの質問にはグラフの探索が必要です。Code-Crawler はグラフを一度構築し(ファイルごとに冪等に処理します)、上限付きの再帰 SQL クエリで回答します。
機能
- 4 つの言語を 1 つのグラフに:Java(
tree-sitter-java)、Python (tree-sitter-python)、TypeScript(tree-sitter-typescript、tree-sitter-tsx)、および JavaScript(tree-sitter-javascript)に対応しています。すべて WASM で動作し、ネイティブのビルド工程は不要です。 言語はファイルごとに検出されるため、複数言語が混在するリポジトリも 1 つのグラフにまとめられます。 - 静的グラフ上で動的トレースを実現 —
DYNAMIC_DISPATCHエッジは、インターフェースや基底クラスの 呼び出しとプロジェクト内のすべてのオーバーライドをつなぎ、ADVISESエッジは AspectJ/Spring AOP の アドバイスを実行トレースに織り込みます(before、after、around、after-returning、after-throwing、名前付きの@Pointcut参照、&&/||/!およびexecution、within、@annotation、@within、target、this、argsの各プリミティブ)。 - 実行時の間接参照も名前付きで保持 — Java のリフレクション/
ServiceLoader、Python のgetattr/importlib、JavaScript のrequire/動的なimport()は、対象を静的に特定できる場合は 解決済みシンボルへのREFLECTSエッジを生成し、特定できない場合は__reflect__:マーカーへの エッジを生成します。 - フレームワークの配線 — 依存性注入(
@Autowired、NestJS のコンストラクターインジェクション、 FastAPI のDepends)はINJECTSエッジになり、HTTP ルート(@GetMapping、@RequestMapping、 NestJS の@Controller/@Get、FastAPI/Flask/Quart のデコレーター、Express のapp.get)は ハンドラーへのROUTESエッジになります。ハンドラーにはエントリーポイントのマークも付与されます。 - 呼び出しエッジ上の制御フロー — すべての
CALLSエッジには、呼び出しが条件付きかどうかと、 それを囲むガードやループの簡潔なソーステキストが記録されます。これにより、エージェントはファイルを 読まずに正常系とエラー系を見分けられます。 - 外部依存関係を明示 — サードパーティーのインポートと実行時グローバルは、
REFERENCESエッジを持つ パッケージレベルのexternal_symbolノードになり、プロジェクトのコードとは区別されたfind_external_dependenciesの概要に表示されます。 - アノテーションを第一級ノードとして扱う —
@Transactional、@Cacheable、@Async、@Retryable、Python のデコレーター、TypeScript のデコレーターは、ANNOTATED_WITHエッジを持つannotationノードになります。これにより、型、メソッド、フィールドに付与されたデコレーターを検索できます。 - 単純な文字列照合を超える呼び出し解決のヒューリスティック:
ローカル変数、パラメーター、フィールド、
new T()式からのレシーバー型の推定、self/thisのスコープ、 ドット区切りパス(service.repo.find)、ループ変数の要素型、裸の呼び出し/this/super呼び出し、 静的呼び出し/修飾された呼び出し、スーパークラスの連鎖に対応します。 解決できない呼び出しは、resolved:falseエッジを持つunknown_symbolの仮ノードになります。 そのため、グラフのトラバーサルを継続できます。 - ファイル単位の増分インデックス作成 — クロールごとにファイル別のマニフェスト
(
size、mtime、SHA-256)が記録され、内容が変わっていないファイルにはキャッシュ済みの解析結果が 再利用されるため、再クロールで解析し直すのは実際に変更されたファイルだけです。変更はfilesAdded/filesUpdated/filesUnchanged/filesRemovedとして報告されます。 派生した動的エッジと孤立ノードの削除は、変更があった場合にのみ再構築されます。完全な再クロールでは、 消失したファイルも引き続き削除され、グラフの重複も発生しません。また、スコープを指定したクロール (fileFilterまたは強制したlanguage)では、スコープ外のファイルは削除されません。チェックアウト、rsync -t、mtime を保持する unzip、またはクロックのずれによって、古いサイズと mtime のまま編集内容が 復元されると、このショートカットでは変更を検出できません。その場合はforce(CLI では--force)を 渡して、すべてを再解析してください。 - FTS5 ベースのシンボル検索 — シンボル検索は、BM25 ランキングと完全一致/前方一致のブースト機能を備えた
外部コンテンツの FTS5 インデックスを使って実行されます。FTS で結果が見つからない場合に限り、
LIKEによるスキャンにフォールバックします。グラフが大きくなっても検索の性能は低下しません。 - 自動移行に対応したバージョン管理スキーマ — データベースにはスキーマバージョンが記録され、 開くと自動的にその場でアップグレードされます。新しいビルドで書き込まれたデータベースは、既知の スキーマであるかのように読み込むのではなく、明確なメッセージを表示して拒否されます。
- プロジェクトごとに 1 つのデータベース — インデックスは
<project>/.code-crawler/index.dbに 保存されるため、2 つのリポジトリが競合することはありません。データが格納されたデータベースを別の プロジェクトに割り当てると、最初のインデックスを黙って消去するのではなく、clear_indexのヒントを 表示して失敗します。 - 分析 — ホットスポット(ファンイン/ファンアウト/アドバイスの数)とデッドコードの候補。
- 自己完結型:単一の SQLite ファイルで動作し、外部サービスは不要です。
- LLM に適した設計:各ツールは構造化 JSON を返し、不明なシンボルにはあいまい検索の候補が表示されます。
インストールとビルド
Node.js ≥ 22.12 が必要です(better-sqlite3@13 と Vitest ツールチェーンの両方で必要です)。
npm install
npm run build # tsc → dist/
npm test # vitest (full suite; set CODECRAWLER_BENCH=1 for the scale test)
npm run lint # biome check (lint + format, fails CI)
npm run format # biome format --write
npm run coverage # vitest run --coverage (thresholds in vitest.config.ts)
npm run bench # crawl/query benchmark on a generated ~137k-line project
CLI
codecrawler crawl <path> # index a project
codecrawler crawl <path> --force # re-parse every file, ignoring cached metadata
codecrawler status # index summary
codecrawler query <symbol> # fuzzy-lookup a symbol
codecrawler serve # start the MCP server over stdio (default)
環境変数:
| 変数 | デフォルト | 用途 |
|---|---|---|
CODECRAWLER_DB | <project>/.code-crawler/index.db | データベースのパスです。cwd から上方向に解決されるため、各プロジェクトに専用のファイルが作成されます。cwd を含むプロジェクトがない場合は ~/.code-crawler/index.db にフォールバックします。ホームディレクトリはフォールバック先としてのみ使われ、cwd を含むプロジェクトとは見なされません |
CODECRAWLER_EXCLUDE_DIRS | .git,node_modules,dist,build,target,... | クロール時にスキップするディレクトリ |
CODECRAWLER_DEFAULT_LIMIT | 50 | デフォルトの結果上限 |
CODECRAWLER_MAX_DEPTH | 10 | トラバーサルの深さの上限(1~100) |
CODECRAWLER_MAX_FILE_BYTES | 1000000 | このサイズを超えるファイルは解析されず、スキップされます |
CODECRAWLER_RESPECT_GITIGNORE | true | 検出時にプロジェクトの .gitignore を適用します |
CODECRAWLER_HELPFUL_ERRORS | true | シンボルが見つからない場合に、あいまい検索による候補を提示します |
CODECRAWLER_PLUGIN | unset | プラグインモード:起動時にファイルを1つ開くのではなく、呼び出し時にプロジェクトごとのデータベースを解決します |
CODECRAWLER_PLUGIN_ROOT | unset | プラグインのインストールディレクトリ。プロジェクトとしてインデックス化されることはありません |
CODECRAWLER_PLUGIN_DATA | temp dir | プロジェクトがない場合のフォールバックデータベース用の書き込み可能なディレクトリ |
無効な値を指定してもサーバーがクラッシュすることはありません。ブール値はデフォルト値に戻され、整数値はドキュメントに記載された範囲内に制限されます。いずれの場合も、stderr に1行の警告が出力されます。
インデックス化の対象
crawl はプロジェクトをたどり、.git、node_modules、ビルド出力、およびその他の CODECRAWLER_EXCLUDE_DIRS に含まれるエントリをスキップします。さらに、以下も適用されます。
-
プロジェクトの
.gitignoreが適用されます(CODECRAWLER_RESPECT_GITIGNORE=falseで無効化できます)。 -
プロジェクトのルートに任意で置ける
.crawlerrcを使うと、gitignore 形式の glob で検出対象を絞り込んだり広げたりできるほか、モジュール ID の開始位置を変更できます。{ "include": ["src/", "packages/core/"], "exclude": ["**/generated/"], "moduleRoots": ["src"] }includeが空でない場合、一致するファイルのみがインデックス化されます。不正な形式の.crawlerrcはクロールを失敗させず、警告を出して無視されます。moduleRootsはオプトインです。["src"]を指定すると、src/orders/service.tsはsrc.orders.serviceではなくorders.serviceモジュールになります。これはbaseUrlまたはPYTHONPATHを使うプロジェクトが実際にインポートする名前です。既存のインデックスの番号が暗黙に変わってしまうため、自動推定は行われません。TypeScript および JavaScript のプロジェクトでは、パスエイリアスも自動的に利用できます。tsconfig.json(またはjsconfig.json)からcompilerOptions.pathsとbaseUrlが読み込まれ、プロジェクト内のextendsもたどります。そのため、import { x } from "@app/orders/service"は外部モジュールとして記録されず、実際のモジュールに解決されます。どちらかの設定を変更すると、次回のクロール時にキャッシュされたファイルが再解析されます。 -
CODECRAWLER_MAX_FILE_BYTESを超えるファイルとバイナリと思われるファイルはスキップされます。crawl_projectはその理由とともにskippedFilesに報告します。 -
ファイルごとの解析エラーでクロールが中断されることはありません。エラーは
parseErrorsに報告されます。
ルートの .gitignore のみが読み込まれます。ネストされた .gitignore ファイルにはまだ対応していません。
増分クロール
クロールでは、ファイルごとにマニフェストの行(size、mtime、SHA-256、言語)が記録されます。次回のクロールでは、サイズと切り詰められた mtime がどちらも一致するファイルは、再読み込みや再解析を行わず、キャッシュされた解析結果が使用されます。mtime が変わっていてもハッシュが同じファイルも、キャッシュから再利用されます。解決、ファントムノードの作成、派生エッジの処理は、引き続きメモリ上のファイルセット全体に対して実行されるため、ファイル間のエッジは正しく保たれます。スキップされるのは I/O、解析、データベースへの書き込みのみです。
crawl_project は次の内訳を報告します。
| Field | Meaning |
|---|---|
filesAdded | このクロールで初めて検出されたファイル |
filesUpdated | 内容が変更され、再解析されたファイル |
filesUnchanged | 解析キャッシュから再利用されたファイル |
filesRemoved | ディスク上から消え、削除されたファイル |
既知の制限: 変更されていないファイルのエッジは書き換えられないため、別のファイルの変更によってのみ呼び出しが新たに解決可能になる場合(たとえば、メソッドにオーバーロードが追加された場合や、以前は曖昧だった呼び出しのバインド先となるクラスが追加された場合)、変更されていないファイル内の呼び出しは更新されません。そのファイルに変更を加えるか、clear_index を実行して、完全な解決処理を強制してください。
ベンチマーク
npm run bench は、合成 TypeScript プロジェクト(575 モジュール、約 137k 行、約 9.8k メソッド)を生成してクロールし、クロールの各フェーズとクエリのレイテンシのパーセンタイルを報告します。
tests/perf.test.ts は同じ予算を検証しますが、現実的なコーパスのクロールには時間がかかるため、オプトイン方式です。
npm run bench # human-readable report
CODECRAWLER_BENCH=1 npm test -- tests/perf.test.ts # enforce the budgets
CODECRAWLER_BENCH_LINES=20000 npm run bench # smaller corpus
ディスクキャッシュがウォーム状態の Windows 開発用ノート PC で測定しました。絶対値は変動しますが、重要なのは比率とインデックスの使用状況です。
| Phase | Duration | Added | Updated | Unchanged |
|---|---|---|---|---|
| コールドクロール | 22.5 s | 575 | 0 | 0 |
| 再クロール、変更なし | 0.91 s | 0 | 0 | 575 |
| 1 ファイル編集後の再クロール | 0.75 s | 0 | 1 | 574 |
| Query | p50 | p95 | Budget (p95) |
|---|---|---|---|
search_symbols(完全一致) | 0.69 ms | 1.96 ms | 50 ms |
search_symbols(プレフィックス) | 1.60 ms | 4.09 ms | 50 ms |
get_callers(深さ 2) | 0.16 ms | 0.21 ms | 50 ms |
get_callees(深さ 2) | 0.11 ms | 0.15 ms | 50 ms |
get_subgraph(半径 2) | 0.16 ms | 0.27 ms | 50 ms |
find_entry_points | 0.12 ms | 0.29 ms | 50 ms |
find_hotspots | 145.5 ms | 181.4 ms | 1000 ms |
find_dead_code | 99.8 ms | 290.3 ms | 1000 ms |
このインデックスは、14.4k 個のノードと 38.8k 個のエッジに対して 66 MB です。find_hotspots と
find_dead_code は、すべてのエッジとノードを対象とするプロジェクト全体の集計であるため、シンボル検索より許容幅が 1 桁広くなっています。どちらも
EXPLAIN QUERY PLAN でプロファイリングされ、idx_edges_target_kind によって処理されます。
CI と公開
GitHub Actions はすべてのプルリクエストで実行されます(pull-request.yml)。npm ci → 型チェック → テスト → ビルド → ビルド済み CLI のスモークテストを行います。
main へのマージをきっかけに publish.yml が実行され、同じチェックを再度行います。すべて成功した場合は、次の手順で自動リリースします。
- 直近の
v*タグ(初回実行時はpackage.jsonのバージョン)を読み取り、次のパッチバージョンを算出して、vX.Y.Zタグをプッシュします。 - 対応する GitHub リリースを作成します。
- プロベナンス(OIDC による信頼された公開)を付与して、パッケージを npm レジストリに公開します。トークンやリポジトリシークレットは不要です。このステップは冪等で、再試行にも対応しています。npm にすでに登録されているバージョンはスキップし、一時的な透明性ログまたはレジストリの障害でリリースが中断されることもありません。
- 別個の再実行可能なジョブで、
ExaDev/mcp-registry-publishを使用してserver.jsonをio.github.nithin554/code-crawlerとして公式 MCP Registry に公開します。このジョブはmcp-registry-publish環境内で実行され、デプロイブランチポリシーはmainに限定されています。server.jsonをリリースバージョンに固定し、GitHub OIDC で認証し、レジストリにすでに登録されているバージョンはスキップして、一時的な npm の反映遅延やレジストリエラーが発生した場合は再試行します。所有権はpackage.jsonのmcpNameフィールドで検証されます。
MCP サーバーとしての使用
エージェントプラグインとしてインストールする
このリポジトリはエージェントプラグインでもあるため、Claude Code と Copilot CLI ではサーバーとスキルをまとめてインストールできます。
# Claude Code
/plugin marketplace add nithin554/code-crawler
/plugin install code-crawler@code-crawler
# Copilot CLI
copilot plugin marketplace add nithin554/code-crawler
copilot plugin install code-crawler@code-crawler
プラグインは npx -y @nithin554/code-crawler serve を実行します。エージェントプラグインのクライアントは、プラグインのディレクトリ内でプラグインの stdio サーバーを起動するため、サーバーはそのディレクトリをチェックアウト先として扱いません。代わりに、crawl_project、クライアントのワークスペースルート、またはこのセッションですでに選択されているプロジェクトからプロジェクトを特定し、そのグラフを <project>/.code-crawler/index.db に保持します。リポジトリごとにデータベースが 1 つ作成され、CLI と同じ配置になります。データベースを 1 つのファイルに固定したい場合は、引き続き CODECRAWLER_DB を使用できます。
同じスキルは ClawHub に code-crawler として公開されており、プラグインも公開されています。
- スキル —
clawhub install code-crawler。ClawHub では、すでに公開されているバージョンのパッチ番号を増やしてバージョンを割り当てます。そのため、npm のバージョンをそのままコピーするのではなく、1 リリースずつ進みます。スキルの公開に失敗したリリースでは、次回の公開まで両方の番号が 1 つずれた状態になります。 - プラグイン —
code-crawlerバンドルプラグインとして公開され、リリースタグに基づいてバージョンが付与されます。リリースv0.1.67では、バンドルが0.1.67として公開されます。バンドル内のplugins/code-crawler/package.jsonはパッケージング用メタデータです。ClawHub がバンドルを検査して ClawPack アーティファクトをビルドするにはパッケージマニフェストが必要で、マニフェストがないと警告が表示されます。そのため、リリースワークフローではタグのバージョンをファイルに設定し、バンドルをパックして、その tarball を公開します。コミット済みのversionはプレースホルダーにすぎません。
プラグインの公開では、upstream の再利用可能な package-publish.yml を呼び出すのではなく、Node 上で公式の clawhub CLI 自体を実行します。このワークフローではこのバンドルを公開できません。パック済みアーティファクトを bun ... package validate で検査しますが、CLI は Bun での実行を拒否するためです(「Plugin validation requires Node.js 22.13+ (22.x) or 24+」)。ClawPack には必ず package/package.json が含まれ、このステップを省略する入力もありません。そのため、この呼び出しが成功したのは、バンドルにマニフェストがなかったときだけです。これは ClawHub が警告するまさにその状態です。
公開は main に限定されています。公開ジョブは clawhub-publish 環境を通じてデプロイされます。この環境のデプロイブランチポリシーでは、ほかの ref は拒否されるため、フィーチャーブランチから手動で実行しても、アップロード前に停止します。CLAWHUB_TOKEN は環境シークレットではなく、リポジトリシークレットです。スキルの呼び出しではこれを upstream に渡し、upstream は clawhub_token として読み取ります。また、再利用可能なワークフローを呼び出すジョブでは環境を宣言できません。ジョブの出力を介して値を渡しても解決しません。GitHub はシークレット値を含む出力の出力を拒否し、Skip output 'clawhub_token' since it may contain secret と記録します。
コマンド 1 つで設定
add-mcp は、指定したクライアント(Claude Code、Cursor、VS Code、Claude Desktop、Codex、OpenCode、Zed など)にサーバーを登録します(npx add-mcp list-agents)。インデックスを作成するリポジトリ内で実行してください。
npx add-mcp @nithin554/code-crawler --args serve -a cursor
これにより、コードの隣にプロジェクト単位の設定ファイル(.mcp.json、.cursor/mcp.json、.vscode/mcp.json など)が書き込まれるため、各リポジトリに独自の登録情報と独自の .code-crawler/index.db が保持されます。サーバー名 code-crawler はパッケージ名から生成されます。
--env CODECRAWLER_DB は任意です。データベースを別の場所に置く場合のみ追加してください。例:--env CODECRAWLER_DB=/absolute/path/to/index.db。-g を指定すると、ユーザーレベルの設定が書き込まれます。これを使うのは、チェックアウト先を作業ディレクトリとしてサーバーを起動するクライアントに限ることをおすすめします。-g を指定し、チェックアウト先とは関係のない作業ディレクトリから起動した場合(Claude Desktop は独自のインストールフォルダーで起動します)、サーバーは ~/.code-crawler/index.db にフォールバックし、すべてのリポジトリで 1 つのファイルを取り合うことになります。
プロジェクトごとに1つのサーバー
プラグインモード以外では、サーバープロセスは起動時に1つのデータベースを開き、データベースには正確に1つのプロジェクトが格納されます。そのため、リポジトリごとに1つ登録する形になります。これは上記のプロジェクトごとの設定で実現できます。一方、プラグインのインストールでは、呼び出し時にプロジェクトごとのデータベースが解決されるため、開いたすべてのリポジトリで1つのプラグインを使用できます。リポジトリを再クロールする際は既存のファイルを再利用し、変更された部分のみを再解析します。 2つのリポジトリが同じファイルを共有することはないため、競合することはありません。同時に開いた状態にするプロジェクトデータベースは少数に限られ(アイドル状態のものは閉じられます)、クライアントが切断するとすべてのハンドルが解放されます。
MCP Registry / npx
このサーバーは、MCP Registry に io.github.nithin554/code-crawler として登録されています。
npx を利用できるクライアントなら、ローカルにチェックアウトせずに実行できます。
{
"mcpServers": {
"code-crawler": {
"command": "npx",
"args": ["-y", "@nithin554/code-crawler", "serve"]
}
}
}
Claude Desktop
claude_desktop_config.json:
{
"mcpServers": {
"code-crawler": {
"command": "node",
"args": ["/absolute/path/to/code-crawler/dist/index.js", "serve"],
"env": { "CODECRAWLER_DB": "/absolute/path/to/your/index.db" }
}
}
}
Cursor / その他の stdio MCP クライアント
クライアントに同じコマンドを指定します。LLM エージェントの一般的なワークフローは次のとおりです。
- リポジトリに対して
crawl_projectを一度実行します。 find_entry_pointsで、実際に実行が始まる場所(ルート、リスナー、メイン関数)を確認します。search_symbolsで、対象のシンボルを探します。get_callers/get_callees/trace_pathで、呼び出しグラフを分析します。trace_executionでランタイムのディスパッチとアスペクトアドバイスを追跡します。また、find_aspects、get_decorators、find_annotatedで、動作を変更するアノテーションを調べます。find_routes、find_injections、find_reflections、find_external_dependenciesで、フレームワークの配線とサードパーティとの接点を把握します。
タスク別の詳しい手順については、USAGE.md を参照してください。
MCP の機能
ツール
| ツール | 目的 |
|---|---|
crawl_project | ディレクトリをインデックス化します(冪等。データベースごとに 1 つのプロジェクト) |
index_status | ノード/エッジ/ファイル数と最終クロール日時 |
search_symbols | 名前または FQN であいまい検索します。種類による絞り込みも可能です |
get_node | 1 つのシンボルのメタデータとソース位置 |
get_callers | 直接または推移的な呼び出し元(深さを指定可能) |
get_callees | 直接または推移的な呼び出し先(深さを指定可能) |
trace_path | 2 つのシンボル間の静的な呼び出しパス(幅優先探索、最短パスから表示) |
trace_execution | 動的なトレース:静的呼び出し+仮想ディスパッチ+ウィーブされたアドバイス |
find_implementations | インターフェースまたはスーパークラスの実装クラス/サブクラス |
find_aspects | アスペクト、アドバイスの種類、ポイントカット、インターセプト対象のメソッド |
get_decorators | シンボルと、必要に応じてそのメンバーに付与されたアノテーション/デコレーター |
find_annotated | 指定されたアノテーションが付与されたすべてのシンボル |
find_hotspots | ファンイン、ファンアウト、アドバイスによるインターセプト数に基づくメソッドのランキング |
find_dead_code | 呼び出し/ディスパッチ/アドバイスのエッジが入っていないメソッド |
find_entry_points | フレームワークが呼び出すルート:HTTP ルート、リスナー、スケジューラー、CLI のメイン関数、テスト |
find_routes | HTTP ルート → ハンドラの対応付け(@GetMapping、NestJS、FastAPI、Express) |
find_injections | DI によって提供される依存関係(@Autowired、NestJS、FastAPI Depends) |
find_reflections | 実行時の検索:Class.forName、getattr、importlib、動的な import() |
find_external_dependencies | 参照数とファイル数を含むサードパーティーパッケージ |
find_unresolved | リゾルバーが紐付けられなかった呼び出し箇所。失敗理由ごとに分類 |
impact_analysis | 呼び出し元+エントリーポイント+ルート+オーバーライド+リスク区分を 1 回の呼び出しで取得 |
explain_symbol | メンバー、デコレーター、呼び出し元、呼び出し先、配線情報をまとめて取得 |
find_cycles | 呼び出しサイクル(SCC)と、サンプルの閉路パス、および直接再帰 |
export_graph | 近傍を Mermaid または Graphviz DOT 形式で出力 |
get_subgraph | 可視化のための近傍の抽出 |
get_schema | グラフモデルの説明 |
clear_index | データベースをリセット |
リソース:codecrawler://schema、codecrawler://status
プロンプト:trace-call-path(from, to)
トークン予算。 結果リストを返す 18 個のクエリツール、つまりペイロードが単一の結果リストであるすべてのツールは、max_tokens(100~200000)と cursor を受け付けます。いずれかを渡すと、totalCount、returnedCount、truncated、estimatedTokens、nextCursor を含む page ブロックが追加されます。どちらも省略した場合はレスポンスの形式は変わらないため、既存のクライアントも引き続き動作します。項目が残っている場合に空のページが返されることはないため、継続処理のループは必ず終了します。トークン数は JSON の長さ(トークンあたり約 4 文字)に基づく推定値です。トークナイザーへの依存はなく、モデル間で決定的です。
get_subgraph は例外です。nodes と edges は同じスライスを異なる形で表したものであり、一方のリストを分割すると、エッジが省略されたノードを参照してしまいます。そのため、代わりに radius と limit で上限を設定します。集約ツール(impact_analysis、explain_symbol、export_graph)と単一オブジェクトを返すツール(get_node、index_status、get_schema)は 1 つのオブジェクトを返すため、予算の指定は不要です。
エージェントスキル
サーバーはエージェントに「何」を呼び出せるかを伝え、スキルは「いつ」呼び出すかを伝えます。skills/code-crawler/
は npm パッケージに含まれており、プレーンな Markdown です。探索用の SKILL.md とクロール優先のワークフロー、27 個すべてのツールをそれぞれが答える質問に対応付けた reference/tools.md、および confidence、external、ファントムノードについて説明する reference/edge-semantics.md で構成されています。
npx skills add nithin554/code-crawler
skills CLI は規約に従ってこのスキルを見つけ、選択したエージェントにインストールします。npx skills update で更新できます。手動でインストールする場合は、ディレクトリをクライアントのスキルフォルダー(~/.claude/skills/code-crawler/、
.claude/skills/code-crawler/、またはプラグインの skills/ ルート)にコピーしてください。ビルド手順はありません。USAGE.md を参照してください。
tests/skill.test.ts は、スキルのツールテーブルと実際のレジストリを照合するため、ツールが追加されても差異が生じません。
グラフモデル
ノード — kind は file | package | module | class | interface | enum | method | constructor | field | import | external_symbol | aspect | annotation_type | annotation | unknown_symbol のいずれかです。すべてのノードはグローバルに一意な qualifiedName と、JSON の properties
blob(シグネチャ、修飾子、行番号、アノテーションなど)を持ちます。
エッジ — kind は CALLS | DECLARED_IN | CONTAINS | IMPLEMENTS | EXTENDS | IMPORTS | REFERENCES | DYNAMIC_DISPATCH | ADVISES | ANNOTATED_WITH | REFLECTS | INJECTS | ROUTES のいずれかです。CALLS エッジには line、resolved、confidence が含まれます。また、呼び出しが制御フローの背後にある場合は、conditional、controlFlow、guards も含まれます。ANNOTATED_WITH エッジには line と arguments が含まれます。ADVISES エッジには adviceKind と解決済みの pointcut が含まれます。INJECTS には injectedName と framework、REFLECTS には mechanism、REFERENCES には external が含まれます。
ID の規則:
| シンボル | 例 |
|---|---|
| 型 | com.acme.OrderService |
| メソッド | com.acme.OrderService#place |
| コンストラクター | com.acme.OrderService#<init> |
| フィールド | com.acme.OrderService$repo |
| アノテーション | @Transactional |
| インポート | __import__:java.util.List |
| 未解決の呼び出し | __unknown__:System.out.println |
| Python/TS モジュール | module:app.service |
| モジュールレベルの関数 | module:app.api#read_order |
| モジュールレベルのフィールド | module:app.service$AUDIT_LOG |
| インラインのアロー関数ハンドラー | module:src.routes#<anonymous@7> |
| 外部パッケージ | ext:fastapi |
| リフレクションマーカー | __reflect__:./plugins/${name} |
| インジェクションマーカー | __inject__:Repo |
動的な振る舞い
静的な呼び出しエッジは、「ソースコードで文字どおり何が呼び出されているか」に答えます。実行時の振る舞いは 2 つの点で異なり、どちらもクロールのたびに再構築される派生エッジとしてモデル化されます。
仮想ディスパッチ
インターフェイスまたは基底クラスのメソッドの呼び出しは、任意のオーバーライドを実行する可能性があります。すべてのファイルのインデックス作成後、解決済みの CALLS エッジのうち、ターゲットがオーバーライド可能なメソッドであるものに対して、プロジェクト内で見つかった各オーバーライドへの DYNAMIC_DISPATCH エッジが追加されます。
Checkout#checkout --CALLS--> Payment#pay
Payment#pay --DYNAMIC_DISPATCH--> CardPayment#pay
Payment#pay --DYNAMIC_DISPATCH--> UpiPayment#pay
コンストラクターおよび private/static/final メソッドはオーバーライドできないため、対象外です。候補の一覧表示には find_implementations を、候補をたどるには trace_execution を使用してください。
アスペクト、アドバイス、デコレーター
@Aspect 型は aspect ノードとしてインデックス化されます。アドバイスメソッドは
@Before、@After、@Around、@AfterReturning、@AfterThrowing、@Pointcut によって認識されます。
名前付きポイントカット(@Around("paymentCall()"))は対応する @Pointcut
式に解決され、その後、プロジェクト内のすべてのメソッドと照合されて ADVISES エッジが作成されます。
AuditAspect#auditPayment --ADVISES--> Payment#pay
AuditAspect#auditPayment --ADVISES--> CardPayment#pay
AuditAspect#auditPayment --ADVISES--> UpiPayment#pay
AuditAspect#beforeCheckout --ADVISES--> Checkout#checkout
trace_execution はこれらを INTERCEPT ホップとして織り込むため、トレースは次のようになります。
Checkout#checkout
INTERCEPT AuditAspect#beforeCheckout
CALLS Payment#pay
INTERCEPT AuditAspect#auditPayment
DYNAMIC_DISPATCH CardPayment#pay -> authorize
DYNAMIC_DISPATCH UpiPayment#pay -> settle
それ以外のすべてのアノテーションは、ANNOTATED_WITH エッジを持つ annotation ノードとしてインデックス化されます。
フレームワークのデコレーター(@Transactional、@Cacheable、@Async、@Retryable、
@PreAuthorize、@Scheduled など)には、さらに decorator: true のフラグが付与されるため、
get_decorators と find_annotated で実行時セマンティクスを持つアノテーションを取得できます。
Python のデコレーターと TypeScript のデコレーターも同じようにモデル化されます。@router.get(...)、
@injectable、@Controller(...)、@Get(':id') などは、宣言元の型またはメソッドの annotations に登録され、
フレームワーク関連のものはさらにルート、インジェクション、またはエントリーポイントのマークを生成します。
リフレクションと実行時の間接呼び出し
コンパイラーが追跡できないルックアップは REFLECTS エッジとして記録されます。ターゲットを静的に特定できる場合(文字列リテラル、リテラルのプレフィックスと変数の組み合わせ
(importlib.import_module("app.plugins." + name))、getattr(obj, "run")、
require("./x") など)は、エッジは解決済みのシンボルを指します。特定できない場合は、
mechanism を持つ __reflect__: マーカーを指します。
module:app.dynamic#load_plugin --REFLECTS--> __reflect__:app.plugins. (importlib.import_module)
module:src.dynamic#loadPlugin --REFLECTS--> __reflect__:./plugins/${name} (import())
プロジェクト独自の名前空間に属する動的なモジュールプレフィックスはプロジェクト内にとどまり、 実際に外部のパッケージだけが外部依存関係になります。
依存性注入
フレームワークが提供する依存関係は、呼び出しの欠落ではなく INJECTS エッジになります
(find_injections)。
| フレームワーク | 検出元 |
|---|---|
| Spring | @Autowired フィールド、メソッド、コンストラクター |
| NestJS | デコレーター付きのコンストラクターパラメーター、@Injectable() クラス |
| FastAPI | Depends(...) パラメーター |
| dependency-injector | @injectable クラスのコンストラクターパラメーター |
| plain TS/JS | プロジェクト内クラスの型が指定されたコンストラクターパラメーター |
プリミティブ型と構造型のパラメーター(string、{ id: string }、list[str])はカウントされますが、
エッジは生成されないため、@Body() body: { id: string } がグラフを不必要に増やすことはありません。
フレームワークのエントリーポイントとルート
フレームワークが呼び出すメソッドにはソースレベルの呼び出し元が存在しないため、これらにマークを付けることで、
デッドコード分析の正確性を保ち、trace_execution にルートを与えます(find_entry_points、find_routes)。
| 言語 | 認識されるもの |
|---|---|
| Java | @GetMapping、@PostMapping、@RequestMapping、@Scheduled、@EventListener、リスナーのアノテーション、テスト、main |
| Python | FastAPI(@router.get、@app.post、@router.websocket)、Flask(@bp.route、@app.get)、Quart(@bp.route)、if __name__ == "__main__"、pytest テスト |
| TypeScript | NestJS の @Controller + @Get/@Post/...、Express の app.get('/x', handler)、Jest テスト |
インラインで記述された Express ハンドラーには、合成メソッドノード
(module:src.routes#<anonymous@7>)が割り当てられるため、その本体にも呼び出しエッジ、包含関係、
ルートエッジが生成されます。
呼び出しエッジ上の制御フロー
各 CALLS エッジには、ガードされているかどうかが記録されます。
{
"kind": "CALLS",
"source": "app.repository.OrderRepository#create",
"target": "ext:builtins",
"properties": { "line": 14, "conditional": true, "controlFlow": ["branch", "loop"],
"guards": ["row.get(\"id\") == order_id", "self.rows"] }
}
controlFlow は branch | loop | exception | predicate を使用します。ガードはシンボル制約ではなくソーステキストです。
これにより、呼び出しが条件付きであることと、その条件がどのように記述されているかをエージェントに伝えますが、
条件の真偽値をモデル化しているかのように扱うことはありません。
解決時のヒューリスティック
Java:
- コンストラクター呼び出し(
new Foo(...))→Fooを解決 →#<init>(暗黙の場合はデフォルトコンストラクター)。 - 裸の呼び出し/
this./super.による呼び出し → 包含する型とそのスーパークラスの階層を検索します。 - 型修飾された呼び出し(
com.acme.Foo.bar)→ 型を直接解決します。 - インスタンス呼び出し(
x.method())→ ローカル変数 → パラメーター → フィールドの順にレシーバーの型を推論し、 その型と祖先を検索します。 - それ以外 →
resolved:falseのファントムunknown_symbolノードを作成し、推論に失敗した理由をエッジに付与します。
Python と TypeScript では、同じパイプラインにモジュールを考慮した解決処理を追加します。
- インポートを考慮したスコープ —
from app.repository import OrderRepositoryはローカル名をapp.repository.OrderRepositoryに対応付けます。相対モジュールとプロジェクトのモジュールはサフィックスで解決され、裸の指定子はパッケージルートにフォールバックします。 self.x/this.xは包含するクラスのフィールドに対して解決します。self/this/cls/superで始まるレシーバーが外部パッケージになることはありません。- ドット区切りのレシーバー(
service.repo.find)はセグメントごとにたどります。最初のセグメントは型に、次はその型のフィールドに解決されます。また、list.appendなどのコンテナーのメンバーは不明なものではなく、組み込みとして認識されます。 - ローカル変数は、パラメーター、型注釈付き代入、
new T()、および推論されたループ/変数の要素型から型付けされます(for row in self.rows:→row: dict)。 - モジュール関数(
module:app.api#read_order)は、クラスメソッドと同様にディスパッチ、ルート、エントリーポイントのマーキングに参加します。
解決された各エッジには confidence スコアと、人が読める reason のトレース(例:via local orders: OrderService)が付与されるため、LLM クライアントはその信頼度を判断できます。
実装済みの言語
| 言語 | 拡張子 | 抽出対象 | 動的機能 |
|---|---|---|---|
| Java | .java | パッケージ、クラス、インターフェース、列挙型、アノテーション、コンストラクター、メソッド、フィールド | 仮想ディスパッチ、AspectJ/Spring AOP のアドバイス、@Autowired、@RequestMapping ファミリー、Class.forName、ServiceLoader |
| Python | .py、.pyi | モジュール、クラス、関数、メソッド、フィールド、デコレーター | @injectable/Depends によるインジェクション、FastAPI/Flask/Quart のルート、getattr、importlib、__main__、テスト |
| TypeScript | .ts、.tsx、.mts、.cts | モジュール、クラス、インターフェース、型エイリアス、列挙型、メソッド、フィールド、アロー関数 | NestJS/Angular のデコレーター、DI コンストラクターインジェクション、NestJS/Express のルート、import()、require() |
| JavaScript | .js、.jsx、.mjs、.cjs | モジュール、クラス、関数、フィールド | デコレーター、Express のルート、require() |
ディレクトリをクロールすると、これらの言語はすべて自動的に混在して処理されます。言語はファイルごとに拡張子から選択され、1 回のクロールで languages: ["java", "python", "typescript"] を返すこともできます。
言語を追加するには、次の作業が必要です。
src/parser/languages/<lang>.ts—parseFileを実装するLanguageDescriptor(モジュール/パッケージの抽出、型/メンバーの抽出、生の呼び出し箇所、ローカル型テーブル)に加え、宣言的なフィールドを 3 つ用意します。resolver(処理を担当する呼び出しリゾルバー)、frameworks(パーサーが認識するフレームワーク)、fixture(適合性テスト用ディレクトリ)です。src/parser/languages/index.tsに行を 1 つ追加します。tests/language-conformance.test.tsのCONTRACTSテーブルに行を 1 つ追加します。これにより、テストスイートで新しい言語にも他のすべての言語と同じグラフ不変条件が適用されます。- 必要に応じて、
src/resolver/registry.tsを通じて公開するリゾルバーをsrc/resolver/に追加します。ほとんどの言語は共有のmoduleリゾルバーで動作し、言語固有の組み込み要素だけをオーバーライドします。 - まだ登録されていない、認識対象とするフレームワークを追加します。エントリーポイント、インジェクション、マーカーを宣言するモジュールを
src/parser/frameworks/に作成します。これはデータの変更であり、パーサーは編集しません。
フレームワークは、まずファイルごとにインポートの証拠に基づいて解決され、次にディスクリプターの frameworks の順序に従い、その後、登録済みのすべてのモジュールが対象になります。dependency_injector をインポートするファイルでは、その @inject 属性が該当フレームワークに割り当てられます。一方、そのようなインポートがない Java ファイルでも、アノテーションを失わないよう、レジストリへのフォールバックが行われます。パーサーでは、呼び出し形式のルートにおけるレシーバー名、パスの結合、エントリーポイントの詳細として記録されるテキストなど、構文に本質的な要素を処理します。
既存の言語モジュールを編集する必要はありません。src/crawler.ts のディスパッチはディスクリプターの resolver を参照するため、言語が条件分岐に登場することはありません。
グラフスキーマ、ストア、トラバーサルクエリ、MCP のサーフェスは、すべての言語で共通です。次に追加する候補の言語と、それぞれに必要なモデリングは、ROADMAP.md のフェーズ 3 に優先順位付きで記載されています。
モデル化されていない内容
以下の共通項目に加えて、言語固有の未対応項目があります。
| 言語 | モデル化されていない内容 |
|---|---|
java | record は record: true を持つ class としてインデックス化されます。コンポーネントはそれぞれ private final フィールドと合成アクセサーになりますが、暗黙の正規コンストラクターには、呼び出しが解決されるまでシグネチャが割り当てられません。ラムダ本体はインデックス化されますが、this::handle のようなメソッド参照には静的なターゲットがなく、呼び出しエッジは生成されません。static {} ブロックとインスタンス初期化子ブロックは抽出されません。ジェネリック型パラメーターは消去されるため、List<T> フィールド経由の呼び出しは、具体的な引数ではなく宣言された境界型にバインドされます。 |
python | メタクラス、ディスクリプター、__getattr__、__getattribute__ はモデル化されません。@dataclass の __init__ や __eq__、メタクラスが追加するものなど、デコレーターが生成するだけでコード上に記述されていないメンバーには、参照先となる宣言がないため、それらの呼び出しは未解決のままです。インポート時のモンキーパッチは追跡されません。属性に格納されて後から呼び出される lambda にはターゲットがありません。 |
typescript | namespace X {} ブロックはモジュールノードを生成しないため、その内部で宣言されたメンバーは名前で解決できません。JSX は問題なく解析されますが、要素ツリーはモデル化されません。型レベルの構文(条件型、マップ型、テンプレートリテラル型、交差型)は評価されないため、そのような型のレシーバーは未解決になります。static {} ブロックと accessor フィールドは抽出されません。 |
javascript | TypeScript パーサーで処理されるため、上記のすべての未対応項目が該当します。アノテーションがない場合、レシーバーの推論元は new、代入された初期化子、言語非依存のヒューリスティックに限られるため、動的型付けコードはアノテーション付きコードより解決されにくくなります。 |
設計上、まだモデル化されていない内容:
- 値の流れと分岐の実行可能性。エッジは呼び出しが条件付きであることを示し、ガードのテキストを記録しますが、どの分岐が選択されるかは示しません。
- リポジトリをまたぐ解決。クロール対象ツリーの外にあるライブラリはクロールせず、
ext:パッケージとして要約されます。 - 完全に動的なターゲット(
getattr(obj, name)、require(userInput))はシンボルではなく__reflect__:マーカーを指します。静的に参照できるものがないためです。 - コードではなく設定ファイルから組み立てられる、実行時の DI グラフ。
- 名前ではなく式からのレシーバー推論。
getService().run()、items[0].run()、三項演算子、キャストなどを含む呼び出しは未解決として報告されます。 - オーバーロードの選択では、まず引数の数を使用し、次に呼び出し箇所で型が明示されている各引数(リテラル、
new式、キャスト)の型を使用します。呼び出し側で区別できない2つのオーバーロード(f(count)に対するf(int)とf(String)など)は、引き続きソース順で最初の宣言にバインドされます。オーバーロードされた宣言は、最初の宣言以降、それぞれ異なる ID(Type#f、Type#f(int)、Type#<init>(String))を保持します。ID の方式についてはUSAGE.mdを参照してください。
未対応項目の全リストと、それぞれに対してモデル化される内容については、
USAGE.md を参照してください。
アーキテクチャ
src/
├── index.ts CLI (crawl | status | query | serve)
├── server.ts MCP server: tools, resources, prompt (thin handlers)
├── crawler.ts file discovery → parse → index → resolve → persist
├── config.ts env-overridable configuration
├── graph/
│ ├── schema.ts node/edge kinds, id scheme, property shapes
│ ├── store.ts better-sqlite3 schema + idempotent file-scoped upserts
│ └── queries.ts recursive-CTE traversal (callers/callees/path/subgraph)
├── parser/
│ ├── language.ts LanguageConfig / LanguageDescriptor contracts
│ ├── treeSitter.ts WASM runtime + grammar loading + CST walk helpers
│ ├── controlFlow.ts enclosing branch/loop/try/catch + guard text
│ ├── moduleId.ts import-aware module id derivation
│ ├── methodId.ts method id scheme (overload signatures, constructor ids)
│ ├── frameworks/
│ │ ├── types.ts FrameworkModule / FrameworkScope contracts
│ │ ├── index.ts registry + scope/entry-point/injection lookups
│ │ └── <framework>.ts one module per framework (spring, nestjs, fastapi, …)
│ └── languages/
│ ├── index.ts descriptor table + per-file language detection
│ ├── java.ts Java structural extraction
│ ├── python.ts Python structural extraction
│ └── typescript.ts TypeScript, TSX and JavaScript extraction
└── resolver/
├── types.ts TypeIndex (global name/method index) + Resolver contract
├── registry.ts resolver lookup, capability query, default fallback
├── common.ts builtin types, external packages, receiver inference
├── dynamic.ts virtual dispatch + AspectJ pointcut matching/advice edges
├── genericResolver.ts the `module` resolver (imports, barrels, overloads)
└── javaResolver.ts the `java` resolver (declared types, hierarchy, overloads)
ロードマップ
言語非依存のアーキテクチャ、対応言語の追加、解決精度の向上については
ROADMAP.md で追跡しています。直近の目標は、新しい言語の追加を1つのモジュールの変更で済ませることです。その後、この仕組みを利用して Go、C#、Kotlin を追加します。
ドキュメントサイト
docs/ にある静的ドキュメントサイトは、.github/workflows/pages.yml によって GitHub Pages にデプロイされています。クイックスタート、MCP ツールのリファレンス、実例を掲載しています。ローカルで docs/index.html を開くか、
https://nithin554.github.io/code-crawler/ にアクセスしてください。
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。