Symfony MCP Bundle : Intégrez le Model Context Protocol dans vos applications

Découvrez comment le Symfony MCP Bundle permet d'intégrer facilement le Model Context Protocol d'Anthropic dans vos applications Symfony pour créer des agents IA intelligents et contextuels.

07 Oct, 2025 12 min de lecture
Symfony MCP Bundle : Intégrez le Model Context Protocol dans vos applications

Qu'est-ce que le Model Context Protocol (MCP) ?

Le Model Context Protocol est un standard ouvert développé par Anthropic pour permettre aux applications IA d'accéder de manière sécurisée et structurée à des contextes externes : bases de données, APIs, systèmes de fichiers, outils métier, etc.

🤖 En résumé : MCP permet à Claude (et autres LLM) d'interagir avec vos données et systèmes de manière contrôlée, sans exposer directement vos credentials ou votre logique métier.

Le Symfony MCP Bundle simplifie l'intégration de ce protocole dans vos applications Symfony, vous permettant de créer des serveurs MCP personnalisés en quelques lignes de code.

Installation et configuration

Installation via Composer

composer require anthropic/symfony-mcp-bundle

# Si ce n'est pas fait automatiquement
php bin/console mcp:install

Configuration de base

Créez le fichier de configuration config/packages/mcp.yaml :

mcp:
    # Nom de votre serveur MCP
    server_name: "my-symfony-app"
    
    # Version du protocole
    protocol_version: "2024-11-05"
    
    # Configuration des transports
    transports:
        stdio:
            enabled: true
        sse:
            enabled: true
            path: /mcp/events
    
    # Sécurité
    security:
        enabled: true
        api_keys:
            - "%env(MCP_API_KEY)%"

Créer votre premier outil MCP

1. Définir un outil avec l'attribut PHP

Les outils MCP sont de simples services Symfony annotés :

namespace App\Mcp\Tool;

use Anthropic\Mcp\Attribute\McpTool;
use Anthropic\Mcp\Attribute\McpParameter;

class UserSearchTool
{
    public function __construct(
        private UserRepository $userRepository
    ) {}
    
    #[McpTool(
        name: 'search_users',
        description: 'Recherche des utilisateurs par email ou nom'
    )]
    public function search(
        #[McpParameter(
            description: 'Terme de recherche',
            required: true
        )]
        string $query,
        
        #[McpParameter(
            description: 'Nombre maximum de résultats',
            required: false,
            default: 10
        )]
        int $limit = 10
    ): array {
        $users = $this->userRepository->search($query, $limit);
        
        return array_map(fn($user) => [
            'id' => $user->getId(),
            'email' => $user->getEmail(),
            'name' => $user->getFullName(),
            'created_at' => $user->getCreatedAt()->format('Y-m-d'),
        ], $users);
    }
}

2. Enregistrer l'outil

Si vous utilisez l'autoconfiguration Symfony (par défaut), c'est automatique ! Sinon :

# config/services.yaml
services:
    App\Mcp\Tool\UserSearchTool:
        tags: ['mcp.tool']

Types d'outils disponibles

Outils de lecture de données

#[McpTool(
    name: 'get_order_details',
    description: 'Récupère les détails d\'une commande'
)]
public function getOrderDetails(
    #[McpParameter(description: 'ID de la commande')]
    int $orderId
): array {
    $order = $this->orderRepository->find($orderId);
    
    if (!$order) {
        throw new McpToolException("Commande #{$orderId} introuvable");
    }
    
    return [
        'id' => $order->getId(),
        'customer' => [
            'name' => $order->getCustomer()->getName(),
            'email' => $order->getCustomer()->getEmail(),
        ],
        'items' => array_map(fn($item) => [
            'product' => $item->getProduct()->getName(),
            'quantity' => $item->getQuantity(),
            'price' => $item->getPrice(),
        ], $order->getItems()->toArray()),
        'total' => $order->getTotal(),
        'status' => $order->getStatus()->value,
    ];
}

Outils d'écriture avec validation

