こんにちは。ネットワールドで Cloudflare を担当しております。
前回は Cloudflare Workers 上に MCP サーバーを1つ作り、Okta のカスタム認可サーバーで保護しました ( こちら ) 。 今回はその続きで、Cloudflare の MCP サーバーポータルを使い、複数の MCP サーバーの入口をひとつにまとめます。
- 記事の目的
- MCP サーバーが増えたときに接続先と認証が分散する問題を、Cloudflare MCP サーバーポータルでどう解決するかを示すことです。特に、2026年7月に追加された手動 OAuth を使って企業 IdP(今回は Okta)を上流に据える手順を、実機の画面で追います。
- 検証の背景
- MCP サーバーポータルは、上流の OAuth プロバイダーへ動的にクライアント登録する仕組みを前提としていました。しかし動的クライアント登録に対応していない、あるいは無認証での登録を許していない IdP は多く、そのままでは上流に据えられませんでした。2026年7月31日に追加された手動 OAuth(Static OAuth) は、管理者が事前登録した資格情報を使うことでこの制約を外しています。ここで当然の疑問が湧きます。管理者が1組の資格情報を登録するなら、全員が同じアカウントとしてアクセスすることになるのではないか。その疑問に実機で答えるのが今回の検証です。
- 登場する製品の位置づけ
- 本検証の主役は Cloudflare One の MCP サーバーポータル(手動 OAuth)です。Okta は「事前登録型で使う企業向け IdP」の例として、前回ブログで作った Workers 上の自作 MCP サーバーは「OAuth で保護された上流 MCP サーバー」の代役として使っています。同種の IdP や任意の上流 MCP サーバーに読み替えられる内容です。
- 今回検証した範囲
- ポータルの構築、手動 OAuth による自作 MCP サーバーの登録、Claude からの接続、そしてポータルを経由しても利用者本人として認可されるかの確認までです。併せて、ツール単位の監査ログに何が残るかも見ています。実際につまずいた点についても記載してます。
- 検証時点と前提
- 2026年8月時点の検証です。Cloudflare は Enterprise プラン、MCP サーバーポータルはベータ版の機能を使用しています。MCP の認可仕様は改訂が続いている領域なので、画面や挙動が変わっている可能性があります。最新の情報は公式ドキュメントをご確認ください。
1. サーバーが1つで済まないという問題
前回の記事では MCP サーバーを1つ作りました。しかし現実の社内環境では、用途ごとにサーバーが増えていきます。
| サーバーが増えると起きること | 誰が困るか |
|---|---|
| 利用者が接続先を何個も登録することになる | 利用者 |
| サーバーごとに認証設定を作り込む必要がある | 構築側 |
| 「誰がどのサーバーに繋いでいるか」を横断で把握できない | 管理側 |
| 新しいサーバーを追加するたびに、全利用者に案内が必要 | 全員 |
Web アプリケーションの世界では、この問題はとうに解かれています。個々のアプリに認証を作り込むのではなく、手前にリバースプロキシや Zero Trust の層を置いて、そこで一括して認証する。同じ発想を MCP に持ち込んだのが、Cloudflare の MCP サーバーポータルです。
2. CloudflareのMCP サーバーポータルとは
複数の MCP サーバーをまとめ、利用者からは1つのエンドポイントに見えるようにする仕組みです。ポータル自体は Cloudflare Access で保護されるため、入口の認証は Access のポリシーで一元管理できます。
利用者が登録する接続先はポータルの URL ひとつだけです。サーバーが増えてもポータル側に追加すれば、利用者側の設定変更は要りません。
この構成には認可が2段ある
ここが今回の記事で押さえてほしい点です。ポータルを挟むと、認可が二段構えになります。
| 段 | 区間 | 何を決めるか | 担当 |
|---|---|---|---|
| 1段目 | Claude → ポータル | そもそもポータルに入れるか | Cloudflare Access(Okta認証) |
| 2段目 | ポータル → 自作MCPサーバー | その人としてどのツールを使えるか | Okta のカスタム認可サーバー |
2段目は、前回の記事で作ったものがそのまま使われます。Workers 側のコードは1行も変えていません。変わるのは「誰が OAuth のクライアントになるか」だけで、前回の記事では Claude が担っていた役割を、今回はポータルが担います。
3. なぜ「手動 OAuth(Static OAuth)」が必要なのか
CloudflareのMCP サーバーポータルが上流の MCP サーバーに接続するとき、OAuth のクライアントとして振る舞う必要があります。その資格情報をどう用意するかで、2つの方式があります。

