Skip to main content

Qu’est-ce que MCP ?

Le Model Context Protocol (MCP) est une spécification qui définit un protocole standardisé pour la communication entre des clients IA (Claude, Cursor, GitHub Copilot, etc.) et une application. En implémentant un serveur MCP, un agent IA peut accéder aux données de votre application Laravel ou y exécuter des actions.
Laravel MCP est un package officiel introduit dans Laravel 13. Distribué sous le nom laravel/mcp, il fournit tout le nécessaire pour construire un serveur MCP.
Un serveur MCP peut exposer trois types de fonctionnalités.

Installation

Installez le package avec Composer.
Puis exécutez la commande Artisan vendor:publish pour générer le fichier routes/ai.php.
Cette commande crée routes/ai.php, où vous déclarez vos serveurs MCP.

Création d’un serveur

Générez la classe de serveur avec la commande make:mcp-server.
La classe est créée dans le répertoire app/Mcp/Servers.

Enregistrer le serveur

Une fois la classe créée, déclarez-la dans routes/ai.php. Deux modes sont disponibles : serveur Web et serveur local.

Serveur Web

Un serveur Web est accessible via une requête HTTP POST. Il convient parfaitement aux clients IA distants et aux intégrations Web.
Vous pouvez y appliquer des middlewares comme sur n’importe quelle route.

Serveur local

Un serveur local s’exécute comme une commande Artisan. Il est destiné aux clients IA locaux comme Claude Desktop.
Les serveurs locaux sont généralement lancés automatiquement par le client MCP. Inutile d’exécuter mcp:start à la main.

Tools

Les tools sont les fonctions que le client IA peut appeler : lecture de données, intégration à une API externe, opérations en base, etc.

Créer un tool

Générez la classe avec la commande Artisan make:mcp-tool.
Enregistrez-la dans la propriété $tools du serveur.
Voici un exemple d’implémentation.

Nom et description du tool

Le nom et le titre sont générés par défaut à partir du nom de classe. Pour CurrentWeatherTool, le nom devient current-weather et le titre Current Weather Tool. Personnalisez-les via les attributs Name et Title.
La description d’un tool (Description) n’est pas générée automatiquement. Elle est indispensable pour que le modèle comprenne comment utiliser le tool : fournissez toujours une description explicite.

Schéma d’entrée

La méthode schema définit le schéma des paramètres d’entrée. Le builder JSON schema de Laravel permet d’exprimer types et contraintes.

Schéma de sortie

outputSchema définit la structure de la réponse, ce qui facilite son parsing par le client IA.

Validation

Utilisez la validation standard de Laravel dans handle.
Après un échec de validation, le client IA réessaiera en s’appuyant sur le message d’erreur. Fournissez des messages précis et exploitables.

Injection de dépendances

Les tools sont résolus via le service container Laravel : vous pouvez donc type-hinter des dépendances dans le constructeur ou dans handle.

Annotations

Vous pouvez ajouter des annotations aux tools pour informer le client IA sur leur comportement.

Enregistrement conditionnel

En implémentant shouldRegister, vous décidez à l’exécution si un tool doit être exposé.
En renvoyant false, le tool est masqué aux clients IA.

Réponses

Un tool doit retourner une instance de Laravel\Mcp\Response.
Renvoie une donnée structurée facilement analysable par le client IA.
Envoie l’avancement en temps réel pour les traitements longs.

Prompts

Les prompts sont des templates réutilisables. Ils permettent d’offrir aux clients IA des requêtes prêtes à l’emploi pour dialoguer avec le modèle de langage.

Créer un prompt

Enregistrez-le dans la propriété $prompts du serveur.

Arguments d’un prompt

Déclarez les paramètres du prompt via arguments.

Validation

Les arguments d’un prompt sont validés automatiquement d’après leur définition, mais vous pouvez appliquer des règles plus complexes. Laravel MCP s’intègre nativement à la validation de Laravel. Validez les arguments à l’intérieur du handle du prompt.
En cas d’échec, le client IA réessaiera à partir du message : fournissez des messages précis et exploitables.

