MCP 服务器参考

本页内容

EmDash 在 /_emdash/api/mcp 提供内置 Model Context Protocol(MCP)服务器。MCP 客户端通过它读取和管理内容、署名、架构、媒体、分类法、菜单、修订和设置,并导出或导入整个站点。

认证

MCP 端点需要 Bearer 令牌。EmDash 支持以下令牌流程:

方式用途
OAuth 2.1 Authorization Code with Proof Key for Code Exchange (PKCE)交互式 MCP 客户端。用户在浏览器中批准请求的 scope。
Personal access token面向客户端或自动化的长期访问。令牌使用 ec_pat_ 前缀,在管理后台创建。
OAuth 2.0 Device Authorization Grant命令行客户端,要求用户在浏览器中批准代码。emdash login 使用此流程。

会话 Cookie 不能用于认证 MCP 端点。

Scopes

OAuth 和个人访问令牌限制客户端可调用的工具。用户角色单独检查,因此 scope 不会授予用户没有的权限。

Scope访问
content:read读取和搜索内容、署名、分类法、术语、菜单和修订。类草稿内容还需要用户的 content:read_drafts 权限。
content:write创建和修改内容、署名和修订。为兼容现有令牌,还授予 taxonomies:manage 和 menus:manage。
media:read读取媒体记录。
media:write上传、注册、更新和删除媒体。
schema:read读取集合和字段。
schema:write创建、更新和删除集合和字段。
taxonomies:manage创建、更新和删除分类法定义和术语。
menus:manage创建、更新和删除菜单和菜单项。
settings:read读取站点设置。
settings:manage更新站点设置。
mcp:tools调用任何已启用插件暴露的 MCP 工具。
mcp:tools:<pluginId>调用某一已启用插件暴露的 MCP 工具。
transfer:export将整个站点导出为站点包并下载。
transfer:analyze上传站点包并分析以准备导入。
transfer:execute启动、推进、取消和放弃站点导入。
admin调用所有核心工具,包括站点转移工具。插件工具仍需要 mcp:tools 或插件专用 scope。

admin scope 包含 transfer:export、transfer:analyze 和 transfer:execute。每个转移 scope 仅授予自身操作,且需要管理员角色。若希望客户端(如智能体)在不导出或导入的情况下分析站点包,应授予 transfer:analyze 而非 admin。

授权码同意页允许用户移除请求的 scope。EmDash 还会将请求与客户端注册的 scope 和用户角色取交集,并拒绝空授权。

角色要求

下表列出各类能力的最低角色要求。当用户操作他人内容时,所有权检查可能要求更高角色。

能力最低角色
读取已发布内容、媒体、分类法、术语和菜单Subscriber
读取草稿、定时内容、回收站、对比和修订Contributor
创建内容或上传媒体Contributor
编辑或发布自己的内容并注册媒体Author
管理署名、分类法、菜单或所有用户的内容Editor
读取架构或设置Editor
修改架构或设置、永久删除内容或修复媒体使用Admin
导出或导入整个站点Admin

完整角色定义见用户角色。

传输

服务器使用无状态 Streamable HTTP。每个请求独立;服务器不保持 MCP 会话或 Server-Sent Events 连接。

方法端点行为
POST/_emdash/api/mcp接受 JSON-RPC 初始化、工具列表和工具调用。
GET/_emdash/api/mcp返回 405 Method Not Allowed。
DELETE/_emdash/api/mcp返回 405 Method Not Allowed。

响应使用 JSON-RPC 2.0。构造工具请求前请调用 tools/list 获取当前输入 schema 和 MCP 注解。

工具清单

以下清单与 tools/list 返回的静态工具一致。包含注册标题,因为客户端可能显示标题而非工具名。

内容工具

ToolRegistered titleRequired scope
content_listList Contentcontent:read
content_getGet Contentcontent:read
content_createCreate Contentcontent:write
content_updateUpdate Contentcontent:write
content_deleteDelete Content (Trash)content:write
content_restoreRestore Contentcontent:write
content_permanent_deletePermanently Delete Contentcontent:write
content_publishPublish Contentcontent:write
content_unpublishUnpublish Contentcontent:write
content_scheduleSchedule Contentcontent:write
content_unscheduleCancel Scheduled Publicationcontent:write
content_compareCompare Live vs Draftcontent:read
content_discard_draftDiscard Draftcontent:write
content_list_trashedList Trashed Contentcontent:read
content_duplicateDuplicate Contentcontent:write
content_translationsGet Content Translationscontent:read