| 方式 | やること | 前提 |
|---|---|---|
| 自動(推奨) | Cloudflare が初回利用時に上流へクライアントを動的登録する | 上流が動的クライアント登録(RFC 7591)に対応し、かつ無認証での登録を許していること |
| 手動の資格情報 | 管理者が上流に登録済みの client_id と client_secret を入力する | なし |
問題は、動的クライアント登録に対応していない上流プロバイダーが存在することです。GitHub や Slack など、広く使われている OAuth プロバイダーの多くがこれにあたります。
2026年7月31日に追加された手動 OAuth が、この制約を外しました。
MCP サーバーを追加する際、管理者はアップストリームのプロバイダーに登録した OAuth アプリケーションのクライアント ID とクライアントシークレットを入力できます。この設定では、カスタム OAuth エンドポイント、スコープ、および client_secret_post と client_secret_basic の認証方式もサポートされます。 原文: When adding an MCP server, administrators can enter the client ID and client secret from an OAuth application registered with the upstream provider. The configuration also supports custom OAuth endpoints, scopes, and the client_secret_post and client_secret_basic authentication methods.
出典: https://developers.cloudflare.com/changelog/post/2026-07-31-mcp-portal-manual-oauth/
仕様の側でも「事前登録」が本流になりつつあります
ここで補足しておきたい動きがあります。この機能追加とほぼ同じ時期に、MCP の仕様側でも動的クライアント登録の位置づけが変わりました。
動的クライアント登録は非推奨です。新しい実装では代わりに Client ID Metadata Documents を使用すべきです。このオプションは、Client ID Metadata Documents をサポートしない認可サーバーとの後方互換性のために残されています。 原文: Dynamic Client Registration is deprecated. New implementations should use Client ID Metadata Documents instead. This option remains available for backwards compatibility with authorization servers that do not support Client ID Metadata Documents.
出典: https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/client-registration
同じ仕様書では、クライアントが取るべき登録方式の優先順位も示されています。
| 優先順位 | 方式 | 今回との関係 |
|---|---|---|
| 1 | 事前登録済みのクライアント情報を使う | 手動 OAuth はこれにあたります |
| 2 | Client ID Metadata Documents を使う | 認可サーバー側の対応が必要 |
| 3 | 動的クライアント登録をフォールバックとして使う | ポータルの「自動」がこれ |
| 4 | 利用者にクライアント情報を入力してもらう | — |
つまり手動 OAuth は、「動的登録に対応していない IdP のための救済策」であると同時に、仕様が推す方向とも合致しています。ポータルの画面では「自動(推奨)」と表示されますが、何れ変わる可能性があります。
ここで湧く疑問
管理者が1組の client_id / client_secret を登録するということは、全員が同じアカウントとしてアクセスすることになるのではという疑問が出ます。それでは 前回の記事でやったことが台無しです。
結論を先に書くと、そうはなりません。client_id / client_secret は「アプリケーションの身分証」であって、「利用者の身分証」ではないためです。認可の流れは次のようになります。
client_id / client_secret が使われるのは「ポータルというアプリケーションが Okta に対して名乗る」場面だけで、誰として認可するかは、その都度ブラウザで本人が決めます。8章でこれを実データで確認します。
4. Cloudflare Access に Okta を繋ぐ
まず入口を作ります。Okta を IdP として Cloudflare One に登録します。
Okta 側:Web アプリケーションを作る
前回作った Claude 用のアプリ(ネイティブ / PKCE)とは別に、Web アプリケーションとして新規に作ります。Cloudflare Access はクライアントシークレットを保持できる機密クライアントなので、種別が異なります。


