claude-code-actionのallowedToolsで列挙外のMCPツールが送られ続ける理由
claude-code-actionの--allowedToolsは実行を止めるだけで、列挙外のMCPツール定義はモデルに送られ続けるという報告です。トークンの無駄を抑える設定側の手順をまとめます。
claude-code-actionで--allowedToolsにMCPツールを1〜2個だけ書いても、そのMCPサーバーが持つ他のツール定義は、リクエストのたびにモデルへ送られる。2026年10月13日に起票されたIssue #1899は、この挙動を指摘しています。許可リストは「実行してよいツール」を決めるだけで、「モデルに見せるツール」は決めません。見せる範囲を絞る手段は--disallowedToolsや--mcp-configの側にあります。
報告されている挙動 — 実行は止まるが定義は残る
Issue #1899のタイトルは「--allowedTools does not keep unlisted MCP tools out of the model context」です。本文の主張は次の3点です。
--allowedToolsが制御するのは、Claudeが実行できるツールだけ--mcp-configで渡したMCPサーバーの全ツールは、--disallowedToolsに挙げない限りモデルへ送られる- GitHub MCPサーバーのような大きなサーバーから1〜2個だけ使う構成では、未使用ツールの定義ぶんが毎ターンの入力トークンになる(報告者の見立てでは、リクエストあたり数千トークン規模)
報告者は、回避に必要な作業も具体的に書いています。
現状の回避手順(Issueの記述)
- 1
ツール一覧を集める
実行ログの
system/initイベントから、各サーバーが公開する全ツール名を取り出します。 - 2
使わないツールを列挙する
使わないツールをすべて
--disallowedToolsに書き写します。 - 3
サーバー更新のたびに見直す
サーバー側でツールが増えたら、リストも更新します。
Issue #533も、ユーザー側から同じ問題(トークンの大量消費)を報告したものとして挙げられています。コメント欄には、特定ユーザーへのメンションだけの投稿が1件あります。
提案されているopt-in入力とその前提
報告者はdisallow_unlisted_mcp_tools: "true"のような任意入力の追加を提案しています。仕組みは次のとおりです。
- Claudeの起動前に、
--allowedToolsが一部のツールだけを挙げたサーバーへアクションが接続する tools/listを呼ぶ- 挙げられていないツールを
--disallowedToolsへ自動で追記する
対象外の条件も明示されています。サーバー全体を許可した場合(mcp__serverやmcp__server__*)と、--allowedToolsに登場しないサーバーはそのままです。mcp__server__get_*のようなワイルドカードは、一致するツールを全部残します。到達できないサーバーは警告つきで飛ばし、現状と同じ動きにします。
既定で有効にしない理由も書かれています。disallowされたツールはbypassPermissionsでも使えないため、既定オンにすると既存ワークフローの挙動が変わるからです。これは提案であり、アクションに入力として存在するという意味ではありません。アクションの入力一覧(usageドキュメントのInputs表)にこの名前は載っておらず、workflowに書いても効く保証はありません。
実際にどれだけ送られるかはtool searchで変わる
ここで切り分けが必要です。Issueは「全ツールが毎回送られる」と書いていますが、Claude Code本体のドキュメントでは、MCPツールの扱いが設定で変わります。
- 既定(
ENABLE_TOOL_SEARCH未設定)では、MCPツールは遅延ロードされ、セッション開始時にはツール名とサーバー指示だけが載る ENABLE_TOOL_SEARCH=falseなら、すべてのMCPツールが最初から読み込まれるANTHROPIC_BASE_URLが第一者ではないホストを指すと、既定では先読みに切り替わる(trueで遅延を維持)- Opus 4やSonnet 4より前のモデルでも、先読みになる
Issueの本文は、アクション実行時にtool searchが有効だったかどうかに触れていません。したがって、定義がフルで送られるのは「先読みになる構成」で最も問題になる、と読むのが安全です。遅延ロードの構成でも、名前の一覧とサーバー指示は載ります。仕組みの全体像はMCPのツール定義はなぜコンテキストを圧迫するのかにまとまっています。
自分のworkflowがどちらなのかは、initイベントのモデル名と環境変数で見当がつきます。プロキシやゲートウェイ経由、あるいはAzure上のFoundryを使っているなら、先読みになっている可能性を先に疑う価値があります。
アクションが自動で足すMCPサーバーにも注意する
列挙外のツール定義を送ってくるのは、自分で--mcp-configに書いたサーバーだけとは限りません。claude-code-actionのFAQには、アクションが次の2つのMCPサーバーを自動で設定すると書かれています。
- GitHub MCPサーバー(GitHub APIの操作用)
- ファイル操作サーバー(高度なファイル操作用)
同じFAQは、これらのサーバーのツールもclaude_argsの--allowedToolsで明示して初めて使える、とも説明しています。つまり許可の仕組みは自前のサーバーと同じで、--allowedToolsに挙げたツール以外の定義がモデルに届くかどうかも、Issue #1899と同じ論点になりえます。GitHub連携のツールを1〜2個しか使わないworkflowで入力トークンが多いときは、自分で渡したサーバーだけでなく、アクションが足したサーバーのツールもinitイベントで数えてみてください。
FAQにはこの2サーバーが持つツール名の一覧は載っていないため、--disallowedToolsに書く名前は、実行ログのinitに出たものから拾います。
設定側で絞る4つの手段
アクションのallowed_tools・disallowed_tools・mcp_configの各入力は非推奨で、claude_argsへの移行が案内されています。以下はすべてclaude_argsに書く前提です。
MCPの定義量を減らす手段
1. --disallowedToolsで名指しする
裸のツール名は、該当ツールをClaudeのコンテキストから取り除きます。
mcp__github__create_issueのようにツール単位でも、mcp__github__*のようにサーバー単位でも書けます。2. 使わないサーバーを渡さない
--strict-mcp-configを付けると、--mcp-configで渡したサーバー以外の設定を無視します。リポジトリの.mcp.jsonが意図せず混ざる事故も防げます。アクションが自動で足すサーバーにこの指定が及ぶかは、ドキュメントに記載がありません。3. tool searchを維持する
ENABLE_TOOL_SEARCHをfalseにしない、非標準のベースURL利用時はtrueを明示する、が基本です。4. alwaysLoadを使い分ける
常用するサーバーだけ
"alwaysLoad": trueにし、それ以外は遅延のままにします。"alwaysLoad": falseなら、サーバー作者が先読み指定したツールも遅延に戻せます(v2.1.287以降)。
--disallowedToolsのMCP向け書式は、権限ルールの書式に従います。ツール名の全形はmcp__<server>__<tool>で、mcp__*は全サーバーの全MCPツールにマッチします。注意点として、権限設定ファイルのmcp__ルールは括弧つきだとスキップされます。引数まで絞りたい拒否ルールは、--disallowedToolsで渡します。
workflowの書き方 — 許可と除外を対にする
1つのツールだけ使うGitHub MCPの例を、claude_argsで組むと次の形になります(ツール名は説明用の例です)。
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: "PRの差分を読み、結果をコメントする"
claude_args: |
--mcp-config ./mcp.json
--strict-mcp-config
--allowedTools "mcp__github__get_pull_request_diff"
--disallowedTools "mcp__github__create_issue,mcp__github__merge_pull_request"許可リストに載せたツールと、除外リストに載せたツールは別の役割です。除外リストへ書いたツールは、bypassPermissionsでも使えません。Issueが慎重に既定オフを提案した理由はここにあります。
--disallowedToolsは拒否が最優先なので、あとから「やはりこのツールも使いたい」となったとき、除外側から外し忘れると、許可リストに足しても動きません。変更のたびに両方を見る運用が安全です。
ツール一覧を取り出す方法
除外リストを作る入口は、Issueが挙げるsystem/initイベントです。アクションの実行ログ、または手元でSDK出力を取ったときのinitメッセージに、そのセッションで見えているツールとMCPサーバーの状態が載ります。
claude -p "ok" --output-format stream-json --verbose \
--mcp-config ./mcp.json --strict-mcp-config \
| jq -c 'select(.type=="system" and .subtype=="init")'出力されたツール名のうち、使うものを許可リストへ、使わないものを除外リストへ振り分けます。--strict-mcp-configを付けた状態で、アクションが足すGitHub連携のツールがinitに残るかどうかも、ここで確認できます。サーバーの更新でツールが増えた場合に備え、除外リストはリポジトリで管理しておくと差分が追えます。
症状別の切り分け
入力トークンが想定より多いとき
- QMCPサーバーを複数渡していますか?答えが次の確認へ答えがはい
--strict-mcp-configで必要なサーバーだけに絞ります。 - Q`ENABLE_TOOL_SEARCH=false`、または非標準のベースURLを使っていますか?答えが次の確認へ答えがはい
MCPツールが先読みされています。
trueへの変更か、--disallowedToolsによる除外を検討します。 - Q大きなサーバーから数個だけ使っていますか?答えが定義以外(プロンプトや出力量)も疑います答えがはい
使うツールを許可リストに、残りを
--disallowedToolsに書きます。
定義の量を減らせた
次の実行のinitで、見えているツールが減ったことを確かめます。
CLIを直接起動する場合の許可・拒否の書き分けは、allowedTools/disallowedToolsの解説に、claude_argsの渡し方はGitHub Actionsのパラメータの解説にあります。ツール説明文の長さで定義量を抑える設定はMCPツール説明文の文字数上限で扱っています。
実装の行方を見るときの視点
Issue #1899にはenhancement・performance・mcp・feature-request・p3のラベルが付いています。優先度ラベルはp3で、短期間で入力が追加されるとは限りません。報告者は実装を用意していると書いており、PRが出た時点で入力名や挙動が変わる余地もあります。
当面の現実解は、除外リストを自分で管理するか、先読みを避ける構成に寄せるかの二択です。ツール数が少ない小さなサーバーしか使わないworkflowでは、影響は小さいままです。逆に、GitHub MCPのようにツールが多いサーバーを毎回の自動実行に載せているチームでは、initのツール数を一度確かめておく価値があります。