GEMINI LABEN
V0.60.0 — gemini-cli の安定版は v0.60.0 のままです。中身は web fetch の宛先検証や MCP OAuth の issuer 検証など、ほとんどがセキュリティ修正でした9/30 — gemini-omni-flash-preview が9月30日に止まります。残り9日。置き換え先は gemini-omni-1.1-flash ですCODE13 — 同じ動画を続けて上げると、成功と code 13 の失敗が交互に返るという報告が出ています。再現条件が見えないため、再試行の設計を決めておきたいところですNEW — Gemini アプリの画像機能を分ける、13歳・18歳・管理者という三本の線2.5GA — Gemini 2.5 の Pro・Flash・Flash-Lite は、いまも shutdown date が公表されていません。廃止表の表記は No shutdown date announced のままです3.8FLASH — Gemini 3.8 Flash の価格は導入価格です。2026年12月31日までで、2027年1月1日から入力も出力も倍になりますV0.60.0 — gemini-cli の安定版は v0.60.0 のままです。中身は web fetch の宛先検証や MCP OAuth の issuer 検証など、ほとんどがセキュリティ修正でした9/30 — gemini-omni-flash-preview が9月30日に止まります。残り9日。置き換え先は gemini-omni-1.1-flash ですCODE13 — 同じ動画を続けて上げると、成功と code 13 の失敗が交互に返るという報告が出ています。再現条件が見えないため、再試行の設計を決めておきたいところですNEW — Gemini アプリの画像機能を分ける、13歳・18歳・管理者という三本の線2.5GA — Gemini 2.5 の Pro・Flash・Flash-Lite は、いまも shutdown date が公表されていません。廃止表の表記は No shutdown date announced のままです3.8FLASH — Gemini 3.8 Flash の価格は導入価格です。2026年12月31日までで、2027年1月1日から入力も出力も倍になります
記事一覧/開発ツール
開発ツール/2026-09-21中級

つないだ MCP を初めて外した日 — 常時有効にするツールを選ぶ基準

MCP サーバーを足し続けると、API の上限である 512 個の関数宣言に当たる手前で応答の質が落ちます。Gemini CLI の includeTools と excludeTools を使い、常時有効にするツールを選ぶ基準と外し方をまとめます。

Gemini CLI9MCP5ツール設計個人開発119settings.json

MCP サーバーを一つ外したのは、つなぎ始めてから初めてのことでした。

きっかけは、Lab のサイト運用を Gemini CLI に手伝ってもらっていた夜です。ファイルの整理を頼んだはずが、返ってきた関数呼び出しには身に覚えのない引数が混ざっておりました。別のサーバーが持っているツールのパラメータです。API からは 400 が返り、頼んだ処理とは何の関係もない「そのプロパティは文字列でなければならない」という文言だけが残りました。

設定ファイルを開いて、私は少し手が止まりました。便利そうなサーバーを見つけるたびに mcpServers へ足してきたのですが、外した記録が一件もありません。足す手順は自分の中に出来上がっていて、減らす基準だけが無かったのです。

最初にお伝えしたいのは、気にすべき数字は公式が定める上限そのものではない、ということです。上限に当たるより先に、応答の質のほうが落ちます。

512 という上限は、壊れ始める場所ではありません

Gemini API には、1 リクエストに載せられる関数宣言の数にはっきりした上限があります。超えると、モデルが動き出す前にリクエストごと弾かれます。

[API Error: [{
  "error": {
    "code": 400,
    "message": "The GenerateContentRequest proto is invalid:\n  * tools[0].function_declarations: [FIELD_INVALID] At most 512 function declarations can be specified.",
    "status": "INVALID_ARGUMENT"
  }
}]]

これは gemini-cli の Issue #19083 として報告されている挙動で、報告者は MCP サーバーを 20 台以上つないだ状態で踏んでいます。エラーは即座に返り、途中まで進んで失敗するわけではありません。その意味では、まだ親切な壊れ方です。

やっかいなのは、その手前で起きるほうです。188 個のツールを持つサーバーを 1 台つないだ事例では、ログイン用のツールを明示的に呼んだにもかかわらず、まったく別のツールのパラメータが引数へ紛れ込み、やはり 400 になりました。上限の 512 には遠く届いていません。私が踏んだのも、おそらくこちら側です。

ツールの説明文は、モデルにとってはどれも似た形の候補です。候補が増えるほど、どれを呼ぶか・どの引数を渡すかの判断は曖昧になります。上限は API が決めますが、使ってよい数は自分で決めます。 公式の MCP サーバー設定ドキュメントには接続方法とフィルタの書式が丁寧に載っていますが、何個までにすべきかという目安は書かれておりません。そこは自分で埋める部分なのだと、私は受け取りました。

つないだツールを、まず数えます

