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 copre i dettagli del protocollo: autenticazione, trasporto, specifiche degli strumenti, scoperta OAuth e gestione degli errori.
Autenticazione
Il server MCP supporta tre metodi di autenticazione:
| Metodo | Come funziona |
|---|---|
| OAuth 2.1 Authorization Code + PKCE | Flusso standard per i client MCP. L’utente approva gli scope nel browser. |
| Personal Access Token (PAT) | Token ec_pat_* a lunga durata creati nel pannello di amministrazione. |
| Device Flow | Flusso tipo CLI dove approvi un codice nel browser. Usato da emdash login. |
I cookie di sessione (dall’UI di amministrazione) funzionano anche ma non sono pratici per client MCP esterni.
Scope
I token hanno portata limitata per restringere le operazioni che un client può eseguire. Gli scope vengono richiesti durante l’autorizzazione OAuth e applicati ad ogni chiamata di strumento.
| Scope | Concede accesso a |
|---|---|
content:read | Elencare, ottenere, confrontare e cercare contenuti. Elencare tassonomie, termini e menu. |
content:write | Creare, aggiornare, eliminare, pubblicare, depubblicare, programmare, deprogrammare, duplicare e ripristinare contenuti. Concede implicitamente taxonomies:manage e menus:manage. |
media:read | Elencare e ottenere elementi multimediali. |
media:write | Registrare (creare), aggiornare e eliminare metadati multimediali. |
schema:read | Elencare collezioni e ottenere schemi. |
schema:write | Creare e eliminare collezioni e campi. |
taxonomies:manage | Creare, aggiornare e eliminare termini di tassonomia. |
menus:manage | Creare, aggiornare e eliminare menu di navigazione e i loro elementi. |
settings:read | Leggere le impostazioni del sito. |
settings:manage | Aggiornare le impostazioni del sito. |
mcp:tools | Invocare strumenti MCP esplicitamente abilitati da qualsiasi plugin. |
mcp:tools:<pluginId> | Invocare strumenti MCP esplicitamente abilitati da un plugin. |
admin | Accesso completo a tutte le operazioni. |
Requisiti di ruolo
| Operazione | Ruolo minimo |
|---|---|
| Lettura contenuti | Subscriber (10) per pubblicati; Contributor (20) per bozze, programmati, cestino e revisioni |
| Creazione contenuti | Contributor (20) |
| Modifica/eliminazione propri | Author (30) |
| Pubblicazione contenuti | Author (30) per propri; Editor (40) per quelli altrui |
| Lettura schema | Editor (40) |
| Scrittura schema | Admin (50) |
| Gestione tassonomie | Editor (40) |
| Gestione menu | Editor (40) |
| Lettura impostazioni | Editor (40) |
| Gestione impostazioni | Admin (50) |
Upload multimediale (media_upload) | Contributor (20) |
Registrazione multimediale (media_create) | Author (30) |
| Riparazione uso multimediale | Admin (50) |
Consulta la guida all’autenticazione per le definizioni dei ruoli.
Trasporto
Il server utilizza il trasporto Streamable HTTP in modalità stateless. Ogni richiesta è indipendente.
POST /_emdash/api/mcp— Inviare chiamate di strumenti JSON-RPCGET /_emdash/api/mcp— Restituisce 405DELETE /_emdash/api/mcp— Restituisce 405
Le risposte seguono il formato JSON-RPC 2.0.
Strumenti
Il server espone strumenti in otto domini: contenuto, schema, media, ricerca, tassonomie, menu, revisioni e impostazioni. Ogni strumento restituisce risultati come contenuto testo JSON, o un messaggio di errore con isError: true in caso di fallimento.
Strumenti di contenuto
content_list
Elenca gli elementi di contenuto in una collezione con filtro e paginazione opzionali.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
status | string | No | Filtro: draft, published o scheduled |
limit | integer | No | Max elementi (1-100, default 50) |
cursor | string | No | Cursore di paginazione |
orderBy | string | No | Campo di ordinamento |
order | string | No | Direzione: asc o desc (default desc) |
locale | string | No | Filtrare per locale |
Scope: content:read | Sola lettura: Sì
content_get
Ottiene un singolo elemento di contenuto per ID o slug.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
id | string | Sì | ID elemento (ULID) o slug |
locale | string | No | Locale per la ricerca per slug |
Scope: content:read | Sola lettura: Sì
content_create
Crea un nuovo elemento di contenuto.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
data | object | Sì | Valori dei campi come coppie chiave-valore |
slug | string | No | Slug URL (auto-generato dal titolo se omesso) |
status | string | No | Stato iniziale: draft o published (default draft) |
locale | string | No | Locale per questo contenuto |
translationOf | string | No | ID dell’elemento di cui questo è una traduzione |
Scope: content:write
content_update
Aggiorna un elemento di contenuto esistente. Includi solo i campi da modificare.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
id | string | Sì | ID elemento o slug |
data | object | No | Valori dei campi da aggiornare |
slug | string | No | Nuovo slug URL |
status | string | No | Nuovo stato |
_rev | string | No | Token di revisione per rilevazione conflitti |
Scope: content:write
content_delete
Elimina un elemento spostandolo nel cestino.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
id | string | Sì | ID elemento o slug |
Scope: content:write | Distruttivo: Sì
content_restore
Ripristina un elemento dal cestino.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
id | string | Sì | ID elemento o slug |
Scope: content:write
content_permanent_delete
Elimina permanentemente e irreversibilmente un elemento dal cestino.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
id | string | Sì | ID elemento o slug |
Scope: content:write | Distruttivo: Sì
content_publish
Pubblica un elemento di contenuto, rendendolo visibile sul sito.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
id | string | Sì | ID elemento o slug |
Scope: content:write
content_unpublish
Riporta un elemento pubblicato allo stato di bozza.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
id | string | Sì | ID elemento o slug |
Scope: content:write
content_schedule
Programma un elemento per pubblicazione futura.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
id | string | Sì | ID elemento o slug |
scheduledAt | string | Sì | Data/ora ISO 8601 |
Scope: content:write
content_unschedule
Annulla una pubblicazione programmata.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
id | string | Sì | ID elemento o slug |
Scope: content:write
content_compare
Confronta la versione pubblicata con la bozza corrente.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
id | string | Sì | ID elemento o slug |
Scope: content:read | Sola lettura: Sì
content_discard_draft
Scarta la bozza corrente e ripristina l’ultima versione pubblicata.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
id | string | Sì | ID elemento o slug |
Scope: content:write | Distruttivo: Sì
content_list_trashed
Elenca gli elementi eliminati nel cestino di una collezione.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
limit | integer | No | Max elementi (1-100, default 50) |
cursor | string | No | Cursore di paginazione |
Scope: content:read | Sola lettura: Sì
content_duplicate
Crea una copia di un elemento esistente.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
id | string | Sì | ID o slug da duplicare |
Scope: content:write
content_translations
Ottiene tutte le varianti di locale di un elemento.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
id | string | Sì | ID elemento o slug |
Scope: content:read | Sola lettura: Sì
Strumenti di schema
schema_list_collections
Elenca tutte le collezioni di contenuto.
Nessun parametro.
Scope: schema:read | Ruolo minimo: Editor | Sola lettura: Sì
schema_get_collection
Ottiene informazioni dettagliate su una collezione.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
slug | string | Sì | Slug della collezione |
Scope: schema:read | Ruolo minimo: Editor | Sola lettura: Sì
schema_create_collection
Crea una nuova collezione di contenuto.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
slug | string | Sì | Identificatore unico (/^[a-z][a-z0-9_]*$/) |
label | string | Sì | Nome visualizzato (plurale) |
labelSingular | string | No | Nome singolare |
description | string | No | Descrizione |
icon | string | No | Nome icona per l’UI admin |
supports | string[] | No | Funzionalità: drafts, revisions, preview, scheduling, search |
Scope: schema:write | Ruolo minimo: Admin
schema_delete_collection
Elimina una collezione e la sua tabella. Irreversibile.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
slug | string | Sì | Slug da eliminare |
force | boolean | No | Forzare anche se ha contenuto |
Scope: schema:write | Ruolo minimo: Admin | Distruttivo: Sì
schema_create_field
Aggiunge un nuovo campo a una collezione.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
slug | string | Sì | Identificatore del campo |
label | string | Sì | Nome visualizzato |
type | string | Sì | Tipo di dati |
required | boolean | No | Se obbligatorio |
unique | boolean | No | Se i valori devono essere unici |
defaultValue | any | No | Valore predefinito |
validation | object | No | Vincoli |
options | object | No | Config widget |
searchable | boolean | No | Includere nella ricerca full-text |
translatable | boolean | No | Se traducibile (default true) |
Tipi di campo: string, text, number, integer, boolean, datetime, select, multiSelect, portableText, image, file, reference, json, slug.
Scope: schema:write | Ruolo minimo: Admin
schema_delete_field
Rimuove un campo da una collezione. Irreversibile.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
fieldSlug | string | Sì | Slug del campo |
Scope: schema:write | Ruolo minimo: Admin | Distruttivo: Sì
Strumenti multimediali
media_list
Elenca i file multimediali caricati.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
mimeType | string | No | Filtrare per prefisso tipo MIME |
limit | integer | No | Max elementi (1-100, default 50) |
cursor | string | No | Cursore di paginazione |
Scope: media:read | Sola lettura: Sì
media_upload
Carica un file multimediale da dati base64 o un URL esterno.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
filename | string | Sì | Nome file con estensione |
base64 | string | Uno tra base64 / url | Contenuto codificato base64 |
url | string | Uno tra base64 / url | URL http(s) pubblico |
contentType | string | Con base64 | Tipo MIME |
alt | string | No | Testo alternativo |
Scope: media:write | Ruolo minimo: Contributor
media_create
Registra un file multimediale già caricato nello storage.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
filename | string | Sì | Nome file originale |
mimeType | string | Sì | Tipo MIME |
storageKey | string | Sì | Percorso/chiave di storage |
size | integer | No | Dimensione in byte |
width | integer | No | Larghezza immagine |
height | integer | No | Altezza immagine |
contentHash | string | No | Hash del contenuto |
blurhash | string | No | Blurhash per placeholder |
dominantColor | string | No | Colore dominante esadecimale |
Scope: media:write | Ruolo minimo: Author
media_get
Ottiene i dettagli di un file multimediale per ID.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
id | string | Sì | ID elemento multimediale |
Scope: media:read | Sola lettura: Sì
media_update
Aggiorna i metadati di un file multimediale.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
id | string | Sì | ID elemento |
alt | string | No | Testo alternativo |
caption | string | No | Didascalia |
width | integer | No | Larghezza |
height | integer | No | Altezza |
Scope: media:write
media_delete
Elimina permanentemente un file multimediale.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
id | string | Sì | ID elemento |
Scope: media:write | Distruttivo: Sì
media_usage_repair
Ripara gli indici di utilizzo dei media.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
scope | "collection" | "all" | Sì | Riparare una o tutte le collezioni |
collection | string | Per scope collezione | Slug della collezione |
Scope: admin | Ruolo minimo: Admin
Strumento di ricerca
search
Ricerca full-text nelle collezioni di contenuto.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
query | string | Sì | Testo di ricerca |
collections | string[] | No | Limitare a collezioni specifiche |
locale | string | No | Filtrare per locale |
limit | integer | No | Max risultati (1-50, default 20) |
Scope: content:read | Sola lettura: Sì
Strumenti di tassonomia
taxonomy_list
Elenca tutte le definizioni di tassonomia.
Nessun parametro.
Scope: content:read | Sola lettura: Sì
taxonomy_list_terms
Elenca i termini in una tassonomia.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
taxonomy | string | Sì | Nome della tassonomia |
limit | integer | No | Max elementi (1-100, default 50) |
cursor | string | No | Cursore di paginazione |
Scope: content:read | Sola lettura: Sì
taxonomy_create_term
Crea un nuovo termine.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
taxonomy | string | Sì | Nome della tassonomia |
slug | string | Sì | Identificatore URL-safe |
label | string | Sì | Nome visualizzato |
parentId | string | No | ID termine padre |
description | string | No | Descrizione |
Scope: taxonomies:manage | Ruolo minimo: Editor
taxonomy_update_term
Aggiorna un termine esistente.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
taxonomy | string | Sì | Nome della tassonomia |
termSlug | string | Sì | Slug attuale del termine |
slug | string | No | Nuovo slug |
label | string | No | Nuovo nome |
parentId | string | null | No | Nuovo ID padre; null per scollegare |
description | string | No | Nuova descrizione |
Scope: taxonomies:manage | Ruolo minimo: Editor
taxonomy_delete_term
Elimina permanentemente un termine.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
taxonomy | string | Sì | Nome della tassonomia |
termSlug | string | Sì | Slug del termine |
Scope: taxonomies:manage | Ruolo minimo: Editor | Distruttivo: Sì
Strumenti di menu
menu_list
Elenca i menu di navigazione.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
locale | string | No | Filtrare per locale |
Scope: content:read | Sola lettura: Sì
menu_get
Ottiene un menu per nome con tutti i suoi elementi.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
name | string | Sì | Nome del menu |
locale | string | No | Locale per risolvere il menu |
Scope: content:read | Sola lettura: Sì
menu_create
Crea un nuovo menu di navigazione.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
name | string | Sì | Identificatore stabile |
label | string | Sì | Nome visualizzato |
locale | string | No | Locale per questo menu |
translationOf | string | No | ID menu esistente per la variante locale |
Scope: menus:manage | Ruolo minimo: Editor
menu_update
Aggiorna l’etichetta di un menu.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
name | string | Sì | Nome del menu |
label | string | Sì | Nuova etichetta |
locale | string | No | Locale del menu |
Scope: menus:manage | Ruolo minimo: Editor
menu_delete
Elimina un menu e tutti i suoi elementi. Irreversibile.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
name | string | Sì | Nome del menu |
locale | string | No | Locale del menu |
Scope: menus:manage | Ruolo minimo: Editor | Distruttivo: Sì
menu_set_items
Sostituisce l’intera lista di elementi di un menu. Atomico.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
name | string | Sì | Nome del menu |
locale | string | No | Locale del menu |
items | MenuItem[] | Sì | Lista ordinata di elementi |
Ogni MenuItem ha:
| Campo | Tipo | Richiesto | Descrizione |
|---|---|---|---|
label | string | Sì | Testo visualizzato |
type | string | Sì | Uno tra custom, page, post, taxonomy, collection |
customUrl | string | No | URL per type: "custom" |
referenceCollection | string | No | Slug collezione target |
referenceId | string | No | ID contenuto/termine target |
titleAttr | string | No | Attributo HTML title |
target | string | No | Attributo HTML target |
cssClasses | string | No | Classi CSS |
parentIndex | integer | No | Indice dell’elemento padre |
Scope: menus:manage | Ruolo minimo: Editor
Strumenti di revisione
revision_list
Elenca la cronologia delle revisioni, più recente per prima.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
collection | string | Sì | Slug della collezione |
id | string | Sì | ID elemento o slug |
limit | integer | No | Max revisioni (1-50, default 20) |
Scope: content:read | Sola lettura: Sì
revision_restore
Ripristina un elemento a una revisione precedente.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
revisionId | string | Sì | ID revisione da ripristinare |
Scope: content:write
Strumenti impostazioni
settings_get
Ottiene tutte le impostazioni del sito.
Nessun parametro.
Scope: settings:read | Ruolo minimo: Editor | Sola lettura: Sì
settings_update
Aggiorna una o più impostazioni del sito.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
title | string | No | Titolo del sito |
tagline | string | No | Breve descrizione |
logo | MediaRef | No | Riferimento media logo |
favicon | MediaRef | No | Riferimento media favicon |
url | string | No | URL canonico del sito |
postsPerPage | integer | No | Dimensione pagina predefinita (1-100) |
dateFormat | string | No | Formato data |
timezone | string | No | Identificatore fuso orario IANA |
social | object | No | Handle social |
seo | object | No | Valori SEO predefiniti |
Scope: settings:manage | Ruolo minimo: Admin
Scoperta OAuth
Metadati della 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 del server di autorizzazione
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"
}
Gestione degli errori
Gli errori degli strumenti vengono restituiti come contenuto testo con isError: true:
{
"content": [{ "type": "text", "text": "[NOT_FOUND] Collection 'nonexistent' not found" }],
"isError": true,
"_meta": { "code": "NOT_FOUND" }
}
{
"content": [
{ "type": "text", "text": "[INSUFFICIENT_SCOPE] Insufficient scope: requires content:write" }
],
"isError": true,
"_meta": { "code": "INSUFFICIENT_SCOPE" }
}
Gli errori a livello di trasporto restituiscono il codice di errore JSON-RPC -32603 (Errore interno) senza divulgare dettagli di implementazione.