MCP 服务器参考

本页内容

EmDash 在 /_emdash/api/mcp 路径内置了 Model Context Protocol(MCP)服务器,将内容管理操作作为工具暴露给 AI 助手。

本页涵盖协议详情:认证、传输、工具规范、OAuth 发现和错误处理。

认证

MCP 服务器支持三种认证方式:

方式工作原理
OAuth 2.1 Authorization Code + PKCEMCP 客户端的标准流程。用户在浏览器中批准权限范围。
个人访问令牌(PAT)在管理面板中创建的长期有效 ec_pat_* 令牌。
设备流CLI 风格的流程,在浏览器中批准代码。由 emdash login 使用。

会话 Cookie(来自管理 UI)也可用,但对外部 MCP 客户端不实用。

权限范围

令牌通过范围限制客户端可执行的操作。范围在 OAuth 授权期间请求,并在每次工具调用时强制执行。

范围授予的访问权限
content:read列出、获取、比较和搜索内容。列出分类法术语和菜单。
content:write创建、更新、删除、发布、取消发布、定时发布、复制和恢复内容。创建分类法术语。
media:read列出和获取媒体项。
media:write更新和删除媒体元数据。
schema:read列出集合和获取集合模式。
schema:write创建和删除集合及字段。
admin所有操作的完全访问权限。

admin 范围授予对所有内容的访问权限。基于会话的认证(无令牌)也根据用户角色拥有完全访问权限。

角色要求

除权限范围外,某些工具需要最低 RBAC 角色:

操作最低角色
内容操作无最低要求(由范围控制访问)
模式读取编辑者(40)
模式写入管理员(50)

角色定义参见认证指南

传输

服务器使用无状态模式的 Streamable HTTP 传输。每个请求是独立的——没有会话或长期连接。

  • POST /_emdash/api/mcp — 发送 JSON-RPC 工具调用
  • GET /_emdash/api/mcp — 返回 405(无状态模式下无 SSE)
  • DELETE /_emdash/api/mcp — 返回 405(无会话可关闭)

响应遵循 JSON-RPC 2.0 格式。错误使用标准 JSON-RPC 错误码,范围和权限失败使用 MCP 特定码。

工具

服务器在七个领域暴露 33 个工具。每个工具以 JSON 文本内容返回结果,失败时返回带有 isError: true 的错误消息。

内容工具

content_list

列出集合中的内容项,支持可选过滤和分页。

