EmDash 包含一个内置的 Model Context Protocol(MCP)服务器,位于 /_emdash/api/mcp,将内容管理操作作为工具暴露给 AI 助手。
本页涵盖协议详情:身份验证、传输、工具规范、OAuth 发现和错误处理。
身份验证
MCP 服务器支持三种身份验证方式:
| 方式 | 工作原理 |
|---|---|
| OAuth 2.1 Authorization Code + PKCE | MCP 客户端的标准流程。用户在浏览器中批准范围。 |
| 个人访问令牌(PAT) | 在管理面板中创建的长期有效 ec_pat_* 令牌。 |
| 设备流 | CLI 风格的流程,您在浏览器中批准代码。由 emdash login 使用。 |
会话 Cookie(来自管理 UI)也可以使用,但对外部 MCP 客户端不实用。
范围
令牌的范围限制客户端可以执行的操作。范围在 OAuth 授权期间请求,并在每次工具调用时强制执行。在授权码同意页面上,默认选择所有请求的范围以保持兼容性;用户可以在批准前移除范围,但不能添加客户端未请求的范围。有效授权还受客户端已注册范围和用户角色的限制,EmDash 拒绝空授权。
| 范围 | 授予访问权限 |
|---|---|
content:read | 列出、获取、比较和搜索内容。列出分类法、分类法术语和菜单。 |
content:write | 创建、更新、删除、发布、取消发布、安排、取消安排、复制和恢复内容。为向后兼容隐式授予 taxonomies:manage 和 menus:manage。 |
media:read | 列出和获取媒体项。 |
media:write | 注册(创建)、更新和删除媒体元数据。 |
schema:read | 列出集合和获取集合 schema。 |
schema:write | 创建、更新和删除集合和字段。 |
taxonomies:manage | 创建、更新和删除分类法术语。 |
menus:manage | 创建、更新和删除导航菜单及其项目。 |
settings:read | 读取站点范围的设置。 |
settings:manage | 更新站点范围的设置。 |
mcp:tools | 调用任何插件中显式启用的 MCP 工具。 |
mcp:tools:<pluginId> | 调用一个插件中显式启用的 MCP 工具。 |
admin | 所有操作的完全访问权限。 |
admin 范围授予核心操作的访问权限,但不授予插件 MCP 访问权限。插件工具始终需要 mcp:tools 或匹配的插件特定范围。基于会话的身份验证根据用户角色和插件的显式管理员启用来确定访问权限。
content:write 隐式授予 taxonomies:manage 和 menus:manage,因此在这些范围拆分之前发放的个人访问令牌无需重新发放即可继续使用。新令牌应请求细粒度范围。
角色要求
除了范围之外,某些工具还需要最低的 RBAC 角色。两者都必须满足——即使令牌拥有正确的范围,如果调用用户的角色过低也会失败。
插件工具使用其底层路由声明的权限。在管理员启用该插件的 MCP 表面之前,它们不会出现在 tools/list 中。工具名称使用确定性的 <pluginId>__<localName> 形式,调用记录在审计日志中,包含插件、工具、路由和操作者来源。
| 操作 | 最低角色 |
|---|---|
| 内容读取 | 订阅者(10)用于已发布项目;贡献者(20)用于草稿、已安排、回收站和修订版本 |
| 内容创建 | 贡献者(20) |
| 编辑/删除自己的内容 | 作者(30) |
| 内容发布 | 作者(30)用于自己的项目;编辑者(40)用于操作他人的项目 |
| Schema 读取 | 编辑者(40) |
| Schema 写入 | 管理员(50) |
| 分类法管理 | 编辑者(40) |
| 菜单管理 | 编辑者(40) |
| 设置读取 | 编辑者(40) |
| 设置管理 | 管理员(50) |
媒体上传(media_upload) | 贡献者(20) |
媒体注册(media_create) | 作者(30) |
| 媒体使用修复 | 管理员(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 特定码。
工具
服务器跨八个领域暴露工具:内容、schema、媒体、搜索、分类法、菜单、修订版本和设置。每个工具以 JSON 文本内容返回结果,失败时返回带有 isError: true 的错误消息。
内容工具
content_list
列出集合中的内容项,支持可选的过滤和分页。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug(例如 posts、pages) |
status | string | 否 | 过滤:draft、published 或 scheduled |
limit | integer | 否 | 最大返回项数(1-100,默认 50) |
cursor | string | 否 | 来自上一响应的分页游标 |
orderBy | string | 否 | 排序字段(例如 created_at、updated_at) |
order | string | 否 | 排序方向:asc 或 desc(默认 desc) |
locale | string | 否 | 按语言区域过滤(例如 en、fr)。仅在 i18n 时相关。 |
范围: content:read | 只读: 是
content_get
按 ID 或 slug 获取单个内容项。返回所有字段值、元数据和 _rev 令牌。content_update、content_publish、content_unpublish 和 content_discard_draft 需要该令牌,因此在调用它们之前先在这里读取项目。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 内容项 ID(ULID)或 slug |
locale | string | 否 | 用于 slug 查找的语言区域。ID 是全局唯一的。 |
范围: content:read | 只读: 是
content_create
创建新的内容项。data 对象应包含与集合 schema 匹配的字段值——使用 schema_get_collection 检查可用字段。默认创建为 draft。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
data | object | 是 | 键值对形式的字段值 |
slug | string | 否 | URL slug(省略时从标题自动生成) |
status | string | 否 | 初始状态:draft 或 published(默认 draft) |
locale | string | 否 | 此内容的语言区域(默认为站点默认值) |
translationOf | string | 否 | 此项是其翻译的项目 ID |
范围: content:write
content_update
更新现有内容项。仅包含要更改的字段——未指定的字段保持不变。当未设置 status 时,对已发布项目的更改作为草稿暂存:响应显示新值,而实时版本保持旧值直到 content_publish。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 内容项 ID 或 slug |
data | object | 否 | 要更新的字段值 |
slug | string | 否 | 新 URL slug |
status | string | 否 | 新状态:draft 或 published |
_rev | string | 是 | 来自 content_get 的修订令牌。如果项目在该读取后已更改,更新将因冲突而失败。 |
范围: content:write
content_delete
通过移至回收站软删除内容项。使用 content_restore 撤销,或 content_permanent_delete 永久删除。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 内容项 ID 或 slug |
范围: content:write | 破坏性: 是
content_restore
从回收站恢复软删除的内容项。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 内容项 ID 或 slug |
范围: content:write
content_permanent_delete
永久且不可逆地删除已回收的内容项。项目必须先在回收站中。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 内容项 ID 或 slug |
范围: content:write | 破坏性: 是
content_publish
发布内容项,使其在站点上可见。从当前草稿创建已发布的修订版本。后续编辑创建新草稿而不影响实时版本,直到重新发布。不带 publishedAt 重新发布会重用保留的发布日期。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 内容项 ID 或 slug |
publishedAt | string | 否 | ISO 8601 发布日期。设置它需要 content:publish_any。 |
_rev | string | 是 | 来自 content_get 的修订令牌。如果项目在该读取后已更改,调用将因冲突而失败。 |
范围: content:write
content_unpublish
将已发布的项目恢复为草稿状态。它将不再在实时站点上可见,但其内容和发布日期会被保留。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 内容项 ID 或 slug |
_rev | string | 是 | 来自 content_get 的修订令牌。如果项目在该读取后已更改,调用将因冲突而失败。 |
范围: content:write
content_schedule
安排内容项在未来发布。它将在指定的日期/时间自动发布。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 内容项 ID 或 slug |
scheduledAt | string | 是 | ISO 8601 日期时间(例如 2026-06-01T09:00:00Z) |
范围: content:write
content_unschedule
取消先前安排的发布。项目保持其当前状态;仅清除 scheduledAt 时间戳。幂等——对未安排的项目调用是无操作的。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 内容项 ID 或 slug |
范围: content:write
content_compare
比较内容项的已发布(实时)版本与其当前草稿。返回两个版本和一个指示是否有更改的标志。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 内容项 ID 或 slug |
范围: content:read | 只读: 是
content_discard_draft
丢弃当前草稿并恢复到最后的已发布版本。仅适用于至少发布过一次的项目。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 内容项 ID 或 slug |
_rev | string | 是 | 来自 content_get 的修订令牌。如果项目在该读取后已更改,调用将因冲突而失败。 |
范围: content:write | 破坏性: 是
content_list_trashed
列出集合回收站中软删除的内容项。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
limit | integer | 否 | 最大项数(1-100,默认 50) |
cursor | string | 否 | 分页游标 |
范围: content:read | 只读: 是
content_duplicate
创建现有内容项的副本。副本创建为草稿,标题附加”(Copy)“并自动生成 slug。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 要复制的内容项 ID 或 slug |
范围: content:write
content_translations
获取内容项的所有语言区域变体。返回翻译组和每个语言区域版本的摘要。仅在启用 i18n 时相关。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 内容项 ID 或 slug |
范围: content:read | 只读: 是
Schema 工具
schema_list_collections
列出 CMS 中定义的所有内容集合。返回 slug、标签、支持的特性和时间戳。
无参数。
范围: schema:read | 最低角色: 编辑者 | 只读: 是
schema_get_collection
获取集合的详细信息,包括所有字段定义。字段描述数据模型:名称、类型、约束和验证规则。使用此工具了解 content_create 和 content_update 期望的内容。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
slug | string | 是 | 集合 slug(例如 posts) |
范围: schema:read | 最低角色: 编辑者 | 只读: 是
schema_create_collection
创建新的内容集合。这会创建数据库表和 schema 定义。slug 必须是以字母开头的小写字母数字和下划线。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
slug | string | 是 | 唯一标识符(/^[a-z][a-z0-9_]*$/) |
label | string | 是 | 显示名称(复数,例如 “Blog Posts”) |
labelSingular | string | 否 | 单数显示名称 |
description | string | 否 | 此集合的描述 |
icon | string | 否 | 管理 UI 的图标名称 |
supports | string[] | 否 | 特性:drafts、revisions、preview、scheduling、search、seo(默认:['drafts', 'revisions']) |
范围: schema:write | 最低角色: 管理员
schema_update_collection
更新现有集合而不删除其表、字段或内容。仅更改提供的设置;省略的设置保持当前值。集合 slug 不能更改。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
slug | string | 是 | 要更新的集合 slug |
label | string | 否 | 新的复数显示名称 |
labelSingular | string | 否 | 新的单数显示名称 |
description | string | 否 | 新的集合描述 |
icon | string | 否 | 新的管理 UI 图标名称 |
supports | string[] | 否 | 要启用的完整特性列表;省略保持当前列表 |
urlPattern | string | null | 否 | 新的公共 URL 模式;null 清除它 |
hasSeo | boolean | 否 | 集合是否支持 SEO 元数据 |
commentsEnabled | boolean | 否 | 是否启用评论 |
commentsModeration | string | 否 | 审核策略:all、first_time 或 none |
commentsClosedAfterDays | integer | 否 | 在此天数后关闭评论;0 保持开放 |
commentsAutoApproveUsers | boolean | 否 | 自动批准来自已认证用户的评论 |
范围: schema:write | 最低角色: 管理员
schema_delete_collection
删除集合及其数据库表。这是不可逆的,会删除集合中的所有内容。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
slug | string | 是 | 要删除的集合 slug |
force | boolean | 否 | 即使集合有内容也强制删除 |
范围: schema:write | 最低角色: 管理员 | 破坏性: 是
schema_create_field
向集合的 schema 添加新字段。这会向数据库表添加列。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
slug | string | 是 | 字段标识符(/^[a-z][a-z0-9_]*$/) |
label | string | 是 | 显示名称 |
type | string | 是 | 数据类型(见下文) |
required | boolean | 否 | 该字段是否必需 |
unique | boolean | 否 | 值是否必须唯一 |
defaultValue | any | 否 | 新项目的默认值 |
validation | object | 否 | 约束:min、max、minLength、maxLength、pattern、options |
options | object | 否 | 小部件配置:collection(用于引用)、rows(用于文本区域) |
searchable | boolean | 否 | 包含在全文搜索索引中 |
indexed | boolean | 否 | 启用按此字段的索引排序 |
translatable | boolean | 否 | 该字段是否可翻译(默认 true) |
字段类型:string、text、number、integer、boolean、datetime、select、multiSelect、portableText、image、file、reference、json、slug。
对于 select 和 multiSelect 类型,在 validation.options 中提供允许的值。
范围: schema:write | 最低角色: 管理员
schema_update_field
更新现有字段而不删除其列或存储的值。仅更改提供的设置;省略的设置保持当前值。string、text 和 slug 可以相互更改。需要内容或列迁移的其他类型更改和设置会被拒绝并提供迁移指引。无效的正则表达式和矛盾的验证范围在任何 schema 元数据更改之前被拒绝。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 包含该字段的集合 |
fieldSlug | string | 是 | 要更新的字段 slug |
label | string | 否 | 新显示名称 |
type | string | 否 | 新字段类型;只有 string、text 和 slug 别名可以就地更改 |
required | boolean | 否 | 该字段是否必需;更改需要手动内容迁移 |
unique | boolean | 否 | 字段值是否必须唯一;更改需要手动内容迁移 |
defaultValue | any | 否 | 新内容的默认值 |
validation | object | null | 否 | 验证约束;null 清除它们 |
widget | string | 否 | 管理编辑器小部件名称 |
options | object | 否 | 小部件配置 |
sortOrder | integer | 否 | 内容编辑器中的字段顺序 |
searchable | boolean | 否 | 全文搜索是否索引该字段 |
indexed | boolean | 否 | 创建或移除用于结构化排序的物理索引 |
translatable | boolean | 否 | 值是否因语言区域而异;更改为 false 需要手动内容迁移 |
范围: schema:write | 最低角色: 管理员
schema_delete_field
从集合中移除字段。这会删除列和该字段中的所有数据。不可逆。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
fieldSlug | string | 是 | 要移除的字段 slug |
范围: schema:write | 最低角色: 管理员 | 破坏性: 是
媒体工具
media_list
列出已上传的媒体文件,支持可选的 MIME 类型过滤和分页。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
mimeType | string | 否 | 按 MIME 类型前缀过滤(例如 image/、application/pdf) |
limit | integer | 否 | 最大项数(1-100,默认 50) |
cursor | string | 否 | 分页游标 |
范围: media:read | 只读: 是
media_upload
从 base64 编码数据或外部 URL 上传媒体文件并在媒体库中注册。返回带有 id、storageKey 和 url 的媒体项——可通过 content_create / content_update 直接从内容字段(例如 featured_image)引用。
上传通过内容哈希去重:重新上传相同字节返回带有 deduplicated: true 的现有项。图片上传自动丰富尺寸、blurhash 占位符和主色调。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
filename | string | 是 | 包含扩展名的文件名(例如 cover.png) |
base64 | string | base64 / url 二选一 | Base64 编码的文件内容 |
url | string | base64 / url 二选一 | 获取文件的公共 http(s) URL |
contentType | string | 使用 base64 时需要 | MIME 类型(例如 image/png)。使用 url 时默认为响应的 Content-Type 头。 |
alt | string | 否 | 无障碍替代文本 |
范围: media:write | 最低角色: 贡献者
media_create
注册已上传到存储的媒体文件。调用者负责将文件放置在 storageKey(通常使用来自管理 UI 或单独 API 的签名上传 URL)。此工具持久化元数据记录,使文件可通过 media_list / media_get 发现并被内容引用。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
filename | string | 是 | 原始文件名(例如 logo.png) |
mimeType | string | 是 | MIME 类型(例如 image/png) |
storageKey | string | 是 | 文件上传到的存储路径/键 |
size | integer | 否 | 文件大小(字节) |
width | integer | 否 | 图片宽度(像素) |
height | integer | 否 | 图片高度(像素) |
contentHash | string | 否 | 文件内容的哈希(用于去重) |
blurhash | string | 否 | 图片占位符的 Blurhash |
dominantColor | string | 否 | 图片主色调的十六进制颜色字符串 |
范围: media:write | 最低角色: 作者
media_get
按 ID 获取单个媒体文件的详情。返回元数据,包括文件名、MIME 类型、大小、尺寸、替代文本和 URL。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
id | string | 是 | 媒体项 ID |
范围: media:read | 只读: 是
media_update
更新已上传媒体文件的元数据。文件本身不能更改。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
id | string | 是 | 媒体项 ID |
alt | string | 否 | 无障碍替代文本 |
caption | string | 否 | 标题文本 |
width | integer | 否 | 图片宽度(像素) |
height | integer | 否 | 图片高度(像素) |
范围: media:write
media_delete
永久删除媒体文件。从数据库和存储中移除记录和文件。引用此媒体的内容将出现断开的引用。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
id | string | 是 | 媒体项 ID |
范围: media:write | 破坏性: 是
media_usage_repair
修复一个集合或所有集合的内容媒体使用索引。修复同步运行,在大型站点上可能很慢或开销大;尽可能使用集合范围。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
scope | "collection" | "all" | 是 | 修复一个集合还是所有集合 |
collection | string | 集合范围时需要 | 集合 slug;scope 为 all 时省略 |
结果有 complete、partial、failed 或 stale 的结构化 status,加上聚合和每集合的源计数。所有四种状态都是成功的 MCP 工具结果,因此调用者必须检查 status 而不是依赖 isError。身份验证、验证或意外修复错误返回 isError: true。
范围: admin | 最低角色: 管理员
搜索工具
search
跨内容集合的全文搜索。集合必须在其 supports 列表中包含 search,字段必须标记为 searchable。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
query | string | 是 | 搜索查询文本 |
collections | string[] | 否 | 限制搜索到特定集合 slug |
locale | string | 否 | 按语言区域过滤结果 |
limit | integer | 否 | 最大结果数(1-50,默认 20) |
范围: content:read | 只读: 是
分类法工具
taxonomy_list
列出所有分类法定义(例如 categories、tags)。返回名称、标签、是否层级化和关联的集合。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
locale | string | 否 | 按语言区域过滤(省略则列出所有语言区域变体) |
范围: content:read | 只读: 是
taxonomy_get
按名称获取单个分类法定义。返回名称、标签、单数标签、是否层级化、关联的集合、语言区域和翻译组。传入 locale 以解析特定翻译。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
name | string | 是 | 分类法名称(例如 categories、tags) |
locale | string | 否 | 要解析定义的语言区域 |
范围: content:read | 只读: 是
taxonomy_create
创建新的分类法定义。定义是按语言区域的;当同一分类法名称存在于多个翻译中时传入 locale。collections 命名此分类法适用于哪些内容类型。如果设置了 translationOf,新定义加入源的翻译组,并在省略时从源继承 hierarchical 和 collections。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
name | string | 是 | 分类法名称(/^[a-z][a-z0-9_]*$/) |
label | string | 是 | 显示名称 |
labelSingular | string | 否 | 单数显示名称 |
hierarchical | boolean | 否 | 术语是否支持父/子关系 |
collections | string[] | 否 | 此分类法适用的集合 slug |
locale | string | 否 | 此定义的语言区域(例如 fr-fr) |
translationOf | string | 否 | 从其创建此语言区域变体的现有分类法 ID |
范围: taxonomies:manage | 最低角色: 编辑者
taxonomy_update
更新现有的分类法定义。分类法 name 不能更改。传入 locale 以更新特定翻译;否则更新最低匹配的语言区域。任何字段都可以省略以保持不变。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
name | string | 是 | 要更新的分类法名称 |
label | string | 否 | 新显示名称 |
labelSingular | string | null | 否 | 新单数显示名称;null 清除 |
hierarchical | boolean | 否 | 术语是否支持父/子关系 |
collections | string[] | 否 | 此分类法适用的集合 slug |
locale | string | 否 | 要更新的定义的语言区域 |
范围: taxonomies:manage | 最低角色: 编辑者
taxonomy_delete
删除分类法定义及其在所有语言区域中的所有术语,以及这些术语持有的任何内容分配。这不能撤消。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
name | string | 是 | 要删除的分类法名称 |
范围: taxonomies:manage | 最低角色: 编辑者 | 破坏性: 是
taxonomy_list_terms
分页列出分类法中的术语。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
taxonomy | string | 是 | 分类法名称(例如 categories、tags) |
limit | integer | 否 | 最大项数(1-100,默认 50) |
cursor | string | 否 | 分页游标 |
范围: content:read | 只读: 是
taxonomy_create_term
在分类法中创建新术语。对于层级分类法,指定 parentId 以创建子术语。父级的祖先链不得超过 100 层。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
taxonomy | string | 是 | 分类法名称 |
slug | string | 是 | URL 安全标识符 |
label | string | 是 | 显示名称 |
parentId | string | 否 | 父术语 ID(用于层级分类法) |
description | string | 否 | 术语描述 |
范围: taxonomies:manage | 最低角色: 编辑者
taxonomy_update_term
更新分类法中的现有术语。任何字段都可以省略以保持不变。重命名 slug 不得与同一分类法中的另一个术语冲突。将 parentId 设为 null 以从父级分离。新父级必须存在、属于同一分类法且不引入循环。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
taxonomy | string | 是 | 分类法名称 |
termSlug | string | 是 | 要更新的术语的当前 slug |
slug | string | 否 | 新 slug(在分类法中必须唯一) |
label | string | 否 | 新显示名称 |
parentId | string | null | 否 | 新父术语 ID;null 分离 |
description | string | 否 | 新描述 |
范围: taxonomies:manage | 最低角色: 编辑者
taxonomy_delete_term
从分类法中永久删除术语。标记了该术语的任何内容都会失去关联。不能删除有子级的术语——先删除子级。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
taxonomy | string | 是 | 分类法名称 |
termSlug | string | 是 | 要删除的术语的 slug |
范围: taxonomies:manage | 最低角色: 编辑者 | 破坏性: 是
菜单工具
menu_list
列出导航菜单。菜单是按语言区域的:传入 locale 只返回一个语言区域的行,或省略列出所有语言区域变体。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
locale | string | 否 | 按语言区域过滤(省略则列出所有语言区域变体) |
范围: content:read | 只读: 是
menu_get
按名称获取菜单,包括其所有按顺序排列的项目。项目有标签、URL、类型和可选的父级用于嵌套。当同名菜单存在于多个语言区域时,传入 locale 以解析预期的翻译。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
name | string | 是 | 菜单名称(例如 main、footer) |
locale | string | 否 | 要解析菜单的语言区域 |
范围: content:read | 只读: 是
menu_create
创建新的导航菜单。name 是站点模板使用的稳定标识符;label 是管理面板中显示的人类可读名称。菜单是按语言区域的,当同名菜单存在于多个翻译中时传入 locale。之后使用 menu_set_items 添加项目。如果设置了 translationOf,则还必须设置 locale。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
name | string | 是 | 稳定标识符(/^[a-z][a-z0-9_]*$/) |
label | string | 是 | 管理面板的显示名称 |
locale | string | 否 | 此菜单的语言区域(例如 fr-fr) |
translationOf | string | 否 | 从其创建此语言区域变体的现有菜单 ID |
范围: menus:manage | 最低角色: 编辑者
menu_update
更新菜单的标签。name(稳定标识符)不能更改。在多语言区域安装中,传入 locale 以更新正确的翻译。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
name | string | 是 | 要更新的菜单名称 |
label | string | 是 | 新显示标签 |
locale | string | 否 | 要更新的菜单的语言区域 |
范围: menus:manage | 最低角色: 编辑者
menu_delete
删除菜单及其所有项目。不能撤消。在多语言区域安装中,传入 locale 以仅移除预期的翻译。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
name | string | 是 | 要删除的菜单名称 |
locale | string | 否 | 要删除的菜单的语言区域 |
范围: menus:manage | 最低角色: 编辑者 | 破坏性: 是
menu_set_items
在一次调用中替换菜单的整个项目列表。原子操作:现有项目被删除,新列表按提供的顺序插入。使用此工具而非逐项添加/移除操作,以确保结果顺序和父级链接明确。在多语言区域安装中,传入 locale 以仅重写预期的翻译。
项目按数组索引定位。嵌套通过 parentIndex 表达——parentIndex: 0 的项目嵌套在索引 0 处的项目下。父级必须在列表中较早出现。没有 parentIndex 的项目是顶级的。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
name | string | 是 | 要更新的菜单名称 |
locale | string | 否 | 要重写的菜单的语言区域 |
items | MenuItem[] | 是 | 有序的菜单项列表(见下文) |
每个 MenuItem 有:
| 字段 | 类型 | 必需 | 描述 |
|---|---|---|---|
label | string | 是 | 项目显示文本 |
type | string | 是 | custom、page、post、taxonomy、collection 之一 |
customUrl | string | 否 | type: "custom" 项目的 URL(否则忽略) |
referenceCollection | string | 否 | 内容引用的目标集合 slug |
referenceId | string | 否 | 引用的目标内容/术语 ID |
titleAttr | string | 否 | HTML title 属性 |
target | string | 否 | HTML target 属性(例如 _blank) |
cssClasses | string | 否 | 空格分隔的 CSS 类 |
parentIndex | integer | 否 | 父项目的数组索引。顶级项目省略。 |
范围: menus:manage | 最低角色: 编辑者
修订版本工具
revision_list
列出内容项的修订历史,最新的排在前面。需要集合支持 revisions。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 内容项 ID 或 slug |
limit | integer | 否 | 最大修订数(1-50,默认 20) |
范围: content:read | 只读: 是
revision_restore
将内容项恢复到先前的修订版本。用指定修订版本的数据替换当前草稿。不会自动发布——如果需要,之后使用 content_publish。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
revisionId | string | 是 | 要恢复到的修订版本 ID |
范围: content:write
设置工具
站点范围的设置——标题、标语、logo、favicon、规范 URL、默认页面大小、日期和时间格式、社交账号和 SEO 默认值。
settings_get
获取所有站点范围的设置。媒体引用(logo、favicon、seo.defaultOgImage)包含解析后的 URL 和底层的 mediaId。未设置的值从响应中省略。
无参数。
范围: settings:read | 最低角色: 编辑者 | 只读: 是
settings_update
更新一个或多个站点范围的设置。部分更新:仅更改提供的字段;省略的字段保持不变。更新后返回完整的设置对象。
要设置媒体引用(logo、favicon、seo.defaultOgImage),传入带有 mediaId(和可选 alt)的对象。媒体项必须已存在——先使用 media_create。
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
title | string | 否 | 站点标题 |
tagline | string | 否 | 与标题一起显示的简短描述 |
logo | MediaRef | 否 | Logo 媒体引用({ mediaId, alt? }) |
favicon | MediaRef | 否 | Favicon 媒体引用 |
url | string | 否 | 规范站点 URL(http 或 https)。空字符串清除它。 |
postsPerPage | integer | 否 | 内容列表的默认页面大小(1-100) |
dateFormat | string | 否 | 日期格式令牌字符串 |
timezone | string | 否 | IANA 时区标识符 |
social | object | 否 | 社交账号——twitter、github、facebook、instagram、linkedin、youtube |
seo | object | 否 | SEO 默认值(见下文) |
seo 对象接受:
| 字段 | 类型 | 描述 |
|---|---|---|
titleSeparator | string | 页面标题和站点标题之间的分隔符(例如 " | " 用于竖线) |
defaultOgImage | MediaRef | 内容没有 OG 图片时的默认 Open Graph 图片 |
robotsTxt | string | 自定义 robots.txt 内容。省略使用 EmDash 默认值。 |
googleVerification | string | Google Search Console 验证令牌 |
bingVerification | string | Bing Webmaster Tools 验证令牌 |
范围: settings:manage | 最低角色: 管理员
OAuth 发现
大多数 MCP 客户端会为您处理这些;本节适用于直接针对 EmDash 构建 MCP 客户端。支持 OAuth 2.1 的客户端从服务器发布的两个元数据文档中发现如何进行身份验证:
受保护资源元数据
在以下端点请求受保护资源元数据:
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 的文本内容返回。消息以稳定的 [CODE] 为前缀,相同的代码在 _meta.code 中重复:
{
"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" }
}
传输层错误(服务器配置错误、未处理的异常)返回 JSON-RPC 错误码 -32603(内部错误),不泄露实现细节。