O EmDash inclui um servidor Model Context Protocol (MCP) integrado em /_emdash/api/mcp que expõe operações de gestão de conteúdo como ferramentas para assistentes de IA.
Esta página cobre os detalhes do protocolo: autenticação, transporte, especificações das ferramentas, descoberta OAuth e tratamento de erros.
Autenticação
O servidor MCP suporta três métodos de autenticação:
| Método | Como funciona |
|---|---|
| OAuth 2.1 Authorization Code + PKCE | Fluxo padrão para clientes MCP. O utilizador aprova os escopos no navegador. |
| Token de Acesso Pessoal (PAT) | Tokens ec_pat_* de longa duração criados no painel de administração. |
| Device Flow | Fluxo estilo CLI onde se aprova um código no navegador. Usado pelo emdash login. |
Cookies de sessão (do painel de administração) também funcionam, mas não são práticos para clientes MCP externos.
Escopos
Os tokens são limitados por escopos para restringir as operações que um cliente pode realizar. Os escopos são solicitados durante a autorização OAuth e aplicados em cada chamada de ferramenta.
| Escopo | Concede acesso a |
|---|---|
content:read | Listar, obter, comparar e pesquisar conteúdo. Listar termos de taxonomia e menus. |
content:write | Criar, atualizar, eliminar, publicar, despublicar, agendar, duplicar e restaurar conteúdo. Criar termos de taxonomia. |
media:read | Listar e obter itens de media. |
media:write | Atualizar e eliminar metadados de media. |
schema:read | Listar coleções e obter esquemas de coleções. |
schema:write | Criar e eliminar coleções e campos. |
admin | Acesso total a todas as operações. |
O escopo admin concede acesso a tudo. A autenticação baseada em sessão (sem token) também tem acesso total com base no papel do utilizador.
Requisitos de Papel
Além dos escopos, algumas ferramentas requerem um papel RBAC mínimo:
| Operação | Papel mínimo |
|---|---|
| Operações de conteúdo | Sem mínimo (escopos controlam o acesso) |
| Leitura de esquema | Editor (40) |
| Escrita de esquema | Admin (50) |
Consulte o guia de Autenticação para definições de papéis.
Transporte
O servidor usa o transporte Streamable HTTP em modo sem estado. Cada pedido é independente — não existem sessões ou conexões de longa duração.
POST /_emdash/api/mcp— Enviar chamadas de ferramentas JSON-RPCGET /_emdash/api/mcp— Retorna 405 (sem SSE no modo sem estado)DELETE /_emdash/api/mcp— Retorna 405 (sem sessão para encerrar)
As respostas seguem o formato JSON-RPC 2.0. Os erros usam códigos de erro JSON-RPC padrão, com códigos específicos do MCP para falhas de escopo e permissão.
Ferramentas
O servidor expõe 33 ferramentas em sete domínios. Cada ferramenta retorna resultados como conteúdo de texto JSON, ou uma mensagem de erro com isError: true em caso de falha.
Ferramentas de Conteúdo
content_list
Listar itens de conteúdo numa coleção com filtragem e paginação opcionais.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção (ex.: posts, pages) |
status | string | Não | Filtro: draft, published ou scheduled |
limit | integer | Não | Máximo de itens a retornar (1-100, padrão 50) |
cursor | string | Não | Cursor de paginação de uma resposta anterior |
orderBy | string | Não | Campo para ordenar (ex.: created_at, updated_at) |
order | string | Não | Direção da ordenação: asc ou desc (padrão desc) |
locale | string | Não | Filtrar por locale (ex.: en, fr). Apenas relevante com i18n. |
Escopo: content:read | Somente leitura: Sim
content_get
Obter um único item de conteúdo por ID ou slug. Retorna todos os valores dos campos, metadados e um token _rev para concorrência otimista.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
id | string | Sim | ID do item de conteúdo (ULID) ou slug |
locale | string | Não | Locale para pesquisa por slug. Os IDs são globalmente únicos. |
Escopo: content:read | Somente leitura: Sim
content_create
Criar um novo item de conteúdo. O objeto data deve conter valores de campo correspondentes ao esquema da coleção — use schema_get_collection para verificar quais campos estão disponíveis. Os itens são criados como draft por padrão.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
data | object | Sim | Valores dos campos como pares chave-valor |
slug | string | Não | Slug de URL (gerado automaticamente a partir do título se omitido) |
status | string | Não | Status inicial: draft ou published (padrão draft) |
locale | string | Não | Locale para este conteúdo (padrão do site se omitido) |
translationOf | string | Não | ID do item do qual este é uma tradução |
Escopo: content:write
content_update
Atualizar um item de conteúdo existente. Inclua apenas os campos que deseja alterar — campos não especificados permanecem inalterados.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
id | string | Sim | ID ou slug do item de conteúdo |
data | object | Não | Valores dos campos a atualizar |
slug | string | Não | Novo slug de URL |
status | string | Não | Novo status: draft ou published |
_rev | string | Não | Token de revisão do content_get para deteção de conflitos |
Escopo: content:write
content_delete
Eliminação suave de um item de conteúdo, movendo-o para o lixo. Use content_restore para desfazer, ou content_permanent_delete para removê-lo definitivamente.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
id | string | Sim | ID ou slug do item de conteúdo |
Escopo: content:write | Destrutivo: Sim
content_restore
Restaurar um item de conteúdo eliminado do lixo.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
id | string | Sim | ID ou slug do item de conteúdo |
Escopo: content:write
content_permanent_delete
Eliminar permanente e irreversivelmente um item de conteúdo no lixo. O item deve estar no lixo primeiro.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
id | string | Sim | ID ou slug do item de conteúdo |
Escopo: content:write | Destrutivo: Sim
content_publish
Publicar um item de conteúdo, tornando-o visível no site. Cria uma revisão publicada a partir do rascunho atual. Edições posteriores criam um novo rascunho sem afetar a versão publicada até ser republicado.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
id | string | Sim | ID ou slug do item de conteúdo |
Escopo: content:write
content_unpublish
Reverter um item publicado para o status de rascunho. Deixará de ser visível no site, mas o conteúdo é preservado.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
id | string | Sim | ID ou slug do item de conteúdo |
Escopo: content:write
content_schedule
Agendar um item de conteúdo para publicação futura. Será publicado automaticamente na data/hora especificada.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
id | string | Sim | ID ou slug do item de conteúdo |
scheduledAt | string | Sim | Data/hora ISO 8601 (ex.: 2026-06-01T09:00:00Z) |
Escopo: content:write
content_compare
Comparar a versão publicada (ao vivo) de um item de conteúdo com o seu rascunho atual. Retorna ambas as versões e um indicador de se existem alterações.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
id | string | Sim | ID ou slug do item de conteúdo |
Escopo: content:read | Somente leitura: Sim
content_discard_draft
Descartar o rascunho atual e reverter para a última versão publicada. Funciona apenas em itens que foram publicados pelo menos uma vez.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
id | string | Sim | ID ou slug do item de conteúdo |
Escopo: content:write | Destrutivo: Sim
content_list_trashed
Listar itens de conteúdo eliminados no lixo de uma coleção.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
limit | integer | Não | Máximo de itens (1-100, padrão 50) |
cursor | string | Não | Cursor de paginação |
Escopo: content:read | Somente leitura: Sim
content_duplicate
Criar uma cópia de um item de conteúdo existente. O duplicado é criado como rascunho com “(Copy)” adicionado ao título e um slug gerado automaticamente.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
id | string | Sim | ID ou slug do item de conteúdo a duplicar |
Escopo: content:write
content_translations
Obter todas as variantes de locale de um item de conteúdo. Retorna o grupo de tradução e um resumo de cada versão de locale. Apenas relevante quando o i18n está ativado.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
id | string | Sim | ID ou slug do item de conteúdo |
Escopo: content:read | Somente leitura: Sim
Ferramentas de Esquema
schema_list_collections
Listar todas as coleções de conteúdo definidas no CMS. Retorna slug, rótulo, funcionalidades suportadas e timestamps.
Sem parâmetros.
Escopo: schema:read | Papel mínimo: Editor | Somente leitura: Sim
schema_get_collection
Obter informações detalhadas sobre uma coleção, incluindo todas as definições de campos. Os campos descrevem o modelo de dados: nome, tipo, restrições e regras de validação. Use para entender o que content_create e content_update esperam.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
slug | string | Sim | Slug da coleção (ex.: posts) |
Escopo: schema:read | Papel mínimo: Editor | Somente leitura: Sim
schema_create_collection
Criar uma nova coleção de conteúdo. Isto cria uma tabela na base de dados e uma definição de esquema. O slug deve ser alfanumérico minúsculo com underscores, começando por uma letra.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
slug | string | Sim | Identificador único (/^[a-z][a-z0-9_]*$/) |
label | string | Sim | Nome de exibição (plural, ex.: “Blog Posts”) |
labelSingular | string | Não | Nome de exibição singular |
description | string | Não | Descrição desta coleção |
icon | string | Não | Nome do ícone para o painel de administração |
supports | string[] | Não | Funcionalidades: drafts, revisions, preview, scheduling, search (padrão: ['drafts', 'revisions']) |
Escopo: schema:write | Papel mínimo: Admin
schema_delete_collection
Eliminar uma coleção e a sua tabela na base de dados. Isto é irreversível e elimina todo o conteúdo na coleção.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
slug | string | Sim | Slug da coleção a eliminar |
force | boolean | Não | Forçar eliminação mesmo que a coleção tenha conteúdo |
Escopo: schema:write | Papel mínimo: Admin | Destrutivo: Sim
schema_create_field
Adicionar um novo campo ao esquema de uma coleção. Isto adiciona uma coluna à tabela da base de dados.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
slug | string | Sim | Identificador do campo (/^[a-z][a-z0-9_]*$/) |
label | string | Sim | Nome de exibição |
type | string | Sim | Tipo de dados (ver abaixo) |
required | boolean | Não | Se o campo é obrigatório |
unique | boolean | Não | Se os valores devem ser únicos |
defaultValue | any | Não | Valor padrão para novos itens |
validation | object | Não | Restrições: min, max, minLength, maxLength, pattern, options |
options | object | Não | Configuração de widget: collection (para referências), rows (para textarea) |
searchable | boolean | Não | Incluir no índice de pesquisa de texto completo |
translatable | boolean | Não | Se este campo é traduzível (padrão true) |
Tipos de campo: string, text, number, integer, boolean, datetime, select, multiSelect, portableText, image, file, reference, json, slug.
Para os tipos select e multiSelect, forneça os valores permitidos em validation.options.
Escopo: schema:write | Papel mínimo: Admin
schema_delete_field
Remover um campo de uma coleção. Isto elimina a coluna e todos os dados nesse campo. Irreversível.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
fieldSlug | string | Sim | Slug do campo a remover |
Escopo: schema:write | Papel mínimo: Admin | Destrutivo: Sim
Ferramentas de Media
media_list
Listar ficheiros de media enviados com filtragem opcional por tipo MIME e paginação.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
mimeType | string | Não | Filtrar por prefixo de tipo MIME (ex.: image/, application/pdf) |
limit | integer | Não | Máximo de itens (1-100, padrão 50) |
cursor | string | Não | Cursor de paginação |
Escopo: media:read | Somente leitura: Sim
media_get
Obter detalhes de um único ficheiro de media por ID. Retorna metadados incluindo nome do ficheiro, tipo MIME, tamanho, dimensões, texto alternativo e URL.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | string | Sim | ID do item de media |
Escopo: media:read | Somente leitura: Sim
media_update
Atualizar metadados de um ficheiro de media enviado. O ficheiro em si não pode ser alterado.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | string | Sim | ID do item de media |
alt | string | Não | Texto alternativo para acessibilidade |
caption | string | Não | Texto da legenda |
width | integer | Não | Largura da imagem em pixels |
height | integer | Não | Altura da imagem em pixels |
Escopo: media:write
media_delete
Eliminar permanentemente um ficheiro de media. Remove o registo da base de dados e o ficheiro do armazenamento. Conteúdo que referencia esta media terá referências quebradas.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | string | Sim | ID do item de media |
Escopo: media:write | Destrutivo: Sim
Ferramenta de Pesquisa
search
Pesquisa de texto completo em coleções de conteúdo. As coleções devem ter search na sua lista supports e os campos devem estar marcados como searchable.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
query | string | Sim | Texto da consulta de pesquisa |
collections | string[] | Não | Limitar pesquisa a slugs de coleções específicas |
locale | string | Não | Filtrar resultados por locale |
limit | integer | Não | Máximo de resultados (1-50, padrão 20) |
Escopo: content:read | Somente leitura: Sim
Ferramentas de Taxonomia
taxonomy_list
Listar todas as definições de taxonomia (ex.: categorias, tags). Retorna nome, rótulo, se é hierárquica e coleções associadas.
Sem parâmetros.
Escopo: content:read | Somente leitura: Sim
taxonomy_list_terms
Listar termos numa taxonomia com paginação.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
taxonomy | string | Sim | Nome da taxonomia (ex.: categories, tags) |
limit | integer | Não | Máximo de itens (1-100, padrão 50) |
cursor | string | Não | Cursor de paginação |
Escopo: content:read | Somente leitura: Sim
taxonomy_create_term
Criar um novo termo numa taxonomia. Para taxonomias hierárquicas, especifique um parentId para criar um termo filho.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
taxonomy | string | Sim | Nome da taxonomia |
slug | string | Sim | Identificador seguro para URL |
label | string | Sim | Nome de exibição |
parentId | string | Não | ID do termo pai (para taxonomias hierárquicas) |
description | string | Não | Descrição do termo |
Escopo: content:write
Ferramentas de Menu
menu_list
Listar todos os menus de navegação. Retorna nome, rótulo e timestamps.
Sem parâmetros.
Escopo: content:read | Somente leitura: Sim
menu_get
Obter um menu por nome, incluindo todos os seus itens por ordem. Os itens têm rótulo, URL, tipo e pai opcional para aninhamento.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
name | string | Sim | Nome do menu (ex.: main, footer) |
Escopo: content:read | Somente leitura: Sim
Ferramentas de Revisão
revision_list
Listar histórico de revisões de um item de conteúdo, mais recentes primeiro. Requer que a coleção suporte revisions.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
collection | string | Sim | Slug da coleção |
id | string | Sim | ID ou slug do item de conteúdo |
limit | integer | Não | Máximo de revisões (1-50, padrão 20) |
Escopo: content:read | Somente leitura: Sim
revision_restore
Restaurar um item de conteúdo para uma revisão anterior. Substitui o rascunho atual com os dados da revisão especificada. Não é publicado automaticamente — use content_publish depois se necessário.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
revisionId | string | Sim | ID da revisão a restaurar |
Escopo: content:write
Descoberta OAuth
Os clientes MCP que suportam OAuth 2.1 podem descobrir automaticamente como autenticar. O servidor publica dois documentos de metadados:
Metadados do 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"]
}
Metadados do Servidor de Autorização
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"
}
Quando um pedido não autenticado chega ao endpoint MCP, o servidor retorna:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://example.com/.well-known/oauth-protected-resource"
Isto aciona o fluxo padrão de descoberta do cliente MCP.
Tratamento de Erros
Os erros de ferramentas são retornados como conteúdo de texto com isError: true:
{
"content": [{ "type": "text", "text": "Collection 'nonexistent' not found" }],
"isError": true
}
Erros de escopo e permissão lançam erros do protocolo MCP:
{
"jsonrpc": "2.0",
"error": {
"code": -32600,
"message": "Insufficient scope: requires content:write"
},
"id": 1
}
Erros ao nível do transporte (configuração incorreta do servidor, exceções não tratadas) retornam o código de erro JSON-RPC -32603 (Erro interno) sem expor detalhes de implementação.