# Brancher un agent IA sur un site Elementor avec l’Abilities API et le MCP Adapter

> Exposez deux actions Elementor sous forme d'abilities WordPress, puis ouvrez-les à un agent IA via le MCP Adapter, avec permissions, schémas et garde-fous.

- Auteur : WordPress Développement
- Publié le : 2026-10-05
- Mis à jour le : 2026-09-30
- Catégorie : IA &amp; MCP
- URL : https://www.wpmoderne.fr/ia-mcp/brancher-agent-ia-elementor-abilities-api-mcp-adapter/

## L’essentiel

- Déclarer une catégorie puis des abilities avec schémas et permissions
- Les abilities restent privées tant que meta.mcp.public n'est pas à true
- Tester en STDIO sur un site de préproduction avant tout usage réel

La documentation du MCP Adapter tient en une phrase qui structure tout le reste : les abilities WordPress sont privées par défaut, et c'est à vous d'ouvrir celles que vous voulez rendre visibles à un agent. Cet article fait partie de la série consacrée à l'IA et aux constructeurs de pages. Il montre, pas à pas, comment transformer deux gestes courants sur un site Elementor, lister les modèles et créer une page à partir de l'un d'eux, en abilities que n'importe quel client MCP peut appeler, sous le contrôle des droits WordPress.

## Les trois briques : Abilities API, MCP et MCP Adapter

L'Abilities API est une interface du cœur de WordPress, disponible à partir de WordPress 6.9. Elle permet à une extension, à un thème ou au cœur de déclarer une action sous un nom unique de la forme `espace/nom`, avec une description lisible, un schéma JSON pour les entrées et les sorties, une fonction d'exécution et une fonction de contrôle des droits. Chaque ability appartient à une catégorie, et une seule.

Le Model Context Protocol (MCP) est le protocole ouvert, publié fin 2024, par lequel un agent découvre et appelle des outils. Le MCP Adapter, dépôt officiel `WordPress/mcp-adapter`, est le pont entre les deux : il lit les abilities enregistrées et les présente comme des outils MCP. Un serveur par défaut est fourni. Il est joignable en HTTP à l'adresse `/wp-json/mcp/mcp-adapter-default-server` ou en STDIO via WP-CLI.

Précision utile : Elementor propose désormais sa propre connexion MCP, accessible depuis le menu Elementor de l'administration, qui s'appuie sur un mot de passe d'application. Ce n'est pas l'objet de cet article. Ici, nous construisons la voie générique, celle qui fonctionne pour vos propres actions métier et qui reste sous votre contrôle.

## Déclarer une catégorie et une première ability en lecture seule

> L'essentiel à retenir : Déclarer une catégorie puis des abilities avec schémas et permissions ; Les abilities restent privées tant que meta.mcp.public n'est pas à true ; Tester en STDIO sur un site de préproduction avant tout usage réel

Deux actions d'initialisation sont à connaître : `wp_abilities_api_categories_init` pour les catégories, puis `wp_abilities_api_init` pour les abilities. L'ordre compte, car une ability qui référence une catégorie inexistante est refusée. Voici la catégorie et l'ability qui liste les modèles Elementor. Les modèles sont des contenus du type `elementor_library`, et leur nature est portée par la métadonnée `_elementor_template_type`.

```
<?php
add_action( 'wp_abilities_api_categories_init', function () {
    wp_register_ability_category( 'wpm-elementor', array(
        'label'       => __( 'Elementor (WP Moderne)', 'wpm-abilities' ),
        'description' => __( 'Lecture des modèles et création de pages Elementor.', 'wpm-abilities' ),
    ) );
} );

add_action( 'wp_abilities_api_init', function () {
    wp_register_ability( 'wpm/list-elementor-templates', array(
        'label'               => __( 'Lister les modèles Elementor', 'wpm-abilities' ),
        'description'         => __( 'Retourne les modèles Elementor publiés, filtrés par type.', 'wpm-abilities' ),
        'category'            => 'wpm-elementor',
        'input_schema'        => array(
            'type'       => 'object',
            'properties' => array(
                'type' => array(
                    'type'    => 'string',
                    'enum'    => array( 'page', 'section', 'container' ),
                    'default' => 'page',
                ),
            ),
            'additionalProperties' => false,
        ),
        'output_schema'       => array(
            'type'  => 'array',
            'items' => array(
                'type'       => 'object',
                'properties' => array(
                    'id'    => array( 'type' => 'integer' ),
                    'title' => array( 'type' => 'string' ),
                ),
            ),
        ),
        'execute_callback'    => 'wpm_list_elementor_templates',
        'permission_callback' => function () {
            return current_user_can( 'edit_pages' );
        },
        'meta'                => array(
            'show_in_rest' => true,
            'mcp'          => array( 'public' => true ),
            'annotations'  => array(
                'readonly'    => true,
                'destructive' => false,
                'idempotent'  => true,
            ),
        ),
    ) );
} );

function wpm_list_elementor_templates( $input = array() ) {
    $type  = is_array( $input ) && ! empty( $input['type'] ) ? $input['type'] : 'page';
    $posts = get_posts( array(
        'post_type'      => 'elementor_library',
        'post_status'    => 'publish',
        'posts_per_page' => 50,
        'meta_key'       => '_elementor_template_type',
        'meta_value'     => $type,
    ) );
    $out = array();
    foreach ( $posts as $post ) {
        $out[] = array( 'id' => $post->ID, 'title' => get_the_title( $post ) );
    }
    return $out;
}
```

