◉CLAUDE LABEN
●2.1.301 — vim の % モーション、VS Code パネルでの LaTeX 数式表示、使用量上限待ちのリトライ監視の上限が入りました(10/15)●2.1.299 — 200K トークン超で約54分放置した会話はアイドル圧縮。MCP の許可ルールは名指ししたサーバーだけに一致します●SONNET 4.5 — Claude API での提供終了は 11/30、残り44日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました●2.1.301 — vim の % モーション、VS Code パネルでの LaTeX 数式表示、使用量上限待ちのリトライ監視の上限が入りました(10/15)●2.1.299 — 200K トークン超で約54分放置した会話はアイドル圧縮。MCP の許可ルールは名指ししたサーバーだけに一致します●SONNET 4.5 — Claude API での提供終了は 11/30、残り44日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました
記事一覧/API & SDK
⬡ API & SDK/2026-05-20上級

Claude Agent SDK で複数 MCP サーバを束ねるときのツール名衝突 — 名前空間と動的調停の設計

GitHub MCP と Linear MCP の create_issue が同居したとき、Sonnet 4.6 はどちらを呼ぶか分かりません。複数 MCP を束ねる Claude Agent SDK アプリで踏むツール名衝突の構造、TypeScript で書ける Reconciler の実装、そして本記事に最初に載せた schemaHash が5種類のスキーマ変更を全て見逃していた実測と訂正までをまとめます。

Claude Agent SDK13MCP54TypeScript24本番運用36名前空間3

✦ プレミアム記事

GitHub MCP と Linear MCP を同じ Claude Agent SDK アプリに束ねた日、Sonnet 4.6 が「Linear のチケットを起票してください」というユーザー指示を受けて、迷わず GitHub Issues 側にチケットを作りました。両方の MCP サーバが create_issue という同じ名前のツールを公開しており、後から登録された GitHub MCP のスキーマで上書きされていたためです。原因が分かったのは、SDK のデバッグログにツール一覧をダンプしてからでした。

REST API を自前で束ねていた頃は、エンドポイントの URL が違えば呼び分けは自動的に決まっていました。MCP ではその手がかりが消え、モデルに渡るのはツール名と説明文だけになります。同じ意味の動詞が別々のサーバで重なる頻度は、体感でかなり上がりました。

その衝突を防ぐ名前空間の設計と、TypeScript で書ける動的調停(Reconciler)の実装を、ここに整理しておきます。あわせて、この記事に最初に載せた schemaHash の実装が壊れていたことに後から気づいたので、サンドボックスでの実測とともに訂正します。

ツール名衝突が起きる構造を分解する

Claude Agent SDK は MCP サーバから取得したツール一覧をそのまま tools 配列に渡すだけで、衝突検出を呼び出し側に委ねています。Anthropic Messages API のスキーマでは、tools 配列の name フィールドは「英数字とアンダースコア、ハイフン」しか許されておらず、同名のエントリが 2 つあったときに後勝ちになるか先勝ちになるかは実装次第です。SDK のソースを読むと、Map に詰め直す箇所で後勝ちになる実装が多く、結果として「先に登録したサーバのツールが静かに消える」という挙動になります。

モデル側から見れば、ツールは「name」「description」「input_schema」の 3 点でしか区別できません。同じ name の 2 つのツールが渡されていても、API リクエストの段階で 1 つに畳まれてしまうため、モデルには差異が伝わりません。description だけ違って name が同じ場合、モデルは「片方の description しか見ていない」状態でツールを選びます。これが先ほど GitHub に Linear のチケットが作られた事故の根本原因でした。

衝突の典型例は次のような並びです。

動詞候補となる MCP サーバ
create_issueGitHub MCP / Linear MCP / Jira MCP
searchNotion MCP / Slack MCP / Web Search MCP
uploadS3 MCP / Cloudflare R2 MCP / Stripe Files MCP
send_messageSlack MCP / Discord MCP / SendGrid MCP

私の手元でも、これらのうち 3 種類以上が同居するセッションは日常的に発生します。AdMob レポートを Slack に通知しつつ、GitHub に修正 PR を立て、Linear のチケットを閉じます。この程度の素朴なシナリオが、すでにツール衝突の温床です。

名前空間の付け方を 3 つの方式で比較する

