3行まとめ
MCPサーバーをOAuth protected resourceとして発見できるようにします。
authorization requestとtoken requestの両方で宛先を伝えます。
Tools、Resources、Promptsと副作用で権限を分けます。
別resource向けtokenをMCPサーバーで拒否します。
受け取ったaccess tokenを下流APIへそのまま流しません。
MCP OAuthは、誰がログインしたかだけでなく、どのresource向けに何を許したかを確認します。
MCPサーバーにOAuthを入れるなら、まず見る対象はログイン画面ではなく、そのMCPサーバーがどのOAuth protected resourceとして扱われるかです。
MCP Authorization仕様では、MCPサーバーのProtected Resource Metadata、authorization requestとtoken requestのresource、サーバー側のtoken検証がつながって扱われます。
特に危ないのは、署名検証だけで安心すること、scopeを広く始めること、受け取ったaccess tokenを下流APIへそのまま流すことです。
この記事でわかること
MCP ServerとAuthorization Serverの役割を分けます。
Protected Resource Metadataをclient discoveryに使える状態にします。
authorization requestとtoken requestでresourceを落としません。
read、write、admin、人間承認をscopeで分けます。
audience検証とpassthrough禁止をtestへ落とします。
仕様名を覚えるより、公開前にどの境界を確認するかへ落とすことが重要です。
- Streamable HTTPのMCPサーバーでOAuthを入れる前に決める責任分界
- Protected Resource Metadataを「出しているか」だけでなく「発見に使えるか」で見る方法
- authorization requestとtoken requestに
resourceを入れる理由 - scopeをMCPのTools、Resources、Prompts、副作用、人間承認に合わせて分ける考え方
- audience検証とtoken passthrough禁止を、公開前レビューとテストに落とす方法
- TypeScript SDKのauth helperを使うときに、アプリ側で決めるべき範囲
この記事は2026年6月15日に、MCP Authorization 2025-11-25版、MCP Security Best Practices、RFC 9728、RFC 8707、MCP TypeScript SDK README、npm上の@modelcontextprotocol/sdk 1.29.0を確認して書いています。X/Twitter上のMCP OAuth関連の話題は需要シグナルにとどめ、仕様の根拠には使っていません。
前提知識
stdioのローカル実験とHTTP公開サーバーでは、認可で見る境界が変わります。
MCP OAuthは「ログインを付ける話」だけではない
MCPでOAuthというと、まずブラウザでログインして、access tokenをもらい、MCPサーバーへBearer tokenを付けて呼ぶ流れを想像しがちです。そこだけ見ていると、一般的なAPI認証の延長に見えます。
ただしMCPでは、MCPクライアント、MCPサーバー、Authorization Server、下流API、ホストアプリケーションが混ざります。さらにMCP serverは、モデルがToolsを呼び出したり、Resourcesを読んだり、Promptsを参照したりする入口になります。つまり、単に「ユーザーがログイン済みか」では足りません。
先に決めたいのは次の5点です。
| 見るもの | 何を決めるか | 失敗すると起きること |
|---|---|---|
| Protected Resource Metadata | MCPサーバー自身のresource識別子と認可サーバーの見つけ方 | クライアントが別の認可設定を見に行く |
resourceパラメータ | どのMCPサーバー向けのtokenを要求するか | 別resource向けtokenが混ざる |
| scope | どのTools、Resources、Prompts、操作を許すか | read-onlyとwriteが同じ扱いになる |
| audience検証 | tokenがこのMCPサーバー向けか確認する | 署名は正しいが宛先が違うtokenを受理する |
| token passthrough禁止 | 受け取ったtokenを下流APIへ横流ししない | confused deputyや権限境界の崩壊につながる |
stdioのローカル実験とHTTP公開サーバーは分ける
この記事で扱うのは、Streamable HTTPなどで外部のMCPクライアントから到達できるMCPサーバーです。ローカルのstdioサーバーを自分の端末だけで動かす実験とは、脅威モデルが違います。
stdioなら、OSユーザー、ローカルファイル、起動コマンド、エージェント側の承認設定が主な境界になります。一方、HTTPでMCPサーバーを公開すると、MCPクライアントがどのAuthorization Serverへ向かうか、どのresource向けにtokenを要求するか、サーバーがtokenをどう検証するかが公開前レビューの対象になります。
結果: MCP OAuthはresource境界からレビューする
曖昧なresource境界は、AIエージェントのtool実行リスクとして表れます。
実務では、MCP OAuthを「あとからmiddlewareで足す認証」として扱うより、resource境界を先に固定した方が安全です。
レビューで合格にする最低ラインは、次の状態です。
| レビュー項目 | 合格条件 |
|---|---|
| resource識別子 | productionとstagingで混ざらず、MCPサーバーの公開URLや論理resourceと一致している |
| Protected Resource Metadata | クライアントがAuthorization Server discoveryへ進める情報を持つ |
resource | authorization requestとtoken requestの両方で落ちていない |
| scope | read、write、admin、副作用ありtool、人間承認が必要な操作を分けている |
| token検証 | issuer、署名、期限、audience、scopeを検証し、不一致を拒否する |
| passthrough | MCPサーバー向けaccess tokenを下流APIへそのまま渡さない |
| ログ | token本体を残さず、拒否理由とrequest idを追える |
この表を満たさない状態で公開すると、OAuthを入れたのに「誰の、どのresource向けの、どの操作権限か」が曖昧なままになります。AIエージェントに接続させるMCPでは、この曖昧さがそのままtool実行の危険になります。
Streamable HTTPのMCPサーバーで先に決める責任分界
- 1Host App
ユーザー操作、tool実行承認、監査の入口になります。
- 2MCP Client
Protected Resource Metadataを取得し、認可処理を開始します。
- 3MCP Server
protected resourceとしてresource URL、scope、token検証を持ちます。
- 4Authorization Server
issuer、authorization endpoint、token endpointを提供します。
- 5下流API
必要なら別resourceとして権限を取り直します。
Authorization ServerとMCP Serverの責任を混ぜると、誰が何を検証するかが曖昧になります。
MCP ServerをOAuth protected resourceとして扱う
根拠
RFC 9728は、OAuth protected resourceが自分の設定をメタデータとして公開するための仕様です。MCP Authorization仕様では、MCPサーバーがOAuth 2.0 Protected Resource Metadataを実装し、MCPクライアントがそれをAuthorization Server discoveryに使う前提が置かれています。
ここで大事なのは、MCPサーバーを「tokenを受け取る場所」ではなく「tokenの宛先になるresource」として見ることです。resourceが曖昧なままだと、クライアントがtokenを要求するときも、サーバーがtokenを検証するときも、何に対する権限なのかを判断できません。
確認項目
設計メモには、少なくとも次を書きます。
MCP Resource ID: https://mcp-dev.internal.invalid
MCP Endpoint: https://mcp-dev.internal.invalid/mcp
Protected Resource Metadata: https://mcp-dev.internal.invalid/.well-known/oauth-protected-resource
Expected Authorization Server: https://auth-dev.internal.invalid
Accepted Audience: https://mcp-dev.internal.invalid
Environment: production
実際のURLは自社環境に合わせてください。ここではダミーのinternal.invalidを使っています。
Authorization ServerとMCP Serverの責任を混ぜない
条件
Authorization Serverは、ユーザー認証、同意、authorization code、access token発行、refresh token管理などを担います。MCP Serverは、そのtokenを受け取るprotected resourceとして、自分に向けて発行されたtokenかを検証し、scopeに応じてMCP操作を許可または拒否します。
小さなPoCでは、1つのアプリケーションにAuthorization Server相当の処理とMCP Serverを同居させることもあります。ただし設計レビューでは、役割を別の箱として書いた方が判断しやすくなります。
| 役割 | 主な責任 | MCP実装での確認 |
|---|---|---|
| Host | ユーザー体験、MCP client管理、承認UI | どのserverへ接続しているかユーザーに見えるか |
| MCP Client | metadata discovery、authorization flow、MCP request | resourceとscopeを期待どおり送るか |
| Authorization Server | 認可、同意、token発行 | resource indicatorとscopeを扱えるか |
| MCP Server | Protected Resource Metadata、token検証、tool/resource/prompt制御 | audienceとscope不一致を拒否するか |
| Downstream API | 実データや外部操作 | MCP向けtokenをそのまま受け取らない設計か |
Protected Resource Metadataで何を発見させるか
- 1MCP endpoint
MCPサーバーの公開URLや論理resourceを固定します。
- 2Protected Resource Metadata
resource、authorization_servers、scopes_supportedなどを公開します。
- 3Authorization Server discovery
issuerやauthorization endpointへ機械的に進めます。
- 4Client request
metadataで得た情報を認可要求とtoken要求に反映します。
- 5Server validation
metadataの値と実際のtoken検証が食い違わないことを確認します。
メタデータの有無だけではなく、発見された情報で正しいresource向けtokenになるかを見ます。
metadataはクライアントの発見処理に使われる
根拠
Protected Resource Metadataは、MCPサーバーが「自分にアクセスするにはどの認可サーバーを見るべきか」「どのscopeを使う可能性があるか」などを機械的に伝えるための入口です。
RFC 9728では、protected resource metadataの主なパラメータとしてresource、authorization_servers、jwks_uri、scopes_supported、bearer_methods_supportedなどが定義されています。MCPではこの仕組みを使って、クライアントがAuthorization Server discoveryへ進みます。
最小のレビューでは、次のようなJSONを確認します。
{
"resource": "https://mcp-dev.internal.invalid",
"authorization_servers": ["https://auth-dev.internal.invalid"],
"scopes_supported": [
"mcp:tools:read",
"mcp:tools:call:read",
"mcp:resources:read"
],
"bearer_methods_supported": ["header"]
}
この例は説明用です。実際のmetadataは、MCP仕様、RFC 9728、利用するAuthorization Server、MCPクライアントの対応状況に合わせて決めます。
メタデータの有無だけで合格にしない
評価基準
よくある失敗は、.well-known/oauth-protected-resourceが200を返すだけで合格にしてしまうことです。公開前レビューでは、値の整合性まで見ます。
| 確認項目 | 見る理由 |
|---|---|
resourceが期待するMCPサーバーを指している | tokenの宛先になるresourceがずれるとaudience検証も崩れる |
authorization_serversが本番のissuerと一致する | stagingや別tenantの認可サーバーへ誘導しないため |
| scope候補が広すぎない | clientが過剰scopeを要求する誘因を減らすため |
| reverse proxy配下のURLが正しい | /mcpなどのpathとorigin-level metadataの解決を混同しないため |
| cache更新手順がある | key rotationやissuer変更時に古いmetadataを使い続けないため |
特にreverse proxyやmulti-tenant構成では、外から見えるURL、内部service名、Authorization Serverのissuerがずれがちです。metadataは、そのずれを隠す場所ではありません。クライアントとサーバーが同じresourceを見ているかを確認する場所です。
resourceパラメータをauthorization requestとtoken requestに入れる
- 1authorization request
clientがアクセスしたいprotected resourceをresourceで示します。
- 2user consent
ユーザーが許可する対象resourceとscopeを確認します。
- 3authorization code
認可結果をtoken requestへつなぎます。
- 4token request
code交換時にもresourceを含め、宛先を落としません。
- 5access token
MCPサーバーがaudienceとscopeを検証できるtokenにします。
authorization requestだけでなくtoken requestでもresourceを見ると、別resource向けtokenの混入を見つけやすくなります。
resourceは「どのAPI向けのtokenか」を伝える
根拠
RFC 8707は、OAuthのauthorization requestで、クライアントがアクセスしたいprotected resourceをresourceパラメータで示す仕組みを定義しています。MCP Authorization仕様では、MCPクライアントがauthorization requestとtoken requestにresourceパラメータを含めることが求められます。
このresourceは、単なるURLメモではありません。Authorization Serverが、どのresource向けのaccess tokenを発行するかを判断する材料になります。
概念的には、次のような流れです。
1. MCP Client -> MCP Server
GET /mcp
Authorizationなし
2. MCP Server -> MCP Client
401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://mcp-dev.internal.invalid/.well-known/oauth-protected-resource", scope="mcp:tools:read"
3. MCP Client -> Authorization Server
authorization request
resource=https://mcp-dev.internal.invalid
scope=mcp:tools:read
4. MCP Client -> Authorization Server
token request
resource=https://mcp-dev.internal.invalid
code=...
5. MCP Client -> MCP Server
Authorization: Bearer <access-token-for-https://mcp-dev.internal.invalid>
authorization requestだけでなくtoken requestも見る
確認項目
レビューでは、認可開始のURLだけを見ても足りません。code交換時のtoken request、refresh時のtoken request、再認可時のrequestでresourceが落ちていないかも確認します。
| タイミング | 確認すること | 失敗時の扱い |
|---|---|---|
| authorization request | resource=https://mcp-dev.internal.invalidが入る | 認可開始を失敗させる |
| token request | 同じresourceが入る | token取得を失敗させる |
| refresh | resourceが意図せず変わらない | 再認可または設定修正を要求する |
| MCP request | Bearer tokenが毎HTTP requestに付く | 401にする |
| server-side validation | tokenのaudience/resourceが期待値と一致する | 403または401相当で拒否する |
Authorization Serverやライブラリによって、resourceの扱い、audience claimへの反映、scopeとの関係は違います。ここを「ライブラリがいい感じにするはず」で済ませず、発行されたtokenが本当にMCPサーバー向けになっているかをテストで見るのが安全です。
scopeはMCPの操作とデータ範囲から選ぶ
MCP toolは見た目が同じtool callでも、データ範囲と副作用が大きく違います。
広いロール名より小さい操作単位で見る
条件
MCPのscope設計で避けたいのは、admin、user、readのような大きすぎる名前だけで始めることです。AIエージェントが呼び出すMCP toolは、見た目は同じ「tool call」でも、影響範囲が大きく違います。
たとえば、GitHub連携のMCPサーバーでも、Issue一覧の取得、PR diffの取得、コメント投稿、ラベル変更、workflow再実行は別の権限です。社内DB連携なら、SELECT、集計、エクスポート、更新、削除、外部送信は分けて考えるべきです。
MCPでは、Tools、Resources、Promptsごとに次の軸でscopeを考えます。
| MCP要素 | 例 | scope設計で見ること |
|---|---|---|
| Tools | search_issues, create_ticket, deploy_preview | 副作用、外部API、承認要否 |
| Resources | repo://docs/security.md, db://schema/orders | 読ませる範囲、機密度、tenant境界 |
| Prompts | incident_summary, release_note | 入力source、出力先、社内ルール |
| Sampling/Elicitationなど | ユーザー確認、追加入力 | 人間承認、PII、再実行性 |
read-onlyとwriteを同じscopeにしない
注意点
read-only MCP serverから始める方針はよい出発点です。ただし、read-onlyでも安全の完成形ではありません。Issue、ドキュメント、Slackログ、問い合わせ本文などは、prompt injectionを含む未信頼入力になり得ます。
write操作を入れるなら、最低でも次を分けます。
| 操作 | scope例 | 人間承認 | ログ |
|---|---|---|---|
| tool一覧取得 | mcp:tools:read | 不要なことが多い | 接続元とserver id |
| read-only tool実行 | mcp:tools:call:read | データ次第 | tool名、対象resource、件数 |
| write tool実行 | mcp:tools:call:write | 原則必要 | diff、対象、承認者、request id |
| admin操作 | mcp:admin | 必須 | before/after、承認、rollback |
| resource読み取り | mcp:resources:read | 機密度次第 | URI、tenant、分類 |
scopeは認可サーバーだけで完結しません。MCPサーバー側でも、toolごと、resourceごと、操作種別ごとにscopeを見て拒否できる必要があります。
audience検証で別resource向けtokenを止める
audience不一致は警告にとどめず、tool handlerへ進む前に拒否します。
signature検証だけではMCPサーバー向けとは言えない
根拠
JWTの署名が正しいことと、そのtokenが自分のMCPサーバー向けであることは別です。署名が正しく、期限内で、issuerも信頼できても、audienceが別APIなら、そのtokenをMCPサーバーで受け入れてはいけません。
MCP Authorization仕様とSecurity Best Practicesでは、別resource向けtokenの受理、audience検証失敗、token passthroughが重要なリスクとして扱われています。MCPサーバーは、提示されたaccess tokenが自分向けに発行されたものかを検証し、違う場合は拒否する必要があります。
公開前のtoken検証表は、次のように作れます。
| 検証 | 目的 | 失敗時 |
|---|---|---|
| issuer | 信頼するAuthorization Serverか確認する | 拒否 |
| signature | 改ざんされていないか確認する | 拒否 |
| expiry | 期限切れでないか確認する | 拒否 |
| audience | このMCPサーバー向けか確認する | 拒否 |
| scope | 要求されたMCP操作を許すか確認する | 拒否 |
| tenant/resource | 対象tenantやresource境界が合うか確認する | 拒否 |
| token type | 想定したBearer tokenか確認する | 拒否 |
audience不一致は警告ではなく拒否にする
評価基準
audience不一致をログだけにして処理を続けると、OAuthを入れた意味が薄れます。環境変数でSKIP_AUDIENCE_CHECK=trueのようなdebug bypassを入れる場合も、本番で有効化されない仕組みと検査が必要です。
失敗ログには、次のような情報だけを残します。
{
"event": "mcp_auth_denied",
"reason": "audience_mismatch",
"expected_resource": "https://mcp-dev.internal.invalid",
"issuer": "https://auth-dev.internal.invalid",
"request_id": "req_123",
"tool": "search_issues"
}
access token本体、authorization code、refresh token、秘密鍵、個人情報はログに出しません。原因調査に必要なのは、tokenそのものではなく、どの検証で拒否したかです。
token passthroughを禁止するレビュー観点
下流APIを呼べないという意味ではなく、別resource向けtokenの横流しを避けるという意味です。
passthroughはconfused deputyを起こしやすい
注意点
token passthroughは、MCPサーバーが受け取ったaccess tokenを下流APIへそのまま渡す設計です。一見便利ですが、resource境界を壊しやすい危険な設計です。
たとえば、MCPサーバー向けに発行されたtokenをGitHub APIへそのまま渡す。あるいは、GitHub API向けtokenをMCPサーバーが受け取り、自分向けtokenのように扱う。どちらも「誰が、どのresourceに、何を許したか」が曖昧になります。
| 設計 | 何が問題か |
|---|---|
| 受け取ったtokenを下流APIへそのまま送る | 下流APIがtokenを別の文脈で信頼する可能性がある |
| 下流API向けtokenをMCP tokenとして受け入れる | MCPサーバーのaudience検証が抜ける |
| scope不足時に広いscopeで再試行する | 最小権限が崩れる |
| ユーザー同意なしに別API権限を取る | consentと監査の境界が崩れる |
下流API呼び出しは別の権限設計として扱う
確認項目
token passthrough禁止は、「MCPサーバーから下流APIを呼んではいけない」という意味ではありません。下流APIを呼ぶなら、MCPサーバー向けtokenの検証とは別に、正規の権限設計を作る必要があるという意味です。
選択肢は構成によって変わります。
- サービスアカウントで下流APIを呼び、MCP側でユーザー操作を監査する
- Authorization Serverがon-behalf-of相当の安全なフローを提供する場合だけ使う
- 下流APIごとに別resourceとしてtokenを取り直す
- read-only APIから始め、write操作は人間承認と別scopeにする
- tenant境界をMCPサーバー側と下流API側の両方で検証する
どの構成でも、MCPサーバー向けtokenを「便利な万能token」として扱わないことが重要です。
TypeScript SDKを使うときに過信しない範囲
sampleを写す前に、自社のresource URLと期待するaudienceを固定します。
READMEにあるhelperと本番認可設計は別物
根拠
MCP TypeScript SDKのREADMEでは、MCP server/clientのライブラリ、stdio、Streamable HTTP、auth helpers、ExpressやHonoなどのmiddleware packageが説明されています。2026年6月15日に確認したnpm上の@modelcontextprotocol/sdkは1.29.0でした。
SDKがあることは大きな助けです。ただし、SDK READMEにauth helperがあることを、本番向けの認可設計が自動で完成するという意味に読み替えてはいけません。
| SDKで助かる領域 | アプリ側で決める領域 |
|---|---|
| MCP protocolの型やtransport | resource URLと公開URLの確定 |
| Streamable HTTPの接続処理 | Authorization Serverのissuerとtenant |
| auth関連helper | audience、scope、tenant検証ポリシー |
| Express/Honoなどの薄いadapter | 監査ログ、承認UI、失敗時の運用 |
| examples | production/staging分離、key rotation |
sampleを写す前に自社のresource URLを固定する
確認項目
サンプル実装を写す前に、次の値を固定してください。
PUBLIC_ORIGIN=https://mcp-dev.internal.invalid
MCP_ENDPOINT=https://mcp-dev.internal.invalid/mcp
PROTECTED_RESOURCE_METADATA=https://mcp-dev.internal.invalid/.well-known/oauth-protected-resource
AUTHORIZATION_SERVER_ISSUER=https://auth-dev.internal.invalid
EXPECTED_AUDIENCE=https://mcp-dev.internal.invalid
ENVIRONMENT=production
reverse proxyやAPI gateway配下では、アプリケーション内部のlocalhost:3000やcontainer名をresourceにしてしまう失敗があります。MCPクライアントとAuthorization Serverが見るresourceは、外部から見た安定した識別子にそろえます。
実装レビューで見るテストケース
token検証失敗時にtool handlerが呼ばれないことまで確認します。
metadata discoveryのテスト
確認項目
metadataは、静的JSONを返して終わりではありません。クライアントがそこからAuthorization Server discoveryへ進めるか、scopeのヒントが意図どおりか、stagingとproductionが混ざらないかを見ます。
| ケース | 期待結果 |
|---|---|
| tokenなしでMCP endpointへアクセス | 401とWWW-Authenticateが返る |
resource_metadata URLへアクセス | 正しいProtected Resource Metadataが返る |
| metadata内のAuthorization Serverを発見 | issuerやauthorization endpointが取得できる |
| staging clientでproduction resourceへアクセス | 拒否される |
| 古いmetadata cacheで接続 | 更新または明確な失敗になる |
token検証のnegative test
確認項目
認可のテストは成功ケースより失敗ケースが大事です。少なくとも次をCIまたは手動リリースチェックに入れます。
| 失敗ケース | 期待結果 | ログ |
|---|---|---|
| tokenなし | 401 | missing_token |
| 期限切れ | 401 | token_expired |
| issuer違い | 401または403 | issuer_mismatch |
| audience違い | 403 | audience_mismatch |
| scope不足 | 403 | insufficient_scope |
| 署名不正 | 401 | invalid_signature |
| read scopeでwrite tool | 403 | scope_denied |
| 別tenant resource | 403 | tenant_mismatch |
MCP toolの実行結果まで進む前に拒否できるかを確認します。失敗ケースでtool handlerが呼ばれているなら、認可middlewareの位置や検証順序を見直します。
ログと運用で見逃さないもの
ログが薄いと、原因調査の代わりにscope拡大や検証無効化へ流れやすくなります。
失敗理由は追えるがtoken本体は残さない
注意点
OAuth実装の初期運用では、401と403が増えます。ここでログが薄いと、原因調査のたびにscopeを広げたり、audience検証を一時的に無効化したりしがちです。それは避けたい。
ログに残す項目と残さない項目を先に決めます。
| 残す | 残さない | 集計する |
|---|---|---|
| request id | access token本体 | 401/403件数 |
| client idのハッシュ | authorization code | audience mismatch件数 |
| expected resource | refresh token | scope不足top N |
| issuer | 秘密鍵、client secret | tool別拒否件数 |
| tool名、resource URI | 個人情報の生値 | tenant別エラー率 |
| 拒否理由 | Prompt全文の生ログ | rollout前後の差分 |
rollout時はaudience不一致とscope不足を見る
評価基準
導入初期に見るべきメトリクスは、認可成功率だけではありません。むしろ、audience不一致、scope不足、metadata discovery失敗、Authorization Server discovery失敗の件数を見ます。
audience不一致が多いなら、クライアントが別resource向けtokenを取っているか、metadataのresourceがずれています。scope不足が多いなら、scope設計が細かすぎるのではなく、toolごとの権限要求と説明がずれている可能性があります。
「一時的に広いscopeを許す」は最終手段です。先に、どのtoolで、どのclientが、どのscopeを要求して失敗しているかを見ます。
失敗点
.well-knownが返るだけで、client discoveryやtoken検証まで通っていない。
あとで絞る前提でread、write、adminを混ぜてしまう。
audience検証失敗時に警告だけで処理を続ける。
localhost、internal host、staging issuerがproductionに残る。
token検証失敗後もtool handlerへ進んでしまう。
metadata公開、client discovery、token request、server-side validationを通しで確認して合格にします。
metadata endpointだけ作って検証を忘れる
一番起きやすい失敗です。.well-knownが返る、JSONとして読める、というテストだけでは足りません。
合格条件は、metadata公開、client discovery、authorization request、token request、server-side validationまで通ることです。逆に、metadataは返るのにtokenのaudienceが別resourceになるなら、その実装はまだ公開できません。
scopeを広くしてあとで絞る
初期開発では広いscopeの方が楽です。しかしMCP serverでは、後からscopeを細かくすると、既存client、承認UI、監査ログ、運用手順、ドキュメントをまとめて変えることになります。
最初から完璧なscope名にする必要はありません。ただし、read-only、write、副作用あり、admin、人間承認必須の境界は、最初の公開前に分けておくべきです。
audience検証の失敗をfallbackで通す
開発中は、tokenのaudienceが合わずに詰まることがあります。そこでdebug用fallbackを入れること自体はあります。ただし、本番でfallbackが残ると、別resource向けtokenを受け入れる穴になります。
公開前に見る項目は次です。
- audience検証を無効化する環境変数がproductionで使えない
- staging issuerとproduction issuerが混ざらない
localhostやinternal hostがexpected audienceに残っていない- scope不足時に自動で広いscopeへ昇格しない
- token検証失敗時にtool handlerが呼ばれない
実務で使うなら
- 1. resource
MCPサーバーのresource識別子と公開URLを決めます。
- 2. metadata
Protected Resource Metadataの公開URLと中身を決めます。
- 3. requests
authorization requestとtoken requestにresourceが入ることを確認します。
- 4. validation
issuer、signature、expiry、audience、scopeを検証します。
- 5. scopes
Tools、Resources、Promptsごとに必要scopeを割り当てます。
- 6. passthrough
下流APIの権限設計を別に作ります。
- 7. tests
negative testをCIまたはリリースチェックに入れます。
- 8. logs
token本体を残さない監査ログを用意します。
resource識別子やAuthorization Serverの扱いが固まらない段階では、先に公開しない判断も必要です。
最初のチェックリスト
確認項目
MCP OAuthを実務に入れるなら、次の順で確認すると迷いにくいです。
- MCPサーバーのresource識別子を決める
- Protected Resource Metadataの公開URLと中身を決める
- Authorization Serverのissuerとdiscoveryを確認する
- authorization requestとtoken requestに
resourceが入ることを確認する - access tokenのissuer、signature、expiry、audience、scopeをMCPサーバー側で検証する
- Tools、Resources、Promptsごとに必要scopeを割り当てる
- read-only、write、admin、人間承認必須の境界を分ける
- token passthroughを禁止し、下流APIの権限設計を別に作る
- negative testをCIまたはリリースチェックに入れる
- token本体を残さない監査ログを用意する
導入しない方がよいケース
次に当てはまるなら、HTTP公開のMCP OAuth実装に進む前に設計を戻した方がよいです。
- MCPサーバーの公開URLやresource識別子がまだ変わり続けている
- Authorization Serverがresource indicatorやaudience制御をどう扱うか確認できていない
- read-only toolとwrite toolが同じscopeになっている
- token検証の失敗時に、運用上の理由で処理を続ける設計になっている
- 下流API呼び出しに受け取ったtokenをそのまま使う前提になっている
- 401/403の原因を追えるログがない
この状態で公開すると、問題が起きたときにscope拡大、検証無効化、ログ出力増加のような危ない応急処置に寄りやすくなります。
セキュリティ・コスト注意
セキュリティは単純な勝敗ではなく、扱う操作、tenant、下流API、運用体制で条件が変わります。
セキュリティ注意
MCP OAuthのセキュリティは、OAuthを入れた時点で終わりではありません。むしろ、OAuthを入れたことで「許可された操作」の範囲が明確になり、そこからMCP toolの副作用やデータ境界を細かく見る必要が出ます。
注意点は次です。
- access token、authorization code、refresh tokenをログに残さない
- user consentとtool実行承認を混同しない
- read-only toolでも、未信頼入力やprompt injectionを想定する
- MCPサーバー向けtokenを下流APIの認証に流用しない
- scope不足時に自動で権限昇格しない
- key rotation、issuer変更、metadata cache更新の手順を決める
- multi-tenantではtenant境界をtokenとアプリ側の両方で見る
コスト注意
OAuth自体の金銭コストより、運用コストが効きます。scopeを細かくすると、承認UI、ドキュメント、テスト、問い合わせ対応が増えます。逆にscopeを粗くすると、セキュリティレビューと事故対応のコストが増えます。
小さく始めるなら、read-only tool、限定されたResources、短いtoken lifetime、明確なnegative testから始めるのが現実的です。write toolやadmin操作は、MCP OAuthの接続が安定してから、人間承認と監査ログを付けて追加します。
AI Dev Lab Japanでは、MCPやAIコーディングエージェントの仕様更新、権限設計、検証ログの読み方を継続的に扱っています。更新通知を受け取りたい場合は、記事末尾のニュースレター導線から登録できます。
次に読むなら
参照した主な情報源
- https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization
- https://modelcontextprotocol.io/specification/2025-11-25/basic/security_best_practices
- https://datatracker.ietf.org/doc/html/rfc9728
- https://datatracker.ietf.org/doc/html/rfc8707
- https://github.com/modelcontextprotocol/typescript-sdk/blob/main/README.md
更新履歴
- 2026年6月15日
MCP Authorization 2025-11-25版、MCP Security Best Practices、RFC 9728、RFC 8707、MCP TypeScript SDK README、@modelcontextprotocol/sdk 1.29.0を確認して初稿を作成しました。
導入時には利用中のMCP仕様、Authorization Server、SDK versionを確認してください。
- 2026-06-15: MCP Authorization 2025-11-25版、MCP Security Best Practices、RFC 9728、RFC 8707、MCP TypeScript SDK README、
@modelcontextprotocol/sdk1.29.0を確認して初稿を作成。
