# rest_api_init : une action pour exposer un point d’entrée dédié à un agent

> Ajouter une route dédiée à un agent sans passer par un serveur MCP, quand un projet n'a pas encore basculé vers une version de WordPress plus récente.

- Auteur : WordPress Développement
- Publié le : 2025-05-09
- Mis à jour le : 2026-09-30
- Catégorie : IA &amp; MCP
- URL : https://www.wpmoderne.fr/ia-mcp/rest-api-init-point-entree-agent/

## L’essentiel

- Une route REST classique reste une option valable en attendant l'adoption d'un serveur MCP
- Le hook rest_api_init permet d'enregistrer un point d'entrée avec ses propres règles de permission
- Cette route peut ensuite être décrite manuellement à un agent existant

Tous les projets ne peuvent pas basculer immédiatement vers un serveur MCP dès qu'un besoin d'exposer une fonctionnalité à un agent se présente. Sur un site qui n'a pas encore prévu cette migration, une route REST classique, enregistrée via le hook `rest_api_init`, reste une solution parfaitement fonctionnelle pour donner à un agent un accès contrôlé à une action précise.

Cette recette décrit comment construire un point d'entrée dédié, avec ses propres règles de permission, sans dépendre d'un protocole plus récent que le projet n'a pas encore intégré.

## Le besoin : une action simple exposée à un agent externe

Le cas concret retenu ici est celui d'un agent de support, développé en dehors de WordPress, qui doit pouvoir consulter le statut d'une commande à partir de sa référence, sans disposer d'un accès complet à l'API REST WooCommerce existante, jugée trop large pour ce cas d'usage précis.

## Étape 1 : enregistrer la route sur rest_api_init

> L'essentiel à retenir : Une route REST classique reste une option valable en attendant l'adoption d'un serveur MCP ; Le hook rest_api_init permet d'enregistrer un point d'entrée avec ses propres règles de permission ; Cette route peut ensuite être décrite manuellement à un agent existant

Une précision de vocabulaire avant le code : `rest_api_init` est une action, et non un filtre. On s'y accroche avec `add_action()`, et il se déclenche lorsque le serveur REST s'initialise, au moment où chaque extension peut enregistrer ses routes. C'est l'unique endroit où `register_rest_route()` doit être appelée.

```
add_action( 'rest_api_init', 'support_enregistrer_route_commande' );

function support_enregistrer_route_commande() {
    register_rest_route( 'support/v1', '/commande/(?P<reference>\d+)/statut', array(
        'methods'             => WP_REST_Server::READABLE,
        'callback'            => 'support_lire_statut_commande',
        'permission_callback' => 'support_verifier_droit',
        'args'                => array(
            'reference' => array(
                'description'       => 'Numéro de la commande.',
                'type'              => 'integer',
                'required'          => true,
                'sanitize_callback' => 'absint',
            ),
        ),
    ) );
}
```

L'expression `(?P<reference>\d+)` capture le numéro dans l'adresse, et la restriction à des chiffres évite d'accepter autre chose dès la résolution de la route. Le paramètre est ensuite déclaré dans `args` : cette déclaration sert à la fois à l'assainissement et à la description de la route, nous y reviendrons.

## Étape 2 : des règles de permission strictes

Le `permission_callback` est l'élément le plus important de la route. Il ne se contente pas de demander « l'appelant est-il connecté ? » : il vérifie une capacité précise, créée pour cet usage. On définit un rôle dédié, qui ne possède que la lecture du statut des commandes :

```
register_activation_hook( __FILE__, 'support_creer_role_agent' );

function support_creer_role_agent() {
    add_role( 'agent_support', 'Agent de support', array(
        'read'                        => true,
        'consulter_statut_commande'   => true,
    ) );
}

function support_verifier_droit() {
    if ( current_user_can( 'consulter_statut_commande' ) ) {
        return true;
    }

    return new WP_Error(
        'support_interdit',
        'Vous n\'avez pas le droit de consulter le statut des commandes.',
        array( 'status' => rest_authorization_required_code() )
    );
}
```

