Referencia del servidor MCP

En esta página

EmDash expone un servidor integrado de Model Context Protocol (MCP) en /_emdash/api/mcp. Los clientes MCP lo usan para leer y gestionar contenido, bylines, esquemas, medios, taxonomías, menús, revisiones y ajustes, y para exportar o importar todo el sitio.

Autenticación

El endpoint MCP requiere un token Bearer. EmDash admite estos flujos de token:

MétodoUso
OAuth 2.1 Authorization Code with Proof Key for Code Exchange (PKCE)Clientes MCP interactivos. El usuario aprueba en un navegador los scopes solicitados.
Personal access tokenAcceso de larga duración para un cliente o una automatización. Los tokens usan el prefijo ec_pat_ y se crean en el admin.
OAuth 2.0 Device Authorization GrantClientes de línea de comandos que piden al usuario que apruebe un código en un navegador. emdash login usa este flujo.

Las cookies de sesión no autentican el endpoint MCP.

Scopes

Los tokens de OAuth y los tokens de acceso personal limitan qué herramientas puede llamar un cliente. El rol del usuario se comprueba por separado, de modo que un scope nunca concede un permiso que el usuario no tiene.

ScopeAcceso
content:readLeer y buscar contenido, bylines, taxonomías, términos, menús y revisiones. El contenido de tipo borrador también requiere el permiso content:read_drafts del usuario.
content:writeCrear y modificar contenido, bylines y revisiones. También concede taxonomies:manage y menus:manage por compatibilidad con los tokens existentes.
media:readLeer registros de medios.
media:writeSubir, registrar, actualizar y eliminar medios.
schema:readLeer colecciones y campos.
schema:writeCrear, actualizar y eliminar colecciones y campos.
taxonomies:manageCrear, actualizar y eliminar definiciones de taxonomías y términos.
menus:manageCrear, actualizar y eliminar menús y elementos de menú.
settings:readLeer los ajustes del sitio.
settings:manageActualizar los ajustes del sitio.
mcp:toolsLlamar a las herramientas MCP que exponga cualquier plugin habilitado.
mcp:tools:<pluginId>Llamar a las herramientas MCP que exponga un plugin habilitado concreto.
transfer:exportExportar todo el sitio como un paquete del sitio y descargarlo.
transfer:analyzeSubir un paquete del sitio y analizarlo para su importación.
transfer:executeIniciar, avanzar, cancelar y abandonar una importación del sitio.
adminLlamar a todas las herramientas del núcleo, incluidas las de transferencia de sitio. Las herramientas de plugins siguen requiriendo mcp:tools o el scope específico del plugin.

El scope admin incluye transfer:export, transfer:analyze y transfer:execute. Cada scope de transferencia concede solo sus propias acciones y requiere el rol de administrador. Para que un cliente, como un agente, pueda analizar un paquete del sitio sin exportar ni importar, concede transfer:analyze en lugar de admin.

La página de consentimiento del código de autorización permite al usuario quitar scopes de los solicitados. EmDash también cruza la solicitud con los scopes registrados del cliente y con el rol del usuario, y rechaza una concesión vacía.

Requisitos de rol

La siguiente tabla muestra el rol mínimo para cada capacidad general. Las comprobaciones de propiedad pueden exigir un rol superior cuando un usuario actúa sobre el contenido de otro usuario.

CapacidadRol mínimo
Leer contenido publicado, medios, taxonomías, términos y menúsSubscriber
Leer borradores, contenido programado, papelera, comparaciones y revisionesContributor
Crear contenido o subir mediosContributor
Editar o publicar contenido propio y registrar mediosAuthor
Gestionar bylines, taxonomías, menús o el contenido de todos los usuariosEditor
Leer esquemas o ajustesEditor
Cambiar esquemas o ajustes, eliminar contenido de forma permanente o reparar el uso de mediosAdmin
Exportar o importar todo el sitioAdmin

Consulta los roles de usuario para ver las definiciones completas de los roles.

