Drupal MCP Server

Drupal MCP Server

Piloter son CMS par IA : Claude, ChatGPT, Cursor

CMS & Intelligence Artificielle27 mars 202620 min de lecture
🐉MCP🤖

Drupal + MCP = CMS piloté par IA

create_node, upload_media, publish... depuis Claude ou Cursor

Les CMS sont des silos. Pour créer un article, vous ouvrez le back-office, remplissez les champs, uploadez les images, configurez la taxonomie, puis publiez. Et si votre assistant IA — Claude, ChatGPT ou Cursor — pouvait le faire pour vous, directement depuis une conversation ?

C'est exactement ce que permet le Model Context Protocol (MCP) : un protocole ouvert qui standardise la communication entre les modèles d'IA et les systèmes externes. En transformant Drupal en serveur MCP, on expose des actions (create_node, upload_media, publish_node...) que n'importe quel client MCP peut invoquer.

Chez VOID, nous avons développé un module Drupal qui fait exactement ça. Voici comment.

8
Tools MCP exposés
REST
Transport standard
0
Contrib module requis
10+
Clients compatibles

1MCP en 2 minutes

Model Context Protocol (MCP)

Créé par Anthropic, MCP est un protocole ouvert qui définit comment les modèles d'IA interagissent avec des systèmes externes de manière standardisée. Pensez-y comme une API universelle pour l'IA — au lieu de coder une intégration custom pour chaque outil, un seul protocole les connecte tous.

🔧

Tools

Actions que l'IA peut exécuter. Dans notre cas : create_node, upload_media, publish_node...

📦

Resources

Données que l'IA peut lire. Ici : les types de contenu, les taxonomies, la structure des champs Drupal.

💬

Prompts

Instructions contextuelles que le serveur fournit à l'IA pour guider ses actions (ex : "les articles doivent avoir un champ image").

Architecture : Drupal comme serveur MCP

┌─────────────────┐         ┌──────────────────────────────────┐
│  Client MCP     │         │       DRUPAL (Serveur MCP)       │
│                 │  JSON   │                                  │
│  • Claude       │ ◄─────► │  ┌──────────────────────────┐   │
│  • ChatGPT      │  REST   │  │   Module drupal_mcp       │   │
│  • Cursor       │         │  │                            │   │
│  • Continue.dev │         │  │  Tools:                    │   │
│                 │         │  │   • create_node            │   │
└─────────────────┘         │  │   • upload_media           │   │
                            │  │   • update_node            │   │
                            │  │   • publish_node           │   │
                            │  │   • list_content_types     │   │
                            │  │   • get_node               │   │
                            │  │   • list_taxonomy_terms    │   │
                            │  │   • delete_node            │   │
                            │  └──────────┬───────────────┘   │
                            │             │                    │
                            │  ┌──────────▼───────────────┐   │
                            │  │  Drupal Core APIs         │   │
                            │  │  Node, Media, Taxonomy,   │   │
                            │  │  Field, User, File        │   │
                            │  └──────────────────────────┘   │
                            └──────────────────────────────────┘

2Les Tools MCP exposés par le module

Le module drupal_mcp expose 8 tools couvrant les opérations CRUD essentielles. Chaque tool correspond à une route REST authentifiée.

📝

create_node

Créer un contenu (article, page, landing page)

Params : type, title, body, fields, status

✏️

update_node

Modifier un contenu existant

Params : nid, fields, revision_message

🖼️

upload_media

Uploader une image ou un fichier

Params : file (base64), filename, alt, media_type

📋

list_content_types

Lister les types de contenu disponibles

Params :

🔍

get_node

Récupérer un contenu avec ses champs

Params : nid, include_fields

🏷️

list_taxonomy_terms

Lister les termes d'un vocabulaire

Params : vocabulary_id

🗑️

delete_node

Supprimer un contenu

Params : nid, confirm

🚀

publish_node

Publier / dépublier un contenu

Params : nid, status

Extensibilité

Le module est conçu pour être extensible. Ajouter un nouveau tool (ex : create_menu_link, manage_blocks, clear_cache) revient à créer un nouveau Controller et déclarer la route dans drupal_mcp.routing.yml. Le protocole MCP gère la découverte automatiquement.

3Implémentation : structure du module