#[McpTool(
    name: 'create_support_ticket',
    description: 'Crée un ticket de support client'
)]
public function createTicket(
    #[McpParameter(description: 'Email du client')]
    string $email,
    
    #[McpParameter(description: 'Sujet du ticket')]
    string $subject,
    
    #[McpParameter(description: 'Description du problème')]
    string $description,
    
    #[McpParameter(
        description: 'Priorité',
        enum: ['low', 'medium', 'high', 'urgent']
    )]
    string $priority = 'medium'
): array {
    // Validation
    $user = $this->userRepository->findByEmail($email);
    if (!$user) {
        throw new McpToolException("Utilisateur avec email {$email} introuvable");
    }
    
    // Création
    $ticket = new SupportTicket();
    $ticket->setUser($user);
    $ticket->setSubject($subject);
    $ticket->setDescription($description);
    $ticket->setPriority(Priority::from($priority));
    $ticket->setStatus(TicketStatus::OPEN);
    
    $this->entityManager->persist($ticket);
    $this->entityManager->flush();
    
    // Notification
    $this->notificationService->notifySupportTeam($ticket);
    
    return [
        'ticket_id' => $ticket->getId(),
        'reference' => $ticket->getReference(),
        'status' => 'created',
        'message' => 'Ticket créé avec succès',
    ];
}

Resources : Exposer des données contextuelles

Les resources permettent d'exposer des données que l'IA peut lire pour comprendre le contexte :

namespace App\Mcp\Resource;

use Anthropic\Mcp\Attribute\McpResource;

class ProductCatalogResource
{
    public function __construct(
        private ProductRepository $productRepository
    ) {}
    
    #[McpResource(
        uri: 'catalog://products',
        name: 'Product Catalog',
        description: 'Liste complète des produits disponibles',
        mimeType: 'application/json'
    )]
    public function getProducts(): array {
        $products = $this->productRepository->findAvailable();
        
        return [
            'total' => count($products),
            'products' => array_map(fn($p) => [
                'id' => $p->getId(),
                'name' => $p->getName(),
                'price' => $p->getPrice(),
                'stock' => $p->getStock(),
                'category' => $p->getCategory()->getName(),
            ], $products)
        ];
    }
    
    #[McpResource(
        uri: 'catalog://product/{id}',
        name: 'Product Details',
        description: 'Détails complets d\'un produit spécifique'
    )]
    public function getProductDetails(int $id): array {
        $product = $this->productRepository->find($id);
        
        return [
            'id' => $product->getId(),
            'name' => $product->getName(),
            'description' => $product->getDescription(),
            'price' => $product->getPrice(),
            'reviews' => array_map(fn($r) => [
                'rating' => $r->getRating(),
                'comment' => $r->getComment(),
                'author' => $r->getAuthor()->getName(),
            ], $product->getReviews()->toArray()),
        ];
    }
}

Prompts : Templates réutilisables

Créez des templates de prompts que l'IA peut utiliser :

namespace App\Mcp\Prompt;

use Anthropic\Mcp\Attribute\McpPrompt;
use Anthropic\Mcp\Attribute\McpPromptArgument;

class CustomerServicePrompts
{
    #[McpPrompt(
        name: 'respond_to_complaint',
        description: 'Générer une réponse professionnelle à une réclamation client'
    )]
    public function respondToComplaint(
        #[McpPromptArgument(description: 'Réclamation du client')]
        string $complaint,
        
        #[McpPromptArgument(description: 'Contexte de la commande')]
        array $orderContext
    ): string {
        return <<

Sécurité et permissions

1. Authentication avec API Keys

# .env
MCP_API_KEY=mcp_sk_1234567890abcdef

# config/packages/mcp.yaml
mcp:
    security:
        enabled: true
        api_keys:
            - "%env(MCP_API_KEY)%"

2. Permissions par outil

#[McpTool(
    name: 'delete_user',
    description: 'Supprime un utilisateur',
    permissions: ['ROLE_ADMIN']
)]
public function deleteUser(int $userId): array {
    $this->denyAccessUnlessGranted('ROLE_ADMIN');
    
    // Logique de suppression
}

3. Rate limiting

mcp:
    rate_limiting:
        enabled: true
        requests_per_minute: 60
        burst: 10

Tests automatisés

namespace App\Tests\Mcp;

use Anthropic\Mcp\Test\McpTestCase;