Transporte

El servidor usa HTTP Streamable sin estado. Cada solicitud es independiente; el servidor no mantiene una sesión MCP ni una conexión de Server-Sent Events.

MétodoEndpointComportamiento
POST/_emdash/api/mcpAcepta la inicialización de JSON-RPC, el listado de herramientas y las llamadas a herramientas.
GET/_emdash/api/mcpDevuelve 405 Method Not Allowed.
DELETE/_emdash/api/mcpDevuelve 405 Method Not Allowed.

Las respuestas usan JSON-RPC 2.0. Llama a tools/list para obtener los esquemas de entrada y las anotaciones MCP actuales antes de construir una solicitud de herramienta.

Inventario de herramientas

El siguiente inventario coincide con las herramientas estáticas que devuelve tools/list. Se incluye el título registrado porque los clientes pueden mostrarlo en lugar del nombre de la herramienta.

Herramientas de contenido

HerramientaTítulo registradoScope requerido
content_listList Contentcontent:read
content_getGet Contentcontent:read
content_createCreate Contentcontent:write
content_updateUpdate Contentcontent:write
content_deleteDelete Content (Trash)content:write
content_restoreRestore Contentcontent:write
content_permanent_deletePermanently Delete Contentcontent:write
content_publishPublish Contentcontent:write
content_unpublishUnpublish Contentcontent:write
content_scheduleSchedule Contentcontent:write
content_unscheduleCancel Scheduled Publicationcontent:write
content_compareCompare Live vs Draftcontent:read
content_discard_draftDiscard Draftcontent:write
content_list_trashedList Trashed Contentcontent:read
content_duplicateDuplicate Contentcontent:write
content_translationsGet Content Translationscontent:read

Herramientas de byline

HerramientaTítulo registradoScope requerido
byline_listList Bylinescontent:read
byline_getGet Bylinecontent:read
byline_createCreate Bylinecontent:write
byline_updateUpdate Bylinecontent:write
byline_deleteDelete Bylinecontent:write
byline_translationsList Byline Translationscontent:read

Herramientas de esquema

HerramientaTítulo registradoScope requerido
schema_list_collectionsList Collectionsschema:read
schema_get_collectionGet Collection Schemaschema:read
schema_list_block_typesList Block Typesschema:read
schema_get_block_typeGet Block Typeschema:read
schema_create_block_typeCreate Block Typeschema:write
schema_update_block_typeUpdate Block Typeschema:write
schema_activate_block_type_versionActivate Block Type Versionschema:write
schema_create_collectionCreate Collectionschema:write
schema_delete_collectionDelete Collectionschema:write
schema_update_collectionUpdate Collectionschema:write
schema_create_fieldAdd Field to Collectionschema:write
schema_delete_fieldRemove Field from Collectionschema:write
schema_update_fieldUpdate Fieldschema:write

Herramientas de medios

HerramientaTítulo registradoScope requerido
media_listList Mediamedia:read
media_createConfirm Signed Media Uploadmedia:write
media_uploadUpload Mediamedia:write
media_getGet Media Itemmedia:read
media_updateUpdate Media Metadatamedia:write
media_deleteDelete Mediamedia:write
media_usage_repairRepair Media Usage Indexadmin

Herramienta de búsqueda

HerramientaTítulo registradoScope requerido
searchSearch Contentcontent:read

Herramientas de taxonomía

HerramientaTítulo registradoScope requerido
taxonomy_listList Taxonomiescontent:read
taxonomy_getGet Taxonomy Definitioncontent:read
taxonomy_createCreate Taxonomy Definitiontaxonomies:manage
taxonomy_updateUpdate Taxonomy Definitiontaxonomies:manage
taxonomy_deleteDelete Taxonomy Definitiontaxonomies:manage
taxonomy_list_termsList Taxonomy Termscontent:read
taxonomy_create_termCreate Taxonomy Termtaxonomies:manage
taxonomy_update_termUpdate Taxonomy Termtaxonomies:manage
taxonomy_delete_termDelete Taxonomy Termtaxonomies:manage
taxonomy_term_translationsList Term Translationscontent:read

Herramientas de menú

HerramientaTítulo registradoScope requerido
menu_listList Menuscontent:read
menu_getGet Menu with Itemscontent:read
menu_translationsList Menu Translationscontent:read
menu_createCreate Menumenus:manage
menu_updateUpdate Menumenus:manage
menu_deleteDelete Menumenus:manage
menu_set_itemsSet Menu Itemsmenus:manage

Herramientas de revisión

HerramientaTítulo registradoScope requerido
revision_listList Revisionscontent:read
revision_restoreRestore Revisioncontent:write

Herramientas de ajustes

HerramientaTítulo registradoScope requerido
settings_getGet Site Settingssettings:read
settings_updateUpdate Site Settingssettings:manage

Herramientas de transferencia de sitio

transfer:* significa cualquiera de transfer:export, transfer:analyze o transfer:execute. El scope admin satisface todos los requisitos de esta tabla.

HerramientaTítulo registradoScope requerido
site_transfer_capabilitiesGet Site Transfer Capabilitiestransfer:*
site_export_startStart Site Exporttransfer:export
site_export_statusGet Site Export Statustransfer:export
site_import_analyzeAnalyze Site Importtransfer:analyze
site_import_startStart Site Importtransfer:execute
site_import_statusGet Site Import Statustransfer:*
site_import_resumeResume Site Importtransfer:execute
site_import_receiptGet Site Import Receipttransfer:*

site_export_start y site_import_start también aceptan un token sin el scope cuando un administrador aprueba la solicitud. Para la operación que inicia una solicitud aprobada, site_export_status, site_import_status, site_import_resume y site_import_receipt aceptan entonces el mismo token sin el scope.

Usar los esquemas de las herramientas

tools/list devuelve la descripción, el esquema JSON de entrada y las anotaciones de cada herramienta. Lee esos metadatos antes de construir una llamada para que tu cliente use los campos, los valores permitidos y los límites que admite la versión de EmDash instalada.

Por ejemplo, un cliente que actualiza un artículo llama primero a content_get y conserva el _rev devuelto. Después puede enviar esta solicitud JSON-RPC:

{
	"jsonrpc": "2.0",
	"id": 2,
	"method": "tools/call",
	"params": {
		"name": "content_update",
		"arguments": {
			"collection": "articles",
			"id": "01JARTICLE0000000000000000",
			"data": { "title": "Updated title" },
			"_rev": "opaque-revision-token"
		}
	}
}

El resultado se devuelve como texto JSON en el primer bloque de contenido. Una herramienta con un esquema de salida también puede devolver el mismo valor en structuredContent.

Ciclo de vida del contenido y bylines

La referencia del ciclo de vida del contenido define el comportamiento de estados, revisiones, permisos, conflictos y hooks que comparten MCP, REST, la CLI y el panel de administración.

content_get devuelve un valor _rev opaco. Pásalo a content_update, content_publish, content_unpublish, content_schedule o content_discard_draft. Un valor obsoleto devuelve un conflicto, así que vuelve a leer el elemento antes de reintentar.

content_update es una actualización parcial: los campos omitidos conservan sus valores actuales. Actualizar un elemento publicado prepara un borrador mientras la versión en vivo permanece sin cambios. Usa content_compare para revisar los valores en vivo y del borrador, y luego llama a content_publish para publicar el borrador o a content_discard_draft para eliminarlo. content_delete mueve un elemento a la papelera; solo content_permanent_delete elimina de forma permanente un elemento que está en la papelera.