リダイレクト URI には https://<チームドメイン>.cloudflareaccess.com/cdn-cgi/access/callback を設定します。
忘れるとハマる:グループクレームの設定
ここを飛ばすと後で認証が通りません。私は実際に飛ばして 400 エラーで止まりました(10章参照)。
アプリの 認証 タブで、トークンクレームのレガシー構成を開き、グループクレームフィルターを設定します。
アプリケーションの画面から 認証 タブに移動します。Token claims までスクロールし、Show legacy configuration > Edit を選択します。Groups claim filter を Matches regex に設定し、値を .* にします。 原文: From the application view, go to the Sign On tab. Scroll down to Token claims and select Show legacy configuration > Edit. Set Groups claim filter to Matches regex and its value to .*
出典: https://developers.cloudflare.com/cloudflare-one/integrations/identity-providers/okta/

Cloudflare 側:IdP として登録
Zero Trust の Integrations > Identity providers から Okta を選び、Okta で取得した値を入力します。
| 項目 | 入れる値 |
|---|---|
| Name | 任意の識別名 |
| App ID | Okta のクライアント ID |
| Client secret | Okta のクライアントシークレット |
| Okta account URL | Okta のドメイン |

保存したら 画面上に表示される Test を実行します。成功すると、Okta から返ってきた属性がそのまま表示されます。

groups に Okta のグループが並んでいれば、Access のポリシーでグループ条件を使える状態です。amr に mfa が含まれていれば、多要素認証を経ていることも Cloudflare 側で判定できます。
5. MCP サーバーポータルを作る
Zero Trust の Access コントロール > MCP ポータルから作成します。

ここで指定したカスタムドメインが、利用者が接続する唯一の URL になります。DNS レコードは自動で作られます。
作成時には Access ポリシーを最低1つ紐付ける必要があります。ポリシーが無いと保存できません。

マネージド OAuth をオンにする
詳細設定に「マネージド OAuth」という項目があります。Claude のようなリモートのクライアントから繋ぐ場合、これが必要です。
マネージド OAuth は MCP サーバーポータルで利用可能で、MCP クライアントがブラウザの Cookie フローを使わずに、ポータル経由でユーザーを認証できるようにする仕組みです。 原文: Managed OAuth is available on MCP server portals and is the mechanism that allows MCP clients to authenticate users through the portal without a browser cookie flow.
出典: https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/managed-oauth/
Claude は Anthropic 側でホストされているため、ブラウザの Cookie を持てません。ここをオンにしておきます。

6. 手動 OAuth で自作サーバーを登録する
ここが本題です。MCPサーバポータルに、前回作った MCP サーバーを繋ぎます。
リダイレクト URI を確認する
「手動の資格情報」を選ぶと、上流プロバイダーに登録すべきリダイレクト URI が表示されます。

この URI は Cloudflare 共通のホストになっており、テナントごとには変わりません。画面の説明にも「このサーバーが存在する限り変わりません」とあります。
Okta 側:ポータル用のアプリをもう1つ作る
ここまでで Okta に作ったアプリは2つです。今回3つ目を作ります。役割が全部違うので、整理しておきます。
| アプリ | 種別 | 役割 | 作った記事 |
|---|---|---|---|
| Claude 直結用 | ネイティブ / PKCE | Claude が MCP サーバーの認可を得る | 前回 |
| Cloudflare Access 用 | Web / シークレット | Access が Okta で利用者を認証する | 本記事4章 |
| ポータル用 | Web / シークレット | ポータルが MCP サーバーの認可を得る | 本記事(ここ) |


エンドポイントは自動検出できる
client_id と client_secret を入力したら、「OAuth エンドポイントを検出」ボタンを押してみてください。