参数类型必填描述
collectionstring集合 slug(如 postspages
statusstring过滤:draftpublishedscheduled
limitinteger最大返回数量(1-100,默认 50)
cursorstring上一次响应的分页游标
orderBystring排序字段(如 created_atupdated_at
orderstring排序方向:ascdesc(默认 desc
localestring按语言环境过滤(如 enfr)。仅在启用 i18n 时相关。

范围: content:read | 只读:

content_get

按 ID 或 slug 获取单个内容项。返回所有字段值、元数据和用于乐观并发的 _rev 令牌。

参数类型必填描述
collectionstring集合 slug
idstring内容项 ID(ULID)或 slug
localestring用于 slug 查找的语言环境。ID 全局唯一。

范围: content:read | 只读:

content_create

创建新的内容项。data 对象应包含与集合模式匹配的字段值——使用 schema_get_collection 检查可用字段。默认创建为 draft

参数类型必填描述
collectionstring集合 slug
dataobject键值对形式的字段值
slugstringURL slug(省略时从标题自动生成)
statusstring初始状态:draftpublished(默认 draft
localestring此内容的语言环境(默认为站点默认值)
translationOfstring此条目是其翻译的原条目 ID

范围: content:write

content_update

更新现有内容项。只需包含要更改的字段——未指定的字段保持不变。

参数类型必填描述
collectionstring集合 slug
idstring内容项 ID 或 slug
dataobject要更新的字段值
slugstring新 URL slug
statusstring新状态:draftpublished
_revstring来自 content_get 的修订令牌,用于冲突检测

范围: content:write

content_delete

将内容项软删除至回收站。使用 content_restore 恢复,或使用 content_permanent_delete 永久删除。

参数类型必填描述
collectionstring集合 slug
idstring内容项 ID 或 slug

范围: content:write | 破坏性:

content_restore

从回收站恢复软删除的内容项。

参数类型必填描述
collectionstring集合 slug
idstring内容项 ID 或 slug

范围: content:write

content_permanent_delete

永久且不可逆地删除已回收的内容项。该项必须先在回收站中。

参数类型必填描述
collectionstring集合 slug
idstring内容项 ID 或 slug

范围: content:write | 破坏性:

content_publish

发布内容项,使其在站点上线。从当前草稿创建已发布版本。后续编辑会创建新草稿,不影响线上版本直到重新发布。

参数类型必填描述
collectionstring集合 slug
idstring内容项 ID 或 slug

范围: content:write

content_unpublish

将已发布项恢复为草稿状态。它将不再在线上站点可见,但内容会被保留。

参数类型必填描述
collectionstring集合 slug
idstring内容项 ID 或 slug

范围: content:write

content_schedule

定时发布内容项。它将在指定的日期/时间自动发布。

参数类型必填描述
collectionstring集合 slug
idstring内容项 ID 或 slug
scheduledAtstringISO 8601 日期时间(如 2026-06-01T09:00:00Z

范围: content:write

content_compare

比较内容项的已发布(线上)版本与当前草稿。返回两个版本和一个是否有更改的标志。

参数类型必填描述
collectionstring集合 slug
idstring内容项 ID 或 slug

范围: content:read | 只读:

content_discard_draft

丢弃当前草稿并恢复到最后发布的版本。仅对至少发布过一次的项有效。

参数类型必填描述
collectionstring集合 slug
idstring内容项 ID 或 slug

范围: content:write | 破坏性:

content_list_trashed

列出集合回收站中的软删除内容项。

参数类型必填描述
collectionstring集合 slug
limitinteger最大数量(1-100,默认 50)
cursorstring分页游标

范围: content:read | 只读:

content_duplicate

复制现有内容项。副本创建为草稿,标题追加”(Copy)“,slug 自动生成。

参数类型必填描述
collectionstring集合 slug
idstring要复制的内容项 ID 或 slug

范围: content:write

content_translations

获取内容项的所有语言变体。返回翻译组和每个语言版本的摘要。仅在启用 i18n 时相关。

参数类型必填描述
collectionstring集合 slug
idstring内容项 ID 或 slug

范围: content:read | 只读:

模式工具

schema_list_collections

列出 CMS 中定义的所有内容集合。返回 slug、标签、支持的功能和时间戳。

无参数。

范围: schema:read | 最低角色: 编辑者 | 只读:

schema_get_collection

获取集合的详细信息,包括所有字段定义。字段描述数据模型:名称、类型、约束和验证规则。使用此工具了解 content_createcontent_update 期望的内容。

参数类型必填描述
slugstring集合 slug(如 posts

范围: schema:read | 最低角色: 编辑者 | 只读:

schema_create_collection

创建新的内容集合。这会创建数据库表和模式定义。slug 必须是以字母开头的小写字母数字加下划线。

参数类型必填描述
slugstring唯一标识符(/^[a-z][a-z0-9_]*$/
labelstring显示名称(复数,如 “Blog Posts”)
labelSingularstring单数显示名称
descriptionstring此集合的描述
iconstring管理 UI 的图标名称
supportsstring[]功能:draftsrevisionspreviewschedulingsearch(默认:['drafts', 'revisions']

范围: schema:write | 最低角色: 管理员

schema_delete_collection

删除集合及其数据库表。此操作不可逆,会删除集合中的所有内容。

参数类型必填描述
slugstring要删除的集合 slug
forceboolean即使集合有内容也强制删除

范围: schema:write | 最低角色: 管理员 | 破坏性:

schema_create_field

向集合模式添加新字段。这会向数据库表添加列。

参数类型必填描述
collectionstring集合 slug
slugstring字段标识符(/^[a-z][a-z0-9_]*$/
labelstring显示名称
typestring数据类型(见下文)
requiredboolean字段是否必填
uniqueboolean值是否必须唯一
defaultValueany新条目的默认值
validationobject约束:minmaxminLengthmaxLengthpatternoptions
optionsobject小部件配置:collection(用于引用)、rows(用于文本区域)
searchableboolean是否纳入全文搜索索引
translatableboolean此字段是否可翻译(默认 true)

字段类型:stringtextnumberintegerbooleandatetimeselectmultiSelectportableTextimagefilereferencejsonslug

对于 selectmultiSelect 类型,在 validation.options 中提供允许的值。

范围: schema:write | 最低角色: 管理员

schema_delete_field

从集合中移除字段。这会删除列并删除该字段的所有数据。不可逆。

参数类型必填描述
collectionstring集合 slug
fieldSlugstring要移除的字段 slug

范围: schema:write | 最低角色: 管理员 | 破坏性:

媒体工具

media_list

列出已上传的媒体文件,支持可选 MIME 类型过滤和分页。

参数类型必填描述
mimeTypestring按 MIME 类型前缀过滤(如 image/application/pdf
limitinteger最大数量(1-100,默认 50)
cursorstring分页游标

范围: media:read | 只读:

media_get

按 ID 获取单个媒体文件的详情。返回包括文件名、MIME 类型、大小、尺寸、替代文本和 URL 的元数据。

参数类型必填描述
idstring媒体项 ID

范围: media:read | 只读:

media_update

更新已上传媒体文件的元数据。文件本身不能更改。

参数类型必填描述
idstring媒体项 ID
altstring无障碍替代文本
captionstring说明文字
widthinteger图片宽度(像素)
heightinteger图片高度(像素)

范围: media:write

media_delete

永久删除媒体文件。移除数据库记录和存储中的文件。引用此媒体的内容将出现断裂引用。

参数类型必填描述
idstring媒体项 ID

范围: media:write | 破坏性:

搜索工具

跨内容集合的全文搜索。集合必须在 supports 列表中包含 search,字段必须标记为 searchable

参数类型必填描述
querystring搜索查询文本
collectionsstring[]限制搜索特定集合 slug
localestring按语言环境过滤结果
limitinteger最大结果数(1-50,默认 20)

范围: content:read | 只读:

分类法工具

taxonomy_list

列出所有分类法定义(如分类目录、标签)。返回名称、标签、是否层级以及关联的集合。

无参数。

范围: content:read | 只读:

taxonomy_list_terms

列出分类法中的术语,支持分页。

参数类型必填描述
taxonomystring分类法名称(如 categoriestags
limitinteger最大数量(1-100,默认 50)
cursorstring分页游标

范围: content:read | 只读:

taxonomy_create_term

在分类法中创建新术语。对于层级分类法,指定 parentId 创建子术语。

参数类型必填描述
taxonomystring分类法名称
slugstringURL 安全标识符
labelstring显示名称
parentIdstring父术语 ID(用于层级分类法)
descriptionstring术语描述

范围: content:write

菜单工具

列出所有导航菜单。返回名称、标签和时间戳。

无参数。

范围: content:read | 只读:

按名称获取菜单,包括所有有序项目。项目包含标签、URL、类型和可选的父级(用于嵌套)。

参数类型必填描述
namestring菜单名称(如 mainfooter

范围: content:read | 只读:

修订工具

revision_list

列出内容项的修订历史,最新在前。需要集合支持 revisions

参数类型必填描述
collectionstring集合 slug
idstring内容项 ID 或 slug
limitinteger最大修订数(1-50,默认 20)

范围: content:read | 只读:

revision_restore

将内容项恢复到之前的修订。用指定修订的数据替换当前草稿。不会自动发布——如需要请之后使用 content_publish

参数类型必填描述
revisionIdstring要恢复的修订 ID

范围: content:write

OAuth 发现

支持 OAuth 2.1 的 MCP 客户端可以自动发现认证方式。服务器发布两个元数据文档:

受保护资源元数据

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"]
}

授权服务器元数据

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"
}

当未认证的请求到达 MCP 端点时,服务器返回:

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

这会触发标准的 MCP 客户端发现流程。

错误处理

工具错误以带有 isError: true 的文本内容返回:

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

范围和权限错误抛出 MCP 协议错误:

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

传输层错误(服务器配置错误、未处理异常)返回 JSON-RPC 错误码 -32603(内部错误),不泄露实现细节。