Riferimento al server MCP

In questa pagina

EmDash include un server Model Context Protocol (MCP) integrato in /_emdash/api/mcp che espone le operazioni di gestione dei contenuti come strumenti per gli assistenti IA.

Questa pagina illustra i dettagli del protocollo: autenticazione, trasporto, specifiche degli strumenti, metadati OAuth e gestione degli errori.

Autenticazione

Il server MCP supporta tre metodi di autenticazione:

MetodoFunzionamento
OAuth 2.1 authorization code + PKCEFlusso standard per i client MCP. L’utente approva gli scope nel browser.
Token di accesso personale (PAT)Token ec_pat_* a lunga durata creati nel pannello di amministrazione.
Device flowFlusso stile CLI in cui si approva un codice nel browser. Usato da emdash login.

Anche i cookie di sessione (dall’interfaccia di amministrazione) funzionano, ma non sono pratici per i client MCP esterni.

Scope

I token sono limitati da scope che restringono le operazioni consentite. Gli scope sono richiesti durante l’autorizzazione OAuth e applicati a ogni chiamata agli strumenti.

ScopeConcede accesso a
content:readElencare, recuperare, confrontare e cercare contenuti. Elencare tassonomie, termini e menu.
content:writeCreare, aggiornare, eliminare, pubblicare, annullare pubblicazione, programmare, annullare programmazione, duplicare e ripristinare contenuti. Concede implicitamente taxonomies:manage e menus:manage per compatibilità con token emessi prima dell’esistenza di tali scope.
media:readElencare e recuperare elementi media.
media:writeRegistrare (creare), aggiornare ed eliminare metadati media.
schema:readElencare le collection e ottenere gli schemi.
schema:writeCreare ed eliminare collection e campi.
taxonomies:manageCreare, aggiornare ed eliminare termini di tassonomia.
menus:manageCreare, aggiornare ed eliminare menu di navigazione e relative voci.
settings:readLeggere le impostazioni globali del sito.
settings:manageAggiornare le impostazioni globali del sito.
adminAccesso completo a tutte le operazioni.

Lo scope admin concede accesso a tutto. Anche l’autenticazione basata su sessione (senza token) ha accesso completo in base al ruolo dell’utente.

content:write concede implicitamente taxonomies:manage e menus:manage affinché i token personali emessi prima della separazione di questi scope continuino a funzionare senza riemissione. I nuovi token dovrebbero richiedere gli scope granulari.

Requisiti di ruolo

Oltre agli scope, alcuni strumenti richiedono un ruolo RBAC minimo. Devono essere soddisfatte entrambe le condizioni — un token con lo scope corretto fallisce comunque se il ruolo dell’utente chiamante è troppo basso.

OperazioneRuolo minimo
Lettura contenutiAbbonato (10) per elementi pubblicati; Collaboratore (20) per bozze, programmati, cestino e revisioni
Creazione / modifica propri / eliminazione propriAutore (30)
Pubblicazione contenutiAutore (30) per i propri elementi; Editore (40) per agire su elementi altrui
Lettura schemaEditore (40)
Scrittura schemaAmministratore (50)
Gestione tassonomieEditore (40)
Gestione menuEditore (40)
Lettura impostazioniEditore (40)
Gestione impostazioniAmministratore (50)
Caricamento media (media_create)Autore (30)

Vedi la guida all’autenticazione per le definizioni dei ruoli.

Trasporto

Il server usa il trasporto Streamable HTTP in modalità stateless. Ogni richiesta è indipendente: nessuna sessione né connessioni persistenti.

  • POST /_emdash/api/mcp — Invia chiamate JSON-RPC agli strumenti
  • GET /_emdash/api/mcp — Restituisce 405 (nessun SSE in modalità stateless)
  • DELETE /_emdash/api/mcp — Restituisce 405 (nessuna sessione da chiudere)

Le risposte seguono il formato JSON-RPC 2.0. Gli errori usano i codici JSON-RPC standard; per scope e permessi si usano codici specifici MCP.

Strumenti

Il server espone 43 strumenti in otto ambiti: contenuti, schema, media, ricerca, tassonomie, menu, revisioni e impostazioni. Ogni strumento restituisce risultati come contenuto testuale JSON o, in caso di errore, un messaggio con isError: true.

Strumenti contenuti

content_list

Elenca gli elementi di contenuto di una collection con filtri e paginazione opzionali.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection (es. posts, pages)
statusstringNoFiltro: draft, published o scheduled
limitintegerNoNumero massimo (1-100, predefinito 50)
cursorstringNoCursore di paginazione da una risposta precedente
orderBystringNoCampo di ordinamento (es. created_at, updated_at)
orderstringNoDirezione: asc o desc (predefinito desc)
localestringNoFiltra per locale (es. en, fr). Rilevante solo con i18n.

Scope: content:read | Sola lettura:

content_get

Recupera un singolo elemento per ID o slug. Restituisce tutti i valori dei campi, i metadati e un token _rev per controllo di concorrenza ottimistica.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
idstringID dell’elemento (ULID) o slug
localestringNoLocale per risolvere lo slug. Gli ID sono univoci a livello globale.

Scope: content:read | Sola lettura:

content_create

Crea un nuovo elemento. L’oggetto data deve contenere valori conformi allo schema della collection — usa schema_get_collection per i campi disponibili. Gli elementi sono creati come draft per impostazione predefinita.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
dataobjectValori dei campi come coppie chiave-valore
slugstringNoSlug URL (generato dal titolo se omesso)
statusstringNoStato iniziale: draft o published (predefinito draft)
localestringNoLocale del contenuto (predefinito: sito)
translationOfstringNoID dell’elemento di cui questo è una traduzione

Scope: content:write

content_update

Aggiorna un elemento esistente. Includi solo i campi da modificare — gli altri restano invariati.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
idstringID o slug dell’elemento
dataobjectNoValori da aggiornare
slugstringNoNuovo slug URL
statusstringNoNuovo stato: draft o published
_revstringNoToken di revisione da content_get per i conflitti

Scope: content:write

content_delete

Elimina in modo soft spostando nel cestino. Usa content_restore per annullare o content_permanent_delete per rimuovere definitivamente.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
idstringID o slug dell’elemento

Scope: content:write | Distruttivo:

content_restore

Ripristina un elemento eliminato in soft delete dal cestino.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
idstringID o slug dell’elemento

Scope: content:write

content_permanent_delete

Elimina in modo permanente e irreversibile un elemento nel cestino. L’elemento deve prima essere nel cestino.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
idstringID o slug dell’elemento

Scope: content:write | Distruttivo:

content_publish

Pubblica un elemento, rendendolo visibile sul sito. Crea una revisione pubblicata dalla bozza corrente. Ulteriori modifiche creano una nuova bozza senza alterare la versione live fino a una nuova pubblicazione.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
idstringID o slug dell’elemento

Scope: content:write

content_unpublish

Riporta un elemento pubblicato allo stato bozza. Non sarà più visibile sul sito live, ma il contenuto è preservato.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
idstringID o slug dell’elemento

Scope: content:write

content_schedule

Programma la pubblicazione futura di un elemento. Verrà pubblicato automaticamente alla data/ora specificate.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
idstringID o slug dell’elemento
scheduledAtstringData/ora ISO 8601 (es. 2026-06-01T09:00:00Z)

Scope: content:write

content_unschedule

Annulla una pubblicazione programmata. L’elemento mantiene lo stato corrente; viene cancellato solo il timestamp scheduledAt. Idempotente — chiamare su un elemento non programmato non ha effetto.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
idstringID o slug dell’elemento

Scope: content:write

content_compare

Confronta la versione pubblicata (live) con la bozza corrente. Restituisce entrambe le versioni e un flag che indica se ci sono modifiche.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
idstringID o slug dell’elemento

Scope: content:read | Sola lettura:

content_discard_draft

Elimina la bozza corrente e torna all’ultima versione pubblicata. Funziona solo se l’elemento è stato pubblicato almeno una volta.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
idstringID o slug dell’elemento

Scope: content:write | Distruttivo:

content_list_trashed

Elenca gli elementi eliminati in soft delete nel cestino di una collection.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
limitintegerNoMassimo (1-100, predefinito 50)
cursorstringNoCursore di paginazione

Scope: content:read | Sola lettura:

content_duplicate

Crea una copia di un elemento esistente. Il duplicato è una bozza con «(Copy)» nel titolo e slug generato automaticamente.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
idstringID o slug dell’elemento da duplicare

Scope: content:write

content_translations

Ottiene tutte le varianti per locale di un elemento. Restituisce il gruppo di traduzione e un riepilogo per ogni versione. Rilevante solo con i18n abilitato.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
idstringID o slug dell’elemento

Scope: content:read | Sola lettura:

Strumenti schema

schema_list_collections

Elenca tutte le collection di contenuto definite nel CMS. Restituisce slug, etichetta, funzionalità supportate e timestamp.

Nessun parametro.

Scope: schema:read | Ruolo min.: Editore | Sola lettura:

schema_get_collection

Informazioni dettagliate su una collection, incluse tutte le definizioni dei campi. I campi descrivono il modello dati: nome, tipo, vincoli e regole di validazione. Usalo per capire cosa si aspettano content_create e content_update.

ParametroTipoObbligatorioDescrizione
slugstringSlug della collection (es. posts)

Scope: schema:read | Ruolo min.: Editore | Sola lettura:

schema_create_collection

Crea una nuova collection di contenuto. Crea una tabella nel database e la definizione dello schema. Lo slug deve essere alfanumerico minuscolo con underscore e iniziare con una lettera.

ParametroTipoObbligatorioDescrizione
slugstringIdentificatore univoco (/^[a-z][a-z0-9_]*$/)
labelstringNome visualizzato (plurale, es. «Blog Posts»)
labelSingularstringNoNome singolare
descriptionstringNoDescrizione della collection
iconstringNoNome icona nell’interfaccia di amministrazione
supportsstring[]NoFunzionalità: drafts, revisions, preview, scheduling, search (predefinito: ['drafts', 'revisions'])

Scope: schema:write | Ruolo min.: Amministratore

schema_delete_collection

Elimina una collection e la sua tabella. Irreversibile; elimina tutti i contenuti della collection.

ParametroTipoObbligatorioDescrizione
slugstringSlug della collection da eliminare
forcebooleanNoForza l’eliminazione anche se la collection ha contenuti

Scope: schema:write | Ruolo min.: Amministratore | Distruttivo:

schema_create_field

Aggiunge un nuovo campo allo schema di una collection. Aggiunge una colonna alla tabella.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
slugstringIdentificatore del campo (/^[a-z][a-z0-9_]*$/)
labelstringEtichetta
typestringTipo di dato (vedi sotto)
requiredbooleanNoCampo obbligatorio
uniquebooleanNoValori univoci richiesti
defaultValueanyNoValore predefinito per i nuovi elementi
validationobjectNoVincoli: min, max, minLength, maxLength, pattern, options
optionsobjectNoConfigurazione widget: collection (per riferimenti), rows (per textarea)
searchablebooleanNoIncludi nell’indice di ricerca full-text
translatablebooleanNoCampo traducibile (predefinito true)

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

Per select e multiSelect, specificare i valori consentiti in validation.options.

Scope: schema:write | Ruolo min.: Amministratore

schema_delete_field

Rimuove un campo da una collection. Elimina la colonna e tutti i dati del campo. Irreversibile.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
fieldSlugstringSlug del campo da rimuovere

Scope: schema:write | Ruolo min.: Amministratore | Distruttivo:

Strumenti media

media_list

Elenca i file media caricati con filtro opzionale sul tipo MIME e paginazione.

ParametroTipoObbligatorioDescrizione
mimeTypestringNoFiltra per prefisso MIME (es. image/, application/pdf)
limitintegerNoMassimo (1-100, predefinito 50)
cursorstringNoCursore di paginazione

Scope: media:read | Sola lettura:

media_create

Registra un file media già caricato nello storage. Chi chiama è responsabile di posizionare il file in storageKey (tipicamente con URL di upload firmata dall’admin o da un’altra API). Questo strumento salva il record dei metadati così che il file sia trovabile tramite media_list / media_get e referenziabile nei contenuti.

ParametroTipoObbligatorioDescrizione
filenamestringNome file originale (es. logo.png)
mimeTypestringTipo MIME (es. image/png)
storageKeystringPercorso/chiave di storage dove è stato caricato il file
sizeintegerNoDimensione in byte
widthintegerNoLarghezza immagine in pixel
heightintegerNoAltezza immagine in pixel
contentHashstringNoHash del contenuto (deduplicazione)
blurhashstringNoBlurhash per placeholder
dominantColorstringNoColore dominante in esadecimale

Scope: media:write | Ruolo min.: Autore

media_get

Dettagli di un singolo file media per ID. Metadati: nome file, MIME, dimensione, dimensioni immagine, testo alternativo e URL.

ParametroTipoObbligatorioDescrizione
idstringID elemento media

Scope: media:read | Sola lettura:

media_update

Aggiorna i metadati di un file caricato. Il file stesso non può essere modificato.

ParametroTipoObbligatorioDescrizione
idstringID elemento media
altstringNoTesto alternativo (accessibilità)
captionstringNoDidascalia
widthintegerNoLarghezza in pixel
heightintegerNoAltezza in pixel

Scope: media:write

media_delete

Elimina in modo permanente un file media. Rimuove il record dal database e tutti i file dallo storage. I contenuti che lo referenziano avranno riferimenti non validi.

ParametroTipoObbligatorioDescrizione
idstringID elemento media

Scope: media:write | Distruttivo:

Strumento di ricerca

Ricerca full-text sulle collection di contenuto. Le collection devono avere search in supports e i campi devono essere searchable.

ParametroTipoObbligatorioDescrizione
querystringTesto della ricerca
collectionsstring[]NoLimita a slug di collection specifiche
localestringNoFiltra i risultati per locale
limitintegerNoMassimo risultati (1-50, predefinito 20)

Scope: content:read | Sola lettura:

Strumenti tassonomia

taxonomy_list

Elenca tutte le definizioni di tassonomia (es. categorie, tag). Restituisce nome, etichetta, se gerarchica e collection associate.

Nessun parametro.

Scope: content:read | Sola lettura:

taxonomy_list_terms

Elenca i termini di una tassonomia con paginazione.

ParametroTipoObbligatorioDescrizione
taxonomystringNome tassonomia (es. categories, tags)
limitintegerNoMassimo (1-100, predefinito 50)
cursorstringNoCursore di paginazione

Scope: content:read | Sola lettura:

taxonomy_create_term

Crea un nuovo termine. Per tassonomie gerarchiche, specifica parentId per un termine figlio. La catena di antenati del genitore non deve superare 100 livelli.

ParametroTipoObbligatorioDescrizione
taxonomystringNome tassonomia
slugstringIdentificatore sicuro per URL
labelstringEtichetta
parentIdstringNoID termine padre (tassonomie gerarchiche)
descriptionstringNoDescrizione del termine

Scope: taxonomies:manage | Ruolo min.: Editore

taxonomy_update_term

Aggiorna un termine esistente. Ogni campo può essere omesso per lasciarlo invariato. Rinominare lo slug non deve collidere. Imposta parentId su null per staccare dal genitore. Il nuovo padre deve esistere, appartenere alla stessa tassonomia e non introdurre cicli.

ParametroTipoObbligatorioDescrizione
taxonomystringNome tassonomia
termSlugstringSlug attuale del termine da aggiornare
slugstringNoNuovo slug (univoco nella tassonomia)
labelstringNoNuova etichetta
parentIdstring | nullNoNuovo ID padre; null per staccare
descriptionstringNoNuova descrizione

Scope: taxonomies:manage | Ruolo min.: Editore

taxonomy_delete_term

Elimina in modo permanente un termine. I contenuti taggati perdono l’associazione. Non si può eliminare un termine con figli — elimina prima i figli.

ParametroTipoObbligatorioDescrizione
taxonomystringNome tassonomia
termSlugstringSlug del termine da eliminare

Scope: taxonomies:manage | Ruolo min.: Editore | Distruttivo:

Strumenti menu

Elenca tutti i menu di navigazione. Restituisce nome, etichetta e timestamp.

Nessun parametro.

Scope: content:read | Sola lettura:

Ottiene un menu per nome con tutte le voci in ordine. Ogni voce ha etichetta, URL, tipo e opzionale padre per l’annidamento.

ParametroTipoObbligatorioDescrizione
namestringNome menu (es. main, footer)

Scope: content:read | Sola lettura:

Crea un nuovo menu di navigazione. name è l’identificatore stabile usato dai template; label è il nome leggibile in amministrazione. Aggiungi le voci dopo con menu_set_items.

ParametroTipoObbligatorioDescrizione
namestringIdentificatore stabile (/^[a-z][a-z0-9_]*$/)
labelstringNome visualizzato per l’admin

Scope: menus:manage | Ruolo min.: Editore

Aggiorna l’etichetta di un menu. Il name (identificatore stabile) non può essere modificato.

ParametroTipoObbligatorioDescrizione
namestringNome menu da aggiornare
labelstringNuova etichetta visualizzata

Scope: menus:manage | Ruolo min.: Editore

Elimina un menu e tutte le sue voci. Non annullabile.

ParametroTipoObbligatorioDescrizione
namestringNome menu da eliminare

Scope: menus:manage | Ruolo min.: Editore | Distruttivo:

Sostituisce l’intera lista di voci in una sola chiamata. Atomico: le voci esistenti sono eliminate e la nuova lista inserita nell’ordine fornito. Preferibile alle operazioni per singola voce così ordine e collegamenti padre sono non ambigui.

Le voci sono posizionate per indice array. L’annidamento si esprime con parentIndex — una voce con parentIndex: 0 è annidata sotto la voce all’indice 0. Il padre deve precedere nella lista. Senza parentIndex, la voce è di primo livello.