Injection de dépendances

Les prompts étant résolus via le service container, vous pouvez type-hinter des dépendances dans le constructeur ou dans handle.
handle accepte également des types injectés automatiquement.

Enregistrement conditionnel

En implémentant shouldRegister, vous décidez à l’exécution si le prompt doit être exposé.
Renvoyer false rend le prompt invisible et non-invocable pour le client IA.

Réponse d’un prompt

Un handle de prompt peut renvoyer des messages utilisateur ou assistant. Utilisez asAssistant() pour marquer un message comme provenant de l’assistant.

Resources

Les resources sont des données ou informations que le client IA peut charger comme contexte : documentation, configuration, données dynamiques… tout ce qui améliore la qualité des réponses de l’IA.

Créer une resource

Enregistrez-la dans la propriété $resources.

URI et type MIME

Par défaut, l’URI est déduite du nom de classe (par exemple weather://resources/weather-guidelines). Personnalisez-les via Uri et MimeType.

Resource templates

Pour définir une resource dynamique dont l’URI contient des variables, implémentez l’interface HasUriTemplate.
Les variables de l’URI sont automatiquement injectées dans la requête et récupérables via get.

Requête d’une resource

Contrairement aux tools et aux prompts, les resources ne définissent pas de schéma d’entrée ni d’arguments. Vous accédez néanmoins aux informations de la requête via l’objet Request dans handle.

Injection de dépendances pour les resources

Les resources étant résolues via le service container, vous pouvez type-hinter des dépendances dans le constructeur ou dans handle.
handle accepte également des types injectés.

Annotations de resource

Les resources peuvent porter des annotations d’audience, de priorité, de date de dernière modification, etc.

Enregistrement conditionnel d’une resource

En implémentant shouldRegister, vous décidez à l’exécution si la resource doit être exposée.
Renvoyer false rend la resource invisible et non-accessible.

Réponse d’une resource

Une resource doit retourner une instance de Laravel\Mcp\Response. Pour un contenu texte, utilisez text.
Utilisez resourceLink pour retourner un lien de resource. Contrairement à une resource embarquée, il fournit un pointeur URI que le client IA récupérera de manière indépendante.
Vous pouvez aussi passer directement une classe ou une instance de resource enregistrée : URI, nom, titre, description et MIME type seront hérités.

Réponse Blob

Pour un contenu binaire, utilisez blob. Le type MIME est défini via l’attribut #[MimeType] de la resource.

Réponse d’erreur

Pour signaler une erreur, utilisez error.

Apps

Laravel MCP prend en charge les MCP Apps, une extension du protocole permettant à un tool de rendre une application HTML interactive dans une iframe sandbox à l’intérieur d’un hôte compatible. Cela ouvre la voie à des tableaux de bord, des formulaires, des visualisations et autres expériences riches qui vont bien au-delà d’une simple réponse texte. Une MCP App est composée de deux éléments :
  • App resource — retourne le HTML auto-suffisant de l’application.
  • Tool — associé à l’app resource via l’attribut #[RendersApp]. Lorsque le tool est appelé, l’hôte récupère la resource associée et la rend.

Créer une app resource

La commande Artisan make:mcp-app-resource crée une app resource.
Elle crée deux fichiers : une classe PHP dans app/Mcp/Resources et une vue Blade dans resources/views/mcp. Le nom de la vue est déduit du nom de la classe : WeatherDashboardApp correspond à mcp.weather-dashboard-app.
AppResource hérite de la classe de base Resource et configure automatiquement le schéma d’URI ui:// et le type MIME text/html;profile=mcp-app exigés par la spécification MCP Apps. Comme n’importe quelle resource, elle doit être déclarée dans le tableau $resources du serveur. La vue Blade générée utilise le composant <x-mcp::app>, qui produit un document HTML complet incluant le SDK MCP côté client.
La fonction globale createMcpApp fournie par le SDK gère la connexion de l’iframe au serveur, l’application du thème de l’hôte et expose des helpers comme callServerTool, sendMessage, openLink, ainsi que des callbacks d’événements. Pour l’API cliente complète, référez-vous à la spécification MCP Apps.

Rendre une app depuis un tool

Pour afficher une app resource, liez un tool à celle-ci via l’attribut #[RendersApp]. Quand le tool est appelé, Laravel MCP inclut l’URI de la resource dans les métadonnées du tool afin que l’hôte puisse rendre l’app dans une iframe sandbox.
Dès qu’une AppResource est enregistrée, Laravel MCP annonce automatiquement la capability io.modelcontextprotocol/ui. Aucune configuration serveur supplémentaire n’est requise.

Visibilité des tools d’app

Chaque tool #[RendersApp] peut restreindre ses appelants via l’argument visibility. C’est utile pour masquer au modèle les tools privés que l’UI utilise en interne pour charger ou actualiser des données.
L’enum Visibility a deux valeurs, Model et App ; par défaut les deux sont actives. Utilisez [Visibility::App] pour une action backend appelée uniquement par l’UI, et [Visibility::Model] pour empêcher l’UI de l’utiliser.

Configuration d’une app

L’attribut #[AppMeta] de l’app resource permet de configurer la Content Security Policy de l’iframe, les autorisations du navigateur et les bibliothèques à inclure dans le <head>.
L’enum Library inclut les scripts CDN de bibliothèques front populaires comme Library::Tailwind ou Library::Alpine, dont l’origine CDN est ajoutée automatiquement à la CSP. L’enum Permission couvre les autorisations navigateur : Camera, Microphone, Geolocation, ClipboardWrite, etc.
Pour une configuration dynamique, surchargez la méthode appMeta de la resource en utilisant les builders fluent AppMeta, Csp et Permissions de l’espace de noms Laravel\Mcp\Server\Ui.

Développement d’app avec Boost

Laravel MCP inclut une référence Boost dédiée à la création de MCP Apps. Si Laravel Boost est installé, un agent de code IA peut invoquer la skill mcp-development pour générer automatiquement l’app resource, la vue Blade et le tool associé. Pour la référence complète du protocole (API cliente, détails de schéma…), consultez la documentation officielle MCP Apps.

Métadonnées

Vous pouvez ajouter le champ _meta de la spécification MCP aux réponses des tools, resources et prompts.
Pour attacher des métadonnées à l’enveloppe complète de la réponse, utilisez Response::make.
Pour associer des métadonnées à la classe même du tool, de la resource ou du prompt, définissez la propriété $meta.

Icônes

Les clients MCP peuvent afficher des icônes pour le serveur et ses primitives. Utilisez l’attribut Icon pour déclarer des icônes sur un serveur, un tool, une resource ou un prompt.
L’attribut Icon est répétable : vous pouvez donc en déclarer plusieurs pour différentes tailles ou pour les variantes light / dark. Vous pouvez également définir les icônes de manière programmatique en surchargeant la méthode icons. C’est utile quand elles dépendent de conditions d’exécution.
Les icônes définies via attribut et via la méthode icons sont fusionnées automatiquement. Le chemin est résolu ainsi :
  • Un chemin avec un schéma d’URI (https:, data:, etc.) est utilisé tel quel.
  • Un chemin relatif est transformé en URL via le helper asset de Laravel.

Authentification

Les serveurs Web s’authentifient via les middlewares standard de Laravel.

Sanctum

Authentification par jeton avec Laravel Sanctum. Le client MCP envoie un en-tête Authorization: Bearer <token>.

OAuth 2.1

Authentification OAuth via Laravel Passport. Recommandée lorsque vous avez besoin d’une sécurité renforcée.
Publiez la vue d’autorisation de Passport et configurez-la dans un service provider.

Autorisation

$request->user() renvoie l’utilisateur authentifié, ce qui permet d’appliquer des vérifications d’autorisation dans les tools et resources.

Client MCP

Laravel MCP fournit aussi un client pour se connecter à d’autres serveurs MCP. Grâce à lui, vous pouvez découvrir et invoquer les tools exposés par un serveur MCP externe. C’est particulièrement utile pour donner à un agent IA accès à un serveur MCP externe.

Se connecter à un serveur

Pour un serveur MCP accessible en HTTP, utilisez Client::web en lui passant l’URL.
Pour un serveur MCP local qui se lance comme une commande, utilisez Client::local en indiquant la commande et ses arguments.
Le client se connecte de manière paresseuse (lazy connect) : la connexion est établie automatiquement à la première demande de tools ou au premier appel. Pour un contrôle manuel, utilisez connect, connected, ping et disconnect.
withTimeout personnalise le timeout de requête.

Clients nommés

Plutôt que de construire un client à chaque fois, enregistrez un client nommé réutilisable. Cela se fait généralement dans la méthode boot d’un service provider via la façade Mcp.
Une fois enregistré, résolvez-le par son nom.
Un client nommé est résolu une seule fois par requête et se déconnecte automatiquement à la fin du cycle de la requête.

Authentification du client

Pour un serveur MCP Web protégé par un jeton Bearer, utilisez withToken. Vous pouvez passer une chaîne ou une closure résolue paresseusement.
Pour un serveur protégé par OAuth 2.1, utilisez withOAuth.
Si le serveur MCP prend en charge l’enregistrement dynamique de client, clientId et clientSecret peuvent être omis : le client s’enregistrera lui-même.
Enregistrez ensuite les routes OAuth du client nommé dans routes/ai.php via oAuthRoutesFor. La closure passée reçoit le nom du client et un TokenSet après l’échange du code d’autorisation contre l’access token.
Deux routes nommées sont enregistrées : la route de connexion (mcp.oauth.{client}.connect) qui redirige l’utilisateur vers le serveur d’autorisation, et la route callback (mcp.oauth.{client}.callback) qui échange le code puis appelle le handler. Toutes deux utilisent le groupe de middleware web (surchargeable via l’argument middleware). Pour démarrer le flux d’autorisation, redirigez l’utilisateur vers la route de connexion.

Tools

tools renvoie les tools exposés par le serveur, sous forme de collection indexée par nom.
Le client gère automatiquement la pagination pour récupérer l’ensemble. L’argument limit restreint le nombre de résultats.
Pour invoquer un tool, utilisez callTool en indiquant son nom et ses arguments. L’instance ToolResult retournée expose la réponse.
Vous pouvez aussi invoquer directement un tool depuis l’instance retournée par la liste.
Si vous construisez un agent avec le Laravel AI SDK, passez directement les tools du client MCP à l’agent : le modèle pourra les invoquer en cours de génération. Consultez la section outils MCP de l’AI SDK pour plus de détails.

Prompts

prompts renvoie les prompts exposés par le serveur sous forme de collection indexée par nom.
La pagination est automatique. limit restreint le nombre de résultats.
Pour récupérer un prompt, utilisez getPrompt avec son nom et ses arguments. L’instance PromptResult retournée expose les messages générés.

Resources

resources renvoie les resources exposées par le serveur, indexées par URI.
La pagination est automatique. limit restreint le nombre de résultats.
Pour lire une resource, utilisez readResource en passant son URI. L’instance ResourceReadResult retournée expose son contenu.

Tests

MCP Inspector

Pour tester le comportement d’un serveur MCP, utilisez l’outil de debug interactif « MCP Inspector ».
L’exécution démarre MCP Inspector et vous permet de copier la configuration client. Si un middleware d’authentification est actif, incluez un en-tête Authorization à la connexion.

Tests unitaires

Vous pouvez écrire des tests unitaires pour les tools, les resources et les prompts.
Les prompts et resources se testent de la même manière.
Pour simuler un utilisateur authentifié, utilisez actingAs.
Les assertions les plus utiles :
Pour vérifier la présence ou l’absence d’erreurs, utilisez assertHasErrors / assertHasNoErrors.
Vous pouvez également vérifier le nom, le titre ou la description d’un tool, d’une resource ou d’un prompt.
Pour vérifier les notifications d’une réponse en streaming, utilisez assertSentNotification et assertNotificationCount.
Pour déboguer le contenu d’une réponse, utilisez dd ou dump.
Dernière modification le 2 août 2026