modules/custom/drupal_mcp/
drupal_mcp/
├── drupal_mcp.info.yml          # Déclaration du module
├── drupal_mcp.routing.yml       # Routes REST (/mcp/tools/*)
├── drupal_mcp.permissions.yml   # Permissions granulaires
├── drupal_mcp.services.yml      # Services (auth, rate limit)
├── src/
│   ├── Controller/
│   │   ├── McpDiscoveryController.php   # GET /mcp — liste des tools
│   │   ├── CreateNodeController.php     # POST /mcp/tools/create_node
│   │   ├── UpdateNodeController.php     # PATCH /mcp/tools/update_node
│   │   ├── GetNodeController.php        # GET /mcp/tools/get_node/{nid}
│   │   ├── DeleteNodeController.php     # DELETE /mcp/tools/delete_node/{nid}
│   │   ├── PublishNodeController.php    # POST /mcp/tools/publish_node
│   │   ├── UploadMediaController.php    # POST /mcp/tools/upload_media
│   │   ├── ListContentTypesController.php  # GET /mcp/resources/content_types
│   │   └── ListTaxonomyController.php   # GET /mcp/resources/taxonomy/{vid}
│   ├── Authentication/
│   │   └── McpTokenAuth.php             # Bearer token validation
│   └── EventSubscriber/
│       └── McpAuditSubscriber.php       # Log de toutes les opérations
└── config/
    └── install/
        └── drupal_mcp.settings.yml      # Config par défaut
drupal_mcp.routing.yml
# Découverte MCP — liste tous les tools disponibles
drupal_mcp.discovery:
  path: '/mcp'
  defaults:
    _controller: '\Drupal\drupal_mcp\Controller\McpDiscoveryController::list'
  requirements:
    _permission: 'access mcp api'
  methods: [GET]

# Tool : Créer un node
drupal_mcp.create_node:
  path: '/mcp/tools/create_node'
  defaults:
    _controller: '\Drupal\drupal_mcp\Controller\CreateNodeController::execute'
  requirements:
    _permission: 'mcp create content'
  methods: [POST]

# Tool : Uploader un média
drupal_mcp.upload_media:
  path: '/mcp/tools/upload_media'
  defaults:
    _controller: '\Drupal\drupal_mcp\Controller\UploadMediaController::execute'
  requirements:
    _permission: 'mcp upload media'
  methods: [POST]

# Tool : Publier / dépublier
drupal_mcp.publish_node:
  path: '/mcp/tools/publish_node'
  defaults:
    _controller: '\Drupal\drupal_mcp\Controller\PublishNodeController::execute'
  requirements:
    _permission: 'mcp publish content'
  methods: [POST]
CreateNodeController.php
<?php

namespace Drupal\drupal_mcp\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;

class CreateNodeController extends ControllerBase {

  public function execute(Request $request): JsonResponse {
    $data = json_decode($request->getContent(), TRUE);

    // Validation des paramètres requis
    if (empty($data['type']) || empty($data['title'])) {
      return new JsonResponse([
        'error' => 'Missing required fields: type, title',
      ], 400);
    }

    $node = \Drupal\node\Entity\Node::create([
      'type'   => $data['type'],
      'title'  => $data['title'],
      'body'   => [
        'value'  => $data['body'] ?? '',
        'format' => $data['format'] ?? 'full_html',
      ],
      'status' => $data['status'] ?? 0,  // brouillon par défaut
    ]);

    // Champs dynamiques (field_image, field_tags, etc.)
    if (!empty($data['fields'])) {
      foreach ($data['fields'] as $field_name => $value) {
        if ($node->hasField($field_name)) {
          $node->set($field_name, $value);
        }
      }
    }

    $node->save();

    return new JsonResponse([
      'success' => TRUE,
      'nid'     => (int) $node->id(),
      'uuid'    => $node->uuid(),
      'url'     => $node->toUrl()->toString(),
      'status'  => $node->isPublished() ? 'published' : 'draft',
    ], 201);
  }

}
UploadMediaController.php
<?php

namespace Drupal\drupal_mcp\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;

class UploadMediaController extends ControllerBase {