減らす前に、いま何個あるのかを知る必要がありました。/mcp はサーバーごとのツール名を並べてくれますが、合計を教えてはくれません。そこで、設定ファイルに並んだ stdio 版のサーバーへ順につないで数えるだけの小さなスクリプトを書きました。

#!/usr/bin/env python3
"""~/.gemini/settings.json の stdio 版 MCP サーバーへ順に接続し、公開ツール数を数えます。
 
使い方:  python3 count_mcp_tools.py
出力:    サーバー名 / ツール数 / 名前が長すぎるツールの件数 / 合計
"""
import json
import os
import subprocess
from pathlib import Path
 
SETTINGS_PATH = Path.home() / ".gemini" / "settings.json"
PROTOCOL_VERSION = "2025-06-18"  # サーバーは自分が話せる版を返してきます
 
 
def rpc(proc, payload):
    """JSON-RPC を1行書き、id の一致する応答が来るまで読みます。"""
    proc.stdin.write(json.dumps(payload) + "\n")
    proc.stdin.flush()
    if "id" not in payload:
        return None
    while True:
        line = proc.stdout.readline()
        if not line:
            raise RuntimeError("応答を返す前にサーバーが終了しました")
        try:
            msg = json.loads(line)
        except json.JSONDecodeError:
            continue  # 標準出力へログを吐くサーバーがあるため読み飛ばします
        if msg.get("id") == payload["id"]:
            return msg
 
 
def list_tools(conf):
    env = dict(os.environ)
    env.update({k: os.path.expandvars(v) for k, v in conf.get("env", {}).items()})
    proc = subprocess.Popen(
        [conf["command"]] + conf.get("args", []),
        stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
        cwd=conf.get("cwd"), env=env, text=True, bufsize=1,
    )
    try:
        rpc(proc, {"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {
            "protocolVersion": PROTOCOL_VERSION,
            "capabilities": {},
            "clientInfo": {"name": "tool-counter", "version": "0.1.0"},
        }})
        rpc(proc, {"jsonrpc": "2.0", "method": "notifications/initialized"})
        res = rpc(proc, {"jsonrpc": "2.0", "id": 2, "method": "tools/list"})
        return [t["name"] for t in res.get("result", {}).get("tools", [])]
    finally:
        proc.terminate()
        try:
            proc.wait(timeout=5)
        except subprocess.TimeoutExpired:
            proc.kill()
 
 
def main():
    servers = json.loads(SETTINGS_PATH.read_text()).get("mcpServers", {})
    total = 0
    for name, conf in sorted(servers.items()):
        if "command" not in conf:
            print(f"{name:22} url 接続のため数えません")
            continue
        try:
            tools = list_tools(conf)
        except Exception as err:
            print(f"{name:22} 取得できませんでした: {err}")
            continue
        total += len(tools)
        # 実際に渡る名前は mcp_{サーバー名}_{ツール名} で、63 文字を超えると途中が詰められます
        long_names = [t for t in tools if len(f"mcp_{name}_{t}") > 63]
        note = f"  名前が 63 文字超: {len(long_names)} 件" if long_names else ""
        print(f"{name:22} {len(tools):4}{note}")
    print(f"{'合計':22} {total:4} 個  (API 上限 512 個)")
 
 
if __name__ == "__main__":
    main()

initialize を送ってから notifications/initialized を挟み、そのうえで tools/list を呼ぶ——MCP の stdio 接続はこの順番が決まっております。標準出力へ起動ログを流すサーバーが混ざっていたため、JSON として読めない行は黙って飛ばすようにしました。ここを厳密にすると、数えたいだけなのに例外で止まります。

63 文字の判定を入れたのは、ツール名がそのまま渡るわけではないからです。Gemini CLI は衝突を避けるために mcp_{サーバー名}_{ツール名} という完全修飾名を割り当て、63 文字を超えると中ほどを詰めて短くします。名前が似ているツールが並んでいると、詰められた結果さらに見分けがつきにくくなります。

数えてみると、私の手元は上限の 512 には遠く及びませんでした。それでも、自分が把握している数よりはるかに多い、というのが正直なところでした。

includeTools は「残すもの」を書く場所です

Gemini CLI には、サーバー単位でツールを絞る設定が二つ用意されています。includeTools は許可リストで、書いたツールだけが有効になります。excludeTools は拒否リストで、書いたツールが消えます。何も書かなければ、そのサーバーのツールは全部が有効です。

{
  "mcpServers": {
    "site-ops": {
      "command": "npx",
      "args": ["-y", "@example/site-ops-mcp"],
      "includeTools": ["read_file", "write_file", "list_dir"],
      "timeout": 30000
    }
  }
}

両方を書いた場合は excludeTools が勝ちます。どちらのリストにも載っているツールは消えます。拡張機能が持ち込んだサーバーを上書きするときも同じ考え方で、拒否リストは足し合わされ、許可リストは重なった部分だけが残ります。つまり、拡張機能の側から勝手にツールを復活させられることはありません。手元の設定に拒否権があるという作りです。

