Claude Media
CLAUDE_CODE_MCP_ALLOWLIST_ENVとは — stdio MCPサーバーへの環境変数漏えいを防ぐ

CLAUDE_CODE_MCP_ALLOWLIST_ENVとは — stdio MCPサーバーへの環境変数漏えいを防ぐ

stdio MCPサーバーが起動時にシェルの環境変数をまるごと継承する既定動作を止め、安全なベースラインとサーバー設定のenvだけに絞る設定を解説します。

CLAUDE_CODE_MCP_ALLOWLIST_ENVとは

CLAUDE_CODE_MCP_ALLOWLIST_ENV は、stdio(標準入出力)方式のMCPサーバーに渡す環境変数を絞り込む環境変数です。1 に設定すると、Claude Codeはシェルの環境変数をまるごと引き継ぐ既定の起動方式をやめ、安全なベースラインの環境と、そのサーバーの設定で env に明示した変数だけを渡すようになります。env は .mcp.json のほか、claude mcp add -e で書いた設定にもあります。

既定では逆で、stdio MCPサーバーはClaude Codeを起動したシェルの環境変数にそのままアクセスできます。手動で追加したサーバーだけでなく、プラグイン同梱のMCPサーバーも、手動で追加したサーバーと同じ範囲の環境変数にアクセスできます。由来を問わず継承の範囲は同一です。

くらべる

stdio MCPサーバーが受け取る環境変数

継承

既定(未設定)

.mcp.json の env は、シェル由来の変数に上乗せされる追加分にすぎません。env に書かなくても、サーバーはシェルの変数を読めます。

許可リスト

`CLAUDE_CODE_MCP_ALLOWLIST_ENV=1`

env が、ベースライン以外の変数をサーバーに渡す唯一の経路になります。env に書かない変数は、シェルにあってもサーバーからは見えません。

値の指定方法は他の真偽値系のClaude Code環境変数と共通で、オンは 1・true・yes・on、オフは 0・false・no・off です。大文字・小文字は区別されません。

設定したのに変わらないときは、シェルと設定ファイルの優先順位を疑います。同じ変数がシェルと設定ファイルの env ブロックの両方にあると、ほとんどのセッションでは設定ファイルの値が適用されます。Claude Codeが env の各エントリをプロセス環境に書き込み、シェルから継承した値を置き換えるためです。

例外もあります。Claude Desktopアプリやセルフホスト環境のランナーが起動したセッションでは、起動側が組み立てた環境が優先され、すでに設定済みの変数に対する設定ファイルの値は無視されます。「シェルで export したのに効かない」「設定ファイルに書いたのに効かない」のどちらも、まずこの順序で切り分けられます。

なぜ絞り込みが必要か

stdio MCPサーバーはローカルプロセスとして起動します(通信方式の詳細はMCP stdioトランスポートの仕様を参照してください)。シェルの環境変数を丸ごと渡す既定動作では、ANTHROPIC_API_KEY のような認証情報、クラウドの資格情報、社内システムのトークンなど、そのシェルに存在するあらゆる変数がサーバープロセスから読み取り可能になります。

npx -y <package> のように外部レジストリから取得して実行するサーバーや、サードパーティ製のMCPサーバーを追加する場面では、次の2点が問題になります。

  • サーバーの実装者を完全には信頼していない
  • そのサーバーが本来必要とする変数は数個だけなのに、シェル全体を見せてしまう

この構図はプロンプトインジェクション経由の情報持ち出しにも関係します。悪意のある入力でサーバー内部の処理を誘導されたとき、渡っている環境変数が多いほど持ち出せる情報も増えます。CLAUDE_CODE_MCP_ALLOWLIST_ENV は、渡す変数そのものを最小化してこのリスクの範囲を狭める設定です。

開発マシンのシェルには、複数のプロジェクト・複数のサービス分の認証情報が同居しがちです。あるプロジェクト用に追加したサーバー1本の脆弱性やサプライチェーン侵害が、無関係な別サービスの資格情報まで晒す経路になり得ます。ベースライン+個別 env 方式なら、サーバーAの侵害がサーバーBやシェル全体の秘密情報にまで波及する経路そのものを塞げます。

有効化する方法

シェルで一時的に有効にする場合はこうなります。

export CLAUDE_CODE_MCP_ALLOWLIST_ENV=1
claude

チーム全体や組織全体に適用したい場合は、設定ファイルの env キーに書きます。~/.claude/settings.json なら自分だけ、プロジェクトの .claude/settings.json ならそのプロジェクトで作業する全員に、管理者が配布するmanaged settingsなら組織全体に適用されます。組織全体でMCPサーバーの利用そのものを制御したい場合は、Managed MCPの許可リスト・拒否リストを CLAUDE_CODE_MCP_ALLOWLIST_ENV と併用する構成になります。

{
  "env": {
    "CLAUDE_CODE_MCP_ALLOWLIST_ENV": "1"
  }
}