これは地味ですが、なかなか良い体験でした。前回の記事で Workers に実装した保護リソースメタデータ(RFC 9728)を Cloudflare が読み、そこに書かれた認可サーバーを辿って、各エンドポイントを引き当てています。手で URL を組み立てる必要がありません。
スコープだけは手入力です。ここで指定した値が、全利用者に一律で使われます。前回の記事の4章で「スコープは全員共通、差はグループで」と書いた理由がこれです。
client_secret_post と client_secret_basic を選べますが、画面の注記どおり空欄のままで問題ありませんでした。トークン交換で失敗する場合のみ、明示指定を試すとよいと思います。7. Claude から繋ぐ
全体のトークンフロー
ここから先の画面遷移を追いやすくするため、先に全体の流れを図にしておきます。この構成では3種類のトークンが登場します。図はクリックで拡大できます。
凡例
| 略記 | 役者 | 役割 | 発行するもの |
|---|---|---|---|
| U | 利用者 | すべての許可ボタンを押す本人(リソースオーナー) | なし |
| C | Claude | MCP クライアント | なし |
| P | MCPサーバーポータル | 顔1: Claude への認可サーバー(マネージドOAuth) / 顔2: Okta への OAuth クライアント(手動OAuthで事前登録) | ポータル用アクセストークン(第3段) |
| AC | Cloudflare Access | 入口の門番。ID トークンを検証しポリシー判定 | なし |
| O1 | Okta 組織認可サーバー | ログイン用の発行所 | ID トークン(第1段) |
| O2 | Okta カスタム認可サーバー(mcp-kb) | MCP 用の発行所 | アクセストークン(第2段) |
| W | Workers 自作MCPサーバー | リソースサーバー。検証と判定のみ | なし |
飛んでいるトークンは3種類
| トークン | 発行者 | 宛先(aud) | 役目 |
|---|---|---|---|
| ID トークン | Okta 組織認可サーバー(O1) | Access(cloudflare-access アプリ) | 入口での本人確認 |
| ポータル用アクセストークン | ポータル(P) | ポータル | Claude がポータルに入る鍵 |
| MCP 用アクセストークン | Okta カスタム認可サーバー(O2) | Workers | ツールを叩く鍵(whoami で見えるのはこれ) |
Claudeから繋ぐ
Claudeのカスタムコネクタに、ポータルの URL を登録します。クライアント ID もシークレットも空欄です。マネージド OAuth により、ポータル自身が動的クライアント登録に対応する認可サーバーとして振る舞うためです。

認証は二段階で進む
接続を押すと、まず Cloudflare Access のログイン画面が出ます。


Okta で認証すると、次にポータルが「上流のサーバーを認可してください」と求めてきます。

Authorize を押すと再び Okta の画面を経て、Connected になります。

この画面が、手動 OAuth の本質を示しています。管理者が client_id / client_secret を登録していても、実際に「認可する」ボタンを押すのは利用者本人です。共有アカウントで繋いでいるわけではありません。
8. 本当に本人として通っているのか
画面上の見た目だけでは信用できないので、トークンの中身を確認します。前回作った whoami ツールがそのまま使えます。

| 項目 | 直結時(前回) | ポータル経由(今回) | 判定 |
|---|---|---|---|
| subject | 自分のメールアドレス | 同じ | 本人として通っている |
| groups | 所属グループ | 同じ | 権限も維持されている |
| audience | Worker の URL | 同じ | ポータルは中継しているだけ |
| scopes | クライアントが決めた値 | ポータルの設定値 | 要求元が変わった |
subject が一致したことが決定的です。ポータルという共有の入口を経由しても、下流の MCP サーバーから見えるのは管理者ではなく本人でした。3章で書いた「client_id は利用者の身分証ではない」という説明が、実データで裏付けられた形です。
audience が Worker の URL のまま変わっていない点も重要です。ポータルはトークンを差し替えたり自分宛てに作り直したりせず、上流向けのトークンをそのまま中継しています。
ツールも同じ結果を返す


レスポンスの内容も、ツールのスキーマも、直結時とまったく同じでした。ポータルは加工せずに中継しています。
唯一の違いは、ツール名にポータル側でプレフィックスが付くことです(例:sy-internal-kb-mcp_whoami)。複数サーバーを束ねる以上、名前の衝突を避ける必要があるためです。プロンプトでツール名を直接指定している場合は、影響を受ける可能性があります。
9. 誰が何を叩いたのかが見える
ポータルには、ツール呼び出し単位の実行ログがあります。