class UserSearchToolTest extends McpTestCase
{
    public function testSearchUsers(): void
    {
        $client = $this->createMcpClient();
        
        // Appeler l'outil
        $response = $client->callTool('search_users', [
            'query' => 'john',
            'limit' => 5,
        ]);
        
        // Assertions
        $this->assertCount(5, $response['content']);
        $this->assertArrayHasKey('id', $response['content'][0]);
        $this->assertArrayHasKey('email', $response['content'][0]);
    }
    
    public function testSearchUsersWithInvalidQuery(): void
    {
        $client = $this->createMcpClient();
        
        $this->expectException(McpToolException::class);
        
        $client->callTool('search_users', [
            'query' => '', // Query vide
        ]);
    }
}

Monitoring et logging

Le bundle intègre automatiquement le logging des opérations MCP :

mcp:
    logging:
        enabled: true
        channel: 'mcp'
        level: 'info'
        
    metrics:
        enabled: true
        provider: 'prometheus'

Exemple de logs

[2024-01-15 10:23:45] mcp.INFO: Tool called [] 
  {"tool": "search_users", "params": {"query": "john"}, "duration_ms": 45}

[2024-01-15 10:23:50] mcp.INFO: Resource accessed [] 
  {"uri": "catalog://products", "duration_ms": 120}

[2024-01-15 10:24:10] mcp.ERROR: Tool execution failed [] 
  {"tool": "create_ticket", "error": "User not found"}

Architecture complète d'un projet

src/
├── Mcp/
│   ├── Tool/                    # Outils MCP
│   │   ├── UserSearchTool.php
│   │   ├── OrderManagementTool.php
│   │   └── SupportTicketTool.php
│   │
│   ├── Resource/                # Resources MCP
│   │   ├── ProductCatalogResource.php
│   │   └── DocumentationResource.php
│   │
│   ├── Prompt/                  # Templates de prompts
│   │   └── CustomerServicePrompts.php
│   │
│   └── Security/                # Sécurité custom
│       └── McpVoter.php
│
├── Controller/
│   └── McpController.php        # Endpoints HTTP
│
└── EventSubscriber/
    └── McpEventSubscriber.php   # Événements MCP

Cas d'usage réels

Secteur Use Case Outils MCP
E-commerce Assistant d'achat IA Recherche produits, Gestion panier, Suivi commande
Support client Chatbot intelligent Base de connaissances, Création tickets, Historique client
RH Assistant recrutement Recherche candidats, Analyse CV, Planification entretiens
Finance Analyse financière Extraction données, Calculs, Génération rapports

Déploiement en production

Configuration Nginx

location /mcp/ {
    proxy_pass http://127.0.0.1:8000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    
    # SSE support
    proxy_buffering off;
    proxy_cache off;
}

Docker Compose

version: '3.8'

services:
  app:
    build: .
    environment:
      MCP_API_KEY: ${MCP_API_KEY}
      DATABASE_URL: ${DATABASE_URL}
    ports:
      - "8000:8000"
    volumes:
      - ./:/app
    command: php bin/console server:run 0.0.0.0:8000


Avantages du Symfony MCP Bundle

  •  
  • Intégration native avec l'écosystème Symfony
  •  
  • Type-safe grâce aux attributs PHP 8
  •  
  • Sécurité intégrée avec authentication et permissions
  •  
  • Testabilité avec des outils de test dédiés
  •  
  • Performance optimisée avec cache et async
  •  
  • Monitoring complet avec metrics et logs
  •  

💡 Conseil : Commencez petit avec 2-3 outils simples, testez-les bien, puis étendez progressivement vos capacités MCP. La clé est d'avoir des outils fiables et bien documentés.

Ressources et communauté

Pour aller plus loin :

  1.  
  2. Repository GitHub officiel
  3.  
  4. Spécification MCP
  5.  
  6. Documentation Symfony Bundles
  7.  
  8. Rejoignez le #mcp channel sur le Slack Symfony
  9.  

Conclusion

Le Symfony MCP Bundle ouvre des possibilités infinies pour intégrer l'intelligence artificielle dans vos applications Symfony de manière structurée et sécurisée. Que vous créiez un chatbot, un assistant virtuel ou un système d'automatisation, MCP fournit le cadre idéal pour exposer vos données et logique métier à des modèles de langage.

La combinaison de la robustesse de Symfony et de la puissance de Claude via MCP permet de construire des applications IA de niveau professionnel, prêtes pour la production.