MCP 服务器参考

本页内容

EmDash 在 /_emdash/api/mcp 提供内置 模型上下文协议(MCP)服务器,将内容管理操作作为工具暴露给 AI 助手。

本文说明协议层面内容:身份验证、传输、工具规范、OAuth 发现与错误处理。

身份验证

MCP 服务器支持三种身份验证方式:

方式工作原理
OAuth 2.1 授权码 + PKCEMCP 客户端的标准流程。用户在浏览器中批准权限范围(scope)。
个人访问令牌(PAT)在管理后台创建的长期有效 ec_pat_* 令牌。
设备码流程类似 CLI 的流程,在浏览器中批准验证码。由 emdash login 使用。

管理后台产生的会话 Cookie 也可用,但对外部 MCP 客户端不实用。

权限范围(Scopes)

令牌通过 scope 限制客户端可执行的操作。scope 在 OAuth 授权时申请,并在每次工具调用时强制校验。

Scope授予的权限
content:read列出、获取、比较与搜索内容。列出分类法、分类项与菜单。
content:write创建、更新、删除、发布、撤下发布、定时发布、取消定时、复制与还原内容。为兼容在拆分出下列 scope 之前签发的令牌,隐式包含 taxonomies:managemenus:manage
media:read列出并获取媒体项。
media:write登记(创建)、更新与删除媒体元数据。
schema:read列出集合并获取集合结构(schema)。
schema:write创建与删除集合及字段。
taxonomies:manage创建、更新与删除分类项。
menus:manage创建、更新与删除导航菜单及其条目。
settings:read读取站点级设置。
settings:manage更新站点级设置。
admin对所有操作的完全访问。

admin scope 可访问一切。基于会话的身份验证(无令牌)也会根据用户角色拥有与其角色相符的全部权限。

content:write 隐式包含 taxonomies:managemenus:manage,以便在拆分这些 scope 之前签发的个人访问令牌无需重新签发仍可工作。新签发的令牌应申请更细粒度的 scope。

角色要求

除 scope 外,部分工具还要求最低 RBAC 角色。两者须同时满足——即便令牌 scope 正确,若调用用户角色不足仍会失败。