ユーザー列に、実行した本人のメールアドレスが並びます。共有アカウント方式であれば、この列はすべて同じ名前になり、監査としての意味を失っていたはずです。
| 記録される情報 | 何に使えるか |
|---|---|
| 実行者 | 誰が社内データにアクセスしたか |
| ツール名 | どの機能を使ったか |
| メソッド / 所要時間 | 異常な呼び出しパターンの検知 |
| セッションID | 一連の操作としての追跡 |
前回で「AI が誰の代わりに動いているか分かる」ことを確認しましたが、それが管理画面から一覧で追えるようになったのが、ポータルを挟む実務上の大きな利点です。
10. つまずいた4箇所
ここまで整然と書きましたが、実際には何度も詰まりました。同じ構成を組む方が確実に踏むと思われる箇所を残しておきます。
その1:Okta の IdP テストが 400 で失敗する

Cloudflare 側で IdP のテストを実行すると、Okta が 400 を返して止まりました。厄介だったのは、Okta のシステムログに認可エラーが1件も記録されなかったことです。

切り分けの結果、クライアントシークレットを再生成して Cloudflare 側に入れ直したら解消しました。ただし、シークレットは認可エンドポイントでは使わないはずなので、なぜ認可の段階で 400 になったのかは説明がついていません。原因は未解明のままです。同じ症状が出たら、まずシークレットの再登録を試す価値はあります。
その2:Access ポリシーで Okta グループが選べない
Access ポリシーで Okta のグループを条件にしようとしたところ、ドロップダウンにエラーが出て候補が取得できませんでした。

Okta Groups セレクタは、SCIM 連携を設定が必要だとおもいます。検証ではSCIM連携はしていなかったので、今回はメールアドレスを指定して検証を進めました。

その3:接続できるが「利用可能なサーバーがない」

No allowed servers available, check your Zero Trust policies.
ポータルの認証は通るのに、この画面で止まりました。原因は単純で、MCP サーバー側にも Access ポリシーの紐付けが必要だったためです。ポータルとサーバーは別々にポリシーを持ち、両方を満たす必要があります。

その4:WAF が認証コールバックを誤ブロックする
認証の途中でこの画面が出ました。

Access の拒否画面とは別物で、WAF が止めています。セキュリティイベントを Ray ID で追うと、原因が明確に見えました。

| スコア | 値 | 読み方 |
|---|---|---|
| WAF Attack Score | 31 | 総合。閾値50以下でブロックする設定だった |
| XSS Attack Score | 49 | ここが総合を押し下げている |
| SQLi Attack Score | 87 | 問題なし |
| RCE Attack Score | 92 | 問題なし |
Access の認証コールバックは、state パラメータに Base64 エンコードされた長大な文字列を含みます。これを XSS の検知ロジックが疑わしいと判断した、という筋書きです。SQLi と RCE のスコアが高いことから、明らかな誤検知と判断できます。
対処として、該当ホストの認証パスだけをスキップするルールを、既存ルールより上位に作りました。

(http.host eq "<ポータルのホスト名>" and starts_with(http.request.uri.path, "/cdn-cgi/access/"))
その他:上流トークンの失効

