MCPのOAuthを解説する:401のポインタ、PKCE、動的クライアント登録、スコープを最初から最後まで
MCPの認可はOAuth 2.1です。401がサーバーのメタデータを指し、クライアントが自己登録し、PKCEがコードを守り、スコープ付きの更新可能なトークンが貼り付けた鍵を置き換えます。
目次
MCPの認可は、いくつかの必須要素を加えたOAuth 2.1です。リモートMCPサーバーへの未認証リクエストは、サーバーのメタデータを指す 401 を受け取ります。クライアントはそれをたどって認可サーバーに至り、自分を識別し、ブラウザを開いてユーザーにスコープへの同意を求め、PKCEで保護されたコードを短命のアクセストークンとローテーションするリフレッシュトークンに交換します。結果として得られるのは、設定ファイルに貼り付けた鍵ではなく、スコープ付きで取り消し可能な資格情報です。
これが一段落での全体の流れです。この記事では、MCP認可仕様(リビジョン2025-11-25)に沿って一歩ずつたどり、PKCE、動的クライアント登録、スコープがそれぞれ何から守るのかを説明し、実際のサーバー、つまり私たちのサーバーに対して流れがどう動くかを示します。各段階がクライアント側からどう見えるかが分かるはずです。
そもそもなぜMCPはOAuthを使うのか
stdio経由のローカルMCPサーバーは環境から認証情報を読み、仕様はOAuthを使うべきでないとしています。リモートサーバーは違います。ひとつのデプロイが、それぞれ異なる権限を持つ多くの人に、サーバー運用者が一度も見たことのないAIアプリから仕えます。そこから3つの問題が生じます。
- サーバーは、すべての呼び出しで誰が尋ねているかを知る必要がある。
- ユーザーは、すべてを渡すことなく、アプリが何をできるかを制限する必要がある。
- 両者は、パスワードを変えたり鍵を手でローテーションしたりせずに、後でアクセスを終了する手段を必要とする。
貼り付けたAPIキーは、1つ目の問題を不十分に解決し、残り2つはまったく解決しません。OAuthはまさにこの形、つまりアプリがサービスに対してある人の代わりに動く状況のために設計されており、OAuth 2.1はその統合されたより厳格な版です。OAuth 2.1の用語集エントリに2.0から削除されたものを列挙しています。MCPに関係するのは、PKCEが必須であること、リダイレクトURIが完全一致でなければならないこと、トークンをクエリ文字列に載せてはならないことです。
MCP認可仕様は5つの文書の上に成り立っています。OAuth 2.1ドラフト(draft-ietf-oauth-v2-1-13)、Authorization Server Metadata(RFC 8414)、Dynamic Client Registration(RFC 7591)、Protected Resource Metadata(RFC 9728)、そしてClient ID Metadata Documentsドラフトです。MCPサーバーを使うために読む必要はありませんが、それぞれが以下の問いのひとつに答えています。
流れを一歩ずつ
リモートサーバーを追加した瞬間から、モデルが最初のツール呼び出しを行う瞬間までに起きることです。すべてクライアントが行い、あなたに見えるのはブラウザのタブだけです。
- クライアントがトークンなしでサーバーを呼ぶ。 OAuthリソースサーバーとして振る舞うサーバーは、URLである
resource_metadataを含むWWW-Authenticate: Bearerヘッダー付きで401 Unauthorizedを返します。仕様はサーバーにRFC 9728の実装を、クライアントにこのヘッダーの解析を要求します。ヘッダーがなければ、クライアントは代わりにwell-known URIを試さなければなりません。 - クライアントが保護リソースのメタデータを取得する。 文書は少なくともひとつの
authorization_serversを名指しし、scopes_supportedを列挙することもあります。 - クライアントが認可サーバーを発見する。 RFC 8414(
/.well-known/oauth-authorization-server)またはOpenID Connect Discoveryでそのサーバーのメタデータを取得します。クライアントは両方をサポートしなければなりません。メタデータには認可、トークン、登録の各エンドポイント、サポートするPKCEメソッド、存在すればclient_id_metadata_document_supportedが列挙されています。 - クライアントがPKCEのサポートを確認する。 メタデータに
code_challenge_methods_supportedがなければ、クライアントは続行を拒否しなければなりません。静かなダウングレードはありません。 - クライアントが自分を識別する。 仕様の優先順位で3つの選択肢があります。持っていれば事前登録された資格情報。クライアントIDがクライアント自身のホストするJSONファイルへのHTTPS URLであるClient ID Metadata Document。あるいは登録エンドポイントへの
POSTでその場でclient_idを受け取る動的クライアント登録。仕様は現在、サーバーとクライアントはメタデータ文書をサポートすべきで、動的登録はフォールバックとしてサポートしてもよいとしています。 - クライアントがブラウザを開く。 認可URLには、クライアントID、リダイレクトURI、要求するスコープ、
state値、code_challenge_method=S256付きのPKCEのcode_challenge、そしてMCPサーバーを名指しするresourceパラメータ(RFC 8707)が含まれます。ユーザーはサインインし、クライアント名とスコープを列挙した同意画面を見ます。 - 認可サーバーがコードとともにリダイレクトで戻す。 コードは短命で一度しか使えません。
- クライアントがコードをトークンに交換する。 トークンリクエストには、コード、元のPKCEの
code_verifier、同じresourceパラメータが含まれます。応答はアクセストークンと、通常はリフレッシュトークンです。 - すべてのMCPリクエストがトークンを運ぶ。
Authorization: Bearerに載せ、URLには決して入れません。サーバーは呼び出しごとに、トークンが有効で、このサーバー向けに発行されたものであることを検証します。 - 呼び出しにより広いスコープが必要なとき、 サーバーは
error="insufficient_scope"と必要なスコープを添えて403を返します。クライアントはより広いセットで流れを再実行します。仕様はこれをステップアップ認可と呼び、クライアントに再試行回数の上限を設けるよう求めています。
各要素が何から守るのか
| 仕組み | 定義元 | 防ぐ攻撃 |
|---|---|---|
| 保護リソースメタデータ | RFC 9728 | クライアントが誤った認可サーバーを推測したり誘導されたりすること |
| 認可サーバーメタデータ | RFC 8414 | サーバー変更時に壊れるハードコードされたエンドポイント |
| PKCE(S256) | RFC 7636、OAuth 2.1 | 盗まれた認可コードが他人に引き換えられること |
| リダイレクトURIの完全一致 | OAuth 2.1 | コードを攻撃者に送るオープンリダイレクト |
state パラメータ | OAuth 2.1 | コールバックに対するクロスサイトリクエストフォージェリ |
resource パラメータ | RFC 8707 | あるサーバー向けのトークンが別のサーバーで再利用されること |
| サーバー側のオーディエンス検証 | RFC 8707、OAuth 2.1 | トークンのパススルーと混乱した代理人攻撃 |
| 短命のアクセストークン | OAuth 2.1 | 漏洩したトークンが長く有効であり続けること |
| ローテーションするリフレッシュトークン | OAuth 2.1 | 盗まれたリフレッシュトークンが静かに再利用されること |
| スコープと同意 | OAuth 2.0/2.1 | アプリがユーザーの同意以上のことをすること |
このうち2つは、よく質問されるので詳しく見ておく価値があります。
PKCE:なぜコードは盗んでも役に立たないのか
ほとんどのMCPクライアントはパブリッククライアントです。デスクトップアプリ、エディタ、CLIなど、秘密を保持できないものです。認可コードフローでは、コードはリダイレクトで戻ってきますが、ノートPCやスマートフォンでは同じURLに登録された別のプログラムがそのリダイレクトを横取りできます。PKCE以前は、コードを持つ者が誰でもそれを引き換えられました。
PKCEはサインインごとに一度きりの秘密を加えます。クライアントはランダムな code_verifier を生成して保持し、認可リクエストとともに code_challenge = BASE64URL(SHA256(code_verifier)) を送ります。コードを交換する際には元のverifierを提示します。認可サーバーはそれをハッシュ化し、保存したchallengeと比較し、異なれば交換を拒否します。コードはあってもverifierのない盗人は何も得られません。PKCEのエントリでは plain メソッドと、OAuth 2.1とMCPが可能な限り S256 を使うよう求める理由を扱っています。
動的クライアント登録:なぜ誰もコンソールでアプリを作らないのか
従来のOAuthは、開発者が各アプリを事前に登録することを前提としていました。数千のAIクライアントのどれもが、事前の関係なしに数千のMCPサーバーのどれにでも接続しうる世界では、それはスケールしません。動的クライアント登録(RFC 7591)は、クライアントが名前とリダイレクトURIという自身のメタデータを登録エンドポイントに POST し、即座に client_id を受け取ることを可能にします。
2025-11-25リビジョンはよりすっきりした答え、Client ID Metadata Documentsを追加しました。クライアントID自体が、クライアントを記述するJSON文書を指すHTTPS URLになります。認可サーバーはそれを取得し、文書の client_id がURLと完全に一致することを確認し、リダイレクトURIを照合します。仕様は、クライアントとサーバーはこれをサポートすべきで、互換性のために動的登録を残してもよいとしています。どんなクライアントでも登録できるため、慎重な認可サーバーは登録が信頼を意味しないものとして扱います。同意画面にクライアント名とリダイレクト先ホストを明示し、リダイレクト先がただの localhost ポートである場合は警告します。仕様は、メタデータ文書だけではこれを完全には守れないと注記しています。
スコープ:狭めることはあっても広げることはない
スコープは同意画面に並ぶ名前です。work.read、crm.write などです。アプリがセットを要求し、ユーザーが一部または全部を承認し、トークンがその結果を運びます。MCP仕様はクライアントに、401 チャレンジの scope パラメータがあればそれを、なければサーバーの scopes_supported を要求し、最初からすべてを求めるのではなく後からステップアップするよう指示しています。
最も重要な規則は、OAuth標準が各APIに委ねているものです。スコープはアプリがユーザーの代わりに求めてよいものを記述するのであって、そのユーザー自身ができることを超えてはなりません。良いサーバーは呼び出しごとに両方を確認します。トークンはそのスコープを持っているか、そしてその背後の人はこのレコードに対してこの操作を許可されているか。
実際のサーバーでの同じ流れ
上の手順が、私たちが運用し日々使っている https://atrix.dev/api/mcp のAtrix MCPサーバーに対してどう見えるかを示します。抽象的な流れを具体的な挙動と照らし合わせられます。開発者ガイドにクライアントごとの手順があります。
Claude Codeでは、設定全体は claude mcp add --transport http atrix https://atrix.dev/api/mcp に続けて /mcp からAuthenticateを選ぶだけです。このコマンドは意図的に認証情報を含みません。その後に起きることは次の通りです。
- 最初のリクエストはRFC 9728のポインタ付きで
401を受け取ります。発見はRFC 8414とRFC 9728に従います。 - クライアントは動的に自己登録します。クライアントシークレットはどこにもありません。私たち自身のアプリを含め、すべてのクライアントがパブリッククライアントだからです。
- PKCEは
S256のみです。サーバーはメタデータでS256だけを公開し、plainを拒否します。 - ブラウザが開き、ワークスペースを選んでスコープを承認します。コードは60秒間有効で、一度しか使えません。
- クライアントは、1時間有効な
atx_oat_で始まるアクセストークンと、90日間有効で使用のたびにローテーションするatx_ort_で始まるリフレッシュトークンを受け取ります。 - スコープがあなたの権限を増やすことはありません。呼び出しごとにトークンの背後のアカウントに対して解決されるため、同僚のアクセスが取り消されれば、その人が作ったすべてのトークンは次のリクエストから何にも届かなくなります。9つのスコープは、案件金額や雇用記録のようにアカウント側の対応する権限も必要とし、給与はまったく付与できません。
- 制限はトークンあたり毎分120呼び出し、30書き込みです。すべての呼び出しはツール、結果、対象で監査され、内容は記録されません。
CIジョブやブラウザのないサーバーには、代わりに atx_pat_ で始まるパーソナルアクセストークンがあり、--header "Authorization: Bearer ..." として送ります。これは動作しますが、ブラウザがある場所ではどこでも劣った選択です。ディスク上に平文で置かれ、作成時に選んだ期間だけ生き、同意画面を飛ばします。私たちはこの選択肢をパイプライン向けに残し、人にはOAuthを勧めています。
PKCEフローと貼り付けたトークン:何を手放すか
| PKCE付きOAuth 2.1 | 貼り付けたパーソナルアクセストークン | |
|---|---|---|
| 接続方法 | URLを追加し、ブラウザで承認 | 設定でトークンを作り、設定ファイルに貼り付け |
| 有効期間 | アクセス1時間、リフレッシュ90日ローテーション(Atrix) | 30日から無期限まで、選択次第 |
| 保存場所 | クライアントの安全なストア | 設定ファイル、多くは平文 |
| 範囲の決め方 | 同意画面、後でステップアップ | 作成時に選択 |
| 取り消し方法 | 付与またはアカウントの取り消し | トークンの削除 |
| ブラウザの要否 | 必要 | 不要 |
| 適した用途 | AIアプリを使う人 | CI、cron、ヘッドレスサーバー |
FAQ
MCPはOAuthを必須としていますか
プロトコル上、認可は任意です。サーバーがHTTPトランスポートを使い認可をサポートする場合、仕様はOAuth 2.1ベースの認可仕様に準拠すべきだとしています。stdioサーバーはこれを使わず、環境から認証情報を取るべきです。
MCPにとってOAuth 2.0と2.1の違いは何ですか
OAuth 2.1はインプリシットグラントとパスワードグラントを削除し、認可コードフローにPKCEを必須とし、リダイレクトURIの完全一致を要求し、クエリ文字列でのベアラートークンを禁止し、パブリッククライアントにはリフレッシュトークンのローテーションまたは送信者制約を要求します。MCPはこれらすべてを引き継いでいます。
なぜ私のMCPクライアントは認可サーバーへの接続を拒否するのですか
最も多い理由はPKCEサポートの欠如です。認可サーバーのメタデータに code_challenge_methods_supported がなければ、MCPクライアントは続行を拒否しなければなりません。次に多いのは、401 の WWW-Authenticate ヘッダーが欠けているか不正な形式であることです。
動的クライアント登録は今も必須ですか
いいえ。2025-11-25リビジョンは、クライアントとサーバーはClient ID Metadata Documentsをサポートすべきで、動的登録はフォールバックとしてサポートしてもよいとしています。Atrixを含む多くのサーバーは、古いクライアントが依存しているため動的登録を提供し続けています。
MCPトークンは作成した本人以上のことができますか
できるべきではありません。スコープはアクセスを狭めるものであり、増やすものではありません。よく作られたサーバーは呼び出しごとに本人の権限を解決するため、トークンが所有者以上に届くことはなく、所有者がアクセスを失った瞬間にトークンも失います。
OAuthではなくパーソナルアクセストークンを使うべきなのはいつですか
ブラウザがない場所だけです。CIパイプライン、cronジョブ、ヘッドレスサーバーです。それ以外のすべての場所では、OAuthのほうが、ディスクに秘密を保存せずに、より短命でスコープ付きの取り消し可能な資格情報を得られます。
次のステップ
開発者ガイドは、Claude Code、Claude Desktop、ChatGPT、Cursor向けの正確なコマンドとともに、Atrixの流れをクライアントごとに解説しています。上の用語が初めてなら、OAuth 2.1とPKCEのエントリが私たちの知る最も短い説明です。