Los bylines son créditos reutilizables de autor o colaborador. byline_create puede crear un crédito de invitado o vincular un byline a un usuario del CMS. Un usuario solo puede tener un byline por configuración regional. Una traducción creada con translationOf conserva el usuario del byline de origen a menos que pases userId; pasa null para dejar la traducción sin vincular. Pasa el ID de byline devuelto en la entrada bylines que aceptan content_create y content_update. Eliminar un byline quita ese crédito del contenido y lo borra como byline principal.

Mientras otro usuario mantiene el bloqueo de edición de una entrada porque la tiene abierta en el admin, content_update, content_delete, content_publish, content_unpublish, content_schedule, content_unschedule, content_discard_draft y revision_restore fallan con ENTRY_LOCKED, y el error indica quién lo mantiene. Volver a leer el elemento no elimina el rechazo. Pasa overrideLock: true para escribir de todos modos.

Traducciones

Las herramientas de traducción de contenido, bylines, términos de taxonomía y menús devuelven todas las variantes de configuración regional del grupo de traducción correspondiente. Usa la entrada translationOf de la herramienta de creación cuando su esquema la ofrezca; tools/list es la fuente autorizada para los campos obligatorios.

content_translations acepta una colección y un ID o slug de contenido. Las herramientas de traducción de bylines, términos de taxonomía y menús aceptan el ID de un registro o el ID compartido del grupo de traducción. Un usuario sin acceso a borradores solo ve las traducciones de contenido publicado.

Esquemas, medios, taxonomías y menús

Las herramientas de esquema cambian la estructura de la base de datos. Usa schema_get_collection antes de crear contenido o cambiar campos; devuelve los nombres de campo, tipos, restricciones y reglas de validación disponibles. Eliminar colecciones y campos borra el contenido o los valores de campo almacenados y no se puede deshacer.

Usa media_upload para enviar bytes codificados en base64. Las subidas están sujetas a los límites de tamaño y de tipo MIME configurados, y unos bytes idénticos pueden devolver un elemento de medios existente con deduplicated: true.

media_create confirma una subida pendiente creada mediante POST /_emdash/api/media/upload-url. Sube el archivo con la URL firmada devuelta y luego llama a media_create desde la misma cuenta de usuario con el storageKey devuelto. La herramienta comprueba que el archivo almacenado existe y que coincide con el tamaño indicado al solicitar la URL de subida antes de ponerlo a disposición en la biblioteca de medios.

Las definiciones de taxonomía describen la clasificación y las colecciones a las que se aplica; los términos son los valores individuales asignados al contenido. Los términos jerárquicos pueden usar parentId, pero el padre debe pertenecer a la misma taxonomía y no puede crear un ciclo. Crear o actualizar un término con parentId en una taxonomía no jerárquica devuelve VALIDATION_ERROR. Un término con hijos debe tener esos hijos eliminados o movidos antes de borrarse.

menu_set_items reemplaza la lista completa de elementos de un menú en una sola operación atómica. El orden del array se convierte en el orden del menú. El parentIndex de un elemento anidado apunta a un elemento anterior del mismo array, así que coloca cada padre antes de sus hijos.

media_usage_repair puede procesar una colección o todas, y puede tardar mucho en un sitio grande. Sus estados complete, partial, failed y stale son respuestas correctas de la herramienta. Inspecciona el estado y los recuentos devueltos en lugar de confiar en isError; los fallos de autenticación, validación y ejecución inesperados establecen isError: true.

Transferencia de sitio

Las herramientas site_* exportan un sitio completo como paquete del sitio e importan un paquete en un sitio vacío. Inician y dirigen las operaciones y devuelven resúmenes acotados. Nunca transportan bytes del paquete, medios, contenido de registros, direcciones de correo de los principales ni URL de descarga. Descarga una exportación y sube un paquete para importarlo con la CLI o la API REST, y luego haz referencia a la operación por su ID.

Todas las herramientas de transferencia requieren el rol Admin. El rol se comprueba antes que el scope, de modo que un llamador que no es administrador recibe INSUFFICIENT_PERMISSIONS y no se crea ninguna solicitud de aprobación.

Exportación

site_export_start acepta comments (por defecto true) y devuelve la nueva operación. site_export_status ejecuta un paso de exportación acotado en cada llamada e informa de la operación y de nextRequestInMs. Vuelve a llamarla después de ese retraso hasta que nextRequestInMs sea null. Pasa advance: false para leer el estado sin ejecutar un paso. Cuando la exportación termina, el resultado también incluye totals: recuentos de registros por tipo, número y bytes de medios, y número y bytes de archivos del paquete.

Importación

Sube primero el paquete. El comando emdash site import <file> --analyze de la CLI lo sube, lo analiza e imprime el ID de la operación.

site_import_analyze ejecuta un paso de análisis acotado en cada llamada. Repítelo hasta que nextRequestInMs sea null; el resultado incluye entonces un resumen del plan con packageDigest, planDigest, executable, recuentos, tamaños, principales, decisiones, transformaciones, advertencias y bloqueos. Cada transformación aparece con su code, el kind del registro cuando lo tiene y un count, sin los IDs ni los valores a los que se aplica. Los principales, las advertencias y los bloqueos se listan con un máximo de 50 elementos cada uno, con el recuento completo en total. Los principales se listan sin direcciones de correo, con los IDs de usuario de destino sugeridos y los asignados actualmente. Pasa decisions para asignar principales a IDs de usuario de destino (o null) y para elegir el título y el eslogan del paquete o del destino. Cada cambio produce un nuevo planDigest.

site_import_start recibe el ID de la operación y el packageDigest y el planDigest del plan más reciente. El plan no debe tener bloqueos. La herramienta tiene destructiveHint: true: una vez iniciada, la importación escribe en el sitio y bloquea otras escrituras hasta que termina o un administrador la abandona. Muestra el plan al usuario y obtén su confirmación antes de llamarla.

site_import_resume ejecuta un paso de importación acotado e informa de la operación y de nextRequestInMs. Llámala hasta que nextRequestInMs sea null; es seguro repetirla después de una desconexión. site_import_status informa de la operación y del número de archivos subidos sin avanzar la importación. site_import_receipt devuelve el recibo completo, incluido receiptDigest, cuando la importación ha terminado.

Mientras se ejecuta una importación, y después de que falle o se cancele hasta que se abandone, cualquier otra herramienta que pueda escribir falla con TRANSFER_IMPORT_IN_PROGRESS. Esto incluye las herramientas de plugins. Las herramientas anotadas con readOnlyHint: true y las ocho herramientas site_* siguen funcionando, y initialize y tools/list nunca se bloquean. Durante la activación del uso de medios, las herramientas de escritura fallan de la misma manera con MEDIA_USAGE_ACTIVATION_IN_PROGRESS.

Los resúmenes de operación incluyen id, kind, state, stage, progress, packageDigest, planDigest, error ({ code } o null) y marcas de tiempo. progress es { done, total } pasos, más records, los registros que una exportación ha escrito hasta el momento, y bytesDone y bytesTotal, una vez conocidos. Las herramientas MCP no pueden cancelar ni abandonar una importación; usa la API REST.

Aprobaciones

Un token con admin o con el scope de transferencia necesario nunca pide aprobación. Para un token sin ninguno de los dos, como un agente al que solo se le concedió transfer:analyze, site_export_start y site_import_start se ejecutan cuando un administrador aprueba la solicitud:

  1. La primera llamada sin el scope crea una solicitud de aprobación pendiente y falla con TRANSFER_APPROVAL_REQUIRED. El texto del mensaje y _meta.details incluyen el approvalId y su expiresAt. Volver a llamar con los mismos argumentos y sin approvalId devuelve la misma solicitud abierta.
  2. Un administrador aprueba la solicitud en Approval requests, dentro de Settings → Transfer, o con el endpoint de aprobación solo de sesión de la API REST. Los tokens de API no pueden aprobar solicitudes.
  3. El cliente repite la llamada con los mismos argumentos y el approvalId. La aprobación se consume cuando esa llamada inicia la operación. Si la operación no llega a iniciarse, el cliente puede reintentar con el mismo approvalId hasta que caduque.