署名工具

ToolRegistered titleRequired scope
byline_listList Bylinescontent:read
byline_getGet Bylinecontent:read
byline_createCreate Bylinecontent:write
byline_updateUpdate Bylinecontent:write
byline_deleteDelete Bylinecontent:write
byline_translationsList Byline Translationscontent:read

架构工具

ToolRegistered titleRequired scope
schema_list_collectionsList Collectionsschema:read
schema_get_collectionGet Collection Schemaschema:read
schema_list_block_typesList Block Typesschema:read
schema_get_block_typeGet Block Typeschema:read
schema_create_block_typeCreate Block Typeschema:write
schema_update_block_typeUpdate Block Typeschema:write
schema_activate_block_type_versionActivate Block Type Versionschema:write
schema_create_collectionCreate Collectionschema:write
schema_delete_collectionDelete Collectionschema:write
schema_update_collectionUpdate Collectionschema:write
schema_create_fieldAdd Field to Collectionschema:write
schema_delete_fieldRemove Field from Collectionschema:write
schema_update_fieldUpdate Fieldschema:write

媒体工具

ToolRegistered titleRequired scope
media_listList Mediamedia:read
media_createConfirm Signed Media Uploadmedia:write
media_uploadUpload Mediamedia:write
media_getGet Media Itemmedia:read
media_updateUpdate Media Metadatamedia:write
media_deleteDelete Mediamedia:write
media_usage_repairRepair Media Usage Indexadmin

搜索工具

ToolRegistered titleRequired scope
searchSearch Contentcontent:read

分类法工具

ToolRegistered titleRequired scope
taxonomy_listList Taxonomiescontent:read
taxonomy_getGet Taxonomy Definitioncontent:read
taxonomy_createCreate Taxonomy Definitiontaxonomies:manage
taxonomy_updateUpdate Taxonomy Definitiontaxonomies:manage
taxonomy_deleteDelete Taxonomy Definitiontaxonomies:manage
taxonomy_list_termsList Taxonomy Termscontent:read
taxonomy_create_termCreate Taxonomy Termtaxonomies:manage
taxonomy_update_termUpdate Taxonomy Termtaxonomies:manage
taxonomy_delete_termDelete Taxonomy Termtaxonomies:manage
taxonomy_term_translationsList Term Translationscontent:read

菜单工具

ToolRegistered titleRequired scope
menu_listList Menuscontent:read
menu_getGet Menu with Itemscontent:read
menu_translationsList Menu Translationscontent:read
menu_createCreate Menumenus:manage
menu_updateUpdate Menumenus:manage
menu_deleteDelete Menumenus:manage
menu_set_itemsSet Menu Itemsmenus:manage

修订工具

ToolRegistered titleRequired scope
revision_listList Revisionscontent:read
revision_restoreRestore Revisioncontent:write

设置工具

ToolRegistered titleRequired scope
settings_getGet Site Settingssettings:read
settings_updateUpdate Site Settingssettings:manage

站点转移工具

transfer:* 表示 transfer:export、transfer:analyze 或 transfer:execute 中的任意一个。admin scope 满足本表所有要求。

ToolRegistered titleRequired scope
site_transfer_capabilitiesGet Site Transfer Capabilitiestransfer:*
site_export_startStart Site Exporttransfer:export
site_export_statusGet Site Export Statustransfer:export
site_import_analyzeAnalyze Site Importtransfer:analyze
site_import_startStart Site Importtransfer:execute
site_import_statusGet Site Import Statustransfer:*
site_import_resumeResume Site Importtransfer:execute
site_import_receiptGet Site Import Receipttransfer:*

管理员批准请求时,site_export_start 和 site_import_start 也可接受无对应 scope 的令牌。对于已批准请求所启动的操作,site_export_status、site_import_status、site_import_resume 和 site_import_receipt 也可接受同一令牌且无需 scope。

使用工具 schema

tools/list 返回每个工具的描述、JSON 输入 schema 和注解。构造调用前请阅读这些元数据,以便客户端使用已安装 EmDash 版本支持的字段、允许值和限制。

例如,更新文章的客户端先调用 content_get 并保留返回的 _rev,然后可发送如下 JSON-RPC 请求:

{
	"jsonrpc": "2.0",
	"id": 2,
	"method": "tools/call",
	"params": {
		"name": "content_update",
		"arguments": {
			"collection": "articles",
			"id": "01JARTICLE0000000000000000",
			"data": { "title": "Updated title" },
			"_rev": "opaque-revision-token"
		}
	}
}

结果以 JSON 文本形式返回在第一个内容块中。带输出 schema 的工具还可能在 structuredContent 中返回相同值。

内容生命周期与署名

内容生命周期参考定义 MCP、REST、CLI 和管理后台共享的状态、修订、 权限、冲突和 hook 行为。

content_get 返回不透明的 _rev 值。将其传给 content_update、content_publish、content_unpublish、content_schedule 或 content_discard_draft。过期值会返回冲突,重试前请重新读取条目。

content_update 为部分更新:未提供的字段保持当前值。更新已发布条目会暂存草稿,线上版本不变。使用 content_compare 对比线上与草稿,再调用 content_publish 发布草稿或 content_discard_draft 丢弃。content_delete 将条目移入回收站;仅 content_permanent_delete 永久删除回收站中的条目。

署名是可复用的作者或贡献者信息。byline_create 可创建访客署名或关联 CMS 用户。将返回的署名 ID 传入 content_create 和 content_update 接受的 bylines 输入。删除署名会从内容中移除该信息并清除主署名。

MCP 写入不参与管理后台的条目编辑锁。_rev 检查保护接受它的操作,但其他写入工具可能在编辑者打开条目时修改条目。

翻译

内容、署名、分类术语和菜单的翻译工具返回相关翻译组中的各语言变体。若创建工具的 schema 提供 translationOf 输入则使用它;必填字段以 tools/list 为准。

content_translations 接受集合及内容 ID 或 slug。署名、术语和菜单翻译工具接受单条记录 ID 或共享翻译组 ID。无草稿访问权限的用户只能看到已发布内容的翻译。

架构、媒体、分类法与菜单

架构工具会改变数据库结构。创建内容或修改字段前请使用 schema_get_collection;它返回可用字段名、类型、约束和验证规则。删除集合和字段会移除已存内容或字段值且无法撤销。

使用 media_upload 发送 base64 编码的字节。上传受配置的大小和 MIME 类型限制;相同字节可能返回已有媒体项并带 deduplicated: true。

media_create 确认通过 POST /_emdash/api/media/upload-url 创建的待处理上传。用返回的签名 URL 上传文件,再以同一用户账号和返回的 storageKey 调用 media_create。工具在媒体库可用前会验证存储文件存在且大小与请求上传 URL 时一致。

分类法定义描述分类及其适用的集合;术语是分配给内容的单个值。层级术语可使用 parentId,但父项须属同一分类法且不能形成环。在非层级分类法中用 parentId 创建或更新术语会返回 VALIDATION_ERROR。有子项的术语须先移除或移动子项才能删除。

menu_set_items 在一次原子操作中替换菜单的完整项列表。数组顺序即菜单顺序。嵌套项的 parentIndex 指向同数组中更早的项,因此每个父项应放在其子项之前。

media_usage_repair 可处理单个或全部集合,在大型站点上可能运行较久。其 complete、partial、failed 和 stale 状态均为成功的工具响应。请检查返回的状态和计数,而非依赖 isError;认证、验证和意外执行失败会设置 isError: true。

站点转移

site_* 工具将整个站点导出为站点包并将包导入空站点。它们启动并驱动操作并返回有限摘要,从不承载包字节、媒体、记录内容、主体邮箱或下载 URL。请用 CLI 或 REST API 下载导出并上传导入包,再按 ID 引用操作。

每个转移工具都需要 Admin 角色。角色在 scope 之前检查;非管理员调用方收到 INSUFFICIENT_PERMISSIONS 且不会创建批准请求。

导出

site_export_start 接受 comments(默认 true)并返回新操作。site_export_status 每次调用执行一个有限导出步骤并报告操作和 nextRequestInMs。在该延迟后重复调用直至 nextRequestInMs 为 null。传入 advance: false 可不执行步骤仅读状态。导出完成后,结果还包含 totals:按类型的记录数、媒体数量与字节、包文件数量与字节。

导入

请先上传包。CLI 的 emdash site import <file> --analyze 会上传、分析并打印操作 ID。

site_import_analyze 每次调用执行一个有限分析步骤。重复直至 nextRequestInMs 为 null;结果将包含计划摘要,含 packageDigest、planDigest、executable、计数、大小、主体、决策、转换、警告和阻塞项。每项转换列出其 code、记录的 kind(如有)和 count,不含所应用的 ID 或值。主体、警告和阻塞项各最多 50 条,完整计数在 total。主体列表不含邮箱,含建议与当前映射的目标用户 ID。传入 decisions 可将主体映射到目标用户 ID(或 null)并选择包或目标的标题与副标题。每次变更产生新的 planDigest。

site_import_start 接受操作 ID 及最新计划的 packageDigest 和 planDigest。计划不得有阻塞项。该工具有 destructiveHint: true:启动后导入会写入站点并阻塞其他写入,直至完成或管理员放弃。调用前向用户展示计划并确认。

site_import_resume 执行一个有限导入步骤并报告操作和 nextRequestInMs。重复直至 nextRequestInMs 为 null;断线后重复安全。site_import_status 报告操作和已上传文件数且不推进导入。site_import_receipt 在导入完成后返回完整回执,含 receiptDigest。

导入执行期间,以及失败或取消后直至放弃前,所有其他可写工具均因 TRANSFER_IMPORT_IN_PROGRESS 失败,包括插件工具。标注 readOnlyHint: true 的工具和八个 site_* 工具仍可用,initialize 和 tools/list 从不阻塞。媒体使用激活期间,写入工具同样因 MEDIA_USAGE_ACTIVATION_IN_PROGRESS 失败。

操作摘要包含 id、kind、state、stage、progress、packageDigest、planDigest、error({ code } 或 null)和时间戳。progress 为 { done, total } 步骤,外加导出已写入的 records,以及已知时的 bytesDone 和 bytesTotal。MCP 工具不能取消或放弃导入;请使用 REST API。

批准

带有 admin 或所需转移 scope 的令牌从不请求批准。对两者皆无的令牌(如仅授予 transfer:analyze 的智能体),管理员批准后 site_export_start 和 site_import_start 才会执行:

  1. 无 scope 的首次调用创建待批准请求并以 TRANSFER_APPROVAL_REQUIRED 失败。消息文本和 _meta.details 携带 approvalId 及其 expiresAt。相同参数且无 approvalId 再次调用返回同一未决请求。
  2. 管理员在 设置 → Transfer 的 Approval requests 中批准,或通过 REST API 的仅会话批准端点。API 令牌不能批准请求。
  3. 客户端以相同参数和 approvalId 重复调用。该调用启动操作时消耗批准。若操作未能启动,客户端可用同一 approvalId 重试直至过期。

请求绑定用户、令牌、操作和精确参数:导出选项,或导入操作 ID 与两个摘要。待决请求在创建后 15 分钟过期,已批准的在批准后 15 分钟过期。参数或令牌不同,或批准被拒绝、过期或已用时,调用因 TRANSFER_APPROVAL_INVALID 失败。

site_import_start 在创建请求前检查摘要、操作状态和计划阻塞项,因此管理员只需批准可执行的导入。批准需要令牌 ID;无令牌 ID 的调用方收到 INSUFFICIENT_SCOPE。

已批准调用启动操作后,同一用户和令牌可无 scope 调用该操作的 site_export_status,或 site_import_status、site_import_resume 和 site_import_receipt。

插件工具

管理员须启用各插件的 MCP 界面。已启用工具在 tools/list 中显示为 <pluginId>__<localName>,令牌认证调用需要 mcp:tools 或 mcp:tools:<pluginId>。EmDash 还会检查插件路由声明的权限,并在审计日志中记录插件、工具、路由和执行者。

插件工具因安装而异,不在上述静态清单中。

OAuth 发现

MCP 客户端从受保护资源元数据发现授权服务器:

GET /.well-known/oauth-protected-resource

响应将 /_emdash/api/mcp 标识为受保护资源并链接到授权服务器。客户端随后读取:

GET /.well-known/oauth-authorization-server/_emdash

该文档提供当前授权、令牌、注册和设备授权端点、支持的 scope、grant 类型及 PKCE 方法 S256。请使用发现值,勿硬编码 OAuth 协议路由。

未认证的 MCP 请求返回带发现 URL 的 401:

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

错误

工具失败时 isError: true。第一个文本块以稳定代码开头,_meta.code 为读取结构化元数据的客户端重复该代码:

{
	"content": [{ "type": "text", "text": "[NOT_FOUND] Collection 'articles' not found" }],
	"isError": true,
	"_meta": { "code": "NOT_FOUND" }
}

认证失败使用如 INSUFFICIENT_SCOPE 和 INSUFFICIENT_PERMISSIONS 等代码。传输失败使用 JSON-RPC 内部错误码 -32603,不暴露底层异常。