project / local settingsには書き込めない変数群があります。保存先や一時ディレクトリを決める CLAUDE_CONFIG_DIR や HOME、OpenTelemetryの送信先を決める変数などで、リポジトリ側に握らせないための仕組みです。CLAUDE_CODE_MCP_ALLOWLIST_ENV はその一覧の例には載っておらず、project settingsやlocal settingsの env にも書けます。プロジェクト側の値は、ワークスペースを信頼した後に適用されます。

有効化後、サーバーは何を受け取るか

有効化すると、サーバーが受け取る変数は、先ほどの比較のとおりベースライン環境とサーバー設定の env だけになります。env は通常のMCPサーバー設定と同じ書き方です。

{
  "mcpServers": {
    "local-weather": {
      "command": "/path/to/weather-cli",
      "args": ["--api-key", "abc123"],
      "env": {
        "CACHE_DIR": "/tmp"
      }
    }
  }
}

この例なら、CLAUDE_CODE_MCP_ALLOWLIST_ENV=1 の状態でも CACHE_DIR はサーバーに渡ります。書いていない変数(シェルにある他のAPIキーなど)は渡りません。サーバーが追加の変数を必要とするなら、env に書き足すのが正しい対応で、変数を丸ごと見せる方向に戻す必要はありません。

コマンドラインから env を足す

JSONを直接編集しなくても、claude mcp add の -e(--env)で env を書き込めます。v2.1.289の claude mcp add --help は次のように案内しています(抜粋)。

claude mcp add --help
  # Add stdio server with environment variables:
  claude mcp add my-server -e API_KEY=xxx -- npx my-mcp-server
 
  # Add stdio server with subprocess flags:
  claude mcp add my-server -- my-command --some-flag arg1
 
Options:
  -e, --env <env...>           Set environment variables (e.g. -e KEY=value)
  -s, --scope <scope>          Configuration scope (local, user, or project)
                               (default: "local")
  -t, --transport <transport>  Transport type (stdio, sse, http). Defaults to
                               stdio if not specified.

-e はサーバー名の後ろ、-- の前に置きます。-- より後ろは、サーバー自身のコマンドと引数としてそのまま渡されます。--env は複数の KEY=value を受け取るため、サーバー名を --env の直後に書くと名前が変数のペアとして読まれて拒否されます。--transport stdio のように別のオプションを間に挟めば避けられます。

CLAUDE_CODE_SUBPROCESS_ENV_SCRUB との違い

似た目的の変数に CLAUDE_CODE_SUBPROCESS_ENV_SCRUB があります。この変数自体の仕組みはCLAUDE_CODE_SUBPROCESS_ENV_SCRUBの記事で扱っており、本記事では CLAUDE_CODE_MCP_ALLOWLIST_ENV との役割分担に絞ります。両者はアプローチが逆で、両方とも既定はオフです。

くらべる

許可リスト方式と除去方式

渡すものを選ぶ

`CLAUDE_CODE_MCP_ALLOWLIST_ENV`

ベースラインとサーバー設定の env だけを渡します。対象はstdio MCPサーバーのみです。資格情報かどうかの判定には頼らないため、名前も値も資格情報らしくない秘密でも、書いていなければ渡りません。

資格情報を取り除く

`CLAUDE_CODE_SUBPROCESS_ENV_SCRUB`

Bashコマンド・hooks・stdio MCPサーバーの環境から、資格情報を取り除きます。名前や値の形で資格情報と判定するので、判定に引っかからない秘密は残ります。

除去方式の残し方は、許可リストを選ぶかどうかの判断材料になります。公式の例では、GITHUB_TOKEN と GH_TOKEN は gh やGitHub APIを呼ぶスクリプトのために残され、HTTP_PROXY と HTTPS_PROXY もURL内のユーザー名・パスワードを含めてそのまま残ります。ANTHROPIC_API_KEY、NPM_TOKEN、DB_PASSWORD のように名前が資格情報らしい変数や、パスワードを含む DATABASE_URL のような値は除去されます。

除去方式は、Bashとhooksの両方に効く範囲の広さが利点です。stdio MCPサーバーを複数運用していて、サーバーごとの必要変数を env で管理できているなら、許可リストの方が漏えい経路を小さくできます。Bashツールやhooksの資格情報も塞ぎたい場合は、両方を併用する構成になります。

有効化前に確認すること

有効化すると、これまでシェルの環境変数に頼っていたstdio MCPサーバーが動かなくなることがあります。次の手順で影響範囲を洗い出してから切り替えるのが安全です。

手順

