Referencia del servidor MCP

En esta página

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étodoCómo funciona
OAuth 2.1 Authorization Code + PKCEFlujo estándar para clientes MCP. El usuario aprueba los scopes en el navegador.
Token de acceso personal (PAT)Tokens de larga duración ec_pat_* creados en el panel de administración.
Device FlowFlujo estilo 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 scopes para limitar qué operaciones puede realizar un cliente. Los scopes se solicitan durante la autorización OAuth y se aplican en cada llamada a herramientas.

ScopeOtorga acceso a
content:readListar, obtener, comparar y buscar contenido. Listar términos de taxonomía y menús.
content:writeCrear, actualizar, eliminar, publicar, despublicar, programar, duplicar y restaurar contenido. Crear términos de taxonomía.
media:readListar y obtener elementos de medios.
media:writeActualizar y eliminar metadatos de medios.
schema:readListar colecciones y obtener esquemas de colección.
schema:writeCrear y eliminar colecciones y campos.
adminAcceso 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.

Requisitos de rol

Además de los scopes, algunas herramientas requieren un rol RBAC mínimo:

OperaciónRol mínimo
Operaciones de contenidoSin mínimo (los scopes controlan el acceso)
Lectura de esquemaEditor (40)
Escritura de esquemaAdmin (50)

Consulta la guía de autenticación para las 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 herramientas JSON-RPC
  • GET /_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 33 herramientas en siete dominios. 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ámetroTipoObligatorioDescripción
collectionstringSlug de la colección (ej. posts, pages)
statusstringNoFiltro: draft, published o scheduled
limitintegerNoMáximo de elementos a devolver (1-100, predeterminado 50)
cursorstringNoCursor de paginación de una respuesta anterior
orderBystringNoCampo para ordenar (ej. created_at, updated_at)
orderstringNoDirección de orden: asc o desc (predeterminado desc)
localestringNoFiltrar por locale (ej. en, fr). Solo relevante con i18n.

Scope: content:read | Solo lectura:

content_get

Obtiene un elemento de contenido por ID o slug. Devuelve todos los valores de campo, metadatos y un token _rev para concurrencia optimista.

ParámetroTipoObligatorioDescripción
collectionstringSlug de la colección
idstringID del elemento (ULID) o slug
localestringNoLocale para búsqueda por slug. Los IDs son globalmente únicos.

Scope: content:read | Solo lectura:

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ámetroTipoObligatorioDescripción
collectionstringSlug de la colección
dataobjectValores de campo como pares clave-valor
slugstringNoSlug de URL (se genera automáticamente del título si se omite)
statusstringNoEstado inicial: draft o published (predeterminado draft)
localestringNoLocale para este contenido (predeterminado: el del sitio)
translationOfstringNoID 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 quieras cambiar — los campos no especificados se dejan sin cambios.

ParámetroTipoObligatorioDescripción
collectionstringSlug de la colección
idstringID del elemento o slug
dataobjectNoValores de campo a actualizar
slugstringNoNuevo slug de URL
statusstringNoNuevo estado: draft o published
_revstringNoToken de revisión de content_get para detección de conflictos

Scope: content:write

content_delete

Eliminación suave de un elemento de contenido moviéndolo a la papelera. Usa content_restore para deshacer, o content_permanent_delete para eliminarlo permanentemente.

ParámetroTipoObligatorioDescripción
collectionstringSlug de la colección
idstringID del elemento o slug

Scope: content:write | Destructivo:

content_restore

Restaura un elemento de contenido eliminado de la papelera.

ParámetroTipoObligatorioDescripción
collectionstringSlug de la colección
idstringID 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 previamente.

ParámetroTipoObligatorioDescripción
collectionstringSlug de la colección
idstringID del elemento o slug

Scope: content:write | Destructivo:

content_publish

Publica un elemento de contenido, haciéndolo visible en el sitio. Crea una revisión publicada a partir del borrador actual. Las ediciones posteriores crean un nuevo borrador sin afectar la versión en vivo hasta que se republique.

ParámetroTipoObligatorioDescripción
collectionstringSlug de la colección
idstringID del elemento o slug

