Introduction
Le Model Context Protocol (MCP) s'impose rapidement comme le standard de facto pour connecter les LLM, comme Claude, à des systèmes externes : bases de données, API métier, outils internes d'entreprise. Derrière cette promesse de simplicité se cache pourtant un détail technique souvent négligé : la découverte automatique de la configuration OAuth/OpenID Connect. Un article récent de Nasrul Hazim Bin Mohamad, publié sur dev.to, met en lumière une astuce simple mais redoutablement efficace dans l'écosystème Laravel : exposer un alias de route vers /.well-known/openid-configuration pour que les connecteurs MCP fonctionnent immédiatement, sans configuration manuelle côté client.
Chez MulerTech, où nous développons des solutions PHP/Symfony robustes pour nos clients, ce sujet résonne particulièrement. Comment exposer proprement nos API métier aux agents IA, sans sacrifier la sécurité ni réinventer notre architecture d'authentification existante ? Voici notre lecture de cette technique, transposée à l'écosystème Symfony.
MCP, le pont entre votre backend PHP et les LLM
Le MCP fonctionne sur un principe simple : un serveur MCP expose des « outils » (tools) et des « ressources » qu'un client IA peut découvrir et invoquer. Concrètement, cela signifie que votre application PHP peut devenir un point d'entrée légitime pour un assistant comme Claude, à condition de respecter le protocole de communication et, surtout, le protocole d'authentification.
La plupart des serveurs MCP en production exigent une authentification OAuth 2.0, car on ne souhaite pas qu'un agent IA accède à des données sensibles sans contrôle d'accès. Et c'est précisément à cette étape que le bât blesse : pour qu'un client MCP sache où envoyer l'utilisateur s'authentifier, il doit pouvoir découvrir automatiquement les métadonnées du serveur d'autorisation, comme le prévoit la RFC 8414 (OAuth 2.0 Authorization Server Metadata) ou la spécification OpenID Connect Discovery.
Le piège de la découverte automatique
La spécification MCP s'appuie sur cette découverte standardisée : le client va chercher un document JSON à une URL bien précise, relative à la racine du domaine exposant la ressource. Dans l'immense majorité des cas, cette URL est /.well-known/openid-configuration.
Le problème, c'est que dans une application Laravel ou Symfony déjà existante, votre serveur d'autorisation OAuth (qu'il s'agisse de Laravel Passport, de League OAuth2 Server, de Keycloak ou d'un fournisseur tiers) expose très souvent son document de découverte ailleurs : /oauth/.well-known/openid-configuration, sur un sous-domaine dédié, ou via un service d'identité totalement séparé de votre API. Le client MCP, lui, va frapper à la racine du domaine, ne trouvera rien, et abandonnera silencieusement la tentative de connexion automatique. Résultat : votre connecteur MCP, pourtant fonctionnel sur le papier, échoue à l'étape de découverte, et l'utilisateur doit configurer manuellement chaque endpoint — une expérience peu engageante pour un outil censé être « plug-and-play ».
La solution : un alias léger plutôt qu'une migration
L'idée défendue dans l'article original est élégante par sa simplicité : plutôt que de déplacer toute votre infrastructure OAuth existante, il suffit de créer une route qui répond à /.well-known/openid-configuration et qui retourne (ou redirige vers) le véritable document de métadonnées. Aucun changement d'architecture, aucune duplication de logique métier — juste un point d'entrée standardisé qui pointe vers vos endpoints réels.
En Symfony, cela peut se traduire par un contrôleur dédié et une déclaration de route explicite :
# config/routes.yaml
well_known_openid_configuration:
path: /.well-known/openid-configuration
controller: App\Controller\WellKnownController::openidConfiguration
methods: [GET]
namespace App\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Attribute\Route;
class WellKnownController
{
#[Route('/.well-known/openid-configuration', name: 'well_known_openid_configuration', methods: ['GET'])]
public function openidConfiguration(): JsonResponse
{
$issuer = 'https://api.monservice.com';
return new JsonResponse([
'issuer' => $issuer,
'authorization_endpoint' => $issuer . '/oauth/authorize',
'token_endpoint' => $issuer . '/oauth/token',
'jwks_uri' => $issuer . '/oauth/jwks',
'response_types_supported' => ['code'],
'grant_types_supported' => ['authorization_code', 'refresh_token'],
'scopes_supported' => ['mcp:read', 'mcp:write'],
]);
}
}
Cette approche présente plusieurs avantages concrets : elle ne touche pas à votre serveur d'autorisation existant, elle reste compatible avec un fournisseur d'identité externe (Keycloak, Auth0, Okta), et elle s'intègre naturellement dans le cycle de vie d'une application Symfony, sans dépendance supplémentaire.
Sécuriser l'alias sans complexifier l'architecture
Même si ce document est public par nature (c'est tout l'intérêt de la découverte), quelques précautions s'imposent côté production :
- Limiter le contenu exposé : ne révéler que les endpoints nécessaires au flux OAuth, sans détails internes sur votre infrastructure.
- Vérifier le champ
issuercôté serveur de ressources, pour s'assurer qu'un jeton émis correspond bien à l'autorité attendue et éviter toute confusion entre environnements (staging vs production). - Mettre en cache la réponse, car ce document est interrogé fréquemment par les clients MCP lors de chaque tentative de connexion.
- Restreindre les scopes exposés aux seuls usages MCP (
mcp:read,mcp:write, etc.), plutôt que de réutiliser l'ensemble des scopes de votre API.
Ces ajustements restent mineurs comparés à une refonte de votre couche d'authentification, ce qui rend cette technique particulièrement adaptée aux projets en production où la stabilité prime.
Conclusion
L'article de Nasrul Hazim Bin Mohamad illustre bien une réalité que nous observons chez MulerTech sur nos projets PHP/Symfony : l'intégration des agents IA via MCP ne nécessite pas toujours une refonte d'architecture. Souvent, un simple alignement sur les standards de découverte — ici, un alias de route vers /.well-known/openid-configuration — suffit à transformer une API existante en connecteur MCP fonctionnel, sans compromis sur la sécurité ni sur la maintenabilité du code.
À mesure que les LLM comme Claude deviennent des consommateurs à part entière de nos API, ce type de détail protocolaire — souvent ignoré dans la documentation officielle — fait toute la différence entre une intégration qui « marche presque » et une intégration réellement transparente pour l'utilisateur final.
Article inspiré de la publication originale de Nasrul Hazim Bin Mohamad sur dev.to : The /.well-known/openid-configuration Alias That Makes MCP Connectors Just Work.