許可リストへの切り替え手順

  1. 1

    使用中のサーバーを洗い出す

    claude mcp list で、使っているstdio MCPサーバーを一覧にします。

  2. 2

    サーバーが読む環境変数を特定する

    各サーバーのドキュメントから、APIキー・接続先URL・キャッシュディレクトリなど、起動時に実際に読んでいる変数を調べます。ソースが公開されているサーバーなら、process.env(Node)や os.environ(Python)の参照箇所を検索するのが確実です。

  3. 3

    `.mcp.json` の `env` に書き足す

    特定した変数を、該当サーバーのエントリの env に追加します。値を直書きせず ${API_KEY} のように展開参照にしておけば、シェル側の値を書き換えるだけで済みます。

  4. 4

    一時的に有効にして確認する

    シェルで CLAUDE_CODE_MCP_ALLOWLIST_ENV=1 を設定して claude を再起動し、各サーバーが /mcp 上で正常に接続すること、ツール呼び出しが従来どおり動くことを確かめます。

  5. 5

    恒久設定にする

    問題がなければ、シェルの一時設定をやめ、managed settingsやプロジェクトの .claude/settings.json の env キーに書きます。個人利用なら ~/.claude/settings.json でも構いません。

途中で接続エラーが出たサーバーは、2番目の手順に戻って見落とした変数がないかを調べます。変数を都度足していく運用は手間に見えますが、サーバーが実際に何を必要としているかが設定ファイルを読むだけで分かるようになる副次効果があります。

接続が止まったときの切り分け

許可リストを有効にした直後によく見られるのは、/mcp でサーバーの状態が接続失敗のまま止まる、あるいはツール一覧が増えてこない症状です。サーバーの起動や認証に必要な変数が env に書かれていない場合が考えられます。

切り分けは単純です。CLAUDE_CODE_MCP_ALLOWLIST_ENV を外して(未設定または 0 で)claude を起動し直し、同じ操作を試します。それで直るなら原因は env の不足、直らないならサーバー自体や接続先の問題です。

${VAR} 展開を使っている場合は、もう1つ確認点があります。展開元の変数が未設定でデフォルトも無いとき、Claude Codeは claude mcp list と /mcp の出力で警告を出したうえで、${VAR} の文字列をそのまま使ってサーバーを読み込みます。接続できないサーバーでは、env の値が展開されずに ${VAR} のまま残っていないかを最初に調べます。${VAR:-default} と書けば、未設定のときの値を指定できます。

使い分けの目安

状況有効化の判断理由
npm/PyPIから取得したstdio MCPサーバーを使う有効化の判断効果が大きい理由実装者を完全には検証できないため、渡す変数を最小化する価値が大きい
社内で自作したstdio MCPサーバーのみ有効化の判断任意理由信頼できる実装でも、暗黙にシェル変数を読む処理が混じっていないかを env で棚卸しできる
リモート(HTTP/SSE)MCPサーバーのみで運用有効化の判断効果なし理由本設定はstdio専用で、リモート接続には影響しない
プラグイン同梱のMCPサーバーを複数有効化している有効化の判断効果が大きい理由シェル環境の届き先が、プラグインのサーバー数だけ増える

社内の秘密情報とstdio MCPサーバーが同じ開発マシン・同じシェルセッションに同居している構成ほど、有効化の効果が大きくなります。逆に、機密性の高い環境変数がそもそも存在しない検証環境では、有効化してもリスクは大きく減りません。

リモートMCPサーバーには効かない

CLAUDE_CODE_MCP_ALLOWLIST_ENV が絞るのはstdio(ローカルプロセス)サーバーへの環境変数だけです。HTTP・SSE・WebSocket・claude.aiコネクタ経由のリモートMCPサーバーは別の接続方式で、ローカルプロセスとしてシェル環境を継承する仕組みそのものがありません。認証情報は .mcp.json の headers や headersHelper で別に管理します。

リモートサーバーの url と headers では、${VAR} 展開に別のルールがあります。ANTHROPIC_API_KEY、ANTHROPIC_AUTH_TOKEN、AWS_BEARER_TOKEN_BEDROCK のようにClaude Codeや各クラウドの資格情報にあたる名前や、HTTPS_PROXY・NPM_TOKEN のような環境上のその他の資格情報は、変数を設定していても空として扱われます。:-default を付けても無視されます。

たとえば Bearer ${ANTHROPIC_AUTH_TOKEN} と書くと、サーバーには Bearer だけが届いて拒否されます。多くは 401 で、Claude Code上は接続失敗として表示されます。API_KEY のように名前がその一覧に入らない変数は、書いたとおりに展開されます。その一覧に入る資格情報を渡したいときは、自分で決めた名前の変数にコピーして、そちらを参照します。

なお、SSE(Server-Sent Events)方式のリモートトランスポートは非推奨で、HTTPサーバーの利用が案内されています。新しくリモートMCPサーバーを構成するなら、通常のHTTPトランスポートを選ぶのが無難です。

まとめ

判断の分かれ目は、サードパーティ製のサーバーと社内の秘密情報が同じシェルに同居しているかどうかです。同居しているチームなら、切り替え前に env を各サーバーの必要変数で埋めておくと、動作を止めずに継承範囲だけを最小化できます。

この記事を共有:XはてブLinkedIn