Scope: content:write

content_unpublish

Revierte un elemento publicado a estado de borrador. Ya no será visible en el sitio en vivo pero su contenido se preserva.

ParámetroTipoObligatorioDescripción
collectionstringSlug de la colección
idstringID 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ámetroTipoObligatorioDescripción
collectionstringSlug de la colección
idstringID del elemento o slug
scheduledAtstringFecha y hora ISO 8601 (ej. 2026-06-01T09:00:00Z)

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 flag indicando si hay cambios.

ParámetroTipoObligatorioDescripción
collectionstringSlug de la colección
idstringID del elemento o slug

Scope: content:read | Solo lectura:

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ámetroTipoObligatorioDescripción
collectionstringSlug de la colección
idstringID del elemento o slug

Scope: content:write | Destructivo:

content_list_trashed

Lista los elementos de contenido eliminados en la papelera de una colección.

ParámetroTipoObligatorioDescripción
collectionstringSlug de la colección
limitintegerNoMáximo de elementos (1-100, predeterminado 50)
cursorstringNoCursor de paginación

Scope: content:read | Solo lectura:

content_duplicate

Crea una copia de un elemento de contenido existente. El duplicado se crea como borrador con “(Copy)” añadido al título y un slug generado automáticamente.

ParámetroTipoObligatorioDescripción
collectionstringSlug de la colección
idstringID 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 por locale. Solo relevante cuando i18n está habilitado.

ParámetroTipoObligatorioDescripción
collectionstringSlug de la colección
idstringID del elemento o slug

Scope: content:read | Solo lectura:

Herramientas de esquema

schema_list_collections

Lista todas las colecciones de contenido definidas en el CMS. Devuelve slug, etiqueta, funciones soportadas y marcas de tiempo.

Sin parámetros.

Scope: schema:read | Rol mínimo: Editor | Solo lectura:

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. Úsalo para entender qué esperan content_create y content_update.

ParámetroTipoObligatorioDescripción
slugstringSlug de la colección (ej. posts)

Scope: schema:read | Rol mínimo: Editor | Solo lectura:

schema_create_collection

Crea una nueva colección de contenido. Esto crea una tabla de base de datos y una definición de esquema. El slug debe ser alfanumérico en minúsculas con guiones bajos, comenzando con una letra.

