EmDash incluye un servidor Model Context Protocol (MCP) integrado en /_emdash/api/mcp que expone operaciones de gestión de contenido como herramientas para asistentes de IA.
Esta página cubre los detalles del protocolo: autenticación, transporte, especificaciones de herramientas, descubrimiento OAuth y manejo de errores.
Autenticación
El servidor MCP soporta tres métodos de autenticación:
| Método | Cómo funciona |
|---|---|
| OAuth 2.1 Authorization Code + PKCE | Flujo estándar para clientes MCP. El usuario aprueba scopes en el navegador. |
| Personal Access Token (PAT) | Tokens ec_pat_* de larga duración creados en el panel de administración. |
| Device Flow | Flujo tipo CLI donde apruebas un código en el navegador. Usado por emdash login. |
Las cookies de sesión (de la UI de administración) también funcionan pero no son prácticas para clientes MCP externos.
Scopes
Los tokens tienen alcance limitado para restringir qué operaciones puede realizar un cliente. Los scopes se solicitan durante la autorización OAuth y se aplican en cada llamada a herramienta. En la página de consentimiento del código de autorización, todos los scopes solicitados están seleccionados por defecto; el usuario puede quitar scopes antes de aprobar pero no puede añadir scopes que el cliente no solicitó. La concesión efectiva también está restringida por los scopes registrados del cliente y el rol del usuario, y EmDash rechaza una concesión vacía.
| Scope | Concede acceso a |
|---|---|
content:read | Listar, obtener, comparar y buscar contenido. Listar taxonomías, términos de taxonomía y menús. |
content:write | Crear, actualizar, eliminar, publicar, despublicar, programar, desprogramar, duplicar y restaurar contenido. Concede implícitamente taxonomies:manage y menus:manage para compatibilidad retroactiva con tokens emitidos antes de que existieran esos scopes. |
media:read | Listar y obtener elementos multimedia. |
media:write | Registrar (crear), actualizar y eliminar metadatos multimedia. |
schema:read | Listar colecciones y obtener esquemas de colección. |
schema:write | Crear y eliminar colecciones y campos. |
taxonomies:manage | Crear, actualizar y eliminar términos de taxonomía. |
menus:manage | Crear, actualizar y eliminar menús de navegación y sus elementos. |
settings:read | Leer configuraciones del sitio. |
settings:manage | Actualizar configuraciones del sitio. |
mcp:tools | Invocar herramientas MCP explícitamente habilitadas de cualquier plugin. |
mcp:tools:<pluginId> | Invocar herramientas MCP explícitamente habilitadas de un plugin. |
admin | Acceso completo a todas las operaciones. |
El scope admin concede acceso a operaciones principales, pero no concede acceso MCP de plugins. Las herramientas de plugins siempre requieren mcp:tools o el scope específico del plugin correspondiente. La autenticación basada en sesión tiene acceso basado en el rol del usuario y la habilitación explícita del admin del plugin.
content:write concede implícitamente taxonomies:manage y menus:manage para que los tokens de acceso personal emitidos antes de la separación de esos scopes sigan funcionando sin re-emisión. Los nuevos tokens deberían solicitar los scopes granulares.
Requisitos de rol
Además de los scopes, algunas herramientas requieren un rol RBAC mínimo. Ambos deben cumplirse — un token con el scope correcto aún falla si el rol del usuario llamante es demasiado bajo.
Las herramientas de plugins usan el permiso declarado por su ruta subyacente. Están ausentes de tools/list hasta que un administrador habilite la superficie MCP de ese plugin. Los nombres de herramientas usan la forma determinista <pluginId>__<localName>, y las invocaciones se registran en el log de auditoría con procedencia de plugin, herramienta, ruta y actor.
| Operación | Rol mínimo |
|---|---|
| Lectura de contenido | Subscriber (10) para elementos publicados; Contributor (20) para borradores, programados, papelera y revisiones |
| Creación de contenido | Contributor (20) |
| Editar/eliminar propio | Author (30) |
| Publicar contenido | Author (30) para propios; Editor (40) para actuar sobre elementos de otros |
| Lectura de esquema | Editor (40) |
| Escritura de esquema | Admin (50) |
| Gestión de taxonomías | Editor (40) |
| Gestión de menús | Editor (40) |
| Lectura de configuración | Editor (40) |
| Gestión de configuración | Admin (50) |
Subir multimedia (media_upload) | Contributor (20) |
Registrar multimedia (media_create) | Author (30) |
| Reparación de uso multimedia | Admin (50) |
Consulta la guía de autenticación para definiciones de roles.
Transporte
El servidor usa el transporte Streamable HTTP en modo sin estado. Cada solicitud es independiente — no hay sesiones ni conexiones de larga duración.
POST /_emdash/api/mcp— Enviar llamadas de herramienta JSON-RPCGET /_emdash/api/mcp— Devuelve 405 (sin SSE en modo sin estado)DELETE /_emdash/api/mcp— Devuelve 405 (sin sesión que cerrar)
Las respuestas siguen el formato JSON-RPC 2.0. Los errores usan códigos de error JSON-RPC estándar, con códigos específicos de MCP para fallos de scope y permisos.
Herramientas
El servidor expone herramientas en ocho dominios: contenido, esquema, multimedia, búsqueda, taxonomías, menús, revisiones y configuración. Cada herramienta devuelve resultados como contenido de texto JSON, o un mensaje de error con isError: true en caso de fallo.
Herramientas de contenido
content_list
Lista elementos de contenido en una colección con filtrado y paginación opcionales.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección (ej. posts, pages) |
status | string | No | Filtro: draft, published o scheduled |
limit | integer | No | Máx. elementos a devolver (1-100, defecto 50) |
cursor | string | No | Cursor de paginación de una respuesta anterior |
orderBy | string | No | Campo para ordenar (ej. created_at, updated_at) |
order | string | No | Dirección de orden: asc o desc (defecto desc) |
locale | string | No | Filtrar por locale (ej. en, fr). Solo relevante con i18n. |
Scope: content:read | Solo lectura: Sí
content_get
Obtiene un elemento de contenido único por ID o slug. Devuelve todos los valores de campo, metadatos y un token _rev para concurrencia optimista.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
id | string | Sí | ID del elemento (ULID) o slug |
locale | string | No | Locale para búsqueda por slug. Los IDs son globalmente únicos. |
Scope: content:read | Solo lectura: Sí
content_create
Crea un nuevo elemento de contenido. El objeto data debe contener valores de campo que coincidan con el esquema de la colección — usa schema_get_collection para verificar qué campos están disponibles. Los elementos se crean como draft por defecto.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
data | object | Sí | Valores de campo como pares clave-valor |
slug | string | No | Slug URL (auto-generado del título si se omite) |
status | string | No | Estado inicial: draft o published (defecto draft) |
locale | string | No | Locale para este contenido (defecto: predeterminado del sitio) |
translationOf | string | No | ID del elemento del que este es una traducción |
Scope: content:write
content_update
Actualiza un elemento de contenido existente. Solo incluye los campos que quieres cambiar — los campos no especificados quedan sin cambios.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
id | string | Sí | ID del elemento o slug |
data | object | No | Valores de campo a actualizar |
slug | string | No | Nuevo slug URL |
status | string | No | Nuevo estado: draft o published |
_rev | string | No | Token de revisión de content_get para detección de conflictos |
Scope: content:write
content_delete
Elimina suavemente un elemento de contenido moviéndolo a la papelera. Usa content_restore para deshacer o content_permanent_delete para eliminarlo permanentemente.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
id | string | Sí | ID del elemento o slug |
Scope: content:write | Destructivo: Sí
content_restore
Restaura un elemento de contenido eliminado suavemente desde la papelera.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
id | string | Sí | ID del elemento o slug |
Scope: content:write
content_permanent_delete
Elimina permanente e irreversiblemente un elemento de la papelera. El elemento debe estar en la papelera primero.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
id | string | Sí | ID del elemento o slug |
Scope: content:write | Destructivo: Sí
content_publish
Publica un elemento de contenido, haciéndolo visible en el sitio. Crea una revisión publicada del borrador actual. Ediciones posteriores crean un nuevo borrador sin afectar la versión en vivo hasta que se re-publique.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
id | string | Sí | ID del elemento o slug |
Scope: content:write
content_unpublish
Revierte un elemento publicado a estado borrador. Ya no será visible en el sitio en vivo pero su contenido se preserva.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
id | string | Sí | ID del elemento o slug |
Scope: content:write
content_schedule
Programa un elemento de contenido para publicación futura. Se publicará automáticamente en la fecha/hora especificada.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
id | string | Sí | ID del elemento o slug |
scheduledAt | string | Sí | Fecha/hora ISO 8601 (ej. 2026-06-01T09:00:00Z) |
Scope: content:write
content_unschedule
Cancela una publicación programada previamente. El elemento mantiene su estado actual; solo se limpia la marca de tiempo scheduledAt. Idempotente — llamar sobre un elemento no programado es una no-op.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
id | string | Sí | ID del elemento o slug |
Scope: content:write
content_compare
Compara la versión publicada (en vivo) de un elemento de contenido con su borrador actual. Devuelve ambas versiones y un indicador de si hay cambios.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
id | string | Sí | ID del elemento o slug |
Scope: content:read | Solo lectura: Sí
content_discard_draft
Descarta el borrador actual y revierte a la última versión publicada. Solo funciona en elementos que han sido publicados al menos una vez.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
id | string | Sí | ID del elemento o slug |
Scope: content:write | Destructivo: Sí
content_list_trashed
Lista elementos de contenido eliminados suavemente en la papelera de una colección.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
limit | integer | No | Máx. elementos (1-100, defecto 50) |
cursor | string | No | Cursor de paginación |
Scope: content:read | Solo lectura: Sí
content_duplicate
Crea una copia de un elemento de contenido existente. El duplicado se crea como borrador con “(Copia)” añadido al título y un slug auto-generado.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
id | string | Sí | ID o slug del elemento a duplicar |
Scope: content:write
content_translations
Obtiene todas las variantes de locale de un elemento de contenido. Devuelve el grupo de traducción y un resumen de cada versión de locale. Solo relevante cuando i18n está habilitado.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
id | string | Sí | ID del elemento o slug |
Scope: content:read | Solo lectura: Sí
Herramientas de esquema
schema_list_collections
Lista todas las colecciones de contenido definidas en el CMS. Devuelve slug, etiqueta, características soportadas y marcas de tiempo.
Sin parámetros.
Scope: schema:read | Rol mínimo: Editor | Solo lectura: Sí
schema_get_collection
Obtiene información detallada sobre una colección incluyendo todas las definiciones de campo. Los campos describen el modelo de datos: nombre, tipo, restricciones y reglas de validación. Usa esto para entender qué esperan content_create y content_update.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
slug | string | Sí | Slug de la colección (ej. posts) |
Scope: schema:read | Rol mínimo: Editor | Solo lectura: Sí
schema_create_collection
Crea una nueva colección de contenido. Esto crea una tabla de base de datos y definición de esquema. El slug debe ser alfanumérico en minúsculas con guiones bajos, comenzando con una letra.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
slug | string | Sí | Identificador único (/^[a-z][a-z0-9_]*$/) |
label | string | Sí | Nombre para mostrar (plural, ej. “Artículos del Blog”) |
labelSingular | string | No | Nombre singular |
description | string | No | Descripción de esta colección |
icon | string | No | Nombre de icono para la UI de admin |
supports | string[] | No | Características: drafts, revisions, preview, scheduling, search (defecto: ['drafts', 'revisions']) |
Scope: schema:write | Rol mínimo: Admin
schema_delete_collection
Elimina una colección y su tabla de base de datos. Esto es irreversible y elimina todo el contenido de la colección.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
slug | string | Sí | Slug de la colección a eliminar |
force | boolean | No | Forzar eliminación incluso si la colección tiene contenido |
Scope: schema:write | Rol mínimo: Admin | Destructivo: Sí
schema_create_field
Añade un nuevo campo al esquema de una colección. Esto añade una columna a la tabla de base de datos.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
slug | string | Sí | Identificador del campo (/^[a-z][a-z0-9_]*$/) |
label | string | Sí | Nombre para mostrar |
type | string | Sí | Tipo de datos (ver abajo) |
required | boolean | No | Si el campo es obligatorio |
unique | boolean | No | Si los valores deben ser únicos |
defaultValue | any | No | Valor por defecto para nuevos elementos |
validation | object | No | Restricciones: min, max, minLength, maxLength, pattern, options |
options | object | No | Config del widget: collection (para referencias), rows (para textarea) |
searchable | boolean | No | Incluir en índice de búsqueda de texto completo |
translatable | boolean | No | Si este campo es traducible (defecto true) |
Tipos de campo: string, text, number, integer, boolean, datetime, select, multiSelect, portableText, image, file, reference, json, slug.
Para tipos select y multiSelect, proporciona valores permitidos en validation.options.
Scope: schema:write | Rol mínimo: Admin
schema_delete_field
Elimina un campo de una colección. Esto elimina la columna y todos los datos de ese campo. Irreversible.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
fieldSlug | string | Sí | Slug del campo a eliminar |
Scope: schema:write | Rol mínimo: Admin | Destructivo: Sí
Herramientas de multimedia
media_list
Lista archivos multimedia subidos con filtrado opcional por tipo MIME y paginación.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
mimeType | string | No | Filtrar por prefijo de tipo MIME (ej. image/, application/pdf) |
limit | integer | No | Máx. elementos (1-100, defecto 50) |
cursor | string | No | Cursor de paginación |
Scope: media:read | Solo lectura: Sí
media_upload
Sube un archivo multimedia desde datos codificados en base64 o una URL externa y lo registra en la biblioteca de medios. Devuelve el elemento multimedia con id, storageKey y url — listo para referenciar desde campos de contenido (ej. featured_image) vía content_create / content_update.
Las subidas se deduplican por hash de contenido: re-subir bytes idénticos devuelve el elemento existente con deduplicated: true. Las subidas de imágenes se enriquecen automáticamente con dimensiones, un placeholder blurhash y el color dominante.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
filename | string | Sí | Nombre de archivo incluyendo extensión (ej. cover.png) |
base64 | string | Uno de base64 / url | Contenido del archivo codificado en base64 |
url | string | Uno de base64 / url | URL http(s) pública para descargar el archivo |
contentType | string | Con base64 | Tipo MIME (ej. image/png). Con url se usa el header Content-Type de la respuesta. |
alt | string | No | Texto alternativo para accesibilidad |
Scope: media:write | Rol mínimo: Contributor
media_create
Registra un archivo multimedia que ya ha sido subido al almacenamiento. El llamante es responsable de colocar el archivo en storageKey. Esta herramienta persiste el registro de metadatos para que el archivo sea descubrible vía media_list / media_get y pueda ser referenciado por contenido.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
filename | string | Sí | Nombre de archivo original (ej. logo.png) |
mimeType | string | Sí | Tipo MIME (ej. image/png) |
storageKey | string | Sí | Ruta/clave de almacenamiento donde se subió el archivo |
size | integer | No | Tamaño del archivo en bytes |
width | integer | No | Ancho de imagen en píxeles |
height | integer | No | Alto de imagen en píxeles |
contentHash | string | No | Hash del contenido del archivo (para deduplicación) |
blurhash | string | No | Blurhash para placeholders de imagen |
dominantColor | string | No | Color hexadecimal del color dominante de la imagen |
Scope: media:write | Rol mínimo: Author
media_get
Obtiene detalles de un archivo multimedia individual por ID. Devuelve metadatos incluyendo nombre de archivo, tipo MIME, tamaño, dimensiones, texto alternativo y URL.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
id | string | Sí | ID del elemento multimedia |
Scope: media:read | Solo lectura: Sí
media_update
Actualiza metadatos de un archivo multimedia subido. El archivo en sí no puede ser cambiado.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
id | string | Sí | ID del elemento multimedia |
alt | string | No | Texto alternativo para accesibilidad |
caption | string | No | Texto de leyenda |
width | integer | No | Ancho de imagen en píxeles |
height | integer | No | Alto de imagen en píxeles |
Scope: media:write
media_delete
Elimina permanentemente un archivo multimedia. Elimina el registro de base de datos y el archivo del almacenamiento. El contenido que referencia este medio tendrá referencias rotas.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
id | string | Sí | ID del elemento multimedia |
Scope: media:write | Destructivo: Sí
media_usage_repair
Repara índices de uso de medios en contenido para una colección o todas las colecciones. La reparación se ejecuta sincrónicamente y puede ser lenta o costosa en sitios grandes; prefiere el alcance de colección cuando sea posible.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
scope | "collection" | "all" | Sí | Si reparar una colección o todas |
collection | string | Para alcance de colección | Slug de la colección; omitir cuando scope es all |
El resultado tiene un status estructurado de complete, partial, failed o stale, más conteos agregados y por colección. Los cuatro estados son resultados exitosos de herramienta MCP, por lo que los llamantes deben inspeccionar status en lugar de confiar en isError. Errores de autenticación, validación o reparación inesperados devuelven isError: true.
Scope: admin | Rol mínimo: Admin
Herramienta de búsqueda
search
Búsqueda de texto completo a través de colecciones de contenido. Las colecciones deben tener search en su lista supports y los campos deben estar marcados como searchable.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
query | string | Sí | Texto de búsqueda |
collections | string[] | No | Limitar búsqueda a slugs de colección específicos |
locale | string | No | Filtrar resultados por locale |
limit | integer | No | Máx. resultados (1-50, defecto 20) |
Scope: content:read | Solo lectura: Sí
Herramientas de taxonomía
taxonomy_list
Lista todas las definiciones de taxonomía (ej. categorías, etiquetas). Devuelve nombre, etiqueta, si es jerárquica y colecciones asociadas.
Sin parámetros.
Scope: content:read | Solo lectura: Sí
taxonomy_list_terms
Lista términos en una taxonomía con paginación.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
taxonomy | string | Sí | Nombre de taxonomía (ej. categories, tags) |
limit | integer | No | Máx. elementos (1-100, defecto 50) |
cursor | string | No | Cursor de paginación |
Scope: content:read | Solo lectura: Sí
taxonomy_create_term
Crea un nuevo término en una taxonomía. Para taxonomías jerárquicas, especifica un parentId para crear un término hijo. La cadena de ancestros del padre no debe exceder 100 niveles.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
taxonomy | string | Sí | Nombre de taxonomía |
slug | string | Sí | Identificador seguro para URL |
label | string | Sí | Nombre para mostrar |
parentId | string | No | ID del término padre (para taxonomías jerárquicas) |
description | string | No | Descripción del término |
Scope: taxonomies:manage | Rol mínimo: Editor
taxonomy_update_term
Actualiza un término existente en una taxonomía. Cualquier campo puede omitirse para dejarlo sin cambios. Renombrar un slug no debe colisionar con otro término en la misma taxonomía. Establece parentId a null para desvincularse de un padre. El nuevo padre debe existir, pertenecer a la misma taxonomía y no introducir un ciclo.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
taxonomy | string | Sí | Nombre de taxonomía |
termSlug | string | Sí | Slug actual del término a actualizar |
slug | string | No | Nuevo slug (debe ser único en la taxonomía) |
label | string | No | Nuevo nombre para mostrar |
parentId | string | null | No | Nuevo ID del término padre; null para desvincular |
description | string | No | Nueva descripción |
Scope: taxonomies:manage | Rol mínimo: Editor
taxonomy_delete_term
Elimina permanentemente un término de una taxonomía. Todo contenido etiquetado con el término pierde la asociación. No puede eliminar un término que tiene hijos — elimina los hijos primero.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
taxonomy | string | Sí | Nombre de taxonomía |
termSlug | string | Sí | Slug del término a eliminar |
Scope: taxonomies:manage | Rol mínimo: Editor | Destructivo: Sí
Herramientas de menú
menu_list
Lista menús de navegación. Los menús son por locale: pasa locale para devolver solo las filas de un locale, u omítelo para listar todas las variantes de locale.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
locale | string | No | Filtrar por locale (omitir para todas las variantes) |
Scope: content:read | Solo lectura: Sí
menu_get
Obtiene un menú por nombre incluyendo todos sus elementos en orden. Los elementos tienen etiqueta, URL, tipo y padre opcional para anidamiento. Cuando el mismo nombre de menú existe en múltiples locales, pasa locale para resolver la traducción deseada.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
name | string | Sí | Nombre del menú (ej. main, footer) |
locale | string | No | Locale para resolver el menú |
Scope: content:read | Solo lectura: Sí
menu_create
Crea un nuevo menú de navegación. El name es el identificador estable usado por las plantillas del sitio; label es el nombre legible mostrado en el admin. Los menús son por locale, así que pasa locale cuando el mismo nombre de menú existe en múltiples traducciones. Añade elementos después con menu_set_items. Si se establece translationOf, también debe establecerse locale.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
name | string | Sí | Identificador estable (/^[a-z][a-z0-9_]*$/) |
label | string | Sí | Nombre para mostrar en el admin |
locale | string | No | Locale para este menú (ej. fr-fr) |
translationOf | string | No | ID de menú existente del que crear esta variante de locale |
Scope: menus:manage | Rol mínimo: Editor
menu_update
Actualiza la etiqueta de un menú. El name (identificador estable) no puede cambiarse. En instalaciones multi-locale, pasa locale para que se actualice la traducción correcta.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
name | string | Sí | Nombre del menú a actualizar |
label | string | Sí | Nueva etiqueta para mostrar |
locale | string | No | Locale del menú a actualizar |
Scope: menus:manage | Rol mínimo: Editor
menu_delete
Elimina un menú y todos sus elementos. No puede deshacerse. En instalaciones multi-locale, pasa locale para que solo se elimine la traducción deseada.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
name | string | Sí | Nombre del menú a eliminar |
locale | string | No | Locale del menú a eliminar |
Scope: menus:manage | Rol mínimo: Editor | Destructivo: Sí
menu_set_items
Reemplaza la lista completa de elementos de un menú en una llamada. Atómico: los elementos existentes se eliminan y la nueva lista se inserta en el orden proporcionado. Usa esto en lugar de operaciones individuales de añadir/eliminar para que el orden y los enlaces padre resultantes sean inequívocos. En instalaciones multi-locale, pasa locale para que solo se reescriba la traducción deseada.
Los elementos se posicionan por índice de array. La anidación se expresa vía parentIndex — un elemento con parentIndex: 0 está anidado bajo el elemento en el índice 0. El padre debe aparecer antes en la lista. Elementos sin parentIndex son de nivel superior.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
name | string | Sí | Nombre del menú a actualizar |
locale | string | No | Locale del menú a reescribir |
items | MenuItem[] | Sí | Lista ordenada de elementos de menú (ver abajo) |
Cada MenuItem tiene:
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
label | string | Sí | Texto de visualización del elemento |
type | string | Sí | Uno de custom, page, post, taxonomy, collection |
customUrl | string | No | URL para elementos type: "custom" (ignorado en otros casos) |
referenceCollection | string | No | Slug de colección destino para referencias de contenido |
referenceId | string | No | ID de contenido / término destino para referencias |
titleAttr | string | No | Atributo HTML title |
target | string | No | Atributo HTML target (ej. _blank) |
cssClasses | string | No | Clases CSS separadas por espacios |
parentIndex | integer | No | Índice de array del elemento padre. Omitir para elementos de nivel superior. |
Scope: menus:manage | Rol mínimo: Editor
Herramientas de revisiones
revision_list
Lista el historial de revisiones de un elemento de contenido, más reciente primero. Requiere que la colección soporte revisions.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de la colección |
id | string | Sí | ID del elemento o slug |
limit | integer | No | Máx. revisiones (1-50, defecto 20) |
Scope: content:read | Solo lectura: Sí
revision_restore
Restaura un elemento de contenido a una revisión anterior. Reemplaza el borrador actual con los datos de la revisión especificada. No se publica automáticamente — usa content_publish después si es necesario.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
revisionId | string | Sí | ID de la revisión a restaurar |
Scope: content:write
Herramientas de configuración
Configuraciones del sitio — título, eslogan, logo, favicon, URL canónica, tamaño de página predeterminado, formato de fecha y hora, handles sociales y valores SEO predeterminados.
settings_get
Obtiene todas las configuraciones del sitio. Las referencias de medios (logo, favicon, seo.defaultOgImage) incluyen URLs resueltas junto con el mediaId subyacente. Los valores no establecidos se omiten de la respuesta.
Sin parámetros.
Scope: settings:read | Rol mínimo: Editor | Solo lectura: Sí
settings_update
Actualiza una o más configuraciones del sitio. Actualización parcial: solo los campos proporcionados se cambian; los campos omitidos se dejan como están. Devuelve el objeto de configuraciones completo después de la actualización.
Para establecer una referencia de medios (logo, favicon, seo.defaultOgImage), pasa un objeto con mediaId (y alt opcional). El elemento multimedia debe existir previamente — usa media_create primero.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
title | string | No | Título del sitio |
tagline | string | No | Descripción corta mostrada junto al título |
logo | MediaRef | No | Referencia de medios del logo ({ mediaId, alt? }) |
favicon | MediaRef | No | Referencia de medios del favicon |
url | string | No | URL canónica del sitio (http o https). String vacío la limpia. |
postsPerPage | integer | No | Tamaño de página predeterminado para listados de contenido (1-100) |
dateFormat | string | No | String de formato de fecha |
timezone | string | No | Identificador de zona horaria IANA |
social | object | No | Handles sociales — twitter, github, facebook, instagram, linkedin, youtube |
seo | object | No | Valores SEO predeterminados (ver abajo) |
El objeto seo acepta:
| Campo | Tipo | Descripción |
|---|---|---|
titleSeparator | string | Separador entre título de página y título del sitio (ej. " | " para una barra vertical) |
defaultOgImage | MediaRef | Imagen Open Graph predeterminada cuando el contenido no tiene ninguna |
robotsTxt | string | Cuerpo personalizado de robots.txt. Omitir para usar el predeterminado de EmDash. |
googleVerification | string | Token de verificación de Google Search Console |
bingVerification | string | Token de verificación de Bing Webmaster Tools |
Scope: settings:manage | Rol mínimo: Admin
Descubrimiento OAuth
La mayoría de clientes MCP manejan esto por ti; esta sección es para construir un cliente MCP directamente contra EmDash. Los clientes que soportan OAuth 2.1 descubren cómo autenticarse desde dos documentos de metadatos que el servidor publica:
Metadatos del recurso protegido
Solicita los metadatos del recurso protegido en el siguiente endpoint:
GET /.well-known/oauth-protected-resource
El servidor responde con el identificador del recurso, su servidor de autorización y scopes soportados:
{
"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",
"taxonomies:manage", "menus:manage",
"settings:read", "settings:manage",
"admin"
],
"bearer_methods_supported": ["header"]
}
Metadatos del servidor de autorización
Solicita los metadatos del servidor de autorización en el siguiente endpoint:
GET /.well-known/oauth-authorization-server/_emdash
El servidor responde con los endpoints, scopes y tipos de concesión que soporta:
{
"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"
}
Cuando una solicitud no autenticada llega al endpoint MCP, el servidor devuelve:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://example.com/.well-known/oauth-protected-resource"
Esto desencadena el flujo de descubrimiento estándar del cliente MCP.
Manejo de errores
Los errores de herramientas se devuelven como contenido de texto con isError: true. El mensaje tiene un prefijo [CODE] estable, y el mismo código se repite en _meta.code:
{
"content": [{ "type": "text", "text": "[NOT_FOUND] Collection 'nonexistent' not found" }],
"isError": true,
"_meta": { "code": "NOT_FOUND" }
}
Los errores de scope y permisos usan el mismo formato de error de herramienta:
{
"content": [
{ "type": "text", "text": "[INSUFFICIENT_SCOPE] Insufficient scope: requires content:write" }
],
"isError": true,
"_meta": { "code": "INSUFFICIENT_SCOPE" }
}
Los errores a nivel de transporte (mala configuración del servidor, excepciones no manejadas) devuelven código de error JSON-RPC -32603 (Error interno) sin filtrar detalles de implementación.