衝突を解く方法はいくつかありますが、私が試したうえで本番に残したのは「サーバ識別子をプレフィックスとして付ける」アプローチです。検討した 3 案を比較します。

第 1 案は ドット表記 です。github.create_issue のようにドットで区切ると人間には読みやすい一方、Anthropic Messages API の name フィールドはドットを許容しないため、そのままでは 400 を返します。エスケープや代替文字へ変換する処理を挟むことになり、bidirectional に元の名前へ戻すマッピングが必要になります。

第 2 案は スラッシュ表記 ですが、これも name フィールドの制約で使えません。第 1 案と同じ問題に行き着きます。

第 3 案が 二重アンダースコア区切り です。github__create_issue / linear__create_issue のように、サーバ識別子と元のツール名を __ で繋ぎます。仕様で許される文字だけで構成され、モデルから見たときも「github 側の create_issue」「linear 側の create_issue」と読み下せます。私が Sonnet 4.6 と Haiku 4.5 で同じプロンプトを 50 回ずつ動かして比較したところ、二重アンダースコア方式が最も誤呼び出し率が低く、gh_ のような短縮プレフィックスより 7% ほど安定しました。短いプレフィックスは「gh」と「ghp」など別の意味と取り違えるリスクがあり、説明文に頼ることになるため、推奨しません。

実運用では、サーバ識別子をプレフィックスに使う際に次のルールを敷きました。

  1. プレフィックスは英小文字のみ。3〜10 文字に収めます
  2. 元のツール名は変更しません。プレフィックスを足すだけにします
  3. 衝突がなければプレフィックスを付けません。衝突したときだけ、そのツール名を持つ全エントリにプレフィックスを足します

3 番目が重要で、無条件にすべてのツール名を書き換えるとモデルが学習している慣用名(web_search 等)を変えてしまい、ツール選択精度が落ちます。衝突したサーバ群だけをスコープにプレフィックスを付けるのが、最もモデルに優しい設計です。

実は計測のセットアップ自体にも一工夫が必要でした。プロンプトを 50 回流すだけでは温度設定でゆらぐ結果が混ざるので、temperature: 0.0 で固定し、同じシステムプロンプトと同じユーザー指示を 50 回投げて誤呼び出し率を見ました。さらに、AdMob 関連の MCP 4 つ・GitHub 系 2 つ・Slack 系 1 つの計 7 サーバを束ねた状態で計測しないと、本番に近い「ツール 60 個前後」の負荷で何が起きるか見えません。本番の数字は手元の小規模実験よりも常に悪化方向にずれるので、計測条件は本番にできるだけ寄せておくのが結局のところ役に立ちます。

✦

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦GitHub MCP と Linear MCP の create_issue が衝突したときに Sonnet 4.6 が誤呼び出しを起こす実例と、原因が name か description のどちらに偏るかの観測結果
✦ツール名を二重アンダースコアで前置する Reconciler の TypeScript 実装と、双方向 alias map で元の MCP に呼び出しを逆引きするコード
✦本記事に最初に載せた schemaHash が JSON.stringify の replacer を誤用しており、型変更・プロパティ追加・改名など5種類のスキーマ差分を5件中5件見逃していた実測と、再帰的な正規化による修正版の実装
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

⬡ API & SDK2026-05-04
Bun × Claude API で本番運用するエッジAIサービス — Node.js移行の判断軸と落とし穴を回避する実装パターン
Claude APIをBun上で本番運用するための実装ガイド。Node.jsからの移行判断軸・組み込みSQLite/WebSocketの活用・ストリーミング最適化・典型的な落とし穴の回避策まで、動作するコードと実測値で解説します。
⬡ API & SDK2026-09-21
非推奨の通知が出た朝、設定を書き換える前にバージョンを確かめた話
Claude Desktop / Cowork の管理構成キーが 10 月 7 日に受付終了します。先に書き換えると壊れるもの、触らなくても意味が変わるものを仕分ける手順を書き残します。
⬡ API & SDK2026-08-19
サーバーレスに置いた MCP サーバーで、listen ストリームが張り直され続けていました
エラーは何も出ていないのに、MCP サーバーへの接続だけが増え続ける。固定タイムアウトで切られるストリームと再購読が噛み合ったときの挙動を、最小の再現コードで確かめました。