Si vous avez passé des années à maintenir de la logique métier au sein d'applications PHP, regarder des tutoriels sur le Model Context Protocol peut donner l'impression d'être devant une porte verrouillée. Presque tous les guides partent du principe que vous utilisez TypeScript ou Python. Ils passent en revue les SDK officiels, les installations npm et les paquets pip. Cela laisse une quantité énorme de données métier — dossiers clients, historiques de commandes, systèmes d'inventaire — stockées dans des bases de code PHP qui semblent invisibles pour la vague actuelle d'outils d'IA.

La bonne nouvelle est que rien dans le MCP ne nécessite ces SDK. Le MCP n'est pas une bibliothèque. C'est un protocole de communication (wire protocol). Si votre environnement d'exécution peut lire une ligne de texte depuis l'entrée standard, analyser du JSON et réécrire du JSON, il peut parler le protocole. C'est exactement ce que fait PHP depuis bien avant l'existence des LLM.

Ce qu'est réellement le MCP

MCP signifie Model Context Protocol. À la base, il s'agit d'un standard ouvert pour connecter les assistants d'IA aux données, aux outils et aux API externes. Au lieu de construire une intégration personnalisée pour chaque assistant ou modèle, vous construisez une interface conforme. Tout client comprenant le MCP peut alors communiquer avec votre serveur sans rien savoir de PHP, de Laravel ou de votre schéma de base de données spécifique.

Sous le capot, le MCP utilise JSON-RPC 2.0. Cela signifie que chaque requête est un simple objet JSON contenant un nom de méthode, des paramètres et un identifiant. Le serveur répond avec un autre objet JSON transportant soit un résultat, soit une erreur.

Un serveur expose trois primitives :

  • Tools : Des actions que le modèle peut invoquer. Un outil peut interroger une base de données, mettre à jour un statut ou appeler une API tierce.
  • Resources : Des données statiques ou semi-statiques que le modèle peut référencer via une URI. Pensez à des fichiers, des documents de configuration ou des jeux de données de référence.
  • Prompts : Des modèles prédéfinis qui aident l'utilisateur à interagir avec le système.

Il y a une distinction de contrôle importante à retenir. Les Tools sont contrôlés par le modèle. L'assistant décide quand en appeler un. Les Resources sont contrôlées par l'application. Le serveur décide quelles données sont disponibles et le modèle se contente de lire ce qui est proposé. Bien faire cette distinction permet de garder une architecture prévisible. Vous ne voulez pas qu'un modèle cherche des ressources qui auraient dû être des outils, ou inversement.

Fonctionnement du transport

Le MCP définit deux méthodes de transport, et votre choix détermine la manière dont vous écrirez la partie PHP.

stdio est la méthode la plus simple. Le client MCP lance votre script PHP en tant que sous-processus. Le client écrit des messages JSON-RPC dans l'entrée standard de votre script, et votre script écrit les réponses dans la sortie standard. Il n'y a pas de sockets à gérer, pas de ports à ouvrir et pas de headers d'authentification à analyser. Si votre outil et votre client résident sur la même machine, c'est généralement par là qu'il faut commencer.

L'exécution via stdio impose deux règles strictes à votre processus PHP. Premièrement, votre application ne doit jamais écrire de données non liées au protocole sur stdout. Si vous faites un echo d'une instruction de débogage ou si vous laissez passer une notice PHP, vous casserez l'analyseur (parser) du client. Dirigez tous les logs et diagnostics vers stderr. Deuxièmement, désactivez entièrement la mise en mémoire tampon de la sortie (output buffering). PHP aime mettre stdout en tampon, surtout dans les contextes CGI ou web, mais même les scripts CLI peuvent conserver des données. Videz (flush) chaque réponse immédiatement. Si vous utilisez des flux (streams), définissez stream_set_write_buffer(STDOUT, 0) ou désactivez la mise en mémoire tampon implicite pour que le client reçoive le saut de ligne à l'instant même où vous l'envoyez.

Streamable HTTP fonctionne différemment. Votre application PHP s'exécute en tant que point de terminaison (endpoint) HTTP persistant, généralement accessible via des requêtes POST. Cela est utile lorsque le serveur se trouve sur un hôte différent, ou lorsque vous souhaitez un démon (daemon) de longue durée accessible par plusieurs clients. En PHP, cela signifie généralement s'exécuter sous RoadRunner, FrankenPHP ou un gestionnaire de processus similaire, plutôt que via le cycle requête-réponse traditionnel qui s'arrête après chaque appel.

Le construire en PHP

Vous n'avez pas besoin de framework pour commencer. Un serveur MCP minimal en PHP est une boucle qui lit depuis STDIN, décode le JSON, délègue à un gestionnaire (handler) et encode le résultat.

while ($line = fgets(STDIN)) {
    $request = json_decode($line, true);
    // route to tool or resource handler
    // write JSON-RPC response to STDOUT
}

À l'intérieur de cette boucle, le véritable travail consiste à construire des interfaces qui font sens pour un modèle.

Générez les schémas d'outils à partir du code. L'un des moyens les plus rapides de créer des problèmes est d'écrire manuellement des schémas JSON pour les paramètres de vos outils et de les laisser se désynchroniser de votre logique de validation réelle. PHP possède de riches capacités de réflexion (reflection). Inspectez vos signatures de méthodes, lisez les règles de validation existantes de vos formulaires ou de vos objets de commande, et générez le schéma à partir de ces contraintes. Si votre code interne exige un format d'e-mail valide, votre schéma MCP doit dire la même chose. Lorsque les règles de validation changent, le schéma se met à jour automatiquement. Pas de dérive, pas d'échecs silencieux.

Séparez les erreurs de protocole des erreurs d'outil. JSON-RPC possède son propre espace d'erreurs. Utilisez-le pour les erreurs de protocole : JSON malformé, méthodes inconnues ou IDs de requête manquants. Lorsqu'un outil s'exécute correctement mais rencontre un problème métier, renvoyez un résultat normal avec un indicateur d'erreur à l'intérieur de la charge utile (payload). Si un outil de recherche de client ne trouve aucun enregistrement correspondant, ce n'est pas un plantage du protocole. Renvoyer un résultat structuré tel que {"found": false} permet au modèle de comprendre ce qui s'est passé et de choisir l'étape suivante. Il pourrait tenter une recherche plus large ou demander des précisions à l'utilisateur. Si, au lieu de cela, vous déclenchez une erreur JSON-RPC, le modèle perd souvent le contexte.

Prévoyez les tâches de longue durée. PHP est conçu pour des requêtes courtes. Une requête web peut expirer en trente secondes, et même les scripts CLI peuvent épuiser la mémoire ou la patience. Si un outil nécessite plusieurs minutes pour se terminer — par exemple pour compiler un rapport volumineux ou synchroniser des données entre plusieurs systèmes — ne faites pas attendre le modèle. Renvoyez immédiatement un identifiant de tâche. Ensuite, exposez un second outil pour vérifier le statut via cet ID. Vous pouvez stocker la progression dans Redis, une table de base de données ou même un fichier plat si le volume est faible. Le modèle reçoit l'ID, revient vérifier plus tard et finit par récupérer le résultat terminé.

Sécurité lorsque le modèle possède des clés

Donner accès à un outil à un modèle d'IA n'est pas la même chose que de le donner à un utilisateur humain. Un modèle agit vite, littéralement, et peut mal interpréter les descriptions. Considérez chaque outil exposé comme un risque d'escalade de privilèges.

Limitez strictement le périmètre. N'exposez jamais un outil générique run_sql. Créez des outils spécifiques et restreints comme find_customer_by_email ou update_order_status. Le modèle ne doit pouvoir faire que ce que vous nommez, avec les paramètres que vous avez définis.

Séparez les chemins de lecture et d'écriture. Les outils en lecture seule présentent un risque moindre. Placez toute action destructive derrière un mécanisme de confirmation explicite, ou restreignez-la entièrement à un second serveur. Si votre client le permet, exigez une étape d'approbation humaine avant l'exécution d'un outil d'écriture.

Rédigez les descriptions des outils comme s'il s'agissait d'instructions supplémentaires, car c'est le cas. Soyez précis sur le moment où le modèle doit appeler un outil. Si un outil recherche des prix, dites-le. S'il ne doit être utilisé qu'après avoir vérifié l'ID du client, précisez-le clairement. Des descriptions vagues mènent à des comportements vagues.

Filtrez votre sortie. Ne sérialisez pas un modèle Eloquent ou une entité Doctrine entier pour le déverser dans le résultat. Ne renvoyez que les champs dont le modèle a réellement besoin. Les champs internes — prix de revient, notes d'employés, IDs de base de données qui doivent rester internes — n'ont rien à faire sur le réseau. Soyez explicite sur la structure de votre retour.

Enfin, journalisez tout. Enregistrez le nom de l'outil, les arguments passés et le résultat. Si un modèle commence à boucler sur une requête coûteuse ou à sonder les outils dans un ordre inattendu, vos journaux seront votre seul moyen de le voir.

Par où commencer

Vous n'avez pas besoin de la permission d'un mainteneur de SDK pour connecter votre application PHP à un assistant IA. Vous avez besoin de JSON-RPC, d'une boucle et d'une certaine discipline concernant la sortie standard (stdout).

Résistez à l'envie de reconstruire l'intégralité de votre API en outils MCP dès le premier jour. Choisissez trois opérations en lecture seule sur lesquelles quelqu'un dans votre organisation pose régulièrement des questions. Il peut s'agir de vérifier le statut d'une commande, de récupérer un résumé de client ou de lister des factures récentes. Encapsulez-les en tant qu'outils, servez-les via stdio et laissez un collègue les utiliser. Observez ce que le modèle fait bien et là où il trébuche. Vous apprendrez plus de ces trois outils que de la planification de trente.

MCP est un pont, pas un remplacement de votre application. Votre code PHP connaît déjà votre métier. Le protocole permet simplement au modèle de traverser pour lui poser des questions.