Dépannage MCP
Cette page couvre les problèmes liés au serveur MCP intégré de Casdoor ainsi qu'à vos propres serveurs MCP qui utilisent Casdoor comme fournisseur OAuth 2.0.
Problèmes courants
Le serveur MCP répond avec une erreur HTTP 401
Causes
- Le jeton d'accès a expiré.
- La revendication
aud(audience) du jeton ne correspond pas à l'URI de la ressource du serveur MCP. - La requête n'a pas d'en-tête
Authorization: Bearer.
Solution
- Décodez le jeton, par exemple sur jwt.io, et vérifiez la revendication
exp. - Vérifiez que la revendication
audcorrespond exactement à l'URI de votre serveur MCP, y compris le schéma, l'hôte et le port. - Vérifiez que la requête porte l'en-tête
Authorization: Bearer <access-token>. - Si votre client envoie le paramètre
resourcedans le flux OAuth 2.0, vérifiez qu'il s'agit bien de l'URI du serveur MCP.
# Example: Check token claims
curl -X GET https://your-mcp-server.com/api/mcp \
-H "Authorization: Bearer YOUR_TOKEN"
# If 401, inspect token at jwt.io:
# - exp: 1735689600 (must be in future)
# - aud: "https://your-mcp-server.com" (must match server URI)
# - scope: "read:application" (must include required scopes)
Le navigateur signale une erreur CORS
Cause
L'origine du client MCP n'est pas une origine approuvée par Casdoor. Casdoor autorise les requêtes inter-origines provenant des origines listées dans les Redirect URLs de vos applications.
Solution
- Dans la console d'administration Casdoor, ouvrez la page d'édition de l'application.
- Ajoutez une URL contenant l'origine du client MCP, y compris le schéma et un port non standard, dans Redirect URLs. Pour le développement local, ajoutez
http://localhost:<port>.
Consultez Appeler l'API depuis un navigateur.
L'URL de redirection ne correspond pas
Causes
- Le
redirect_uride la demande d'autorisation n'est pas présent dans les Redirect URLs de l'application. - Le schéma (
httpouhttps), le port ou une barre oblique finale diffèrent.
Solution
- Copiez exactement le
redirect_uride la demande d'autorisation. - Ajoutez-le aux Redirect URLs de l'application.
Les URL suivantes sont toutes différentes :
# These are all different redirect URIs:
http://localhost:3000/callback
https://localhost:3000/callback # Different scheme
http://localhost:3000/callback/ # Trailing slash
http://localhost:3001/callback # Different port
Un point de terminaison de découverte renvoie HTTP 404
Cause
Le client demande un chemin de découverte qui ne correspond pas à son rôle.
Solution
Demandez le point de terminaison correspondant à votre cas d'utilisation :
-
Métadonnées du serveur d'autorisation OAuth 2.0 (RFC 8414) :
curl https://your-casdoor.com/.well-known/oauth-authorization-server -
Découverte OpenID Connect :
curl https://your-casdoor.com/.well-known/openid-configuration -
Métadonnées des ressources protégées OAuth 2.0 (RFC 9728) :
curl https://your-casdoor.com/.well-known/oauth-protected-resource
Un serveur MCP qui est un serveur de ressources publie le document oauth-protected-resource pour annoncer son serveur d'autorisation.
L'enregistrement dynamique des clients est rejeté
Causes
- L'enregistrement dynamique des clients (DCR) est désactivé pour l'organisation.
- La demande d'enregistrement manque de champs obligatoires.
Solution
-
Dans la console d'administration Casdoor, ouvrez la page d'édition de l'organisation et activez Enable dynamic client registration. Un client s'enregistre dans l'organisation
built-insauf si l'URL d'enregistrement contient un paramètreorganization. -
Envoyez toutes les métadonnées requises dans la demande d'enregistrement :
{
"client_name": "My MCP Client",
"redirect_uris": ["https://client.example.com/callback"],
"grant_types": ["authorization_code"],
"token_endpoint_auth_method": "client_secret_basic"
}
Voir Enregistrement dynamique des clients.
L'écran de consentement ne s'affiche pas
Causes
- L'application n'a pas de portée personnalisée. Casdoor demande un consentement uniquement pour les portées personnalisées.
- Le client ne demande pas de portée personnalisée.
- The user has already granted or declined the requested scopes for the application. Casdoor doesn't ask again, and the token carries only the granted scopes.
Solution
- Vérifiez que l'application définit les portées et que le client les demande. Voir Portées personnalisées.
- Pour tester à nouveau l'écran de consentement, révoquez l'autorisation précédente sur la page Consents.
Un appel d'outil échoue avec insufficient_scope
Cause
Le jeton d'accès ne contient pas la portée requise par l'outil.
Solution
-
Lisez
required_scopeetgranted_scopesdans l'erreur :{
"error": {
"code": -32001,
"message": "insufficient_scope",
"data": {
"tool": "add_application",
"granted_scopes": ["read:application"],
"required_scope": "write:application"
}
}
} -
Demandez un nouveau jeton avec la portée requise :
curl -X POST https://your-casdoor.com/api/login/oauth/access_token \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=read:application write:application"
Voir la référence des portées.
La demande d'autorisation échoue avec invalid_target
Causes
- Le paramètre
resourcen'est pas un URI absolu, comme l'exige la RFC 8707. - L'URI de la ressource ne comporte pas de schéma.
Solution
-
Envoyez une URL complète dans
resource:# Correct:
resource=https://your-server.com
resource=https://api.example.com:8080
# Incorrect:
resource=your-server.com # Missing scheme
resource=localhost:3000 # Missing scheme -
N'oubliez pas que la valeur de
resourcedevient la revendicationauddu jeton d'accès. Elle doit correspondre exactement à l'audience attendue par le serveur MCP.
Claude Desktop ou Cursor ne peuvent pas se connecter à votre propre serveur MCP
Causes
- Votre serveur MCP ne renvoie pas de métadonnées de ressource protégée valides.
- L'en-tête
WWW-Authenticateest manquant ou mal formé. - Le client ne peut pas atteindre les points de terminaison de découverte.
- Votre serveur MCP ne parvient pas à valider le jeton.
Solution
-
Vérifiez que le point de terminaison des métadonnées renvoie un JSON valide :
curl https://your-mcp-server.com/.well-known/oauth-protected-resourceRéponse attendue :
{
"resource": "https://your-mcp-server.com",
"authorization_servers": [
"https://your-casdoor.com"
]
} -
Vérifiez l'en-tête
WWW-Authenticated'une demande non authentifiée :curl -v https://your-mcp-server.com/api/mcpEn-tête attendu :
WWW-Authenticate: Bearer realm="mcp-server",
authorization_uri="https://your-casdoor.com/login/oauth/authorize",
scope="read:application write:application" -
Exécutez manuellement le flux OAuth 2.0 :
# 1. Get authorization code (requires browser)
# 2. Exchange for token
curl -X POST https://your-casdoor.com/api/login/oauth/access_token \
-d "grant_type=authorization_code" \
-d "code=AUTH_CODE" \
-d "redirect_uri=YOUR_REDIRECT_URI" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
# 3. Test MCP endpoint with token
curl https://your-mcp-server.com/api/mcp \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Outils de débogage
MCP Inspector
Le MCP Inspector officiel permet de tester une connexion MCP de manière interactive. Il parcourt et appelle les outils, affiche les demandes et réponses JSON-RPC, et exécute le flux OAuth 2.0.
npx @modelcontextprotocol/inspector
Points de terminaison de découverte
Vérifiez que chaque point de terminaison de découverte renvoie un JSON valide :
# OAuth Authorization Server
curl -s https://your-casdoor.com/.well-known/oauth-authorization-server | jq
# OIDC Configuration
curl -s https://your-casdoor.com/.well-known/openid-configuration | jq
# Protected Resource (for MCP resource servers)
curl -s https://your-mcp-server.com/.well-known/oauth-protected-resource | jq
Revendications du jeton
Décodez le jeton d'accès sur jwt.io, ou en ligne de commande :
# Alternative: Decode token with jq
echo "YOUR_JWT_TOKEN" | cut -d. -f2 | base64 -d | jq
| Claim | Check |
|---|---|
aud | Matches the URI of the MCP server |
scope | Contains the scopes that the tools require |
exp | Is in the future. The value is a Unix timestamp |
iss | Is the URL of Casdoor |
sub | Is the ID of the user |
client_id | Is the application that received the token |
Introspection du jeton
Demandez à Casdoor si un jeton est valide et ce qu'il contient (RFC 7662) :
curl -X POST https://your-casdoor.com/api/login/oauth/introspect \
-H "Content-Type: application/x-www-form-urlencoded" \
-u "CLIENT_ID:CLIENT_SECRET" \
-d "token=ACCESS_TOKEN"
La réponse :
{
"active": true,
"scope": "read:application write:application",
"client_id": "your-client-id",
"username": "admin",
"exp": 1735689600,
"iat": 1735603200,
"aud": "https://your-mcp-server.com"
}
Flux OAuth 2.0 avec curl
# 1. Test authorization endpoint (requires browser)
# Open in browser:
https://your-casdoor.com/login/oauth/authorize?
client_id=YOUR_CLIENT_ID&
redirect_uri=http://localhost:8080/callback&
response_type=code&
scope=read:application&
state=random-state
# 2. Exchange authorization code for token
curl -X POST https://your-casdoor.com/api/login/oauth/access_token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTHORIZATION_CODE" \
-d "redirect_uri=http://localhost:8080/callback" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
# 3. Use access token with MCP server
curl https://your-mcp-server.com/api/mcp \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Journaux et traces réseau
-
Client MCP : Activez le mode debug ou verbose, et consultez le journal pour la redirection, l'échange de jetons et les appels d'outils.
-
Serveur MCP : Journalisez chaque demande entrante, le résultat de la validation du jeton avec la raison de l'échec, ainsi que les vérifications de portée.
-
Navigateur : Ouvrez les outils de développement. L'onglet réseau affiche les redirections et les appels API, tandis que la console affiche les erreurs JavaScript.
-
Clients CLI : Acheminez le client via mitmproxy pour voir ses requêtes :
mitmproxy -p 8080
# Configure client to use proxy: http://localhost:8080