Un serveur MCP permet à un client IA de découvrir et d’appeler des outils que ton application expose explicitement. Dans Symfony, le bundle MCP relie ces capacités au conteneur de services : tu conserves tes services PHP et tu ajoutes une interface dédiée au client.[4]

L’objectif ici est volontairement réduit : exposer une information de diagnostic en lecture seule, puis vérifier son appel avant de brancher un assistant de code. La vidéo de 2025 reste disponible ; les configurations ci-dessous suivent la documentation du bundle 0.14.1. Le parcours Inspector reste documenté, non exécuté ici. Les contrôles locaux ont été exécutés avec PHP 8.4.26, Symfony 7.4.20 et le bundle MCP 0.14.1 : syntaxe PHP et YAML valides, debug:mcp a recensé symfony-version, debug:router a montré /mcp, et l’appel direct de la méthode a renvoyé 7.4.20. Ces contrôles ne valident pas la connexion HTTP d’un client MCP.

1. Partir d’une application compatible

Prévois une application Symfony fonctionnelle, Composer, PHP compatible avec ses dépendances et Node.js 22.19 ou plus récent pour lancer Inspector.[5] Travaille en développement, pas sur un serveur contenant des secrets de production.

composer require 'symfony/mcp-bundle:^0.14'
composer check-platform-reqs
php bin/console about

Symfony Flex active normalement le bundle via sa recette. Sans Flex, vérifie son enregistrement dans config/bundles.php. Consulte la documentation versionnée du bundle si ta configuration diffère : les anciens exemples ne correspondent pas nécessairement à la structure actuelle.[4]

2. Déclarer le serveur HTTP

Dans config/packages/mcp.yaml, configure un serveur nommé default et limite son registre à une seule classe :

mcp:
  servers:
    default:
      name: 'symfony-diagnostic'
      transports:
        http: true
      http:
        path: /mcp
      registry:
        tools: ['App\Mcp\DiagnosticTool']

Ajoute l’import de routes dans config/routes/mcp.yaml :

mcp:
  resource: .
  type: mcp

Le registre est une liste d’exposition, pas seulement une option de découverte. Une classe portant un attribut MCP doit aussi être un service Symfony et être sélectionnée par ce registre.[4] Évite d’exposer automatiquement tout le conteneur : une liste explicite rend le périmètre vérifiable.

3. Créer un outil sans commande arbitraire

Crée src/Mcp/DiagnosticTool.php. L’outil renvoie uniquement la version du framework : il n’exécute pas de commande transmise par le modèle et ne lit aucun fichier utilisateur.

<?php

namespace App\Mcp;

use Mcp\Capability\Attribute\McpTool;
use Symfony\Component\HttpKernel\Kernel;

final class DiagnosticTool
{
    #[McpTool(name: 'symfony-version')]
    public function version(): string
    {
        return Kernel::VERSION;
    }
}

Cet exemple adapte le mécanisme d’attributs documenté par le bundle.[4] Avec la configuration Symfony habituelle, les classes de src/ sont enregistrées et autoconfigurées. Si tu as exclu le dossier Mcp dans services.yaml, réenregistre la classe comme service.

Contrôle ensuite la configuration :

php -l src/Mcp/DiagnosticTool.php
php bin/console lint:yaml config/packages/mcp.yaml config/routes/mcp.yaml
php bin/console debug:mcp
php bin/console debug:router

Résultat attendu : le diagnostic MCP recense l’outil exposé, et le routeur contient le point d’entrée /mcp. Aucune sortie de ces commandes n’est présentée ici comme un résultat observé.

4. Appeler l’outil avec Inspector

Pour une démonstration locale uniquement, démarre l’application sur la boucle locale :

php -S 127.0.0.1:8000 -t public

Dans un autre terminal :

npx -y @modelcontextprotocol/inspector

Inspector fournit une interface de connexion et de test des outils.[5] Ouvre l’URL indiquée dans ton terminal, choisis le transport Streamable HTTP, puis connecte-toi à http://127.0.0.1:8000/mcp. Liste les outils et appelle symfony-version sans argument.

Résultat attendu : l’outil apparaît et son appel renvoie la version Symfony installée. Vérifie cette valeur contre php bin/console about. Une page ouverte dans le navigateur ne constitue pas ce test : MCP implique une initialisation de session et des messages de protocole, pas seulement un GET sur une route.[5]

5. Étendre le diagnostic sans ouvrir trop de droits

Après validation, remplace ou complète la démonstration par une capacité métier étroite : un résumé de statut, une lecture filtrée ou une recherche limitée. Garde des paramètres typés et impose les autorisations dans le code serveur. Le nom d’un outil ne protège pas son implémentation.

N’expose pas une méthode qui accepte une commande shell libre, un chemin de fichier arbitraire ou une requête SQL fournie par le modèle. Pour des actions modifiant des données, ajoute une validation humaine et conserve une trace des opérations. Un client IA n’est pas une autorité de sécurité.[8]

Erreurs courantes et limite de ce guide

Si l’outil manque, vérifie l’attribut importé, son enregistrement comme service et sa présence dans registry. Si la route manque, vérifie l’import type: mcp. Si Composer ou le conteneur refuse une ancienne configuration, compare-la avec la documentation de la version installée avant de renommer des clés au hasard.[4]

Ce serveur reste local et n’a pas d’authentification configurée. Ne le publie pas tel quel. Le guide de déploiement MCP distant traite séparément du transport réseau, du reverse proxy et du contrôle d’accès. Regarde la vidéo associée pour retrouver le contexte du serveur Symfony d’origine.

Sources

[4] https://github.com/symfony/ai/blob/v0.14.1/docs/bundles/mcp-bundle.rst [5] https://modelcontextprotocol.io/docs/tools/inspector [8] https://modelcontextprotocol.io/specification/latest/basic/security_best_practices