サーバーをまるごと止めたいときは、mcpServers を消さずに上位の mcp で扱えます。

{
  "mcp": {
    "excluded": ["experimental-server"]
  }
}

一つだけ、名前の付け方に落とし穴があります。サーバー名にアンダースコアを使わないでください。完全修飾名を解釈する側は mcp_ の次に現れる最初のアンダースコアでサーバー名とツール名を切り分けるため、my_server のような名前だと境目を取り違えます。しかもエラーにはならず、権限のルールだけが当たらなくなります。my-server のようにハイフンで書くのが安全です。

常時有効・その場だけ・外す、に仕分けます

数えたツールを、私は三つに分けました。判断の軸は「便利かどうか」ではなく、「今週これを呼ばなかったら困るか」です。

扱い条件設定の書き方
常時有効ほぼ毎日呼ぶ。呼ばれないと作業が止まるincludeTools に明記する
その場だけ月に数回。呼ぶ場面を自分で言える普段は無効。使う回だけセッション単位で戻す
外す入れた理由を思い出せない。代わりに手でやれるmcp.excluded へ移す

三つ目の条件を入れたことで、判断がずいぶん速くなりました。「入れた理由を思い出せない」は、私の設定ファイルではかなりの数に当てはまったのです。試したときは面白かったのですが、そのあと一度も呼んでおりません。

同じサーバーの中でも仕分けは効きます。読み取り系のツールだけを includeTools に残し、書き込み系を落とすと、候補の数が減るうえに、誤って呼ばれたときの被害も小さくなります。個人開発で使う道具は、権限の広いものほど普段は畳んでおきたいところです。

一方で、絞りすぎると「あのツールが無い」と気づくまでに時間がかかります。ですので、外したものを一覧にして設定ファイルの隣へ置いております。消すのではなく、片付ける——その区別を自分の中で保つための一手間です。

外したあとに、戻る道を残します

仕分けを決めても、必要になったその場で戻せなければ、結局また全部を常時有効へ引き戻してしまいます。Gemini CLI はサーバー単位の出し入れをコマンドで扱えます。

# いま何がつながっているかを確認します
gemini mcp list
 
# 普段は落としておきます
gemini mcp disable experimental-server
 
# その回のセッションだけ戻します
gemini mcp enable experimental-server --session

対話中であれば /mcp で状態を見て、/mcp enable <名前> でそのまま戻せます。無効にしたサーバーは一覧に残り、接続だけがされません。存在を忘れずに済むという意味で、設定ファイルから削除するより私はこちらを好みます。

なお、接続そのものが失敗しているときは数の問題ではありません。認証やパスの側を先に疑ってください。そのあたりはGemini CLI が起動しない・認証が通らないときに見る場所に書き残しております。接続のしかた自体をこれから整える方は、Gemini CLI で MCP サーバーを使うから読んでいただくと順序が合うかと思います。

自分でサーバーを書く場合は、公開するツールの数そのものを設計の対象にできます。用途の違う機能を 1 台へ詰め込むより、小さく分けて必要な側だけをつなぐほうが、結果として呼び間違いが減りました。作り方はTypeScript でカスタム MCP サーバーを構築するにまとめてあります。

まず1つやるなら

今夜のうちに、上のスクリプトを一度走らせて合計だけ控えておいてください。512 という上限と比べるためではなく、自分が把握していた数とのずれを見るためです。私の場合、そのずれの大きさが、減らす基準を決める気にさせてくれました。

読んでくださってありがとうございました。道具を増やす話は楽しいのですが、減らす話も同じくらい自分の役に立っております。

シェア

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

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

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

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

開発ツール2026-05-04
Gemini CLI で MCP サーバーを使う — ファイル操作からDB連携まで
Gemini CLI に MCP サーバーを接続して外部ツール・DBを直接操作する方法を実践的に解説。GEMINI.md の設定から filesystem・SQLite・GitHub MCP の活用例まで、動くコードで丁寧に紹介します。
開発ツール2026-03-11
Gemini CLI をシェルと CI に組み込む — ヘッドレス実行とセッション再開の実践
Gemini CLI を対話利用で終わらせず、ヘッドレス実行・JSON出力・セッション再開・承認モード・MCP連携までを実践します。シェルとCIへの組み込み手順に加え、ヘッドレス実行で詰まる箇所の切り分けと、pro/flash/flash-lite を自分の入力で実測した比較まで扱います。
開発ツール2026-09-10
浮世絵カタログの表記ゆれ照合を、正規化と候補列挙の二層で組む手順
同じ絵師名が三通りに散らばったカタログを揃えるとき、Gemini に同一判定をさせると世代違いが混ざります。正規化を先に置き、モデルには候補の列挙だけを頼む二層構成を、動くコードと費用の見積もりつきでお伝えします。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます