Riferimento del server MCP

In questa pagina

EmDash espone un server Model Context Protocol (MCP) integrato su /_emdash/api/mcp. I client MCP lo usano per leggere e gestire contenuti, byline, schemi, media, tassonomie, menu, revisioni e impostazioni, e per esportare o importare l’intero sito.

Autenticazione

L’endpoint MCP richiede un token Bearer. EmDash supporta questi flussi di token:

MetodoUso
OAuth 2.1 Authorization Code with Proof Key for Code Exchange (PKCE)Client MCP interattivi. L’utente approva in un browser gli scope richiesti.
Personal access tokenAccesso di lunga durata per un client o un’automazione. I token usano il prefisso ec_pat_ e si creano nell’admin.
OAuth 2.0 Device Authorization GrantClient da riga di comando che chiedono all’utente di approvare un codice in un browser. emdash login usa questo flusso.

I cookie di sessione non autenticano l’endpoint MCP.

Scope

I token OAuth e i token di accesso personali limitano quali strumenti un client può chiamare. Il ruolo dell’utente viene verificato separatamente, quindi uno scope non concede mai un permesso che l’utente non ha.

ScopeAccesso
content:readLeggere e cercare contenuti, byline, tassonomie, termini, menu e revisioni. I contenuti di tipo bozza richiedono anche il permesso content:read_drafts dell’utente.
content:writeCreare e modificare contenuti, byline e revisioni. Concede anche taxonomies:manage e menus:manage per compatibilità con i token esistenti.
media:readLeggere i record dei media.
media:writeCaricare, registrare, aggiornare ed eliminare media.
schema:readLeggere collezioni e campi.
schema:writeCreare, aggiornare ed eliminare collezioni e campi.
taxonomies:manageCreare, aggiornare ed eliminare definizioni di tassonomie e termini.
menus:manageCreare, aggiornare ed eliminare menu e voci di menu.
settings:readLeggere le impostazioni del sito.
settings:manageAggiornare le impostazioni del sito.
mcp:toolsChiamare gli strumenti MCP esposti da qualsiasi plugin abilitato.
mcp:tools:<pluginId>Chiamare gli strumenti MCP esposti da un singolo plugin abilitato.
transfer:exportEsportare l’intero sito come pacchetto del sito e scaricarlo.
transfer:analyzeCaricare un pacchetto del sito e analizzarlo per l’importazione.
transfer:executeAvviare, far avanzare, annullare e abbandonare un’importazione del sito.
adminChiamare tutti gli strumenti core, compresi quelli di trasferimento del sito. Gli strumenti dei plugin richiedono comunque mcp:tools o lo scope specifico del plugin.

Lo scope admin include transfer:export, transfer:analyze e transfer:execute. Ogni scope di trasferimento concede solo le proprie azioni e richiede il ruolo di amministratore. Per permettere a un client, come un agente, di analizzare un pacchetto del sito senza esportare né importare, concedi transfer:analyze invece di admin.

La pagina di consenso del codice di autorizzazione permette all’utente di rimuovere gli scope richiesti. EmDash interseca inoltre la richiesta con gli scope registrati del client e con il ruolo dell’utente, e rifiuta una concessione vuota.

Requisiti di ruolo

La tabella seguente mostra il ruolo minimo per ciascuna capacità generale. I controlli di proprietà possono richiedere un ruolo più alto quando un utente agisce sui contenuti di un altro utente.

CapacitàRuolo minimo
Leggere contenuti pubblicati, media, tassonomie, termini e menuSubscriber
Leggere bozze, contenuti pianificati, cestino, confronti e revisioniContributor
Creare contenuti o caricare mediaContributor
Modificare o pubblicare i propri contenuti e registrare mediaAuthor
Gestire byline, tassonomie, menu o i contenuti di tutti gli utentiEditor
Leggere schemi o impostazioniEditor
Modificare schemi o impostazioni, eliminare definitivamente contenuti o riparare l’uso dei mediaAdmin
Esportare o importare l’intero sitoAdmin