操作最低角色
内容读取已发布条目:订阅者(10);草稿、定时、回收站与修订:贡献者(20)
内容创建 / 编辑自己的 / 删除自己的作者(30)
内容发布自己的条目:作者(30);操作他人条目:编辑(40)
结构读取编辑(40)
结构写入管理员(50)
分类管理编辑(40)
菜单管理编辑(40)
设置读取编辑(40)
设置管理管理员(50)
媒体上传(media_create作者(30)

角色定义见 身份验证指南

传输

服务器在 无状态模式 下使用可流式 HTTP(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 错误码;scope 与权限失败时另有 MCP 专用错误码。

工具

服务器在八个领域中暴露 43 个工具:内容、结构(schema)、媒体、搜索、分类法、菜单、修订与设置。成功时每个工具以 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 时有效。

Scope: content:read | 只读:

content_get

按 ID 或 slug 获取单条内容。返回全部字段值、元数据,以及用于乐观并发控制的 _rev 令牌。

参数类型必填说明
collectionstring集合 slug
idstring内容项 ID(ULID)或 slug
localestring通过 slug 查找时的语言区域。ID 全局唯一。

Scope: content:read | 只读:

content_create

新建内容项。data 对象中的字段值须符合集合 schema——可用 schema_get_collection 查看可用字段。默认以 draft 创建。

参数类型必填说明
collectionstring集合 slug
dataobject字段键值对
slugstringURL slug(省略时通常由标题生成)
statusstring初始状态:draftpublished(默认 draft
localestring该内容的语言区域(默认站点默认语言)
translationOfstring若本条为翻译,所指向的源条目 ID

Scope: content:write

content_update

更新已有内容。只传需要修改的字段——未出现的字段保持不变。

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

Scope: content:write

content_delete

软删除:将内容移入回收站。可用 content_restore 恢复,或用 content_permanent_delete 永久删除。

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

Scope: content:write | 破坏性:

content_restore

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

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

Scope: content:write

content_permanent_delete

永久且不可逆地删除已在回收站中的内容项。条目须先位于回收站。

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

Scope: content:write | 破坏性:

content_publish

发布内容,使其在站点上线。会基于当前草稿创建已发布修订。后续编辑产生新草稿,在再次发布前不会影响线上版本。

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

Scope: content:write

content_unpublish

将已发布条目改回草稿,站点前台不再展示,但内容仍保留。

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

Scope: content:write

content_schedule

为内容项安排未来发布时间,到点自动发布。

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

Scope: content:write

content_unschedule

取消已安排的定时发布。条目保持当前状态;仅清除 scheduledAt 时间戳。幂等:对未安排发布的条目调用无效果。

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

Scope: content:write

content_compare

比较内容项的已发布(线上)版本与当前草稿。返回两个版本及是否有差异的标记。

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

Scope: content:read | 只读:

content_discard_draft

丢弃当前草稿,回退到最后一次已发布版本。仅适用于至少发布过一次的条目。

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

Scope: content:write | 破坏性:

content_list_trashed

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

参数类型必填说明
collectionstring集合 slug
limitinteger最大条数(1–100,默认 50)
cursorstring分页游标

Scope: content:read | 只读:

content_duplicate

复制已有内容项。副本以草稿创建,标题附加「(Copy)」,slug 自动生成。

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

Scope: content:write

content_translations

获取某内容项在各语言区域下的变体。返回翻译分组及每个语言版本的摘要。仅在启用 i18n 时有效。

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

Scope: content:read | 只读:

结构(Schema)工具

schema_list_collections

列出 CMS 中定义的全部内容集合。返回 slug、标签、支持的能力与时间戳。

无参数。

Scope: schema:read | 最低角色: 编辑 | 只读:

schema_get_collection

获取集合详情,含全部字段定义。字段描述数据模型:名称、类型、约束与校验规则。用于理解 content_createcontent_update 的预期。

参数类型必填说明
slugstring集合 slug(如 posts

Scope: schema:read | 最低角色: 编辑 | 只读:

schema_create_collection

新建内容集合。会创建数据库表与结构定义。slug 须为小写字母数字加下划线,且以字母开头。

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

Scope: schema:write | 最低角色: 管理员

schema_delete_collection

删除集合及其数据库表。不可逆,会删除集合内全部内容。

参数类型必填说明
slugstring要删除的集合 slug
forceboolean若集合仍有内容是否仍强制删除

Scope: 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 中。

Scope: schema:write | 最低角色: 管理员

schema_delete_field

从集合移除字段。会删除列及该列全部数据。不可逆。

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

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

媒体工具

media_list

列出已上传的媒体文件,支持按 MIME 类型前缀筛选与分页。

参数类型必填说明
mimeTypestringMIME 类型前缀(如 image/application/pdf
limitinteger最大条数(1–100,默认 50)
cursorstring分页游标

Scope: media:read | 只读:

media_create

登记已上传到存储的媒体文件。调用方须负责将文件放到 storageKey(通常使用管理后台或独立 API 返回的签名上传 URL)。该工具持久化元数据,使文件可通过 media_list / media_get 发现并被内容引用。

参数类型必填说明
filenamestring原始文件名(如 logo.png
mimeTypestringMIME 类型(如 image/png
storageKeystring文件在存储中的路径/键
sizeinteger文件大小(字节)
widthinteger图片宽度(像素)
heightinteger图片高度(像素)
contentHashstring内容哈希(去重用)
blurhashstring图片占位用 Blurhash
dominantColorstring主色十六进制色值

Scope: media:write | 最低角色: 作者

media_get

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

参数类型必填说明
idstring媒体项 ID

Scope: media:read | 只读:

media_update

更新已上传媒体文件的元数据。文件二进制不可更换。

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

Scope: media:write

media_delete

永久删除媒体文件:删除数据库记录与存储中的文件。引用该媒体的内容将出现坏链。

参数类型必填说明
idstring媒体项 ID

Scope: media:write | 破坏性:

搜索工具

跨内容集合全文搜索。集合的 supports 须包含 search,且字段须标记为 searchable

参数类型必填说明
querystring搜索关键词
collectionsstring[]仅搜索指定集合 slug
localestring按语言区域筛选结果
limitinteger最大结果数(1–50,默认 20)

Scope: content:read | 只读:

分类法工具

taxonomy_list

列出全部分类法定义(如分类、标签)。返回名称、标签、是否层级式及关联集合。

无参数。

Scope: content:read | 只读:

taxonomy_list_terms

分页列出某分类法下的词条。

参数类型必填说明
taxonomystring分类法名称(如 categoriestags
limitinteger最大条数(1–100,默认 50)
cursorstring分页游标

Scope: content:read | 只读:

taxonomy_create_term

在分类法下新建词条。层级式分类法可指定 parentId 创建子项。父级祖先链深度不得超过 100 层。

参数类型必填说明
taxonomystring分类法名称
slugstringURL 安全标识
labelstring显示名称
parentIdstring父词条 ID(层级式分类法)
descriptionstring词条说明

Scope: taxonomies:manage | 最低角色: 编辑

taxonomy_update_term

更新分类法中已有词条。可省略字段以保持原值。重命名 slug 不得与同分类法下其他词条冲突。将 parentId 设为 null 可脱离父级。新父级须存在、同属该分类法,且不得产生环。

参数类型必填说明
taxonomystring分类法名称
termSlugstring待更新词条的当前 slug
slugstring新 slug(在分类法内唯一)
labelstring新显示名称
parentIdstring | null新父词条 ID;null 表示脱离父级
descriptionstring新说明

Scope: taxonomies:manage | 最低角色: 编辑

taxonomy_delete_term

从分类法永久删除词条。曾打上该标签的内容将失去关联。若词条仍有子项则不可删——须先删除子项。

参数类型必填说明
taxonomystring分类法名称
termSlugstring要删除词条的 slug

Scope: taxonomies:manage | 最低角色: 编辑 | 破坏性:

菜单工具

列出全部导航菜单。返回名称、标签与时间戳。

无参数。

Scope: content:read | 只读:

按名称获取菜单及其有序条目。条目含标签、URL、类型及可选父级以支持嵌套。

参数类型必填说明
namestring菜单名称(如 mainfooter

Scope: content:read | 只读:

新建导航菜单。name 为站点模板使用的稳定标识;label 为管理后台展示名。条目稍后通过 menu_set_items 添加。

参数类型必填说明
namestring稳定标识(/^[a-z][a-z0-9_]*$/
labelstring管理后台显示名称

Scope: menus:manage | 最低角色: 编辑

更新菜单的标签。稳定标识 name 不可改。

参数类型必填说明
namestring要更新的菜单名称
labelstring新显示标签

Scope: menus:manage | 最低角色: 编辑

删除菜单及其全部条目。不可恢复。

参数类型必填说明
namestring要删除的菜单名称

Scope: menus:manage | 最低角色: 编辑 | 破坏性:

单次调用替换菜单的全部条目。原子操作:先删旧条目,再按给定顺序插入新列表。比逐条增删更清晰,顺序与父子关系明确。

条目位置由数组下标决定。嵌套通过 parentIndex 表达——parentIndex: 0 表示嵌套在索引 0 的条目下。父项须出现在列表更前位置。无 parentIndex 的为顶级项。

参数类型必填说明
namestring要更新的菜单名称
itemsMenuItem[]有序菜单条目列表(见下)

每个 MenuItem 字段:

字段类型必填说明
labelstring显示文本
typestringcustompageposttaxonomycollection 之一
customUrlstringtype: "custom" 时的 URL(其他类型忽略)
referenceCollectionstring内容引用目标集合 slug
referenceIdstring引用目标内容/词条 ID
titleAttrstringHTML title 属性
targetstringHTML target(如 _blank
cssClassesstring空格分隔的 CSS 类名
parentIndexinteger父条目在数组中的索引;顶级项省略

Scope: menus:manage | 最低角色: 编辑

修订工具

revision_list

列出内容项的修订历史,新的在前。集合须启用 revisions

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

Scope: content:read | 只读:

revision_restore

将内容项恢复到某次修订:用指定修订的数据替换当前草稿。不会自动发布——需要时请再调用 content_publish

参数类型必填说明
revisionIdstring要恢复的修订 ID

Scope: content:write

设置工具

站点级设置——标题、标语、Logo、网站图标、规范 URL、默认分页大小、日期与时间格式、社交账号及 SEO 默认值等。

settings_get

获取全部站点级设置。媒体引用(logofaviconseo.defaultOgImage)在返回中含解析后的 URL 及底层 mediaId。未设置的值不出现在响应中。

无参数。

Scope: settings:read | 最低角色: 编辑 | 只读:

settings_update

更新一项或多项站点级设置。部分更新:仅修改提供的字段;未提供的保持不变。返回更新后的完整设置对象。

设置媒体引用(logofaviconseo.defaultOgImage)时传入带 mediaId(及可选 alt)的对象。媒体项须已存在——请先 media_create

参数类型必填说明
titlestring站点标题
taglinestring标题旁简短描述
logoMediaRefLogo 媒体引用({ mediaId, alt? }
faviconMediaRef网站图标媒体引用
urlstring站点规范 URL(http 或 https)。空字符串表示清空。
postsPerPageinteger内容列表默认每页条数(1–100)
dateFormatstring日期格式占位串
timezonestringIANA 时区标识
socialobject社交账号——twittergithubfacebookinstagramlinkedinyoutube
seoobjectSEO 默认值(见下)

seo 对象字段:

字段类型说明
titleSeparatorstring页面标题与站点标题之间的分隔符(如 " | " 表示竖线)
defaultOgImageMediaRef内容无图时的默认 Open Graph 图片
robotsTxtstring自定义 robots.txt 正文。省略则使用 EmDash 默认。
googleVerificationstringGoogle Search Console 验证令牌
bingVerificationstringBing 网站管理员工具验证令牌

Scope: settings:manage | 最低角色: 管理员

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

授权服务器元数据

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

当未经认证的请求命中 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
}

Scope 与权限错误以 MCP 协议错误形式抛出:

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

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