Trois points méritent l'attention. Le schéma d'entrée avec `additionalProperties` à `false` évite que l'agent invente des paramètres. La limite de 50 résultats protège le contexte du modèle, qui paie chaque ligne retournée. Enfin les annotations `readonly`, `destructive` et `idempotent` sont des indications pour les clients : elles ne remplacent jamais la fonction de permission.

## Une ability d'écriture : créer une page à partir d'un modèle

Créer du contenu est un geste d'une autre nature. Elementor stocke la mise en page d'un document en JSON dans la métadonnée `_elementor_data`, accompagnée de `_elementor_edit_mode`, `_elementor_template_type` et `_elementor_version`. La documentation des développeurs d'Elementor cite ces quatre clés mais ne garantit pas leur format interne : c'est un détail d'implémentation, qui peut évoluer. Notre ability copie donc les données d'un modèle existant, sans jamais les fabriquer elle-même, et elle crée la page en brouillon.

```
add_action( 'wp_abilities_api_init', function () {
    wp_register_ability( 'wpm/create-page-from-template', array(
        'label'               => __( 'Créer une page depuis un modèle', 'wpm-abilities' ),
        'description'         => __( 'Crée une page en brouillon à partir d\'un modèle Elementor.', 'wpm-abilities' ),
        'category'            => 'wpm-elementor',
        'input_schema'        => array(
            'type'       => 'object',
            'properties' => array(
                'template_id' => array( 'type' => 'integer', 'minimum' => 1 ),
                'title'       => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 120 ),
            ),
            'required'             => array( 'template_id', 'title' ),
            'additionalProperties' => false,
        ),
        'output_schema'       => array(
            'type'       => 'object',
            'properties' => array(
                'page_id'  => array( 'type' => 'integer' ),
                'edit_url' => array( 'type' => 'string' ),
            ),
        ),
        'execute_callback'    => 'wpm_create_page_from_template',
        'permission_callback' => function () {
            return current_user_can( 'publish_pages' );
        },
        'meta'                => array(
            'mcp'         => array( 'public' => true ),
            'annotations' => array(
                'readonly'    => false,
                'destructive' => false,
                'idempotent'  => false,
            ),
        ),
    ) );
} );

function wpm_create_page_from_template( $input ) {
    $template = get_post( (int) $input['template_id'] );
    if ( ! $template || 'elementor_library' !== $template->post_type ) {
        return new WP_Error( 'wpm_bad_template', 'Modèle Elementor introuvable.' );
    }
    $data = get_post_meta( $template->ID, '_elementor_data', true );
    if ( empty( $data ) ) {
        return new WP_Error( 'wpm_empty_template', 'Le modèle ne contient pas de données Elementor.' );
    }
    $page_id = wp_insert_post( array(
        'post_type'   => 'page',
        'post_status' => 'draft',
        'post_title'  => sanitize_text_field( $input['title'] ),
    ), true );
    if ( is_wp_error( $page_id ) ) {
        return $page_id;
    }
    update_post_meta( $page_id, '_elementor_data', wp_slash( $data ) );
    update_post_meta( $page_id, '_elementor_edit_mode', 'builder' );
    update_post_meta( $page_id, '_elementor_template_type', 'wp-page' );
    if ( defined( 'ELEMENTOR_VERSION' ) ) {
        update_post_meta( $page_id, '_elementor_version', ELEMENTOR_VERSION );
    }
    if ( class_exists( '\Elementor\Plugin' ) ) {
        \Elementor\Plugin::$instance->files_manager->clear_cache();
    }
    return array(
        'page_id'  => $page_id,
        'edit_url' => admin_url( 'post.php?post=' . $page_id . '&action=elementor' ),
    );
}
```