  public function execute(Request $request): JsonResponse {
    $data = json_decode($request->getContent(), TRUE);

    if (empty($data['file']) || empty($data['filename'])) {
      return new JsonResponse([
        'error' => 'Missing required fields: file (base64), filename',
      ], 400);
    }

    // Décoder le fichier base64
    $file_data = base64_decode($data['file']);
    $directory = 'public://mcp-uploads/' . date('Y-m');
    \Drupal::service('file_system')->prepareDirectory(
      $directory, 
      \Drupal\Core\File\FileSystemInterface::CREATE_DIRECTORY
    );

    $file = \Drupal::service('file.repository')->writeData(
      $file_data,
      $directory . '/' . $data['filename'],
      \Drupal\Core\File\FileExists::Rename
    );

    // Créer l'entité Media
    $media = \Drupal\media\Entity\Media::create([
      'bundle'            => $data['media_type'] ?? 'image',
      'name'              => $data['alt'] ?? $data['filename'],
      'field_media_image' => [
        'target_id' => $file->id(),
        'alt'       => $data['alt'] ?? $data['filename'],
      ],
      'status' => 1,
    ]);
    $media->save();

    return new JsonResponse([
      'success'  => TRUE,
      'mid'      => (int) $media->id(),
      'fid'      => (int) $file->id(),
      'url'      => \Drupal::service('file_url_generator')
                     ->generateAbsoluteString($file->getFileUri()),
    ], 201);
  }

}

4Endpoint de découverte : GET /mcp

Le point d'entrée /mcp retourne la liste des tools disponibles au format MCP. C'est ce que le client (Claude, Cursor...) appelle en premier pour savoir ce qu'il peut faire.

GET /mcp — réponse JSON
{
  "name": "drupal-mcp-server",
  "version": "1.0.0",
  "description": "Drupal CMS — MCP Server",
  "tools": [
    {
      "name": "create_node",
      "description": "Create a new content node in Drupal",
      "inputSchema": {
        "type": "object",
        "properties": {
          "type":   { "type": "string", "description": "Content type machine name" },
          "title":  { "type": "string", "description": "Node title" },
          "body":   { "type": "string", "description": "Body content (HTML)" },
          "status": { "type": "integer", "description": "1=published, 0=draft" },
          "fields": { "type": "object", "description": "Additional fields" }
        },
        "required": ["type", "title"]
      }
    },
    {
      "name": "upload_media",
      "description": "Upload an image or file to Drupal media library",
      "inputSchema": {
        "type": "object",
        "properties": {
          "file":       { "type": "string", "description": "Base64 encoded file" },
          "filename":   { "type": "string", "description": "File name with extension" },
          "alt":        { "type": "string", "description": "Alt text for images" },
          "media_type": { "type": "string", "description": "Media bundle (image, document)" }
        },
        "required": ["file", "filename"]
      }
    }
  ],
  "resources": [
    { "uri": "drupal://content_types", "name": "Content Types", "description": "Available content types" },
    { "uri": "drupal://taxonomy/{vid}", "name": "Taxonomy Terms", "description": "Terms for a vocabulary" }
  ]
}

5Sécurité : ne pas exposer son CMS sans garde-fous

Règle d'or

Un serveur MCP expose des capacités d'écriture sur votre CMS. Sans sécurisation rigoureuse, c'est une porte ouverte. Chaque couche ci-dessous est indispensable.

🔑 Authentification

  • Bearer Token dans le header Authorization
  • • Token lié à un utilisateur Drupal (avec ses rôles et permissions)
  • • Rotation périodique des tokens
  • • Rejet immédiat des requêtes sans token valide

🛡️ Permissions granulaires

  • access mcp api — accéder à l'API MCP
  • mcp create content — créer du contenu
  • mcp upload media — uploader des médias
  • mcp publish content — publier (séparé de créer)
  • mcp delete content — supprimer (restreint)

⏱️ Rate Limiting

  • • Max 60 requêtes/minute par token
  • • Max 10 uploads/minute (fichiers volumineux)
  • • Taille max fichier : configurable (défaut 10 Mo)
  • • Réponse 429 Too Many Requests avec Retry-After

📋 Audit Log

  • • Chaque opération MCP est loguée (action, user, timestamp, payload)
  • • Intégration avec le système de log Drupal natif
  • • Alertes sur les opérations sensibles (delete, bulk create)
  • • Export pour compliance
drupal_mcp.permissions.yml
access mcp api:
  title: 'Access MCP API'
  description: 'Access the MCP discovery endpoint and tool listing'

mcp create content:
  title: 'MCP: Create content'
  description: 'Create nodes via MCP tools'
  restrict access: true

