MCP サーバーを Casdoor MCP ゲートウェイの背後に配置する(エンドツーエンド)
このガイドでは完全な例を実演します。企業は 1 つの MCP サーバーを従業員に公開し、従業員は ChatGPT、Claude、Cursor、VS Code からそれを使用します。Casdoor はサーバーの前面にあるゲートウェイであり、ユーザーを認証する認可サーバーでもあります。MCP サーバー自体には OAuth 2.0 のコードは不要です。
学習目標
- MCP クライアントが登録しサインインできるように組織を準備します。
- Casdoor に MCP サーバーを登録し、誰がそれを使用でき、どのツールを利用可能かを決定します。
- 4 つの一般的な MCP クライアントに接続します。
- 1 つの Casdoor インスタンスから複数の組織に対応します。
- アクセスの確認、監査、および取り消しを行います。
必要なもの
- HTTPS 経由でインターネットから到達可能な Casdoor インスタンス(例:
https://auth.example.com)。ChatGPT および Claude のカスタムコネクタはクラウドからこれを呼び出します。 - Streamable HTTP トランスポートに対応した MCP サーバー(例:
https://tickets.example.com/mcp)、必要に応じて静的ベアラートークンで保護されます - Casdoor 管理コンソールへのグローバル管理者アクセス権
例
Acme はチケットシステム用の MCP サーバーを運用しています。Acme は以下を望んでいます:
- 従業員は Acme アカウントでサインインし、Casdoor で既に設定済みのサインイン方法を利用します。
- サポートチームのみがサーバーを使用できます。
- AI クライアントを通じてツール
delete_ticketを呼び出すことはできません。 - サーバー自身の API トークンは Casdoor の外に出ません。
- 管理者は各クライアントを確認し、取り消すことができます。
ステップ 1: 組織の準備
- Casdoor 管理コンソールで、User Management > Organizations に移動し、
acmeを開きます。 - Use organization issuer をオンにします。これにより、組織は独自の認可サーバーとなり、発行者は
https://auth.example.com/orgs/acme、ディスカバリードキュメントはhttps://auth.example.com/.well-known/oauth-authorization-server/orgs/acmeになります。これを見つける MCP クライアントはacmeに登録され、acmeのサインインページでユーザーを認証します。 - Enable dynamic client registration をオンにします。これにより、クライアントはクライアント ID メタデータドキュメント(Claude、VS Code、ChatGPT)で自己識別するか、自己登録(Cursor、古いクライアント)できるようになります。このスイッチを変更できるのはグローバル管理者のみです。
- 組織を保存します。
Use organization issuer なしの場合、ゲートウェイは Casdoor のグローバル発行者を認可サーバーとして指定し、クライアントは built-in に登録されます。built-in 以外のすべての組織で MCP サーバーを公開する場合は、これをオンにしてください。
ステップ 2: 誰がサーバーを使用できるかの決定
ゲートウェイは、サーバーの組織のユーザーのうち、サーバーのアプリケーションにサインインできるユーザーを受け入れます。
- Identity > Applications に移動し、
acmeにアプリケーションを追加します(例:app-tickets)。リダイレクト URL は不要です。MCP クライアントはこれにサインインせず、アクセスルールを保持するだけです。 - サポートチームのみを受け入れるには、Authorization > Permissions に移動し、
acmeに権限を追加します:- Resource type:
Application - Resources:
app-tickets - Groups または Roles: サポートチーム
- Actions:
Read, Effect:Allow
- Resource type:
アプリケーションに対する権限がなくても、acme のすべてのユーザーはサーバーを使用できます。acme の管理者とグローバル管理者は常に使用できます。
ステップ 3: MCP サーバーの登録
-
LLM AI > MCP Servers に移動し、
acmeでサーバーを追加します:フィールド 値 Name ticketsURL https://tickets.example.com/mcpApplication app-ticketsAccess token チケットサーバーが必要とする場合、その API トークン -
サーバーを保存し、Tool の下にある Sync を選択します。Casdoor はサーバーのツールリストを取得します。
-
delete_ticketをブロックして保存します。ゲートウェイは、ブロックされたツールまたはリストにないツールへの呼び出しに対してエラーを返し、転送しません。 -
Base URL をコピーします:
https://auth.example.com/api/server/acme/tickets。これは、ユーザーが MCP クライアントに追加する URL です。
ゲートウェイは、各リクエストから Cookie ヘッダーとユーザーの Authorization ヘッダーを削除し、代わりにサーバーの Access token を送信します。Casdoor は API レスポンスでトークンを返しません。
built-in 以外の組織のサーバーの場合、URL は公開インターネットアドレスである必要があります。ゲートウェイはテナントのためにプライベートアドレスやループバックアドレスへ到達することを拒否します。内部ネットワーク上の MCP サーバーを公開するには、built-in に登録してください。
ステップ 4: 発見チェーンの確認
すべての MCP クライアントは同じチェーンに従います。クライアントを接続する前に curl を使用して確認してください:
curl -i -X POST https://auth.example.com/api/server/acme/tickets
Casdoor は HTTP 401 を返し、このサーバーの保護されたリソースメタデータを指定します:
WWW-Authenticate: Bearer realm="casdoor", resource_metadata="https://auth.example.com/.well-known/oauth-protected-resource/api/server/acme/tickets"
curl https://auth.example.com/.well-known/oauth-protected-resource/api/server/acme/tickets
{
"resource": "https://auth.example.com/api/server/acme/tickets",
"authorization_servers": ["https://auth.example.com/orgs/acme"],
"bearer_methods_supported": ["header"],
"scopes_supported": ["openid", "profile", "email", "offline_access"]
}
curl https://auth.example.com/.well-known/oauth-authorization-server/orgs/acme
このドキュメントでは、次を確認します:
issuerはhttps://auth.example.com/orgs/acmeであり、authorization_serversと同じ値です。client_id_metadata_document_supportedがtrueであり、registration_endpointが?organization=acmeで終わっています。token_endpoint_auth_methods_supportedにnoneが含まれており、code_challenge_methods_supportedにS256が含まれています。
ステップ 5: クライアントの接続
各ユーザーはゲートウェイ URL をクライアントに追加し、Acme アカウントでサインインします。
| クライアント | サーバーを追加する場所 | 自己識別方法 | ガイド |
|---|---|---|---|
| ChatGPT | Plugins > + > Add custom MCP server | CIMD https://chatgpt.com/oauth/client.json | Connect ChatGPT |
| Claude Desktop, claude.ai | Customize > Connectors > Add custom connector | CIMD https://claude.ai/oauth/mcp-oauth-client-metadata | Connect Claude |
| Claude Code | claude mcp add --transport http tickets <url> | CIMD https://claude.ai/oauth/claude-code-client-metadata | Connect Claude |
| Cursor | ~/.cursor/mcp.json | DCR | Connect Cursor |
| VS Code | .vscode/mcp.json | CIMD https://vscode.dev/oauth/client-metadata.json | Connect VS Code |
例えば、Cursor では:
{
"mcpServers": {
"tickets": {
"url": "https://auth.example.com/api/server/acme/tickets"
}
}
}
VS Code では:
{
"servers": {
"tickets": {
"type": "http",
"url": "https://auth.example.com/api/server/acme/tickets"
}
}
}
クライアント ID メタデータドキュメントを使用するクライアントは、Casdoor に 1 つのアプリケーションが作成され、その URL がクライアント ID となり、タグは cimd、名前は cimd_ で始まります。自己登録するクライアントは、登録ごとに 1 つのアプリケーションが作成され、タグは dcr です。クライアント用のアプリケーションを手動で作成する必要はありません。
サーバーを保護するもの
| チェック項目 | 場所 | それ以外の場合の動作 |
|---|---|---|
トークンは acme のユーザーのものである | ゲートウェイ | HTTP 401 |
ユーザーは app-tickets にサインインできる | ゲートウェイ | HTTP 401 |
| トークンはこのサーバー向けに発行された (RFC 8707) | ゲートウェイ | HTTP 401: "The access token is for another resource" |
| ツールはリストに含まれており許可されている | ゲートウェイ | JSON-RPC エラー、呼び出しは転送されない |
| クライアントは自己登録したクライアントである | すべての API | そのトークンはサインインフロー、/api/userinfo、/api/mcp、および /api/server/* のみを呼び出すことができ、管理 API は呼び出せない |
クライアントは resource=https://auth.example.com/api/server/acme/tickets を使用してトークンをリクエストし、Casdoor はその URL を aud クレームに入れます。他の MCP サーバー(同じ組織であっても)向けのトークンはここでは機能しないため、悪意のあるサーバーが受信したトークンを再生することはできません。
複数の組織を提供する
1つのCasdoorインスタンスで、SaaSの顧客など、多くの組織向けにMCPサーバーを公開できます。各組織に対して手順1から3を繰り返してください。その後:
- 各組織には独自のイシューア、サインインページ、ユーザー、権限があります。
globexのユーザーはacmeのページでサインインできず、acmeのサーバーを使用することもできません。 - ChatGPT、Claude、VS CodeのクライアントIDメタデータドキュメントにはそれぞれ1つのURLがあり、すべての組織で使用されます。Casdoorは
built-inにそのURLごとの共有アプリケーションを保持し、ユーザーがサインインする組織のアプリケーションとして提供します。これらのクライアントを受け入れるために、各組織では依然として Enable dynamic client registration を有効にする必要があります。 - トークンにはユーザーの組織のイシューアが含まれており、リフレッシュ後も同様です。
- 自己登録を行うクライアント(DCR)は、登録エンドポイントの
organizationパラメータを通じて、ディスカバリドキュメントの組織に登録されます。
確認、監査、失効
- Clients: Identity > Applications に、タグ
cimdおよびdcrを持つクライアントが一覧表示されます。dcr_アプリケーションを削除すると、登録が解除されます。 - Tokens: Auditing > Tokens に、ユーザー、アプリケーション、スコープ、リソースを含む各トークンが一覧表示されます。トークンを削除すると、クライアントへのアクセスが直ちに遮断されます。
- Users: ユーザーを禁止すると、そのユーザーのトークンは次のリクエスト時にゲートウェイで機能しなくなります。
- Tools: サーバーの編集ページでツールをブロックします。変更は次の呼び出し時に反映されます。
エンタープライズユーザーがブラウザをスキップできるようにする
組織の従業員がOktaなどのエンタープライズIDプロバイダーを通じてサインインする場合、Enterprise-Managed Authorizationをサポートするクライアント(Claude TeamおよびEnterprise)は、ブラウザでのサインインなしでゲートウェイトークンを取得できます。IDプロバイダーがID-JAGを発行し、Casdoorがそれをアクセストークンと交換します。詳細については、Enterprise-managed authorizationを参照してください。
トラブルシューティング
サインイン後にゲートウェイが401を返す場合
- サーバーに Application が設定されていません。これがない場合、管理者のみがサーバーを使用できます。アプリケーションを選択してください。詳細は Step 2 を参照してください。
- アプリケーションの権限によりユーザーが除外されています。
- ユーザーがサーバーとは別の組織に属しています。
- クライアントが別のリソース用のトークンを要求しました。トークンの
audクレームを確認してください。これはゲートウェイURLである必要があります。
クライアントが誤った組織でユーザーをサインインさせている場合
Use organization issuer がオフになっているため、保護されたリソースメタデータはグローバルなイシューアを指定しています。これをオンにし、クライアントを再接続してください。
"client ID metadata documents are not accepted"
組織に対して Enable dynamic client registration がオフになっています。また、Casdoorはインターネット経由でクライアントのドキュメントURLに到達できる必要があります。
ゲートウェイが502を返す場合
Casdoorがサーバーの URL に到達できません。URLを確認し、built-in 以外の組織の場合は、パブリックアドレスであることを確認してください。