Issue #24246 を開いたのは、MCP サーバーを 5 つ目まで足した夜でした。タイトルには「128 を超えると 400」とあり、本文には「400 を超える」とあります。同じページの中で数字が食い違っているのです。
最初にお伝えしたいのは、この上限の正体は、私が確認できた範囲では公式ドキュメントに書かれていないということです。Issue は 2026 年 3 月に立ち、私が読んだ時点でも open のまま、エラー本文や再現手順も添えられていませんでした。
それでも、手を打つ価値はあります。数字が確定していなくても、「ツールが増えるほど失敗に近づく」という方向だけは、原因の切り分けに使えるからです。
まず、いま何本載っているかを知る
/mcp を実行すると、サーバーごとの CONNECTED の状態と、読み込まれたツールの一覧が出ます。ここで全部を数えるのは骨が折れます。しかも、includeTools を書いていないサーバーは、そのサーバーが持つツールがすべて載ります。
ドキュメントには、ツール名が mcp_{serverName}_{toolName} の形になり、63 文字を超えると途中が ... で省略されること、同名になった場合は後から登録されたほうが前のものを上書きすることも書かれています。本数が増えるほど、名前の衝突も起きやすくなります。
私は最初、このあたりを読まずに「サーバーを足せば便利になる」とだけ考えて、コード検索、ドキュメント検索、Issue 管理と、思いつくままに登録していました。結果は芳しくありませんでした。何が原因で止まったのか、どのサーバーを外せば直るのかが、分からなくなったのです。いま思えば、足す前に数えておくべきでした。
includeTools で「このタスクの持ち物」を決める
公式ドキュメントでは、includeTools を書くと「そのサーバーから載るのはここに挙げたツールだけ」になり、excludeTools は includeTools より優先される、とされています。両方に同じ名前があれば、除外が勝ちます。
.gemini/settings.json は、たとえば次のようになります。
{
"mcpServers": {
"repo": {
"command": "npx",
"args": ["-y", "YOUR_REPO_MCP_SERVER"],
"includeTools": ["search_code", "read_file", "list_commits"],
"excludeTools": ["delete_branch"]
},
"tracker": {
"httpUrl": "https://example.com/mcp",
"includeTools": ["get_issue", "add_comment"]
}
}
}このブロックは「何を解決するか」を一言で言えば、読むだけの作業に、書き込みのツールを持ち込まないことです。書き込み系を最初から外しておくと、本数が減るだけでなく、確認ダイアログを押し間違える余地も減ります。
サーバー名にアンダースコアは使わないようにしてください。ドキュメントによると、ポリシーの解析が mcp_ の後の最初のアンダースコアで分割されるためです。my-repo のようにハイフンにしておけば迷いません。
本数を予算にして、設定ファイルのまま数える
/mcp の画面を目で数える代わりに、設定ファイルから数えます。次のスクリプトは、includeTools に書いた本数から excludeTools を引いて合計し、予算を超えたら、あるいは includeTools を書いていないサーバーがあれば、終了コード 1 で知らせます。
#!/usr/bin/env python3
"""settings.json の mcpServers を読み、includeTools の本数を予算と突き合わせる。"""
import json, sys
BUDGET = 40 # 手元で決めた上限。公式の上限値ではありません
def count(path: str) -> int:
with open(path, encoding="utf-8") as f:
servers = json.load(f).get("mcpServers", {})
total, unknown = 0, []
for name, cfg in servers.items():
inc = cfg.get("includeTools")
if inc is None:
unknown.append(name) # includeTools なし = 全ツールが載る
continue
n = len([t for t in inc if t not in cfg.get("excludeTools", [])])
print(f"{name:<20} {n:>3} 本")
total += n
for name in unknown:
print(f"{name:<20} 全部入り(本数不明)")
print(f"確定分の合計 {total} 本 / 予算 {BUDGET} 本")
return 1 if (unknown or total > BUDGET) else 0
if __name__ == "__main__":
sys.exit(count(sys.argv[1] if len(sys.argv) > 1 else ".gemini/settings.json"))このスクリプトは、手元で小さなサンプル設定を渡し、本数の集計と終了コードが想定どおりになることを確かめています。予算の 40 は、公式の数字ではなく、私が自分の作業のために置いた線です。 上限が確定したら、この一行だけ書き換えれば足ります。
「本数不明」を失敗扱いにしているのは、意図的です。includeTools を書いていないサーバーこそ、本数を勝手に増やす張本人になりやすいからです。
タスクごとに設定を差し替える
もう一歩進めて、作業の種類ごとに設定ファイルを分けておきます。たとえば profiles/review.json と profiles/triage.json を用意して、作業を始める前に、プロジェクトの設定へコピーします。
#!/usr/bin/env bash
# 使い方: ./use-profile.sh review
set -euo pipefail
name="${1:?profile 名を指定してください}"
src="profiles/${name}.json"
[ -f "$src" ] || { echo "見つかりません: $src" >&2; exit 2; }
mkdir -p .gemini
cp "$src" .gemini/settings.json
python3 mcp_budget.py .gemini/settings.jsonコピーの直後にスクリプトを走らせるので、予算を超える設定は、起動する前に気づけます。「止まってから原因を探す」のではなく、「止まる前に数える」順番に変えるわけです。
なお、セッションの途中で設定を差し替えたあとは、CLI を起動し直してからお試しください。MCP の読み込みが走るのは起動時だからです。起動時のエラーは、既定では表に出ません。MCP issues detected. Run /mcp list for status. という案内が出たら、/mcp list を開くのが先です。
それでも 400 が出たときの順番
予算の中に収まっていて、それでも 400 が返るなら、本数以外を疑います。
/mcp listで、DISCONNECTED のサーバーがないか見ます- 直前に足したサーバーを 1 つずつ
mcp.excludedに入れて、再現するか確かめます - 同じ作業を、サーバー 1 つだけの設定で行います
- それでも再現するなら、Issue にエラー本文と本数を添えて報告します
同じ「止まる」でも、モデル名の間違いが原因のことがあります。その切り分けは Gemini API で 404 と 429 が同時に出たとき、最初にモデル名を確かめる にまとめました。失敗の種類を型で分けて受け止めたいときは、例外にならない失敗を型で閉じる も参考になります。
Issue #24246 には、まさにエラー本文と再現手順が足りていません。もしお手元で再現した方がいらっしゃれば、本数とモデル名を添えていただければ、次に読む誰かの助けになるはずです。
持ち物は、サーバー単位ではなく作業単位で決めます。 便利そうだから足すのをやめて、今日の作業に要るものだけを持つ——この線引きだけは、これからも守っていくつもりです。
次の一歩として、まず /mcp を開き、includeTools を書いていないサーバーを 1 つだけ選んで、使っているツール名を絞ってみてください。