internal-kb-mcp
Uses Okta as the authorization server to protect MCP tools, validating OAuth 2.0 access tokens (JWTs) and enforcing scopes and group-based access control.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@internal-kb-mcpsearch the internal wiki for our remote work policy"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
internal-kb-mcp — Okta のカスタム認可サーバーで保護した MCP サーバー
Cloudflare Workers 上に構築した リモート MCP サーバーの検証用実装 です。 アクセス制御を MCP サーバー側で自前実装するのではなく、Okta のカスタム認可サーバーが発行したアクセストークン (JWT) の中身だけを根拠に、ツール単位で認可するという構成を検証します。
このリポジトリは検証記事の付属サンプルです。実運用を想定したものではありません。
何を検証できるか
検証したいこと | このリポジトリでの表現 |
MCP クライアントが「どこで認証すればよいか」を自力で見つけられるか | RFC 9728 の保護リソースメタデータ + 401 応答の |
スコープによるツール単位の認可 |
|
IdP のグループによる特権ツールの制御 |
|
認可の状態を利用者が確認できるか |
|
Related MCP server: Access Self-Hosted MCP Server
認可フロー
sequenceDiagram
autonumber
participant C as MCP<br/>クライアント
participant W as Worker<br/>(MCP サーバー)
participant O as Okta<br/>認可サーバー
C->>W: POST /mcp (トークンなし)
W-->>C: 401 + WWW-Authenticate<br/>resource_metadata=...
C->>W: GET /.well-known/<br/>oauth-protected-resource
W-->>C: resource / authorization_servers<br/>/ scopes_supported
C->>O: 認可リクエスト<br/>(audience = MCP_RESOURCE)
O-->>C: アクセストークン JWT<br/>(scp / groups を含む)
C->>W: POST /mcp<br/>Authorization: Bearer ...
W->>O: JWKS 取得<br/>({issuer}/v1/keys)
O-->>W: 公開鍵
W-->>C: 署名 / iss / aud 検証 OK<br/>→ ツール実行ポイントは、Worker 側がクライアントシークレットを一切持たないことです。 この Worker は OAuth のリソースサーバーであり、JWKS で取得した公開鍵を使って JWT を検証するだけです。認可の判断材料はすべてトークンの中にあります。
ツールと認可条件
ツール | 認可条件 | 引数 | 内容 |
| スコープ | なし | 検証済みトークンの subject / scopes / groups / audience / issuer / 有効期限を返す |
| スコープ |
| 社内ナレッジのダミーデータを全文検索する |
| Okta グループ |
| 顧客の契約情報のダミーデータを返す。省略時は全件 |
判定に使うクレームは次のとおりです。
スコープ: アクセストークンの
scpクレームグループ: アクセストークンの
groupsクレーム(Okta 側でトークンに載せる設定が必要)
条件を満たさない場合はトランスポート層で弾かずに、ツールの応答として「なぜ実行できないか」を返します(isError: true)。認可の効き方が MCP クライアントの画面上で見えるようにするための、意図的な設計です。
データはすべてソースコード内のダミーです(
WIKI/CONTRACTS)。実在の顧客情報は含まれていません。
セットアップ
前提
Cloudflare アカウント(Workers が有効)
Okta のテナント(カスタム認可サーバーを作成できるプラン)
Node.js と npm
1. Okta 側
Okta 管理コンソールの Security > API > Authorization Servers から、カスタム認可サーバーを作成し、以下を設定します(UI の名称は Okta のバージョンにより多少異なります)。
カスタム認可サーバーを作成する
作成すると issuer が
https://<your-okta-domain>.okta.com/oauth2/<authorization-server-id>の形式で払い出されます。これがOKTA_ISSUERになります。
Audience を Worker の URL に設定する
後述の
MCP_RESOURCEと完全に一致させます。ここがずれていると、署名が正しくてもaud不一致で常に 401 になります。
スコープを追加する
whoami.readwiki.read
グループを作成する
mcp-managersを作成し、特権ツールを使わせたいユーザーを所属させます。権限差を確認するために、所属していないユーザーも 1 人用意しておくと検証しやすくなります。
アクセストークンに
groupsクレームを載せるカスタム認可サーバーの Claims で、
groupsという名前のクレームを Access Token に対して追加します。これを設定しないと
contract_lookupは誰も実行できません(グループ判定が常に空になるため)。
アクセスポリシー / ルールを設定する
どのクライアント・どのユーザーに、どのスコープを付与するかを定義します。
MCP クライアントが Okta からトークンを取得するための OAuth クライアントの登録方法(動的クライアント登録を使うか、事前に登録したクライアントを使うか)は、利用する MCP クライアントによって異なります。この部分は検証記事側の手順を参照してください。
2. Cloudflare 側
git clone https://github.com/yamashin55/okta-mcp-cloudflare-demo.git
cd okta-mcp-cloudflare-demo
npm installwrangler.jsonc の vars を、手順 1 で確定した自分の環境の値に必ず書き換えます。
"vars": {
"OKTA_ISSUER": "https://<your-okta-domain>.okta.com/oauth2/<authorization-server-id>",
"MCP_RESOURCE": "https://<worker-name>.<your-subdomain>.workers.dev"
}MCP_RESOURCE はデプロイ後に確定する URL なので、一度デプロイして URL を確認してから書き換え、もう一度デプロイする流れになります。
npx wrangler deployOKTA_ISSUER と MCP_RESOURCE はどちらも秘密情報ではありません。次項のメタデータエンドポイントから無認証で公開される値です。そのため wrangler secret ではなく平文の vars で管理しています。
3. 接続確認
保護リソースメタデータは無認証で取得できます。
curl -s https://<your-worker-url>/.well-known/oauth-protected-resource{
"resource": "https://<your-worker-url>",
"authorization_servers": ["https://<your-okta-domain>.okta.com/oauth2/<authorization-server-id>"],
"scopes_supported": ["whoami.read", "wiki.read"],
"bearer_methods_supported": ["header"]
}トークンなしでツールを呼ぶと、401 と WWW-Authenticate が返ります。MCP クライアントはこのヘッダーを見て、認可サーバーの場所を知ります。
curl -i -X POST https://<your-worker-url>/mcp \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'HTTP/2 401
www-authenticate: Bearer resource_metadata="https://<your-worker-url>/.well-known/oauth-protected-resource"認可が効いていることの確認
確認したいこと | 操作 | 期待される結果 |
トークンが検証されている |
|
|
スコープで守られている |
| 「このツールにはスコープ wiki.read が必要です。」 |
グループで守られている |
| 「このツールは Okta グループ mcp-managers のメンバーのみ実行できます。」 |
audience が効いている |
| すべてのリクエストが 401 |
whoami を最初に実行して、実際にどのスコープとグループがトークンに載っているかを確認してから他のツールを試すと、原因の切り分けが楽になります。
実装
すべて src/index.ts の 1 ファイルです。
箇所 | 役割 |
|
|
| issuer ごとに JWKS を使い回すキャッシュ |
| RFC 9728 に沿った |
| 3 つのツールの登録と、スコープ / グループによる認可判定 |
| 検証済みクレームをツールから参照するためのヘルパー |
検証済みのクレームは createMcpHandler の authContext 経由でツールに渡しています。ツール側はトークンの検証を一切行わず、検証済みの事実だけを見て判断する構造です。
開発
npm run dev # ローカル開発サーバー (wrangler dev)
npm run type-check # 型チェック (tsc --noEmit)
npm run lint:fix # oxlint
npm run format # oxfmt
npm run cf-typegen # wrangler types (バインディング変更時)
npm run deploy # wrangler deploywrangler dev でローカル起動した場合も Okta のトークン検証は有効なままです(JWKS の取得にネットワークアクセスが発生します)。ローカルで検証を通すには、MCP_RESOURCE と Okta の Audience を合わせておく必要があります。
注意事項
本リポジトリは 検証・学習を目的としたサンプル実装です。無保証で提供され、実運用環境での利用は想定していません。
収録しているナレッジ・契約情報はすべてダミーデータです。
wrangler.jsoncの値はプレースホルダです。そのままデプロイしても動作しません。内容の正確性・動作について、作者はいかなる責任も負いません。利用は自己責任でお願いします。
This server cannot be deployed
Maintenance
Related MCP Connectors
Cloudflare Workers MCP server: ai-guardrails
Cloudflare Workers MCP server: blog
Cloudflare Workers MCP server: ai-gateway
Cloudflare Workers MCP server: interactive-api-playground
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceA Cloudflare Workers-based MCP server that enables secure remote connections using built-in OAuth authentication via Cloudflare Access. It provides identity-based access control for MCP tools and supports persistent state management through Durable Objects and SSE.-
- AlicenseNot gradedqualityCmaintenanceAn MCP server protected by Cloudflare Access, validating JWTs to conditionally expose tools based on user identity.681 npmMIT
- FlicenseNot gradedqualityFmaintenanceA remote MCP server deployed on Cloudflare Workers with OAuth authentication, enabling secure tool calling over SSE.-
- FlicenseNot gradedqualityCmaintenanceAn MCP server protected by Cloudflare Access as a self-hosted application, validating Access JWT and conditionally exposing tools based on user identity.-