本文へスキップ
nomunomu0504.dev

BLOG #MCP

Forecall: MCP ツールの説明文を採点するリンターを作って分かったこと

目次

きっかけ

MCP サーバーをいくつか作って使ううちに、エージェントがツールを選び間違える、引数の形を間違える、という場面に何度も出会った。モデルが見ているのは tools/list が返す名前と description と inputSchema だけだ。つまりツール説明の書き方が、そのまま呼ばれ方になる。それなのに、説明文を lint する道具がなかった。

forecall.dev のトップページ
forecall.dev。filesystem サーバーの list_directory_with_sizes は 48 点、list_directory は 38 点

公開サーバーを採点してみた

まず、よく知られた MCP サーバー 8 つ、計 126 ツールを同じ物差しで採点した。平均点はサーバーごとに 33 から 70 の間に散った。Notion の公式サーバーだけで、説明がほぼ同じツールのペアが 57 組あった。

公開 MCP サーバーの採点結果
採点した 8 サーバーのうち 3 つ。70 点以上が clear、40〜69 が cloudy、40 未満が rain

典型例は filesystem サーバーの list_directory と list_directory_with_sizes で、説明の類似度は 0.86。どちらも「何をするか」は書いてあるが、「どちらをいつ使うか」がどこにもない。エージェントから見ればコイントスになる。この 2 つについては、書き換え案を添えて modelcontextprotocol/servers#5071 として報告した。

リンターの採点

採点は 6 観点で 100 点満点にした。

観点 配点 見ているもの
目的 20 名前の言い換えになっていないか、短すぎないか
使いどころ 20 いつ使うか、いつ使わないか、代わりに何を使うか
引数 25 各引数の説明、文字列の制約や例、required
戻り値 15 何が返るか
制約と副作用 10 認証、レート制限、副作用、annotations
例 10 具体的な呼び出し例

ツール単位の指摘とは別に、サーバー全体の問題を出す。ツールが多すぎる、説明がほぼ同一、説明を共有している、の 3 つ。これを分けないと「近い説明がある」という指摘が全ツールに付いてノイズになる。

採点ルールはバージョン管理している(いま v2)。どれかの入力の点数や指摘を変えうる変更はバージョンを上げ、fixture の期待値を更新する。CI のゲートに使う人がいるので、点が黙って動くのがいちばん困る。

npx forecall dump -o tools.json -- node build/index.js   # 自分のサーバーから tools/list を取る
npx forecall lint tools.json                              # 採点する。何も送信しない
Forecall lint pipelineyour MCP servertools/liststdio or remoteforecall dumptools.jsonnames, descriptions,inputSchemaforecall lintscore per tool0–100 + findingsrules v2 · offlineWHAT THE RULES LOOK AT · 100 POINTS20purpose20when to use25arguments15returns10constraints10examplesserver-level findings: too many tools · near-identical · shared descriptions
dump で tools/list を取り、lint で採点する。採点は手元で完結し、何も送信しない

@forecall/lint は依存ゼロでネットワークにも出ない。GitHub Action forecall/forecall-cli@v1 を置くと、PR ごとに採点してジョブサマリーに出し、min-tool-score や fail-on で落とせる。

リンターの先

静的な点数と、実際のモデルがそのツールを選ぶかどうかは別物だ。そこで 2 つ足した。

評価。 ツールごとに「いちばん大きいファイルを探して」のような依頼を用意し、Claude、GPT、Gemini に実際に選ばせて呼ばせ、正しいツールを正しい引数で呼べた割合を測る。干渉用に公開サーバーの tools/list を横に置く。

Failure KB。 MCP ツール呼び出しの既知の失敗と回避策を、エージェントが呼ぶ前後に引ける MCP サーバー。あるエージェントが報告した失敗は、別の 2 チームのエージェントが再現して初めて verified になる。Streamable HTTP のリモートサーバーなので、stdio でしかサーバーを起動できないクライアントには forecall-mcp という小さなリレーを用意した。

静的な点と実測が本当に相関しているかは、同じケース生成と呼び出しを使う較正ツールで測り続けている。点が高ければ選ばれる、とは限らない。

作り

全部 Cloudflare Workers に載せた。API は Hono、公開サイトとダッシュボードは React Router v8、評価は Workflows で 1 インスタンスが 1 スイートを回し、回数制限は Durable Object。DB は Neon の Postgres(pgvector)を Hyperdrive 経由で、各社の LLM は AI Gateway 経由で呼ぶ。リンターと CLI だけ公開リポジトリ forecall/forecall-cli に切り出し、本体は npm に出た版を固定して使っている。

学び

  • 「ほぼ同一の説明」はツールの問題ではなくサーバーの問題。指摘の単位を間違えると直す気が失せる
  • 採点ルールのバージョンは成果物の一部。変えたら言う
  • 最初の採点規則は調査用の Python スクリプトだった。8 サーバーの採点結果を fixture に固定してから TypeScript に移植し、v2 からはそちらを正にした。移植の正しさは fixture が担保する

forecall.dev で JSON を貼れば、登録なしで採点結果のページが作れる。

  1. spendctl: 支払う AI エージェントに「法人カードと経費規程」を持たせる 5 min
  2. hidane: Java なしで動く Firestore エミュレータを Rust で作った 7 min
Hiroki Nomura @nomunomu0504 · CTO, MIRAI STUDIO

Flutter / AWS / 自宅サーバー。個人開発と OSS をいくつか。設計相談や協業の話は X の DM か About から。 About

COMMENTS · GISCUS