Una solicitud está vinculada al usuario, al token, a la acción y a los argumentos exactos: las opciones de exportación, o el ID de la operación de importación y ambos digests. Una solicitud pendiente caduca 15 minutos después de crearse, y una aprobada, 15 minutos después de la aprobación. Una llamada con argumentos distintos o con otro token, o con una aprobación denegada, caducada o ya usada, falla con TRANSFER_APPROVAL_INVALID.

site_import_start comprueba los digests, el estado de la operación y los bloqueos del plan antes de crear una solicitud, de modo que solo se pide a un administrador que apruebe una importación que se puede ejecutar. Una aprobación necesita un ID de token, así que un llamador sin él recibe INSUFFICIENT_SCOPE.

Después de que una llamada aprobada inicie una operación, el mismo usuario y el mismo token pueden llamar a site_export_status, o a site_import_status, site_import_resume y site_import_receipt, para esa operación sin el scope.

Herramientas de plugins

Un administrador debe habilitar la superficie MCP de cada plugin. Las herramientas habilitadas aparecen en tools/list con un prefijo de plugin seguro para MCP seguido de __<localName> (por ejemplo, @acme/calendar y createEvent se convierten en acme__calendar__createEvent) y requieren mcp:tools o mcp:tools:<pluginId> en las llamadas autenticadas con token. EmDash también comprueba el permiso que declara la ruta del plugin y registra el plugin, la herramienta, la ruta y el actor en el registro de auditoría.

Los ID con ámbito (scoped) y separadores ambiguos incluyen un hash corto antes del nombre local de la herramienta. Usa tools/list para descubrir los nombres generados. Si dos herramientas generan el mismo nombre, EmDash conserva la primera y registra una advertencia para la herramienta omitida.

Como las herramientas de plugins dependen de cada instalación, no forman parte del inventario estático anterior.

Descubrimiento de OAuth

Los clientes MCP descubren el servidor de autorización a partir de los metadatos del recurso protegido:

GET /.well-known/oauth-protected-resource

La respuesta identifica /_emdash/api/mcp como el recurso protegido y enlaza con el servidor de autorización. Después, los clientes leen sus metadatos en:

GET /.well-known/oauth-authorization-server/_emdash

Ese documento proporciona los endpoints actuales de autorización, token, registro y autorización de dispositivo, los scopes y tipos de concesión admitidos y el método PKCE S256. Usa los valores descubiertos en lugar de codificar de forma fija las rutas del protocolo OAuth.

Una solicitud MCP sin autenticar devuelve una respuesta 401 con la URL de descubrimiento:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://example.com/.well-known/oauth-protected-resource"

Errores

Un fallo de herramienta tiene isError: true. El primer bloque de texto empieza con un código estable, y _meta.code lo repite para los clientes que leen metadatos estructurados:

{
	"content": [{ "type": "text", "text": "[NOT_FOUND] Collection 'articles' not found" }],
	"isError": true,
	"_meta": { "code": "NOT_FOUND" }
}

Un rechazo por el bloqueo de edición de una entrada incluye quién lo mantiene en _meta.details:

{
	"content": [{ "type": "text", "text": "[ENTRY_LOCKED] Ada is holding this entry" }],
	"isError": true,
	"_meta": {
		"code": "ENTRY_LOCKED",
		"details": {
			"userId": "01JB...",
			"userName": "Ada",
			"acquiredAt": "2026-05-01T09:12:04.117Z",
			"expiresAt": "2026-05-01T09:19:04.117Z"
		}
	}
}

Los fallos de autenticación usan códigos como INSUFFICIENT_SCOPE e INSUFFICIENT_PERMISSIONS. Los fallos de transporte usan el código de error interno de JSON-RPC -32603 y no exponen la excepción subyacente.