mcp upload media:
  title: 'MCP: Upload media'
  description: 'Upload files and create media entities via MCP'
  restrict access: true

mcp publish content:
  title: 'MCP: Publish content'
  description: 'Publish or unpublish nodes via MCP'
  restrict access: true

mcp delete content:
  title: 'MCP: Delete content'
  description: 'Delete nodes via MCP (dangerous)'
  restrict access: true

6Cas d'usage concrets

Production de contenu assistée par IA

Un rédacteur utilise Claude pour générer un article, puis le publie directement sur Drupal sans quitter la conversation.

Prompt dans Claude Desktop :

"Rédige un article de 800 mots sur les tendances e-commerce 2026 au Maroc, puis publie-le sur notre Drupal en brouillon avec la catégorie 'Digital'."

Migration de contenu par batch

Migrer des centaines d'articles depuis un CSV ou un ancien CMS via un prompt conversationnel, sans écrire un script de migration.

Prompt dans Cursor :

"Lis le fichier articles.csv et pour chaque ligne, crée un node 'article' sur Drupal avec title, body et field_category."

Workflow éditorial automatisé

L'IA crée le contenu en brouillon, ajoute les images, applique les tags, et l'éditeur n'a plus qu'à valider et publier.

Flux type :

IA create_node (draft) → IA upload_media → IA update_node (lier image) → Humain review → Humain publish_node

Développeur + Cursor = productivité x10

Un développeur code dans Cursor et peut tester ses contenus directement sur Drupal sans ouvrir le navigateur.

Dans Cursor :

"Crée 5 articles de test sur Drupal avec des titres lorem et publie-les pour tester la page listing."

7Démo : de la conversation au contenu publié

U

Crée un article "Les 5 tendances UX 2026" sur notre Drupal avec un body structuré en H2 et une intro percutante. Type : article. Status : brouillon.

AI

Appel MCP : create_node

{
  "type": "article",
  "title": "Les 5 tendances UX 2026",
  "body": "<p>En 2026, l'expérience utilisateur...</p><h2>1. IA conversationnelle</h2>...",
  "status": 0,
  "fields": {
    "field_category": [{"target_id": 42}]
  }
}

✅ Node #1847 créé en brouillon — voir sur Drupal

U

Ajoute une image hero et publie l'article.

AI

Appels MCP : upload_mediaupdate_nodepublish_node

✅ Image uploadée (mid: 523) — Node #1847 mis à jour — Publié

8Configurer le client MCP

Pour connecter Claude Desktop, Cursor ou tout autre client MCP à votre Drupal, il suffit de déclarer le serveur dans la config du client.

claude_desktop_config.json / .cursor/mcp.json
{
  "mcpServers": {
    "drupal": {
      "url": "https://votre-site.com/mcp",
      "transport": "rest",
      "headers": {
        "Authorization": "Bearer YOUR_MCP_TOKEN"
      }
    }
  }
}

Votre Drupal, piloté par IA

VOID développe et intègre des serveurs MCP sur Drupal pour connecter votre CMS aux assistants IA. Production de contenu accélérée, workflows automatisés, développement assisté.

Questions fréquentes

Qu'est-ce que MCP (Model Context Protocol) ?
MCP est un protocole ouvert créé par Anthropic qui standardise la communication entre les modèles d'IA (Claude, ChatGPT, Cursor) et les systèmes externes. Il définit des Tools (actions), Resources (données) et Prompts que l'IA peut invoquer de manière structurée.
Pourquoi transformer Drupal en serveur MCP ?
Un serveur MCP Drupal permet aux IA de créer du contenu, uploader des médias, gérer les taxonomies et piloter le workflow éditorial directement depuis une conversation. Cela automatise les tâches répétitives et accélère la production de contenu tout en gardant Drupal comme source de vérité.
Est-ce sécurisé d'exposer Drupal via MCP ?
Oui, à condition d'implémenter une authentification par token (Bearer), des permissions granulaires par rôle Drupal, du rate limiting et un audit log de toutes les opérations. Le module MCP s'appuie sur le système de permissions natif de Drupal.
Quels clients MCP sont compatibles ?
Claude Desktop, ChatGPT (via plugins/actions), Cursor IDE, Continue.dev, et tout client implémentant le protocole MCP. Le serveur Drupal expose des endpoints REST standard que n'importe quel client MCP peut consommer.
🌱Site éco-conçu