Le `wp_slash()` n'est pas décoratif : `update_post_meta()` retire les barres obliques d'échappement, et sans cette précaution le JSON serait corrompu dès qu'il contient un guillemet échappé. La fonction retourne un `WP_Error` en cas de problème, ce qui permet à l'agent de recevoir une erreur exploitable plutôt qu'un échec muet. Comparez toujours le résultat avec une page créée à la main dans l'éditeur : si une métadonnée manque pour votre version d'Elementor, vous le verrez immédiatement.

## Rendre les abilities accessibles à l'agent

Installez le MCP Adapter, en extension ou via Composer (`WordPress/mcp-adapter`). Les deux abilities ci-dessus portent `meta.mcp.public` à `true` : elles sont donc visibles. Le serveur par défaut expose trois outils génériques, `mcp-adapter/discover-abilities`, `mcp-adapter/get-ability-info` et `mcp-adapter/execute-ability` : l'agent découvre vos abilities, lit leur schéma, puis les exécute par leur nom. La documentation prévoit aussi la conversion des noms (`wpm/list-elementor-templates` devient `wpm-list-elementor-templates`) pour les serveurs qui exposent chaque ability comme un outil distinct ; c'est un autre mode, lié à la création d'un serveur personnalisé, que nous ne détaillons pas ici.

Pour un test local, la commande suivante lance le serveur par défaut en STDIO, sous l'identité d'un utilisateur existant :

```
wp mcp-adapter serve --server=mcp-adapter-default-server --user=admin
```

La configuration côté client MCP prend alors la forme suivante (chemin à adapter) :

```
{
  "mcpServers": {
    "wordpress": {
      "command": "wp",
      "args": [
        "--path=/chemin/vers/le/site",
        "mcp-adapter",
        "serve",
        "--server=mcp-adapter-default-server",
        "--user=admin"
      ]
    }
  }
}
```

Pour un site distant, la documentation du dépôt décrit un passage par HTTP avec un mot de passe d'application, via un petit relais côté client. Créez pour cela un utilisateur dédié, doté du rôle le plus bas qui suffit (éditeur, ici), et non votre compte d'administrateur.

## Pièges fréquents et cas où il vaut mieux s'abstenir

- **Les droits sont ceux de l'utilisateur connecté.** Un agent lancé sous un compte administrateur peut tout ce que fait l'administrateur. La fonction de permission de chaque ability est votre dernier rempart.
- **Un schéma trop lâche invite à l'improvisation.** Déclarez `required`, bornes et `additionalProperties` : le modèle lit ces contraintes et s'y conforme mieux.
- **Pas de suppression ni de publication directe.** Nous créons en brouillon, et un humain relit avant toute mise en ligne.
- **Les données internes d'Elementor ne sont pas une API publique.** Testez après chaque mise à jour majeure d'Elementor, sur une préproduction.
- **Le contexte coûte cher.** Limitez les listes, renvoyez des identifiants et des titres plutôt que des contenus entiers.

Quand ne pas le faire ? Si votre besoin se limite à rédiger quelques textes, une extension d'assistance dans l'éditeur suffit et n'ouvre aucune porte sur le serveur. Si le site est en production, sans préproduction ni sauvegarde éprouvée, attendez. Et si la connexion MCP intégrée à Elementor couvre déjà votre usage, inutile de redévelopper ses actions : réservez vos abilities aux gestes propres à votre agence.

> Une ability bien conçue se lit comme un contrat : ce qu'elle accepte, ce qu'elle rend, qui a le droit de l'appeler. L'agent n'est qu'un client de plus.

## Conclusion

Deux catégories d'actions, lecture et écriture en brouillon, suffisent pour mesurer ce que change l'Abilities API : vos actions métier deviennent des fonctions décrites, typées et protégées, que le MCP Adapter sait présenter à un agent. Les signatures et les actions d'initialisation présentées ici proviennent de la documentation officielle de l'Abilities API et du dépôt du MCP Adapter, à consulter pour les évolutions : [documentation de l'Abilities API](https://developer.wordpress.org/apis/abilities/) et [dépôt du MCP Adapter](https://github.com/WordPress/mcp-adapter). Commencez par la lecture seule, observez ce que fait l'agent dans les journaux, puis ouvrez l'écriture, toujours en brouillon.
