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 admite 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 de larga duración ec_pat_* creados en el panel de administración. |
| Device Flow | Flujo estilo CLI donde apruebas un código en el navegador. Usado por emdash login. |
Las cookies de sesión (de la interfaz de administración) también funcionan pero no son prácticas para clientes MCP externos.
Scopes
Los tokens tienen scopes para limitar qué operaciones puede realizar un cliente. Los scopes se solicitan durante la autorización OAuth y se aplican en cada llamada de herramienta.
| Scope | Otorga 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. Otorga implícitamente taxonomies:manage y menus:manage para compatibilidad con tokens emitidos antes de que existieran esos scopes. |
media:read | Listar y obtener elementos de medios. |
media:write | Registrar (crear), actualizar y eliminar metadatos de medios. |
schema:read | Listar colecciones y obtener esquemas de colecciones. |
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. |
admin | Acceso completo a todas las operaciones. |
El scope admin otorga acceso a todo. La autenticación basada en sesión (sin token) también tiene acceso completo según el rol del usuario.
content:write otorga 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 reemisión. Los nuevos tokens deben 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 que llama es demasiado bajo.
| 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 propio / eliminar propio | Author (30) |
| Publicar contenido | Author (30) para elementos 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 configuraciones | Editor (40) |
| Gestión de configuraciones | Admin (50) |
Subir medios (media_create) | Author (30) |
Consulta la guía de Autenticación para definiciones de roles.
Transporte
El servidor utiliza el transporte HTTP de transmisión en modo sin estado. Cada solicitud es independiente — no hay sesiones ni conexiones de larga duración.
POST /_emdash/api/mcp— Enviar llamadas de herramientas JSON-RPCGET /_emdash/api/mcp— Devuelve 405 (sin SSE en modo sin estado)DELETE /_emdash/api/mcp— Devuelve 405 (no hay sesión para 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 45 herramientas en ocho dominios: contenido, esquema, medios, búsqueda, taxonomías, menús, revisiones y configuraciones. 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
Listar elementos de contenido en una colección con filtrado y paginación opcionales.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de colección (ej. posts, pages) |
status | string | No | Filtro: draft, published o scheduled |
limit | integer | No | Máx. elementos a devolver (1-100, predeterminado 50) |
cursor | string | No | Cursor de paginación de una respuesta anterior |
orderBy | string | No | Campo por el que ordenar (ej. created_at, updated_at) |
order | string | No | Dirección de ordenamiento: asc o desc (predeterminado desc) |
locale | string | No | Filtrar por locale (ej. en, fr). Solo relevante con i18n. |
Scope: content:read | Solo lectura: Sí
content_get
Obtener un solo elemento de contenido 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 colección |
id | string | Sí | ID de elemento de contenido (ULID) o slug |
locale | string | No | Locale para búsqueda de slug. Los IDs son globalmente únicos. |
Scope: content:read | Solo lectura: Sí
content_create
Crear 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 colección |
data | object | Sí | Valores de campo como pares clave-valor |
slug | string | No | Slug de URL (autogenerado del título si se omite) |
status | string | No | Estado inicial: draft o published (predeterminado draft) |
locale | string | No | Locale para este contenido (predeterminado al predeterminado del sitio) |
translationOf | string | No | ID del elemento del cual este es una traducción |
Scope: content:write
content_update
Actualizar un elemento de contenido existente. Solo incluye campos que desees cambiar — los campos no especificados permanecen sin cambios.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de colección |
id | string | Sí | ID de elemento de contenido o slug |
data | object | No | Valores de campo a actualizar |
slug | string | No | Nuevo slug de 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
Eliminar suavemente un elemento de contenido moviéndolo a la papelera. Usa content_restore para deshacer, o content_permanent_delete para eliminarlo para siempre.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de colección |
id | string | Sí | ID de elemento de contenido o slug |
Scope: content:write | Destructivo: Sí
content_restore
Restaurar un elemento de contenido eliminado suavemente desde la papelera.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de colección |
id | string | Sí | ID de elemento de contenido o slug |
Scope: content:write
content_permanent_delete
Eliminar permanente e irreversiblemente un elemento de contenido en la papelera. El elemento debe estar primero en la papelera.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de colección |
id | string | Sí | ID de elemento de contenido o slug |
Scope: content:write | Destructivo: Sí
content_publish
Publicar un elemento de contenido, haciéndolo visible en el sitio. Crea una revisión publicada del borrador actual. Las ediciones posteriores crean un nuevo borrador sin afectar la versión en vivo hasta que se vuelva a publicar.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de colección |
id | string | Sí | ID de elemento de contenido o slug |
Scope: content:write
content_unpublish
Revertir un elemento publicado a estado de 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 colección |
id | string | Sí | ID de elemento de contenido o slug |
Scope: content:write
content_schedule
Programar 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 colección |
id | string | Sí | ID de elemento de contenido o slug |
scheduledAt | string | Sí | Fecha/hora ISO 8601 (ej. 2026-06-01T09:00:00Z) |
Scope: content:write
content_unschedule
Cancelar una publicación previamente programada. El elemento mantiene su estado actual; solo se borra el timestamp scheduledAt. Idempotente — llamar sobre un elemento no programado es un no-op.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de colección |
id | string | Sí | ID de elemento de contenido o slug |
Scope: content:write
content_compare
Comparar la versión publicada (en vivo) de un elemento de contenido con su borrador actual. Devuelve ambas versiones y una bandera indicando si hay cambios.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de colección |
id | string | Sí | ID de elemento de contenido o slug |
Scope: content:read | Solo lectura: Sí
content_discard_draft
Descartar el borrador actual y revertir a la última versión publicada. Solo funciona en elementos que se han publicado al menos una vez.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de colección |
id | string | Sí | ID de elemento de contenido o slug |
Scope: content:write | Destructivo: Sí
content_list_trashed
Listar elementos de contenido eliminados suavemente en la papelera de una colección.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de colección |
limit | integer | No | Máx. elementos (1-100, predeterminado 50) |
cursor | string | No | Cursor de paginación |
Scope: content:read | Solo lectura: Sí
content_duplicate
Crear una copia de un elemento de contenido existente. El duplicado se crea como borrador con “(Copy)” agregado al título y un slug autogenerado.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de colección |
id | string | Sí | ID de elemento de contenido o slug a duplicar |
Scope: content:write
content_translations
Obtener 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 colección |
id | string | Sí | ID de elemento de contenido o slug |
Scope: content:read | Solo lectura: Sí
Herramientas de Esquema
schema_list_collections
Listar todas las colecciones de contenido definidas en el CMS. Devuelve slug, etiqueta, características soportadas y timestamps.
Sin parámetros.
Scope: schema:read | Rol mínimo: Editor | Solo lectura: Sí
schema_get_collection
Obtener 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 colección (ej. posts) |
Scope: schema:read | Rol mínimo: Editor | Solo lectura: Sí
schema_create_collection
Crear 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. “Publicaciones del Blog”) |
labelSingular | string | No | Nombre para mostrar singular |
description | string | No | Descripción de esta colección |
icon | string | No | Nombre de icono para la interfaz de administración |
supports | string[] | No | Características: drafts, revisions, preview, scheduling, search (predeterminado: ['drafts', 'revisions']) |
Scope: schema:write | Rol mínimo: Admin
schema_delete_collection
Eliminar una colección y su tabla de base de datos. Esto es irreversible y elimina todo el contenido en la colección.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
slug | string | Sí | Slug de 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
Agregar un nuevo campo al esquema de una colección. Esto agrega una columna a la tabla de la base de datos.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de colección |
slug | string | Sí | Identificador de campo (/^[a-z][a-z0-9_]*$/) |
label | string | Sí | Nombre para mostrar |
type | string | Sí | Tipo de dato (ver abajo) |
required | boolean | No | Si el campo es requerido |
unique | boolean | No | Si los valores deben ser únicos |
defaultValue | any | No | Valor predeterminado para nuevos elementos |
validation | object | No | Restricciones: min, max, minLength, maxLength, pattern, options |
options | object | No | Configuración 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 (predeterminado 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
Eliminar un campo de una colección. Esto elimina la columna y todos los datos en ese campo. Irreversible.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
collection | string | Sí | Slug de colección |
fieldSlug | string | Sí | Slug de campo a eliminar |
Scope: schema:write | Rol mínimo: Admin | Destructivo: Sí
Herramientas de Medios
media_list
Listar archivos de medios 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, predeterminado 50) |
cursor | string | No | Cursor de paginación |
Scope: media:read | Solo lectura: Sí
media_create
Registrar un archivo de medios que ya ha sido subido al almacenamiento. El llamador es responsable de colocar el archivo en storageKey (típicamente usando una URL de carga firmada de la interfaz de administración o una API separada). 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 marcadores de posición de imagen |
dominantColor | string | No | Cadena de color hex para el color dominante de la imagen |
Scope: media:write | Rol mínimo: Author
media_get
Obtener detalles de un solo archivo de medios 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 de elemento de medios |
Scope: media:read | Solo lectura: Sí
media_update
Actualizar metadatos de un archivo de medios subido. El archivo en sí no puede ser cambiado.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
id | string | Sí | ID de elemento de medios |
alt | string | No | Texto alternativo para accesibilidad |
caption | string | No | Texto de pie de foto |
width | integer | No | Ancho de imagen en píxeles |
height | integer | No | Alto de imagen en píxeles |
Scope: media:write
media_delete
Eliminar permanentemente un archivo de medios. Elimina el registro de base de datos y el archivo del almacenamiento. El contenido que referencia estos medios tendrá referencias rotas.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
id | string | Sí | ID de elemento de medios |
Scope: media:write | Destructivo: Sí
Herramienta de Búsqueda
search
Búsqueda de texto completo en 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 consulta 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, predeterminado 20) |
Scope: content:read | Solo lectura: Sí
Herramientas de Taxonomía
taxonomy_list
Listar 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
Listar 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, predeterminado 50) |
cursor | string | No | Cursor de paginación |
Scope: content:read | Solo lectura: Sí
taxonomy_create_term
Crear 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 de 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
Actualizar 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 en null para desasociar 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 de término padre; null para desasociar |
description | string | No | Nueva descripción |
Scope: taxonomies:manage | Rol mínimo: Editor
taxonomy_delete_term
Eliminar permanentemente un término de una taxonomía. Cualquier contenido etiquetado con el término pierde la asociación. No puede eliminar un término que tenga hijos — elimina primero los hijos.
| 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
Listar 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 cada variante de locale.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
locale | string | No | Filtrar por locale (omitir para todas las variantes de locale) |
Scope: content:read | Solo lectura: Sí
menu_get
Obtener un menú por nombre incluyendo todos sus elementos en orden. Los elementos tienen una 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 prevista.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
name | string | Sí | Nombre de menú (ej. main, footer) |
locale | string | No | Locale para resolver el menú |
Scope: content:read | Solo lectura: Sí
menu_create
Crear un nuevo menú de navegación. El name es el identificador estable usado por las plantillas del sitio; label es el nombre legible para humanos 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. Agrega elementos después con menu_set_items. Si translationOf está establecido, locale también debe estar establecido.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
name | string | Sí | Identificador estable (/^[a-z][a-z0-9_]*$/) |
label | string | Sí | Nombre para mostrar para el admin |
locale | string | No | Locale para este menú (ej. fr-fr) |
translationOf | string | No | ID de menú existente desde el cual crear esta variante de locale |
Scope: menus:manage | Rol mínimo: Editor
menu_update
Actualizar 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 de 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
Eliminar un menú y todos sus elementos. No puede deshacerse. En instalaciones multi-locale, pasa locale para que solo se elimine la traducción prevista.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
name | string | Sí | Nombre de menú a eliminar |
locale | string | No | Locale del menú a eliminar |
Scope: menus:manage | Rol mínimo: Editor | Destructivo: Sí
menu_set_items
Reemplazar la lista completa de elementos de un menú en una sola llamada. Atómico: los elementos existentes se eliminan y la nueva lista se inserta en el orden proporcionado. Usa esto en lugar de operaciones de agregar/eliminar por elemento para que el orden resultante y los enlaces padre sean inequívocos. En instalaciones multi-locale, pasa locale para que solo se reescriba la traducción prevista.
Los elementos se posicionan por índice de array. El anidamiento se expresa mediante parentIndex — un elemento con parentIndex: 0 está anidado bajo el elemento en el índice 0. El padre debe aparecer antes en la lista. Los elementos sin parentIndex son de nivel superior.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
name | string | Sí | Nombre de 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 de otro modo) |
referenceCollection | string | No | Slug de colección objetivo para referencias de contenido |
referenceId | string | No | ID de contenido / término objetivo 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 Revisión
revision_list
Listar historial de revisión para 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 colección |
id | string | Sí | ID de elemento de contenido o slug |
limit | integer | No | Máx. revisiones (1-50, predeterminado 20) |
Scope: content:read | Solo lectura: Sí
revision_restore
Restaurar 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 revisión a restaurar |
Scope: content:write
Herramientas de Configuración
Configuraciones del sitio — título, tagline, logo, favicon, URL canónica, tamaño de página predeterminado, formato de fecha y hora, handles sociales y valores predeterminados SEO.
settings_get
Obtener todas las configuraciones del sitio. Las referencias de medios (logo, favicon, seo.defaultOgImage) incluyen URLs resueltas junto con la 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
Actualizar 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 de medios debe existir ya — usa media_create primero.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
title | string | No | Título del sitio |
tagline | string | No | Descripción breve mostrada junto al título |
logo | MediaRef | No | Referencia de medios de logo ({ mediaId, alt? }) |
favicon | MediaRef | No | Referencia de medios de favicon |
url | string | No | URL canónica del sitio (http o https). Cadena vacía la borra. |
postsPerPage | integer | No | Tamaño de página predeterminado para listados de contenido (1-100) |
dateFormat | string | No | Cadena de token 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 predeterminados SEO (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 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 los clientes MCP manejan esto por ti; esta sección es para construir un cliente MCP contra EmDash directamente. Los clientes que soportan OAuth 2.1 descubren cómo autenticarse a partir de dos documentos de metadatos que el servidor publica:
Metadatos de Recurso Protegido
Solicita los metadatos de recurso protegido en el siguiente endpoint:
GET /.well-known/oauth-protected-resource
El servidor responde con el identificador de 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 grant 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 dispara 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 con un [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 sobre 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 (configuración errónea del servidor, excepciones no manejadas) devuelven el código de error JSON-RPC -32603 (Internal error) sin revelar detalles de implementación.