ParametroTipoObbligatorioDescrizione
namestringNome menu da aggiornare
itemsMenuItem[]Lista ordinata di voci (vedi sotto)

Ogni MenuItem ha:

CampoTipoObbligatorioDescrizione
labelstringTesto visualizzato
typestringUno tra custom, page, post, taxonomy, collection
customUrlstringNoURL per type: "custom" (altrimenti ignorato)
referenceCollectionstringNoSlug collection di destinazione per riferimenti
referenceIdstringNoID contenuto o termine di destinazione
titleAttrstringNoAttributo HTML title
targetstringNoAttributo HTML target (es. _blank)
cssClassesstringNoClassi CSS separate da spazi
parentIndexintegerNoIndice array della voce padre. Omettere per il primo livello.

Scope: menus:manage | Ruolo min.: Editore

Strumenti revisione

revision_list

Elenca la cronologia delle revisioni, più recenti per prime. La collection deve supportare revisions.

ParametroTipoObbligatorioDescrizione
collectionstringSlug della collection
idstringID o slug dell’elemento
limitintegerNoMassimo revisioni (1-50, predefinito 20)

Scope: content:read | Sola lettura:

revision_restore

Ripristina un elemento a una revisione precedente. Sostituisce la bozza corrente con i dati della revisione specificata. Non viene pubblicato automaticamente — usa content_publish se necessario.

ParametroTipoObbligatorioDescrizione
revisionIdstringID revisione da ripristinare

Scope: content:write

Strumenti impostazioni

Impostazioni globali del sito — titolo, tagline, logo, favicon, URL canonica, dimensione pagina predefinita, formato data e ora, profili social e predefiniti SEO.

settings_get

Ottiene tutte le impostazioni globali. I riferimenti media (logo, favicon, seo.defaultOgImage) includono URL risolti oltre al mediaId. Valori non impostati sono omessi dalla risposta.

Nessun parametro.

Scope: settings:read | Ruolo min.: Editore | Sola lettura:

settings_update

Aggiorna una o più impostazioni globali. Aggiornamento parziale: cambiano solo i campi forniti. Restituisce l’oggetto impostazioni completo dopo l’aggiornamento.

Per un riferimento media (logo, favicon, seo.defaultOgImage), passa un oggetto con mediaId (e opzionale alt). L’elemento media deve già esistere — usa prima media_create.

ParametroTipoObbligatorioDescrizione
titlestringNoTitolo del sito
taglinestringNoBreve descrizione accanto al titolo
logoMediaRefNoRiferimento logo ({ mediaId, alt? })
faviconMediaRefNoRiferimento favicon
urlstringNoURL canonica del sito (http o https). Stringa vuota la cancella.
postsPerPageintegerNoDimensione pagina predefinita per gli elenchi (1-100)
dateFormatstringNoStringa token formato data
timezonestringNoIdentificatore fuso IANA
socialobjectNoProfili social — twitter, github, facebook, instagram, linkedin, youtube
seoobjectNoPredefiniti SEO (vedi sotto)

L’oggetto seo accetta:

CampoTipoDescrizione
titleSeparatorstringSeparatore tra titolo pagina e titolo sito (es. " | " per barra verticale)
defaultOgImageMediaRefImmagine Open Graph predefinita se il contenuto non ne ha
robotsTxtstringCorpo robots.txt personalizzato. Ometti per il default EmDash.
googleVerificationstringToken verifica Google Search Console
bingVerificationstringToken Bing Webmaster Tools

Scope: settings:manage | Ruolo min.: Amministratore

Individuazione OAuth

I client MCP con supporto OAuth 2.1 possono scoprire automaticamente come autenticarsi. Il server pubblica due documenti di metadati:

Metadati risorsa protetta

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",
    "taxonomies:manage", "menus:manage",
    "settings:read", "settings:manage",
    "admin"
  ],
  "bearer_methods_supported": ["header"]
}

Metadati authorization server

GET /.well-known/oauth-authorization-server/_emdash
{
  "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"
}

Quando una richiesta non autenticata raggiunge l’endpoint MCP, il server risponde:

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

Questo avvia il flusso standard di individuazione del client MCP.

Gestione degli errori

Gli errori degli strumenti sono restituiti come contenuto testuale con isError: true:

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

Errori di scope e permesso generano errori di protocollo MCP:

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

Errori a livello di trasporto (configurazione errata, eccezioni non gestite) restituiscono codice JSON-RPC -32603 (errore interno) senza esporre dettagli di implementazione.