検証中、ポータル経由のツール呼び出しが「再認証が必要」というエラーを返す場面がありました。ポータル自体のセッションは生きていても、上流(Okta)へのトークンが失効すると、この状態になります。ポータルの画面から再認可すれば復旧します。
11. まとめ
2本を通して分かったこと
| 問い | 答え |
|---|---|
| AI に社内データを触らせるとき、誰として動いているか分かるか | 分かる。ID 基盤のトークンをそのまま MCP サーバーまで運べる |
| 人によって使えるツールを変えられるか | 変えられる。スコープとグループの2軸で制御できる |
| サーバーが増えても管理できるか | できる。MCPサーバーポータルで入口を1つにまとめられる |
| ポータルを挟むと本人性が失われないか | 失われない。手動 OAuth でも利用者ごとに認可される |
| 監査できるか | できる。ツール単位で実行者が記録される |
設計上、意識しておきたいこと
スコープは全員一律になる。ポータルの手動 OAuth では、管理者が登録したスコープが全利用者に同じく使われます。人による差は、ID 基盤のグループなど別の軸で表現する。
権限変更は即時ではない。トークンに焼き付いた情報は、再発行されるまで更新されません。どこまでの即時性が必要かは、扱うデータの性質次第です。
層が増えると切り分けが難しくなる。Claude、ポータル、Access、WAF、Okta、MCPサーバと関係者が多く、エラーがどこから返っているかを見極める必要があります。今回 WAF で詰まったように、認証と無関係に見える設定が影響することもあります。
Cloudflare の観点で
今回使った機能を整理します。
| 機能 | 役割 |
|---|---|
| Workers | MCP サーバーの実行基盤(前回の記事) |
| Cloudflare Access | ポータルの入口を Okta で保護 |
| MCP サーバーポータル | 複数サーバーの集約、手動 OAuth、実行ログ |
| WAF | (今回は誤検知の当事者でしたが)ポータルも通常の Web トラフィックとして保護対象 |
MCP サーバーポータルは、AI エージェントを社内で使うときに必要な要素が一通り揃っているという印象を持ちました。特に手動 OAuth(Static OAuth) の追加によって、既存の ID 基盤をそのまま活かせるようになった点は大きいと思います。
今回扱ったのは、社員が AI エージェント越しに社内データを触る場面です。人間が指示を出さずに動く自動化エージェントや、コードに手を入れられない他社製エージェントを統治する話は、また別の仕組みが必要になるかと思います。
周辺の動き:この検証の位置づけ(2026年8月時点)
その「別の仕組み」にあたる動きは、すでに具体化しつつあります。2つだけ触れておきます。
1つ目は、MCP 仕様の拡張である Enterprise-Managed Authorization(EMA)です。2026年6月に安定版となり、Anthropic・Microsoft・Okta などが採用を進めています。組織の IdP が MCP サーバーへのアクセス可否を決め、利用者はログイン1回で許可済みのサーバーへまとめて接続できる仕組みで、本記事で行ったサーバーごとの Authorize 操作が不要になります。重要なのは、EMA は本記事の構成の置き換えではなく上乗せだという点です。EMA の仕様は、MCP サーバーが RFC 9728 の保護リソースメタデータで自分の認可サーバーを公開していることを前提としており、前回の記事で Workers に実装したのはまさにその前提部分でした。将来 EMA へ進む場合も、今回の土台はそのまま生きます。
2つ目は、Okta の Agent Gateway です。2026年7月に発表され、現時点では申込制のリサーチリリース段階です。コードに手を入れられない他社製エージェントに対して Okta が経路に立ち、資格情報を仲介して統治する仕組みで、エージェント自身を1つの ID として管理する発想に立っています。本記事の「人間の委任を OAuth でそのまま運ぶ」構成とはレイヤーが異なり、対立ではなく補完の関係です。自分たちで MCP サーバーを用意できる場面は標準の OAuth で(本記事)、手を入れられないエージェントを相手にする場面は Agent Gateway で、という住み分けになると見ています。
| 本記事の構成 | EMA | Agent Gateway | |
|---|---|---|---|
| 認可の主語 | 人間(委任) | 人間(IdP が可否を代行判断) | エージェント自身 |
| 状態 | 利用可能(ポータルはベータ) | 安定版(2026年6月) | リサーチリリース(申込制) |
| 本記事との関係 | — | この構成の上に載る | 別レイヤーの補完 |
採用を検討される際は文末の公式情報をご確認ください。
AI 活用と権限管理の両立で参考になればと思います。
以上です。
参考にした情報
- Cloudflare: MCP サーバーポータルの手動 OAuth(変更履歴)
https://developers.cloudflare.com/changelog/post/2026-07-31-mcp-portal-manual-oauth/ - Cloudflare: Okta を IdP として連携する
https://developers.cloudflare.com/cloudflare-one/integrations/identity-providers/okta/ - Cloudflare: マネージド OAuth
https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/managed-oauth/ - Cloudflare: MCP サーバーの保護
https://developers.cloudflare.com/cloudflare-one/access-controls/ai-controls/secure-mcp-servers/ - Model Context Protocol: クライアント登録(2026-07-28)
https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/client-registration - Model Context Protocol: 2026-07-28 仕様のリリース告知
https://blog.modelcontextprotocol.io/posts/2026-07-28/ - Model Context Protocol: Enterprise-Managed Authorization
https://blog.modelcontextprotocol.io/posts/enterprise-managed-auth/ - Okta: Agent Gateway の紹介
https://www.okta.com/blog/product-innovation/agent-gateway-runtime-governance/ - 前編(A編)
https://blogs.networld.co.jp/entry/2026/08/20/190428