L'agent s'authentifie avec un mot de passe d'application rattaché à un utilisateur de ce rôle, transmis en authentification HTTP de base, exclusivement en HTTPS. Si le compte est compromis, l'attaquant ne peut lire que des statuts : pas de modification, pas d'accès aux clients, pas de connexion à l'interface d'administration avec ce mot de passe. La révocation se fait depuis le profil de l'utilisateur, sans changer le mot de passe principal.

## Étape 3 : une réponse minimale

La fonction de rappel ne renvoie que ce dont l'agent a besoin. Ni nom, ni adresse, ni adresse électronique : le statut et la date de dernière modification suffisent pour répondre à un client :

```
function support_lire_statut_commande( WP_REST_Request $requete ) {
    $commande = wc_get_order( $requete['reference'] );

    if ( ! $commande ) {
        return new WP_Error(
            'support_commande_introuvable',
            'Commande introuvable.',
            array( 'status' => 404 )
        );
    }

    $statut = $commande->get_status();

    return rest_ensure_response( array(
        'reference'    => $commande->get_id(),
        'statut'       => $statut,
        'libelle'      => wc_get_order_status_name( $statut ),
        'modifiee_le'  => $commande->get_date_modified()
            ? $commande->get_date_modified()->date( 'c' )
            : null,
    ) );
}
```

La fonction `wc_get_order()` renvoie `false` pour un identifiant inconnu, ce qui permet de répondre par un 404 explicite plutôt que par une erreur fatale. Attention : le numéro de commande affiché au client peut différer de l'identifiant interne si une extension modifie la numérotation ; précisez dans la description de la route lequel des deux est attendu.

## Étape 4 : décrire la route à l'agent

Un agent existant, construit en dehors de WordPress, ne découvre pas la route tout seul : il faut la lui décrire. La REST API fournit déjà une partie du travail, puisqu'une requête `OPTIONS` sur la route renvoie les méthodes acceptées et la description des arguments déclarés plus haut. On peut en tirer, à la main, une définition d'outil sous forme de schéma JSON, que l'on colle dans la configuration de l'agent :

```
{
    "name": "statut_commande",
    "description": "Retourne le statut actuel d'une commande à partir de son numéro. Ne fournit aucune donnée personnelle.",
    "input_schema": {
        "type": "object",
        "properties": {
            "reference": {
                "type": "integer",
                "description": "Numéro de la commande."
            }
        },
        "required": [ "reference" ]
    }
}
```

L'agent, ou la petite couche qui le pilote, transforme alors un appel d'outil en requête `GET /wp-json/support/v1/commande/1234/statut` accompagnée de l'authentification. La description textuelle compte autant que le schéma : elle doit dire ce que l'outil fait, mais aussi ce qu'il ne fait pas.

> Donner à un agent une route précise et étroite vaut mieux que lui confier une clé qui ouvre toute la maison.

## Les pièges à éviter

- **Laisser `__return_true` comme permission.** Depuis WordPress 5.5, l'absence de `permission_callback` déclenche un avertissement, mais l'écrire avec `__return_true` sur une route qui expose des données d'activité revient à la publier sur Internet.
- **Réutiliser un compte d'administrateur.** Un agent n'a pas besoin de tous les droits : un rôle dédié limite les dégâts en cas de fuite d'un mot de passe d'application.
- **Renvoyer trop de données.** Ce que l'agent reçoit peut se retrouver dans ses réponses : ne lui transmettez que ce qu'il a le droit de dire.
- **Oublier la journalisation et la limitation de débit.** Un agent qui boucle peut saturer le site : journalisez les appels et plafonnez-les au niveau du serveur ou d'une extension de sécurité.
- **Bâtir toute la logique dans la fonction de rappel.** Isolez le calcul métier dans une fonction indépendante de la route : si le projet adopte plus tard un serveur MCP, cette logique sera réutilisable telle quelle.

## Conclusion

En attendant une éventuelle bascule vers un serveur MCP, une route REST classique, enregistrée sur l'action `rest_api_init`, donne à un agent un accès précis et contrôlé : un espace de noms dédié, un `permission_callback` fondé sur une capacité propre, une réponse minimale et une description écrite à la main. La solution reste simple, testable avec `curl` et entièrement sous votre contrôle, ce qui est exactement ce que l'on attend d'une porte ouverte à un programme autonome.
