Tree-sitter+MCPでレビュートークンを8〜49倍削った実測: コードベースは既に巨大なグラフだった
「AI コードレビューが毎回リポジトリ全体を舐めてトークンの 80% を食う」問題を、Tree-sitter で AST に切り分けて MCP ツール経由で渡すように書き換えたら、削減幅が 8 倍のケースと 49 倍のケースの両方が出ました。両方本当の数字で、最初は自分の計測スクリプトのバグを疑って 3 回叩き直したうえでの結果です。
平均値で語ると誤解を招くので、タスク種別ごとに分解します。私が過去 3 週間で計測した 30 本の PR の結果です。
8 倍と 49 倍の間に何が起きているか
タスク種別別の削減倍率を並べます。列は「全ファイルを Anthropic 公式 filesystem MCP で渡していた頃のトークン量 ÷ Tree-sitter で刈った後のトークン量」、つまり「何倍節約できたか」。
| タスク種別 | PR 数 | 平均削減倍率 | 特徴 |
|---|---|---|---|
| 小規模 refactor(単一関数のリネーム系) | 8 本 | 49x | 影響を受けるのは blast radius 内の 5-15 関数のみ |
| N+1 SQL fix(ORM の eager loading) | 4 本 | 32x | 呼び出しチェーン + テスト + マイグレーション |
| type refactor(共通型の追加・変更) | 6 本 | 18x | 型を import している全ファイル + テスト |
| API endpoint 追加(ルーティング + handler + テスト) | 5 本 | 12x | 関連 middleware + 認可 + fixtures を辿る必要 |
| microservice 間境界の変更(protobuf 修正) | 4 本 | 8x | 全サービスの schema import 箇所を横断 |
| 全体アーキ変更(DI コンテナ差し替え) | 3 本 | 1.4x | ほぼ全ファイルを触るので、そもそも刈れない |
真ん中付近が 12-18 倍で落ち着いていて、両端に外れ値がある形です。刈り込みが効くのは「変更の影響範囲がコードベース全体の一部分に閉じている」ケースで、閉じていないほど倍率は 1 に近付きます。当たり前の話ですが、実測すると「じゃあ何倍まで落とせるか」の期待値が具体的になります。

