Placer les serveurs MCP derrière la passerelle MCP de Casdoor, de bout en bout
Ce guide présente un exemple complet : une entreprise publie un serveur MCP à destination de ses employés, qui l'utilisent depuis ChatGPT, Claude, Cursor et VS Code. Casdoor agit à la fois comme passerelle devant le serveur et comme serveur d'autorisation qui authentifie les utilisateurs. Le serveur MCP lui-même n'a besoin d'aucun code OAuth 2.0.
Objectifs d'apprentissage
- Préparer une organisation afin que les clients MCP s'y enregistrent et s'y connectent.
- Enregistrer un serveur MCP dans Casdoor et définir qui peut l'utiliser et quels outils sont accessibles.
- Connecter les quatre clients MCP courants.
- Servir plusieurs organisations depuis une seule instance Casdoor.
- Vérifier, auditer et révoquer les accès.
Prérequis
- Une instance Casdoor accessible depuis Internet via HTTPS, par exemple
https://auth.example.com. Les connecteurs personnalisés de ChatGPT et Claude y accèdent depuis le cloud. - Un serveur MCP utilisant le transport Streamable HTTP, par exemple
https://tickets.example.com/mcp, éventuellement protégé par un jeton bearer statique - Accès administrateur global à la console d'administration Casdoor
L'exemple
Acme exploite un serveur MCP pour son système de tickets. Acme souhaite que :
- Les employés se connectent avec leur compte Acme, via les méthodes de connexion déjà configurées dans Casdoor.
- Seule l'équipe support puisse utiliser le serveur.
- Personne ne puisse appeler l'outil
delete_ticketvia un client IA. - Le jeton API propre au serveur ne quitte jamais Casdoor.
- Un administrateur puisse voir et révoquer chaque client.
Étape 1 : préparer l'organisation
- Dans la console d'administration Casdoor, allez dans User Management > Organizations et ouvrez
acme. - Activez Use organization issuer. L'organisation devient son propre serveur d'autorisation, avec l'émetteur
https://auth.example.com/orgs/acmeet le document de découvertehttps://auth.example.com/.well-known/oauth-authorization-server/orgs/acme. Les clients MCP qui découvrent cet émetteur s'enregistrent dansacmeet authentifient les utilisateurs sur la page de connexion deacme. - Activez Enable dynamic client registration. Cela permet aux clients de s'identifier avec un document de métadonnées d'ID client (Claude, VS Code, ChatGPT) ou de s'enregistrer eux-mêmes (Cursor, anciens clients). Seul un administrateur global peut modifier ce paramètre.
- Enregistrez l'organisation.
Sans Use organization issuer, la passerelle nomme l'émetteur global de Casdoor comme serveur d'autorisation, et les clients s'enregistrent dans built-in. Activez-le pour toute organisation autre que built-in qui publie des serveurs MCP.
Étape 2 : définir qui peut utiliser le serveur
La passerelle autorise l'accès aux utilisateurs de l'organisation du serveur qui ont le droit de se connecter à l'application du serveur.
- Allez dans Identity > Applications et ajoutez une application dans
acme, par exempleapp-tickets. Elle n'a pas besoin d'URL de redirection : les clients MCP ne se connectent pas à elle, elle ne porte que les règles d'accès. - Pour autoriser uniquement l'équipe support, allez dans Authorization > Permissions et ajoutez une permission dans
acme:- Resource type :
Application - Resources :
app-tickets - Groups ou Roles : l'équipe support
- Actions:
Read, Effect:Allow
- Resource type :
Sans aucune autorisation sur l'application, chaque utilisateur de acme peut utiliser le serveur. Les administrateurs de acme et les administrateurs globaux peuvent toujours l'utiliser.
Étape 3 : enregistrer le serveur MCP
-
Accédez à LLM AI > MCP Servers et ajoutez un serveur dans
acme:Champ Valeur Name ticketsURL https://tickets.example.com/mcpApplication app-ticketsAccess token Le jeton API du serveur de tickets, s'il en nécessite un -
Enregistrez le serveur, puis sélectionnez Sync sous Tool. Casdoor récupère la liste des outils du serveur.
-
Bloquez
delete_ticketet enregistrez. La passerelle répond à un appel vers un outil bloqué, ou vers un outil qui n'est pas dans la liste, par une erreur et ne le transmet pas. -
Copiez l'Base URL:
https://auth.example.com/api/server/acme/tickets. C'est l'URL que les utilisateurs ajoutent à leurs clients MCP.
La passerelle supprime l'en-tête Cookie et l'en-tête Authorization de l'utilisateur de chaque requête, et envoie à la place l'Access token du serveur. Casdoor ne renvoie jamais le jeton dans ses réponses API.
Pour un serveur d'une organisation autre que built-in, l'URL doit être une adresse Internet publique: la passerelle refuse d'atteindre des adresses privées et bouclées pour le compte d'un tenant. Pour publier un serveur MCP sur votre réseau interne, enregistrez-le dans built-in.
Étape 4 : vérifier la chaîne de découverte
Chaque client MCP suit la même chaîne. Vérifiez-la avec curl avant de connecter un client:
curl -i -X POST https://auth.example.com/api/server/acme/tickets
Casdoor répond HTTP 401 et nomme les métadonnées de ressource protégée de ce serveur:
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
Dans ce document, vérifiez:
issueresthttps://auth.example.com/orgs/acme, la même valeur que dansauthorization_servers.client_id_metadata_document_supportedesttrue, etregistration_endpointse termine par?organization=acme.token_endpoint_auth_methods_supportedcontientnone, etcode_challenge_methods_supportedcontientS256.
Étape 5 : connecter les clients
Chaque utilisateur ajoute l'URL de la passerelle à son client et se connecte avec son compte Acme.
| Client | Où ajouter le serveur | Comment il s'identifie | Guide |
|---|---|---|---|
| ChatGPT | Plugins > + > Add custom MCP server | CIMD https://chatgpt.com/oauth/client.json | Connecter ChatGPT |
| Claude Desktop, claude.ai | Customize > Connectors > Add custom connector | CIMD https://claude.ai/oauth/mcp-oauth-client-metadata | Connecter Claude |
| Claude Code | claude mcp add --transport http tickets <url> | CIMD https://claude.ai/oauth/claude-code-client-metadata | Connecter Claude |
| Cursor | ~/.cursor/mcp.json | DCR | Connecter Cursor |
| VS Code | .vscode/mcp.json | CIMD https://vscode.dev/oauth/client-metadata.json | Connecter VS Code |
Par exemple, dans Cursor:
{
"mcpServers": {
"tickets": {
"url": "https://auth.example.com/api/server/acme/tickets"
}
}
}
Et dans VS Code:
{
"servers": {
"tickets": {
"type": "http",
"url": "https://auth.example.com/api/server/acme/tickets"
}
}
}
Un client qui utilise un document de métadonnées d'ID client obtient une application dans Casdoor, avec son URL comme ID client, le tag cimd, et un nom commençant par cimd_. Un client qui s'enregistre lui-même obtient une application par enregistrement, avec le tag dcr. Vous ne créez pas d'applications pour les clients.
Ce qui protège le serveur
| Vérification | Où | Ce qui se passe sinon |
|---|---|---|
Le jeton appartient à un utilisateur de acme | Passerelle | HTTP 401 |
L'utilisateur peut se connecter à app-tickets | Passerelle | HTTP 401 |
| Le jeton a été émis pour ce serveur (RFC 8707) | Passerelle | HTTP 401: "The access token is for another resource" |
| L'outil est dans la liste et autorisé | Passerelle | Erreur JSON-RPC, l'appel n'est pas transmis |
| Le client est un client qui s'est enregistré lui-même | Toutes les API | Ses jetons ne peuvent appeler que le flux de connexion, /api/userinfo, /api/mcp, et /api/server/*, jamais les API de gestion |
Les clients demandent le jeton avec resource=https://auth.example.com/api/server/acme/tickets, et Casdoor met cette URL dans la revendication aud. Un jeton pour un autre serveur MCP, même de la même organisation, ne fonctionne pas ici, donc un serveur malveillant ne peut pas rejouer les jetons qu'il reçoit.
Servir plusieurs organisations
Une instance Casdoor peut publier des serveurs MCP pour plusieurs organisations, par exemple les clients d'un SaaS. Répétez les étapes 1 à 3 pour chaque organisation. Ensuite :
- Chaque organisation a son propre émetteur (issuer), sa page de connexion, ses utilisateurs et ses permissions. Un utilisateur de
globexne peut pas se connecter sur la page deacmeet ne peut pas utiliser les serveurs deacme. - Les documents de métadonnées d'ID client de ChatGPT, Claude et VS Code possèdent chacun une URL unique, utilisée par toutes les organisations. Casdoor conserve une application partagée par URL dans
built-inet la sert comme application de l'organisation vers laquelle l'utilisateur se connecte. Chaque organisation doit toujours activer Enable dynamic client registration pour accepter ces clients. - Les jetons portent l'émetteur de l'organisation de l'utilisateur, également après un renouvellement.
- Un client qui s'enregistre lui-même (DCR) s'enregistre dans l'organisation du document de découverte, via le paramètre
organizationdu point de terminaison d'enregistrement.
Vérifier, auditer et révoquer
- Clients : Identity > Applications liste les clients avec les tags
cimdetdcr. Supprimez une applicationdcr_pour retirer un enregistrement. - Tokens : Auditing > Tokens liste chaque jeton avec son utilisateur, son application, son scope et sa ressource. Supprimez un jeton pour couper immédiatement l'accès au client.
- Users : Interdisez un utilisateur, et ses jetons cessent de fonctionner à la passerelle dès la prochaine requête.
- Tools : Bloquez un outil sur la page de modification du serveur. La modification prend effet lors du prochain appel.
Permettre aux utilisateurs d'entreprise d'éviter le navigateur
Lorsque les employés d'une organisation se connectent via un fournisseur d'identité d'entreprise tel que Okta, les clients prenant en charge Enterprise-Managed Authorization (Claude Team and Enterprise) peuvent obtenir le jeton de la passerelle sans connexion via le navigateur : le fournisseur d'identité émet un ID-JAG, et Casdoor l'échange contre un jeton d'accès. Voir Enterprise-managed authorization.
Dépannage
La passerelle répond 401 après la connexion
- Le serveur n'a pas d'Application. Sans cela, seuls les administrateurs peuvent utiliser le serveur. Sélectionnez une application, voir Step 2.
- Une permission sur l'application exclut l'utilisateur.
- L'utilisateur appartient à une autre organisation que le serveur.
- Le client a demandé le jeton pour une autre ressource. Vérifiez la revendication
auddu jeton : elle doit correspondre à l'URL de la passerelle.
Le client connecte les utilisateurs sur la mauvaise organisation
Use organization issuer est désactivé, donc les métadonnées de ressource protégée nomment l'émetteur global. Activez-le, puis reconnectez le client.
"client ID metadata documents are not accepted"
Enable dynamic client registration est désactivé pour l'organisation. Casdoor doit également pouvoir atteindre l'URL du document du client via Internet.
La passerelle répond 502
Casdoor ne peut pas atteindre l'URL du serveur. Vérifiez l'URL et, pour une organisation autre que built-in, assurez-vous qu'il s'agit d'une adresse publique.