Consulta i ruoli utente per le definizioni complete dei ruoli.

Trasporto

Il server usa HTTP Streamable senza stato. Ogni richiesta è indipendente; il server non mantiene una sessione MCP né una connessione Server-Sent Events.

MetodoEndpointComportamento
POST/_emdash/api/mcpAccetta l’inizializzazione JSON-RPC, l’elenco degli strumenti e le chiamate agli strumenti.
GET/_emdash/api/mcpRestituisce 405 Method Not Allowed.
DELETE/_emdash/api/mcpRestituisce 405 Method Not Allowed.

Le risposte usano JSON-RPC 2.0. Chiama tools/list per ottenere gli schemi di input e le annotazioni MCP correnti prima di costruire una richiesta a uno strumento.

Inventario degli strumenti

L’inventario seguente corrisponde agli strumenti statici restituiti da tools/list. Il titolo registrato è incluso perché i client possono mostrarlo al posto del nome dello strumento.

Strumenti per i contenuti

StrumentoTitolo registratoScope richiesto
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

Strumenti per le byline

StrumentoTitolo registratoScope richiesto
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

Strumenti per gli schemi

StrumentoTitolo registratoScope richiesto
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

Strumenti per i media

StrumentoTitolo registratoScope richiesto
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

Strumento di ricerca

StrumentoTitolo registratoScope richiesto
searchSearch Contentcontent:read

Strumenti per le tassonomie

StrumentoTitolo registratoScope richiesto
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

Strumenti per i menu

StrumentoTitolo registratoScope richiesto
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

Strumenti per le revisioni

StrumentoTitolo registratoScope richiesto
revision_listList Revisionscontent:read
revision_restoreRestore Revisioncontent:write

Strumenti per le impostazioni

StrumentoTitolo registratoScope richiesto
settings_getGet Site Settingssettings:read
settings_updateUpdate Site Settingssettings:manage

Strumenti di trasferimento del sito

transfer:* indica uno qualsiasi tra transfer:export, transfer:analyze o transfer:execute. Lo scope admin soddisfa tutti i requisiti di questa tabella.

StrumentoTitolo registratoScope richiesto
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 e site_import_start accettano anche un token privo dello scope quando un amministratore approva la richiesta. Per l’operazione avviata da una richiesta approvata, site_export_status, site_import_status, site_import_resume e site_import_receipt accettano poi lo stesso token privo dello scope.

Usare gli schemi degli strumenti

tools/list restituisce la descrizione, lo schema JSON di input e le annotazioni di ogni strumento. Leggi questi metadati prima di costruire una chiamata, in modo che il tuo client usi i campi, i valori consentiti e i limiti supportati dalla versione di EmDash installata.

Ad esempio, un client che aggiorna un articolo chiama prima content_get e conserva il _rev restituito. Può quindi inviare questa richiesta 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"
		}
	}
}

Il risultato viene restituito come testo JSON nel primo blocco di contenuto. Uno strumento con uno schema di output può restituire lo stesso valore anche in structuredContent.

Ciclo di vita dei contenuti e byline

Il riferimento al ciclo di vita dei contenuti definisce il comportamento di stati, revisioni, permessi, conflitti e hook condiviso da MCP, REST, dalla CLI e dal pannello di amministrazione.

content_get restituisce un valore _rev opaco. Passalo a content_update, content_publish, content_unpublish, content_schedule o content_discard_draft. Un valore obsoleto restituisce un conflitto, quindi rileggi l’elemento prima di riprovare.

content_update è un aggiornamento parziale: i campi omessi mantengono i valori attuali. Aggiornare un elemento pubblicato prepara una bozza mentre la versione live resta invariata. Usa content_compare per rivedere i valori live e quelli della bozza, quindi chiama content_publish per rendere live la bozza o content_discard_draft per rimuoverla. content_delete sposta un elemento nel cestino; solo content_permanent_delete rimuove definitivamente un elemento che si trova nel cestino.

Le byline sono crediti riutilizzabili di autore o collaboratore. byline_create può creare un credito per un ospite o collegare una byline a un utente del CMS. Un utente può avere una sola byline per locale. Una traduzione creata con translationOf mantiene l’utente della byline di origine, a meno che tu non passi userId; passa null per lasciare la traduzione senza collegamento. Passa l’ID della byline restituito nell’input bylines accettato da content_create e content_update. Eliminare una byline rimuove quel credito dai contenuti e la cancella come byline principale.

Finché un altro utente detiene il blocco di modifica di una voce perché l’ha aperta nell’admin, content_update, content_delete, content_publish, content_unpublish, content_schedule, content_unschedule, content_discard_draft e revision_restore falliscono con ENTRY_LOCKED, e l’errore indica chi lo detiene. Rileggere l’elemento non elimina il rifiuto. Passa overrideLock: true per scrivere comunque.

Traduzioni

Gli strumenti di traduzione per contenuti, byline, termini di tassonomia e menu restituiscono ogni variante di locale del gruppo di traduzione interessato. Usa l’input translationOf dello strumento di creazione quando il suo schema ne prevede uno; per i campi obbligatori fa fede tools/list.

content_translations accetta una collezione e un ID o uno slug di contenuto. Gli strumenti di traduzione per byline, termini di tassonomia e menu accettano l’ID di un singolo record oppure l’ID condiviso del gruppo di traduzione. Un utente senza accesso alle bozze vede solo le traduzioni dei contenuti pubblicati.

Schemi, media, tassonomie e menu

Gli strumenti per gli schemi modificano la struttura del database. Usa schema_get_collection prima di creare contenuti o modificare campi; restituisce i nomi dei campi, i tipi, i vincoli e le regole di validazione disponibili. L’eliminazione di collezioni e campi rimuove i contenuti o i valori dei campi archiviati e non può essere annullata.

Usa media_upload per inviare byte codificati in base64. I caricamenti sono soggetti ai limiti di dimensione e di tipo MIME configurati, e byte identici possono restituire un elemento multimediale esistente con deduplicated: true.

media_create conferma un caricamento in sospeso creato tramite POST /_emdash/api/media/upload-url. Carica il file con l’URL firmato restituito, poi chiama media_create dallo stesso account utente con il storageKey restituito. Lo strumento verifica che il file archiviato esista e corrisponda alla dimensione indicata quando è stato richiesto l’URL di caricamento, prima di renderlo disponibile nella libreria multimediale.

Le definizioni di tassonomia descrivono la classificazione e le collezioni a cui si applica; i termini sono i singoli valori assegnati ai contenuti. I termini gerarchici possono usare parentId, ma il genitore deve appartenere alla stessa tassonomia e non può creare un ciclo. Creare o aggiornare un termine con parentId in una tassonomia non gerarchica restituisce VALIDATION_ERROR. Un termine con figli deve avere quei figli rimossi o spostati prima di essere eliminato.

menu_set_items sostituisce l’intero elenco di voci di un menu in un’unica operazione atomica. L’ordine dell’array diventa l’ordine del menu. Il parentIndex di una voce annidata punta a una voce precedente nello stesso array, quindi posiziona ogni genitore prima dei suoi figli.

media_usage_repair può elaborare una collezione o tutte le collezioni e può durare a lungo su un sito grande. I suoi stati complete, partial, failed e stale sono risposte riuscite dello strumento. Controlla lo stato e i conteggi restituiti invece di affidarti a isError; i fallimenti di autenticazione, validazione ed esecuzione imprevisti impostano isError: true.

Trasferimento del sito

Gli strumenti site_* esportano un intero sito come pacchetto del sito e importano un pacchetto in un sito vuoto. Avviano e guidano le operazioni e restituiscono riepiloghi limitati. Non trasportano mai i byte del pacchetto, i media, il contenuto dei record, gli indirizzi e-mail dei principal né gli URL di download. Scarica un’esportazione e carica un pacchetto per l’importazione con la CLI o con l’API REST, poi fai riferimento all’operazione tramite il suo ID.

Ogni strumento di trasferimento richiede il ruolo Admin. Il ruolo viene verificato prima dello scope, quindi un chiamante che non è amministratore riceve INSUFFICIENT_PERMISSIONS e non viene creata alcuna richiesta di approvazione.

Esportazione

site_export_start accetta comments (predefinito true) e restituisce la nuova operazione. site_export_status esegue un passaggio di esportazione limitato a ogni chiamata e riporta l’operazione e nextRequestInMs. Chiamalo di nuovo dopo quel ritardo finché nextRequestInMs non è null. Passa advance: false per leggere lo stato senza eseguire un passaggio. Quando l’esportazione è completa, il risultato include anche totals: conteggi dei record per tipo, numero e byte dei media, e numero e byte dei file del pacchetto.

Importazione

Carica prima il pacchetto. Il comando emdash site import <file> --analyze della CLI lo carica, lo analizza e stampa l’ID dell’operazione.

site_import_analyze esegue un passaggio di analisi limitato a ogni chiamata. Ripetilo finché nextRequestInMs non è null; il risultato include quindi un riepilogo del piano con packageDigest, planDigest, executable, conteggi, dimensioni, principal, decisioni, trasformazioni, avvisi e bloccanti. Ogni trasformazione è elencata con il suo code, il kind del record quando ne ha uno e un count, senza gli ID o i valori a cui si applica. Principal, avvisi e bloccanti elencano al massimo 50 elementi ciascuno, con il conteggio completo in total. I principal sono elencati senza indirizzi e-mail, con gli ID utente di destinazione suggeriti e quelli attualmente mappati. Passa decisions per mappare i principal a ID utente di destinazione (o null) e per scegliere il titolo e lo slogan del pacchetto o della destinazione. Ogni modifica produce un nuovo planDigest.

site_import_start riceve l’ID dell’operazione e il packageDigest e il planDigest del piano più recente. Il piano non deve avere bloccanti. Lo strumento ha destructiveHint: true: una volta avviata, l’importazione scrive nel sito e blocca le altre scritture finché non termina o un amministratore la abbandona. Mostra il piano all’utente e ottieni la sua conferma prima di chiamarlo.

site_import_resume esegue un passaggio di importazione limitato e riporta l’operazione e nextRequestInMs. Chiamalo finché nextRequestInMs non è null; è sicuro ripeterlo dopo una disconnessione. site_import_status riporta l’operazione e il numero di file caricati senza far avanzare l’importazione. site_import_receipt restituisce la ricevuta completa, incluso receiptDigest, una volta completata l’importazione.

Mentre un’importazione è in esecuzione, e dopo che è fallita o è stata annullata fino a quando non viene abbandonata, ogni altro strumento che può scrivere fallisce con TRANSFER_IMPORT_IN_PROGRESS. Questo include gli strumenti dei plugin. Gli strumenti annotati con readOnlyHint: true e gli otto strumenti site_* continuano a funzionare, e initialize e tools/list non vengono mai bloccati. Durante l’attivazione dell’uso dei media, gli strumenti di scrittura falliscono allo stesso modo con MEDIA_USAGE_ACTIVATION_IN_PROGRESS.

I riepiloghi delle operazioni includono id, kind, state, stage, progress, packageDigest, planDigest, error ({ code } o null) e i timestamp. progress è { done, total } passaggi, più records, i record che un’esportazione ha scritto finora, e bytesDone e bytesTotal, una volta noti. Gli strumenti MCP non possono annullare né abbandonare un’importazione; usa l’API REST.