「毎回 80% トークン喰う」の内訳
Tree-sitter に置き換える前の私の構成は、Claude Code に Anthropic 公式の filesystem MCP サーバを繋いで、レビュー対象の PR を read_multiple_files で丸ごと読ませていました。中規模リポ(Python + TypeScript、約 300 ファイル、6.8 万行)で 1 レビューあたり平均 118,000 トークン。その内訳がこうです。
- 変更ファイル本体: 約 8,000 トークン(6.8%)
- 変更ファイルが import している依存ファイル群: 約 46,000 トークン(39%)
- テストファイル(関連しそうなもの全部): 約 38,000 トークン(32%)
- 設定・型定義・スキーマ: 約 26,000 トークン(22%)
「変更ファイル本体」に相当する 6.8% 以外は、レビューの判断のために「たぶん要る」ファイルをまとめて詰めていたぶんです。合計 93.2% が「保険で読ませた」トークンで、そこにモデルの注意が薄く広がって、肝心の変更差分に対する指摘の質が下がります。middle-lost problem の教科書事例をやっていました。
Tree-sitter で何を刈れるようになるか
Tree-sitter は Max Brunsfeld らが Atom の構文解析基盤として開発したパーサジェネレータで、公式のツリーは 23 言語の grammar を保守しています。コミュニティ拡張の tree-sitter-language-pack まで含めると 306 言語超。私の実務では Python / TypeScript / Go / Rust / Java / Ruby の 6 言語しか使わないので、公式 23 で完全に足りています。
AST を取り出せるだけなら Tree-sitter でなくてもよくて、LSP や ctags でも近いことはできます。Tree-sitter を第一選択にしたのは 3 つの実務的な理由でした。
1 つ目、19 言語超に同一 API で AST 抽出できる基盤が他にありません。ast-grep もこの層に乗っています。 2 つ目、構文エラーを含むコードでも部分 AST を返します。PR ブランチが未完成で壊れていてもレビューは進みます。 3 つ目、インクリメンタルパース対応。差分ビルドが数百 ms で回ります。
3 つ目が地味に効きます。私の 6.8 万行リポでフル AST 抽出は約 4 秒、差分だけなら約 200 ms。CI で PR フックに埋め込んでも遅延になりません。
MCP ツールの粒度を 5 本に絞る
MCP(Model Context Protocol) 経由で Tree-sitter が抽出したグラフを Claude Code に露出させる部分は、ツール数の設計が全部でした。CodeGraph の 22 ツールをそのまま模倣したときは Claude Code が呼び出し先を選び切れず、同じ質問に対して blast_radius と get_callers を二重に叩いたり、search_symbols で済むものに get_function を挟んだりして、逆にトークンが増えました。
5 ツールまで削ったら選択精度が安定しました。
@tool
async def get_function(name: str) -> dict:
"""関数のシグネチャ、行範囲、所属クラスを返す"""
@tool
async def get_callers(name: str, max_hops: int = 1) -> list:
"""指定関数の呼び出し元 1 階層。設計判断より軽い質問向け"""
@tool
async def blast_radius(name: str, max_hops: int = 3, min_confidence: float = 0.8) -> dict:
"""変更影響範囲。hop 距離で groupby した dict を返す"""
@tool
async def search_symbols(query: str, kind: str = "function|class") -> list:
"""シンボル横断検索。fuzzy 対応"""
@tool
async def get_file_summary(path: str) -> dict:
"""ファイル単位の関数・クラス・import 一覧。ファイル全読み込みの代替"""
5 本で PR レビュー質問の 8 割は捌けます。残り 2 割はget_tests_callingやget_complexityを追加していけば良い、というのが今のところの結論。命名で意図を区別することが、AI 側での選択エラーを一番減らします。
49 倍が出た PR の話
一番削減率が高かった PR は、Django の 1 メソッドをリネームするだけの変更でした。差分は 3 行。全ファイル方式では 128,000 トークンを消費して、Tree-sitter+MCP 方式では 2,600 トークンで済んだので、比率としては 49.2 倍。
Tree-sitter+MCP 側で何が呼ばれたかログを見ると、こう並んでいます。
get_function(name="UserRepository.find_by_email")- 変更前のシグネチャ確認blast_radius(name="UserRepository.find_by_email", max_hops=3)- 影響範囲 12 関数 + 関連テスト 4 本search_symbols(query="find_by_email")- 文字列参照の残存確認
必要な情報だけ取って、必要ないファイルは開きません。人間のシニアレビュアーが blame と grep で同じ判断をするときの動きに近くて、当たり前と言えば当たり前です。
一方で 8 倍しか出なかった microservice 境界の PR は、7 サービスの schema import を全部辿る必要があって、blast_radius の結果集合がもともと大きくなります。構造で刈るのが効きにくい形をしています。ここで「49 倍出るはず」と期待して構造を無理に絞ると、レビュー精度が落ちます。倍率は目的ではなく結果です。
追試手順
私の構成を最小で再現する場合、以下の順で組みます。
pip install tree-sitter tree-sitter-pythonで 1 言語だけ AST 抽出を走らせて、__str__で S 式が返ることを確認nx.DiGraphに function/class をノード、call/import をエッジとして 500 行程度で書く(初手は Neo4j や Kuzu を使わなくていい)- FastMCP で上記 5 ツールを露出、Claude Code の
settings.jsonに MCP サーバとして登録 - 直近 5 本の PR で
claude -p "review this PR"を実行して、トークン消費量を旧構成と比較
私の実測は Python + TypeScript の 2 言語、初期グラフ構築が 500 行未満で組めました。手が動きやすい規模です。
コードKG実装ガイド: Tree-sitter+MCP+Kuzu で AI コードレビューを 8-49 倍削る本 では、上記 5 ツール実装から 22 ツールへの拡張、Kuzu へのグラフ移行、GitHub Action への埋め込みまでを 15 章で扱っています。
まとめ
- Tree-sitter + MCP でのトークン削減は 8-49 倍のレンジで散る。倍率は変更の影響範囲の広さに反比例
- 「変更ファイル本体は 6.8%、残り 93.2% は保険」という状態が、そもそも middle-lost problem を招いている
- MCP ツール数は 5 本から始める。CodeGraph の 22 ツール構成は選択エラーで逆にトークンが増えた
- 追試は 500 行未満で組める。Python + Tree-sitter +
nx.DiGraph+ FastMCP の 4 部品で足りる
私は knowledge-graph 本を書いていて、これに触れ続けている手前バイアスがあります。ただ 30 PR で計測してから、Anthropic 公式 filesystem MCP で全ファイル読ませる構成には戻れなくなりました。倍率の中央値が 15 倍前後というだけでも、月額 API 費が二桁削れる規模の話です。
関連記事
- Knowledge Graph でコードレビューを 91% 削った実測(30 PR) - 本記事の姉妹編、削減率の別角度からの検証
- コード Knowledge Graph 実践ガイド - 15 章の実装本
関連書籍 ナレッジグラフ活用大全 ナレッジグラフ 活用大全 | GraphRAG・Neo4j・RDF・Property Graph・Emotion AI の実践書 書籍ページを見る → この記事は役に立ちましたか?