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 傳回的靜態工具一致。包含註冊標題,因為用戶端可能顯示標題而非工具名稱。
內容工具
| Tool | Registered title | Required scope |
|---|---|---|
content_list | List Content | content:read |
content_get | Get Content | content:read |
content_create | Create Content | content:write |
content_update | Update Content | content:write |
content_delete | Delete Content (Trash) | content:write |
content_restore | Restore Content | content:write |
content_permanent_delete | Permanently Delete Content | content:write |
content_publish | Publish Content | content:write |
content_unpublish | Unpublish Content | content:write |
content_schedule | Schedule Content | content:write |
content_unschedule | Cancel Scheduled Publication | content:write |
content_compare | Compare Live vs Draft | content:read |
content_discard_draft | Discard Draft | content:write |
content_list_trashed | List Trashed Content | content:read |
content_duplicate | Duplicate Content | content:write |
content_translations | Get Content Translations | content:read |
署名工具
| Tool | Registered title | Required scope |
|---|---|---|
byline_list | List Bylines | content:read |
byline_get | Get Byline | content:read |
byline_create | Create Byline | content:write |
byline_update | Update Byline | content:write |
byline_delete | Delete Byline | content:write |
byline_translations | List Byline Translations | content:read |
結構工具
| Tool | Registered title | Required scope |
|---|---|---|
schema_list_collections | List Collections | schema:read |
schema_get_collection | Get Collection Schema | schema:read |
schema_list_block_types | List Block Types | schema:read |
schema_get_block_type | Get Block Type | schema:read |
schema_create_block_type | Create Block Type | schema:write |
schema_update_block_type | Update Block Type | schema:write |
schema_activate_block_type_version | Activate Block Type Version | schema:write |
schema_create_collection | Create Collection | schema:write |
schema_delete_collection | Delete Collection | schema:write |
schema_update_collection | Update Collection | schema:write |
schema_create_field | Add Field to Collection | schema:write |
schema_delete_field | Remove Field from Collection | schema:write |
schema_update_field | Update Field | schema:write |
媒體工具
| Tool | Registered title | Required scope |
|---|---|---|
media_list | List Media | media:read |
media_create | Confirm Signed Media Upload | media:write |
media_upload | Upload Media | media:write |
media_get | Get Media Item | media:read |
media_update | Update Media Metadata | media:write |
media_delete | Delete Media | media:write |
media_usage_repair | Repair Media Usage Index | admin |
搜尋工具
| Tool | Registered title | Required scope |
|---|---|---|
search | Search Content | content:read |
分類法工具
| Tool | Registered title | Required scope |
|---|---|---|
taxonomy_list | List Taxonomies | content:read |
taxonomy_get | Get Taxonomy Definition | content:read |
taxonomy_create | Create Taxonomy Definition | taxonomies:manage |
taxonomy_update | Update Taxonomy Definition | taxonomies:manage |
taxonomy_delete | Delete Taxonomy Definition | taxonomies:manage |
taxonomy_list_terms | List Taxonomy Terms | content:read |
taxonomy_create_term | Create Taxonomy Term | taxonomies:manage |
taxonomy_update_term | Update Taxonomy Term | taxonomies:manage |
taxonomy_delete_term | Delete Taxonomy Term | taxonomies:manage |
taxonomy_term_translations | List Term Translations | content:read |
選單工具
| Tool | Registered title | Required scope |
|---|---|---|
menu_list | List Menus | content:read |
menu_get | Get Menu with Items | content:read |
menu_translations | List Menu Translations | content:read |
menu_create | Create Menu | menus:manage |
menu_update | Update Menu | menus:manage |
menu_delete | Delete Menu | menus:manage |
menu_set_items | Set Menu Items | menus:manage |
修訂工具
| Tool | Registered title | Required scope |
|---|---|---|
revision_list | List Revisions | content:read |
revision_restore | Restore Revision | content:write |
設定工具
| Tool | Registered title | Required scope |
|---|---|---|
settings_get | Get Site Settings | settings:read |
settings_update | Update Site Settings | settings:manage |
網站轉移工具
transfer:* 表示 transfer:export、transfer:analyze 或 transfer:execute 中的任一項。admin scope 滿足本表所有要求。
| Tool | Registered title | Required scope |
|---|---|---|
site_transfer_capabilities | Get Site Transfer Capabilities | transfer:* |
site_export_start | Start Site Export | transfer:export |
site_export_status | Get Site Export Status | transfer:export |
site_import_analyze | Analyze Site Import | transfer:analyze |
site_import_start | Start Site Import | transfer:execute |
site_import_status | Get Site Import Status | transfer:* |
site_import_resume | Resume Site Import | transfer:execute |
site_import_receipt | Get Site Import Receipt | transfer:* |
管理員核准請求時,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 才會執行:
- 無 scope 的首次呼叫建立待核准請求並以
TRANSFER_APPROVAL_REQUIRED失敗。訊息文字和_meta.details攜帶approvalId及其expiresAt。相同參數且無approvalId再次呼叫傳回同一未決請求。 - 管理員在 設定 → Transfer 的 Approval requests 中核准,或透過 REST API 的僅工作階段核准端點。API 權杖不能核准請求。
- 用戶端以相同參數和
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,不暴露底層例外。