Approvazioni

Un token con admin o con lo scope di trasferimento necessario non chiede mai l’approvazione. Per un token privo di entrambi, come quello di un agente a cui è stato concesso solo transfer:analyze, site_export_start e site_import_start vengono eseguiti quando un amministratore approva la richiesta:

  1. La prima chiamata senza lo scope crea una richiesta di approvazione in sospeso e fallisce con TRANSFER_APPROVAL_REQUIRED. Il testo del messaggio e _meta.details contengono l’approvalId e il suo expiresAt. Chiamare di nuovo con gli stessi argomenti e senza approvalId restituisce la stessa richiesta aperta.
  2. Un amministratore approva la richiesta in Approval requests, sotto Settings → Transfer, oppure con l’endpoint di approvazione solo sessione dell’API REST. I token API non possono approvare le richieste.
  3. Il client ripete la chiamata con gli stessi argomenti e l’approvalId. L’approvazione viene consumata quando quella chiamata avvia l’operazione. Se l’operazione non riesce ad avviarsi, il client può riprovare con lo stesso approvalId fino alla scadenza.

Una richiesta è legata all’utente, al token, all’azione e agli argomenti esatti: le opzioni di esportazione, oppure l’ID dell’operazione di importazione e i due digest. Una richiesta in sospeso scade 15 minuti dopo la creazione, e una approvata 15 minuti dopo l’approvazione. Una chiamata con argomenti diversi o con un altro token, oppure con un’approvazione negata, scaduta o già usata, fallisce con TRANSFER_APPROVAL_INVALID.

site_import_start verifica i digest, lo stato dell’operazione e i bloccanti del piano prima di creare una richiesta, così a un amministratore viene chiesto di approvare solo un’importazione che può essere eseguita. Un’approvazione richiede un ID del token, quindi un chiamante che non ne ha uno riceve INSUFFICIENT_SCOPE.

Dopo che una chiamata approvata ha avviato un’operazione, lo stesso utente e lo stesso token possono chiamare site_export_status, oppure site_import_status, site_import_resume e site_import_receipt, per quell’operazione senza lo scope.

Strumenti dei plugin

Un amministratore deve abilitare la superficie MCP di ciascun plugin. Gli strumenti abilitati compaiono in tools/list come <pluginId>__<localName> e richiedono mcp:tools o mcp:tools:<pluginId> per le chiamate autenticate con token. EmDash verifica inoltre il permesso dichiarato dalla route del plugin e registra plugin, strumento, route e attore nel log di audit.

Poiché gli strumenti dei plugin dipendono dall’installazione, non fanno parte dell’inventario statico qui sopra.

Discovery OAuth

I client MCP scoprono il server di autorizzazione a partire dai metadati della risorsa protetta:

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

La risposta identifica /_emdash/api/mcp come risorsa protetta e rimanda al server di autorizzazione. I client leggono poi i suoi metadati a:

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

Quel documento fornisce gli endpoint correnti di autorizzazione, token, registrazione e autorizzazione del dispositivo, gli scope e i tipi di grant supportati e il metodo PKCE S256. Usa i valori scoperti invece di codificare in modo fisso le route del protocollo OAuth.

Una richiesta MCP non autenticata restituisce una risposta 401 con l’URL di discovery:

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

Errori

Un errore di uno strumento ha isError: true. Il primo blocco di testo inizia con un codice stabile, e _meta.code lo ripete per i client che leggono i metadati strutturati:

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

Un rifiuto dovuto al blocco di modifica di una voce riporta chi lo detiene in _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"
		}
	}
}

Gli errori di autenticazione usano codici come INSUFFICIENT_SCOPE e INSUFFICIENT_PERMISSIONS. Gli errori di trasporto usano il codice di errore interno di JSON-RPC -32603 e non espongono l’eccezione sottostante.