ParámetroTipoObligatorioDescripción
slugstringIdentificador único (/^[a-z][a-z0-9_]*$/)
labelstringNombre para mostrar (plural, ej. “Blog Posts”)
labelSingularstringNoNombre singular para mostrar
descriptionstringNoDescripción de esta colección
iconstringNoNombre del icono para la UI de admin
supportsstring[]NoFunciones: drafts, revisions, preview, scheduling, search (predeterminado: ['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ámetroTipoObligatorioDescripción
slugstringSlug de la colección a eliminar
forcebooleanNoForzar eliminación aunque la colección tenga contenido

Scope: schema:write | Rol mínimo: Admin | Destructivo:

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ámetroTipoObligatorioDescripción
collectionstringSlug de la colección
slugstringIdentificador del campo (/^[a-z][a-z0-9_]*$/)
labelstringNombre para mostrar
typestringTipo de dato (ver abajo)
requiredbooleanNoSi el campo es obligatorio
uniquebooleanNoSi los valores deben ser únicos
defaultValueanyNoValor predeterminado para nuevos elementos
validationobjectNoRestricciones: min, max, minLength, maxLength, pattern, options
optionsobjectNoConfiguración de widget: collection (para referencias), rows (para textarea)
searchablebooleanNoIncluir en el índice de búsqueda de texto completo
translatablebooleanNoSi este campo es traducible (predeterminado true)

Tipos de campo: string, text, number, integer, boolean, datetime, select, multiSelect, portableText, image, file, reference, json, slug.

Para los tipos select y multiSelect, proporciona los 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ámetroTipoObligatorioDescripción
collectionstringSlug de la colección
fieldSlugstringSlug del campo a eliminar

Scope: schema:write | Rol mínimo: Admin | Destructivo:

Herramientas de medios

media_list

Lista archivos de medios subidos con filtrado opcional por tipo MIME y paginación.

ParámetroTipoObligatorioDescripción
mimeTypestringNoFiltrar por prefijo de tipo MIME (ej. image/, application/pdf)
limitintegerNoMáximo de elementos (1-100, predeterminado 50)
cursorstringNoCursor de paginación

Scope: media:read | Solo lectura:

media_get

Obtiene los detalles de un archivo de medios por ID. Devuelve metadatos incluyendo nombre de archivo, tipo MIME, tamaño, dimensiones, texto alternativo y URL.

ParámetroTipoObligatorioDescripción
idstringID del elemento de medios

Scope: media:read | Solo lectura:

media_update

Actualiza los metadatos de un archivo de medios subido. El archivo en sí no se puede cambiar.

ParámetroTipoObligatorioDescripción
idstringID del elemento de medios
altstringNoTexto alternativo para accesibilidad
captionstringNoTexto de leyenda
widthintegerNoAncho de la imagen en píxeles
heightintegerNoAlto de la imagen en píxeles

Scope: media:write

media_delete

Elimina permanentemente un archivo de medios. Elimina el registro de base de datos y el archivo del almacenamiento. El contenido que haga referencia a este medio tendrá referencias rotas.

ParámetroTipoObligatorioDescripción
idstringID del elemento de medios

Scope: media:write | Destructivo:

Herramienta de búsqueda

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ámetroTipoObligatorioDescripción
querystringTexto de consulta de búsqueda
collectionsstring[]NoLimitar búsqueda a slugs de colección específicos
localestringNoFiltrar resultados por locale
limitintegerNoMáximo de resultados (1-50, predeterminado 20)

Scope: content:read | Solo lectura:

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:

taxonomy_list_terms

Lista los términos de una taxonomía con paginación.

ParámetroTipoObligatorioDescripción
taxonomystringNombre de la taxonomía (ej. categories, tags)
limitintegerNoMáximo de elementos (1-100, predeterminado 50)
cursorstringNoCursor de paginación

Scope: content:read | Solo lectura:

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.

ParámetroTipoObligatorioDescripción
taxonomystringNombre de la taxonomía
slugstringIdentificador seguro para URL
labelstringNombre para mostrar
parentIdstringNoID del término padre (para taxonomías jerárquicas)
descriptionstringNoDescripción del término

Scope: content:write

Herramientas de menú

Lista todos los menús de navegación. Devuelve nombre, etiqueta y marcas de tiempo.

Sin parámetros.

Scope: content:read | Solo lectura:

Obtiene un menú por nombre incluyendo todos sus elementos en orden. Los elementos tienen una etiqueta, URL, tipo y padre opcional para anidamiento.

ParámetroTipoObligatorioDescripción
namestringNombre del menú (ej. main, footer)

Scope: content:read | Solo lectura:

Herramientas de revisión

revision_list

Lista el historial de revisiones de un elemento de contenido, más reciente primero. Requiere que la colección soporte revisions.

ParámetroTipoObligatorioDescripción
collectionstringSlug de la colección
idstringID del elemento o slug
limitintegerNoMáximo de revisiones (1-50, predeterminado 20)

Scope: content:read | Solo lectura:

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ámetroTipoObligatorioDescripción
revisionIdstringID de la revisión a restaurar

Scope: content:write

Descubrimiento OAuth

Los clientes MCP que soportan OAuth 2.1 pueden descubrir automáticamente cómo autenticarse. El servidor publica dos documentos de metadatos:

Metadatos de recurso protegido

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"]
}

Metadatos del servidor de autorización

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"
}

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 activa el flujo estándar de descubrimiento del cliente MCP.

Manejo de errores

Los errores de herramientas se devuelven como contenido de texto con isError: true:

{
  "content": [{ "type": "text", "text": "Collection 'nonexistent' not found" }],
  "isError": true
}

Los errores de scope y permisos lanzan errores de protocolo MCP:

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32600,
    "message": "Insufficient scope: requires content:write"
  },
  "id": 1
}

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.