MCPサーバーを「URLだけ共有してチームに配る」とトークンが平文で散らばり、権限も絞れません。本記事では、Claude CodeのOAuth認証付きMCPサーバーを claude mcp login で各自が自分の資格情報でつなぎ、.mcp.json をバージョン管理で配布し、oauth.scopes や managed-mcp.json で組織として絞り込むところまでを、公式仕様に沿って解説します。
結論:このガイドで分かること
結論:MCPサーバーの認証は「ヘッダーに静的トークンを書く」のではなく、HTTPサーバーに対するOAuth 2.0で各メンバーが自分自身として認証するのが、配布性とセキュリティの両立に最も近い。
- 要点1:個人がつなぐときは
/mcp、またはセッション外ならclaude mcp login <name>。トークンは自動更新・キーチェーン保管される。 - 要点2:チーム配布は
--scope projectで.mcp.jsonを作り、これをGitに入れる。秘密情報はファイルに書かず${VAR}展開かOAuthで各自認証。 - 要点3:組織で締めるなら
oauth.scopesでスコープを固定し、managed-mcp.jsonとallowedMcpServers/deniedMcpServersでサーバー集合を統制する。
対象読者:Claude Codeを複数人・チーム・全社で使い始めた開発者、SRE、情報システム/セキュリティ担当。今日できること:手元のMCP接続をヘッダー直書きからOAuthへ移し、リポジトリに安全な .mcp.json をコミットする。
なぜ「ヘッダーにトークン直書き」をやめるのか
リモートMCPサーバーをつなぐとき、もっとも手早い方法は認証ヘッダーを直接渡すやり方だ。GitHubのリモートMCPサーバーはまさにこの形で、個人アクセストークンをBearerヘッダーで渡す。
claude mcp add --transport http github https://api.githubcopilot.com/mcp/ \
--header "Authorization: Bearer YOUR_GITHUB_PAT"
これは1人で試す分には問題ない。だがチームへ配ろうとした瞬間に三つの問題が出る。まず、トークンがコマンド履歴や設定ファイルに残る。次に、全員が同じトークンを使い回すと「誰が何をしたか」が追えない。そして、トークンの権限がサーバー側のアカウント権限そのままになりがちで、必要以上に強い。
Claude Code公式ドキュメントは、クラウド系MCPサーバーの多くが認証を必要とし、そこではOAuth 2.0をサポートすると明記している。OAuthなら各メンバーが自分自身として認証でき、トークンは設定ファイルではなくキーチェーン等に安全に保管され、自動でリフレッシュされる。つまり「配るもの」と「秘密にするもの」を分離できる。これが直書きをやめる最大の理由だ。
個人がOAuthでMCPサーバーにつなぐ手順
Claude Codeは、サーバーが 401 Unauthorized または 403 Forbidden を返したとき、そのサーバーを「認証が必要」とマークし、/mcp でOAuthフローを完了できるようにする。標準的な流れはこうだ。
セッション内:/mcp で認証する
# 1. 認証が必要なサーバーを追加(例:Sentry)
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp
追加したら、Claude Codeのセッション内で /mcp を実行し、ブラウザでログインを完了する。公式の注意点として、ブラウザが自動で開かない場合は表示されたURLを手動で開けばよく、認証後にリダイレクトがコネクションエラーで失敗したら、ブラウザのアドレスバーにあるコールバックURL全体をClaude Code側のプロンプトに貼り付ければ復帰できる。
セッション外:claude mcp login を使う
v2.1.186以降は、セッションの /mcp パネルを開かずに、シェルから直接OAuthフローを回せる。
# OAuthフローをコマンドラインから実行
claude mcp login sentry
# 保存済みの資格情報を消す(再認証したいとき)
claude mcp logout sentry
SSH越しやディスプレイのないLinuxでも使える。v2.1.191以降、claude mcp login はローカルブラウザが無い環境を検知して認可URLを表示する。手元のマシンでそのURLを開き、ブラウザのアドレスバーのリダイレクトURL全体をプロンプトに貼り戻す。貼り付け操作のために対話端末が要るので、SSHは ssh -t でつなぐ。ローカルブラウザがあっても強制的にURL表示にしたいなら --no-browser を付ける。
# SSHセッションなどでブラウザを開かせない
claude mcp login sentry --no-browser
認証が済めば、あとは通常どおりサーバーのツールを使える。トークンはmacOSではシステムキーチェーン、その他では資格情報ファイルに安全に保管され、自動でリフレッシュされる。アクセスを取り消したいときは /mcp メニューの「Clear authentication」を使う。
チームに安全に配る:.mcp.json とスコープ設計
配布の核は「サーバーの定義は共有し、資格情報は共有しない」ことだ。Claude CodeのMCPサーバー設定には三つのスコープがあり、配布の挙動が変わる。
| スコープ | 読み込まれる範囲 | チーム共有 | 保存先 |
|---|---|---|---|
| local(既定) | そのプロジェクトのみ | しない | ~/.claude.json |
| project | そのプロジェクトのみ | する(バージョン管理経由) | プロジェクト直下の .mcp.json |
| user | 自分の全プロジェクト | しない | ~/.claude.json |
チームで同じツール群を使いたいなら --scope project を使う。これはプロジェクト直下に .mcp.json を作り、バージョン管理にコミットする前提の形式になる。
# プロジェクトスコープでサーバーを追加(.mcp.json が作られる)
claude mcp add --transport http paypal --scope project https://mcp.paypal.com/mcp
生成される .mcp.json は標準フォーマットだ。秘密値はここに直書きせず、環境変数展開に逃がす。公式は ${VAR} と ${VAR:-default} の展開をサポートし、url や headers の中でも使える。
{
"mcpServers": {
"api-server": {
"type": "http",
"url": "${API_BASE_URL:-https://api.example.com}/mcp",
"headers": {
"Authorization": "Bearer ${API_KEY}"
}
}
}
}
セキュリティ上の注意:プロジェクトスコープのサーバーは、初回使用時にClaude Codeが承認を求める。承認のやり直しは claude mcp reset-project-choices で行う。なお、OAuth対応サーバーであれば headers にトークンを書く必要すらなく、各メンバーが claude mcp login で自分の資格情報をつなぐのが最もきれいだ。チーム導入の進め方そのものはClaude Code業務導入完全ガイドも参考になる。
OAuthスコープを最小権限に固定する
OAuthでつないでも、サーバーが広いスコープを要求してくると、必要以上の権限を与えてしまう。Claude Codeは oauth.scopes で、認可フロー中に要求するスコープを固定できる。セキュリティチームが承認したサブセットに絞るための、サポートされた方法だ。
{
"mcpServers": {
"slack": {
"type": "http",
"url": "https://mcp.slack.com/mcp",
"oauth": {
"scopes": "channels:read chat:write search:read"
}
}
}
}
値はRFC 6749のscopeパラメータと同じ、スペース区切りの単一文字列で指定する。oauth.scopes は、サーバーが /.well-known で広告するスコープよりも優先される。もしツール呼び出しでサーバーが 403 insufficient_scope を返したら、Claude Codeは同じ固定スコープで再認証する。必要なツールが固定セット外のスコープを要るときだけ、oauth.scopes を広げればよい。
権限を絞る考え方は、MCPに限らずClaude Code全体の権限設計ガイドと地続きだ。MCPの追加・自作の基礎はMCP実践ガイドにまとまっている。
組織として統制する:managed-mcp.json と allow/deny
全社展開では「各自が好きなサーバーを足せる」状態は危うい。管理者はサーバー集合を統制できる。公式が示すパターンは段階的だ。
| パターン | 何をするか | 主な設定 |
|---|---|---|
| 固定配布 | 全員が同じサーバーを持ち、他は追加不可 | managed-mcp.json に許可サーバーを定義 |
| 承認カタログ | 許可リストのサーバーだけ各自が追加できる | allowedMcpServers + allowManagedMcpServersOnly: true |
| 拒否リストのみ | 既知の危険サーバーだけ遮断 | deniedMcpServers |
| MCP無効 | どこでもサーバーを読み込ませない | managed-mcp.json を空のサーバーマップで配布 |
managed-mcp.json を配ると、Claude Codeはそのファイルに定義されたサーバーだけを読み込み、ユーザーはそれ以外を追加・使用できなくなる。配置先はOSごとに決まっている。
| OS | パス |
|---|---|
| macOS | /Library/Application Support/ClaudeCode/managed-mcp.json |
| Linux / WSL | /etc/claude-code/managed-mcp.json |
| Windows | C:\Program Files\ClaudeCode\managed-mcp.json |
ファイル形式はプロジェクトの .mcp.json と同じだ。このファイルは誰でも読めるため、env ブロックにAPIキーを書いてはいけない。${VAR} 展開・OAuth・headersHelper のいずれかで、各ユーザーが自分の資格情報で認証するのが公式の指針だ。
{
"mcpServers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/"
},
"sentry": {
"type": "http",
"url": "https://mcp.sentry.dev/mcp"
}
}
}
許可リストと拒否リストは「どのサーバーをロードしてよいか」をフィルタする。エントリは serverUrl(URL、* ワイルドカード可)、serverCommand(stdioの起動コマンドと引数を完全一致)、serverName(ユーザーが付けたラベル)のいずれかで指定する。重要な注意として、公式は serverName はセキュリティ制御にならないと明言している。名前はユーザーが自由に付けられるラベルにすぎず、どのサーバーが実際に動くかを強制したいなら serverCommand か serverUrl を使う。
{
"allowedMcpServers": [
{ "serverUrl": "https://api.githubcopilot.com/*" },
{ "serverUrl": "https://mcp.sentry.dev/*" }
],
"deniedMcpServers": [
{ "serverUrl": "https://*.untrusted.example.com/*" }
]
}
評価順は三段階だ。まず全ソースの許可・拒否リストをマージし、次に拒否リストを照合し(拒否一致は何にも上書きされない)、最後に許可リストを照合する。allowManagedMcpServersOnly: true を管理設定で立てると、ユーザー・プロジェクト・ローカルの許可リストは無視され、管理側の許可リストだけが効く。ただし拒否リストは常に全ソースからマージされるので、ユーザーは自分のために常にサーバーを遮断できる。全社レベルの統制思想は法人導入セキュリティ完全チェックリストとあわせて設計したい。
ポリシーでサーバーが遮断されたとき、ユーザーに何が見えるかも把握しておく。managed-mcp.json がある状態で claude mcp add を実行すると「enterprise MCP configuration is active and has exclusive control over MCP servers」というエラーになる。一方、すでに設定済みのサーバーが後からポリシーで遮断された場合は、/mcp と claude mcp list から警告なしに静かに消える。そのため新しい制限を展開するときは、どのサーバーが遮断されるかを利用者に事前告知することが推奨されている。
移行でつまずきやすい3つの落とし穴
実際に直書きヘッダーからOAuth+配布へ移すと、ここで止まる。
- ❌ ヘッダーとOAuthを同時に設定して混乱する:
headers.Authorizationを設定していてサーバーがそれを拒否すると、Claude CodeはOAuthへフォールバックせず「接続失敗」と報告する。⭕ 正:OAuthを使うならヘッダーを外す。トークンがMCPエンドポイントに対して有効か確認する。 - ❌
.mcp.jsonにAPIキーを直書きしてGitに上げる:プロジェクト/管理設定のファイルは共有・閲覧される前提だ。⭕ 正:秘密値は${VAR}展開・OAuth・headersHelperに逃がす。必須の環境変数が未設定で既定値も無いと、Claude Codeは設定のパースに失敗する。 - ❌ DCR非対応サーバーで認証が始まらない:「Incompatible auth server: does not support dynamic client registration」が出るサーバーは、事前登録した資格情報が要る。⭕ 正:開発者ポータルでOAuthアプリを登録し、
--client-idと--client-secret、必要なら固定の--callback-portを渡す。シークレットはキーチェーン等に安全に保管され、設定ファイルには残らない。
よくある質問(FAQ)
Q. OAuth認証はどのトランスポートで使えますか?
A. 公式のヒントでは、OAuth認証はHTTPサーバーで動作するとされています。--callback-port や --client-id 等のOAuth関連フラグはHTTPとSSEのトランスポートにのみ適用され、ローカルのstdioサーバーには影響しません。WebSocket(ws)はOAuthをサポートせず、認証はヘッダーのみです。
Q. SSH越しの開発環境でログインできますか?
A. できます。v2.1.191以降、claude mcp login はローカルブラウザが無い環境を検知して認可URLを表示します。手元のマシンでURLを開き、リダイレクトURL全体をプロンプトに貼り戻します。貼り付け操作に対話端末が必要なので ssh -t で接続してください。
Q. 特定のOAuthコールバックポートを固定したいときは?
A. 既定ではランダムな空きポートが使われます。サーバー側に事前登録した http://localhost:PORT/callback 形式のリダイレクトURIに合わせる必要がある場合は --callback-port で固定します。動的クライアント登録のみでも、--client-id と併用しても使えます。
Q. 管理者がMCPを完全に無効化するには?
A. 空のサーバーマップ({"mcpServers": {}})を持つ managed-mcp.json を配置します。ユーザーには /mcp にサーバーが一切表示されなくなり、claude mcp add はエンタープライズポリシーのエラーで失敗します。
Q. claude.aiのコネクターも一緒に統制できますか?
A. managed-mcp.json を配ると、既定ではclaude.aiコネクターは抑制されます。管理設定で allowAllClaudeAiMcps: true(v2.1.149以降)を立てると、管理対象サーバーと並べてロードできます。許可・拒否リストはコネクターにも適用されます。
まとめと次の一手
MCPの認証は「ヘッダー直書き」から「OAuthで各自認証+定義だけ配布」へ移すだけで、配布性と監査性が一段上がる。今日からできる3アクションはこうだ。
- 手元の接続をOAuthへ:ヘッダーを外し、
claude mcp login <name>で自分の資格情報でつなぎ直す。 - リポジトリに安全な
.mcp.jsonを置く:--scope projectで作り、秘密値は${VAR}に逃がしてコミットする。 - スコープと統制を決める:
oauth.scopesで最小権限に固定し、全社ならmanaged-mcp.jsonと allow/deny の方針を情シスと合意する。
次回予告:本記事の「権限を絞る」発想は、MCPだけでなくClaude Code全体の権限・サンドボックス設計に通じる。チーム標準の作り方はsettings.json設定完全ガイドで深掘りする。
著者:佐藤傑(さとう・すぐる)。株式会社Uravation代表取締役。X(@SuguruKun_ai)フォロワー約10万人。100社以上の企業向けAI研修・導入支援に従事。著書『AIエージェント仕事術』(SBクリエイティブ)。
出典
- Anthropic「Connect Claude Code to tools via MCP」 code.claude.com/docs/en/mcp
- Anthropic「Control MCP server access for your organization(Managed MCP configuration)」 code.claude.com/docs/en/managed-mcp
- Anthropic「Claude Code changelog」(v2.1.186 / v2.1.191 / v2.1.149 ほか) code.claude.com/docs/en/changelog