EmDash inclut un serveur Model Context Protocol (MCP) intégré à /_emdash/api/mcp qui expose les opérations de gestion de contenu comme des outils pour les assistants IA.
Cette page couvre les détails du protocole : authentification, transport, spécifications des outils, découverte OAuth et gestion des erreurs.
Authentification
Le serveur MCP prend en charge trois méthodes d’authentification :
| Méthode | Fonctionnement |
|---|---|
| OAuth 2.1 Authorization Code + PKCE | Flux standard pour les clients MCP. L’utilisateur approuve les scopes dans le navigateur. |
| Jeton d’accès personnel (PAT) | Jetons longue durée ec_pat_* créés dans le panneau d’administration. |
| Device Flow | Flux de type CLI où vous approuvez un code dans le navigateur. Utilisé par emdash login. |
Les cookies de session (de l’interface d’administration) fonctionnent également mais ne sont pas pratiques pour les clients MCP externes.
Scopes
Les jetons sont scopés pour limiter les opérations qu’un client peut effectuer. Les scopes sont demandés lors de l’autorisation OAuth et appliqués à chaque appel d’outil.
| Scope | Accorde l’accès à |
|---|---|
content:read | Lister, obtenir, comparer et rechercher du contenu. Lister les termes de taxonomie et les menus. |
content:write | Créer, mettre à jour, supprimer, publier, dépublier, planifier, dupliquer et restaurer du contenu. Créer des termes de taxonomie. |
media:read | Lister et obtenir des éléments médias. |
media:write | Mettre à jour et supprimer les métadonnées des médias. |
schema:read | Lister les collections et obtenir les schémas de collection. |
schema:write | Créer et supprimer des collections et des champs. |
admin | Accès complet à toutes les opérations. |
Le scope admin accorde l’accès à tout. L’authentification par session (sans jeton) dispose également d’un accès complet en fonction du rôle de l’utilisateur.
Exigences de rôle
En plus des scopes, certains outils nécessitent un rôle RBAC minimum :
| Opération | Rôle minimum |
|---|---|
| Opérations de contenu | Aucun minimum (les scopes contrôlent l’accès) |
| Lecture du schéma | Éditeur (40) |
| Écriture du schéma | Admin (50) |
Voir le guide d’authentification pour les définitions des rôles.
Transport
Le serveur utilise le transport Streamable HTTP en mode sans état. Chaque requête est indépendante — il n’y a ni sessions ni connexions persistantes.
POST /_emdash/api/mcp— Envoyer des appels d’outils JSON-RPCGET /_emdash/api/mcp— Retourne 405 (pas de SSE en mode sans état)DELETE /_emdash/api/mcp— Retourne 405 (pas de session à fermer)
Les réponses suivent le format JSON-RPC 2.0. Les erreurs utilisent les codes d’erreur JSON-RPC standard, avec des codes spécifiques MCP pour les échecs de scope et de permission.
Outils
Le serveur expose 33 outils répartis dans sept domaines. Chaque outil retourne les résultats sous forme de contenu texte JSON, ou un message d’erreur avec isError: true en cas d’échec.
Outils de contenu
content_list
Liste les éléments de contenu d’une collection avec filtrage et pagination optionnels.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection (ex. posts, pages) |
status | string | Non | Filtre : draft, published ou scheduled |
limit | integer | Non | Nombre max d’éléments (1-100, défaut 50) |
cursor | string | Non | Curseur de pagination d’une réponse précédente |
orderBy | string | Non | Champ de tri (ex. created_at, updated_at) |
order | string | Non | Direction du tri : asc ou desc (défaut desc) |
locale | string | Non | Filtrer par locale (ex. en, fr). Pertinent uniquement avec i18n. |
Scope : content:read | Lecture seule : Oui
content_get
Obtient un élément de contenu par ID ou slug. Retourne toutes les valeurs de champs, les métadonnées et un jeton _rev pour la concurrence optimiste.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
id | string | Oui | ID de l’élément (ULID) ou slug |
locale | string | Non | Locale pour la recherche par slug. Les ID sont globalement uniques. |
Scope : content:read | Lecture seule : Oui
content_create
Crée un nouvel élément de contenu. L’objet data doit contenir les valeurs de champs correspondant au schéma de la collection — utilisez schema_get_collection pour vérifier les champs disponibles. Les éléments sont créés en draft par défaut.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
data | object | Oui | Valeurs de champs sous forme de paires clé-valeur |
slug | string | Non | Slug d’URL (auto-généré à partir du titre si omis) |
status | string | Non | Statut initial : draft ou published (défaut draft) |
locale | string | Non | Locale pour ce contenu (par défaut la locale du site) |
translationOf | string | Non | ID de l’élément dont celui-ci est une traduction |
Scope : content:write
content_update
Met à jour un élément de contenu existant. N’incluez que les champs que vous souhaitez modifier — les champs non spécifiés restent inchangés.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
id | string | Oui | ID ou slug de l’élément |
data | object | Non | Valeurs de champs à mettre à jour |
slug | string | Non | Nouveau slug d’URL |
status | string | Non | Nouveau statut : draft ou published |
_rev | string | Non | Jeton de révision de content_get pour la détection de conflits |
Scope : content:write
content_delete
Supprime provisoirement un élément de contenu en le déplaçant dans la corbeille. Utilisez content_restore pour annuler, ou content_permanent_delete pour le supprimer définitivement.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
id | string | Oui | ID ou slug de l’élément |
Scope : content:write | Destructif : Oui
content_restore
Restaure un élément de contenu supprimé provisoirement depuis la corbeille.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
id | string | Oui | ID ou slug de l’élément |
Scope : content:write
content_permanent_delete
Supprime définitivement et irréversiblement un élément de contenu dans la corbeille. L’élément doit d’abord se trouver dans la corbeille.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
id | string | Oui | ID ou slug de l’élément |
Scope : content:write | Destructif : Oui
content_publish
Publie un élément de contenu, le rendant visible sur le site. Crée une révision publiée à partir du brouillon actuel. Les modifications ultérieures créent un nouveau brouillon sans affecter la version en ligne jusqu’à une nouvelle publication.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
id | string | Oui | ID ou slug de l’élément |
Scope : content:write
content_unpublish
Repasse un élément publié en statut brouillon. Il ne sera plus visible sur le site en production mais son contenu est préservé.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
id | string | Oui | ID ou slug de l’élément |
Scope : content:write
content_schedule
Planifie un élément de contenu pour une publication future. Il sera automatiquement publié à la date/heure spécifiée.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
id | string | Oui | ID ou slug de l’élément |
scheduledAt | string | Oui | Date/heure ISO 8601 (ex. 2026-06-01T09:00:00Z) |
Scope : content:write
content_compare
Compare la version publiée (en ligne) d’un élément de contenu avec son brouillon actuel. Retourne les deux versions et un indicateur signalant s’il y a des modifications.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
id | string | Oui | ID ou slug de l’élément |
Scope : content:read | Lecture seule : Oui
content_discard_draft
Annule le brouillon actuel et revient à la dernière version publiée. Fonctionne uniquement sur les éléments qui ont été publiés au moins une fois.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
id | string | Oui | ID ou slug de l’élément |
Scope : content:write | Destructif : Oui
content_list_trashed
Liste les éléments de contenu supprimés provisoirement dans la corbeille d’une collection.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
limit | integer | Non | Nombre max d’éléments (1-100, défaut 50) |
cursor | string | Non | Curseur de pagination |
Scope : content:read | Lecture seule : Oui
content_duplicate
Crée une copie d’un élément de contenu existant. Le duplicata est créé en brouillon avec « (Copy) » ajouté au titre et un slug auto-généré.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
id | string | Oui | ID ou slug de l’élément à dupliquer |
Scope : content:write
content_translations
Obtient toutes les variantes linguistiques d’un élément de contenu. Retourne le groupe de traduction et un résumé de chaque version locale. Pertinent uniquement lorsque i18n est activé.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
id | string | Oui | ID ou slug de l’élément |
Scope : content:read | Lecture seule : Oui
Outils de schéma
schema_list_collections
Liste toutes les collections de contenu définies dans le CMS. Retourne le slug, le libellé, les fonctionnalités prises en charge et les horodatages.
Aucun paramètre.
Scope : schema:read | Rôle minimum : Éditeur | Lecture seule : Oui
schema_get_collection
Obtient les informations détaillées d’une collection, y compris toutes les définitions de champs. Les champs décrivent le modèle de données : nom, type, contraintes et règles de validation. Utilisez cet outil pour comprendre ce que content_create et content_update attendent.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
slug | string | Oui | Slug de la collection (ex. posts) |
Scope : schema:read | Rôle minimum : Éditeur | Lecture seule : Oui
schema_create_collection
Crée une nouvelle collection de contenu. Cela crée une table de base de données et une définition de schéma. Le slug doit être alphanumérique en minuscules avec des tirets bas, commençant par une lettre.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
slug | string | Oui | Identifiant unique (/^[a-z][a-z0-9_]*$/) |
label | string | Oui | Nom d’affichage (pluriel, ex. « Articles de blog ») |
labelSingular | string | Non | Nom d’affichage au singulier |
description | string | Non | Description de cette collection |
icon | string | Non | Nom d’icône pour l’interface d’administration |
supports | string[] | Non | Fonctionnalités : drafts, revisions, preview, scheduling, search (défaut : ['drafts', 'revisions']) |
Scope : schema:write | Rôle minimum : Admin
schema_delete_collection
Supprime une collection et sa table de base de données. Cette opération est irréversible et supprime tout le contenu de la collection.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
slug | string | Oui | Slug de la collection à supprimer |
force | boolean | Non | Forcer la suppression même si la collection contient du contenu |
Scope : schema:write | Rôle minimum : Admin | Destructif : Oui
schema_create_field
Ajoute un nouveau champ au schéma d’une collection. Cela ajoute une colonne à la table de base de données.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
slug | string | Oui | Identifiant du champ (/^[a-z][a-z0-9_]*$/) |
label | string | Oui | Nom d’affichage |
type | string | Oui | Type de données (voir ci-dessous) |
required | boolean | Non | Si le champ est obligatoire |
unique | boolean | Non | Si les valeurs doivent être uniques |
defaultValue | any | Non | Valeur par défaut pour les nouveaux éléments |
validation | object | Non | Contraintes : min, max, minLength, maxLength, pattern, options |
options | object | Non | Configuration du widget : collection (pour les références), rows (pour textarea) |
searchable | boolean | Non | Inclure dans l’index de recherche plein texte |
translatable | boolean | Non | Si ce champ est traduisible (défaut true) |
Types de champs : string, text, number, integer, boolean, datetime, select, multiSelect, portableText, image, file, reference, json, slug.
Pour les types select et multiSelect, fournissez les valeurs autorisées dans validation.options.
Scope : schema:write | Rôle minimum : Admin
schema_delete_field
Supprime un champ d’une collection. Cela supprime la colonne et toutes les données de ce champ. Irréversible.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
fieldSlug | string | Oui | Slug du champ à supprimer |
Scope : schema:write | Rôle minimum : Admin | Destructif : Oui
Outils de médias
media_list
Liste les fichiers médias téléversés avec filtrage MIME optionnel et pagination.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
mimeType | string | Non | Filtrer par préfixe de type MIME (ex. image/, application/pdf) |
limit | integer | Non | Nombre max d’éléments (1-100, défaut 50) |
cursor | string | Non | Curseur de pagination |
Scope : media:read | Lecture seule : Oui
media_get
Obtient les détails d’un fichier média par ID. Retourne les métadonnées incluant le nom de fichier, le type MIME, la taille, les dimensions, le texte alternatif et l’URL.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
id | string | Oui | ID de l’élément média |
Scope : media:read | Lecture seule : Oui
media_update
Met à jour les métadonnées d’un fichier média téléversé. Le fichier lui-même ne peut pas être modifié.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
id | string | Oui | ID de l’élément média |
alt | string | Non | Texte alternatif pour l’accessibilité |
caption | string | Non | Texte de légende |
width | integer | Non | Largeur de l’image en pixels |
height | integer | Non | Hauteur de l’image en pixels |
Scope : media:write
media_delete
Supprime définitivement un fichier média. Supprime l’enregistrement de la base de données et le fichier du stockage. Le contenu référençant ce média aura des références brisées.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
id | string | Oui | ID de l’élément média |
Scope : media:write | Destructif : Oui
Outil de recherche
search
Recherche plein texte dans les collections de contenu. Les collections doivent avoir search dans leur liste supports et les champs doivent être marqués comme searchable.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
query | string | Oui | Texte de la requête de recherche |
collections | string[] | Non | Limiter la recherche à des slugs de collection spécifiques |
locale | string | Non | Filtrer les résultats par locale |
limit | integer | Non | Nombre max de résultats (1-50, défaut 20) |
Scope : content:read | Lecture seule : Oui
Outils de taxonomie
taxonomy_list
Liste toutes les définitions de taxonomie (ex. catégories, tags). Retourne le nom, le libellé, si elle est hiérarchique et les collections associées.
Aucun paramètre.
Scope : content:read | Lecture seule : Oui
taxonomy_list_terms
Liste les termes d’une taxonomie avec pagination.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
taxonomy | string | Oui | Nom de la taxonomie (ex. categories, tags) |
limit | integer | Non | Nombre max d’éléments (1-100, défaut 50) |
cursor | string | Non | Curseur de pagination |
Scope : content:read | Lecture seule : Oui
taxonomy_create_term
Crée un nouveau terme dans une taxonomie. Pour les taxonomies hiérarchiques, spécifiez un parentId pour créer un terme enfant.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
taxonomy | string | Oui | Nom de la taxonomie |
slug | string | Oui | Identifiant URL-safe |
label | string | Oui | Nom d’affichage |
parentId | string | Non | ID du terme parent (pour les taxonomies hiérarchiques) |
description | string | Non | Description du terme |
Scope : content:write
Outils de menu
menu_list
Liste tous les menus de navigation. Retourne le nom, le libellé et les horodatages.
Aucun paramètre.
Scope : content:read | Lecture seule : Oui
menu_get
Obtient un menu par son nom, incluant tous ses éléments dans l’ordre. Les éléments ont un libellé, une URL, un type et un parent optionnel pour l’imbrication.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
name | string | Oui | Nom du menu (ex. main, footer) |
Scope : content:read | Lecture seule : Oui
Outils de révision
revision_list
Liste l’historique des révisions d’un élément de contenu, les plus récentes en premier. Nécessite que la collection prenne en charge revisions.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
collection | string | Oui | Slug de la collection |
id | string | Oui | ID ou slug de l’élément |
limit | integer | Non | Nombre max de révisions (1-50, défaut 20) |
Scope : content:read | Lecture seule : Oui
revision_restore
Restaure un élément de contenu à une révision précédente. Remplace le brouillon actuel par les données de la révision spécifiée. N’est pas automatiquement publié — utilisez content_publish ensuite si nécessaire.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
revisionId | string | Oui | ID de la révision à restaurer |
Scope : content:write
Découverte OAuth
Les clients MCP qui prennent en charge OAuth 2.1 peuvent découvrir automatiquement comment s’authentifier. Le serveur publie deux documents de métadonnées :
Métadonnées de la ressource protégée
GET /.well-known/oauth-protected-resource
{
"resource": "https://example.com/_emdash/api/mcp",
"authorization_servers": ["https://example.com/_emdash"],
"scopes_supported": [
"content:read", "content:write",
"media:read", "media:write",
"schema:read", "schema:write",
"admin"
],
"bearer_methods_supported": ["header"]
}
Métadonnées du serveur d’autorisation
GET /_emdash/.well-known/oauth-authorization-server
{
"issuer": "https://example.com/_emdash",
"authorization_endpoint": "https://example.com/_emdash/oauth/authorize",
"token_endpoint": "https://example.com/_emdash/api/oauth/token",
"scopes_supported": ["content:read", "content:write", "..."],
"response_types_supported": ["code"],
"grant_types_supported": [
"authorization_code",
"refresh_token",
"urn:ietf:params:oauth:grant-type:device_code"
],
"code_challenge_methods_supported": ["S256"],
"token_endpoint_auth_methods_supported": ["none"],
"device_authorization_endpoint": "https://example.com/_emdash/api/oauth/device/code"
}
Lorsqu’une requête non authentifiée atteint le point de terminaison MCP, le serveur retourne :
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://example.com/.well-known/oauth-protected-resource"
Cela déclenche le flux standard de découverte du client MCP.
Gestion des erreurs
Les erreurs d’outils sont retournées sous forme de contenu texte avec isError: true :
{
"content": [{ "type": "text", "text": "Collection 'nonexistent' not found" }],
"isError": true
}
Les erreurs de scope et de permission génèrent des erreurs de protocole MCP :
{
"jsonrpc": "2.0",
"error": {
"code": -32600,
"message": "Insufficient scope: requires content:write"
},
"id": 1
}
Les erreurs au niveau du transport (mauvaise configuration du serveur, exceptions non gérées) retournent le code d’erreur JSON-RPC -32603 (erreur interne) sans divulguer les détails d’implémentation.