EmDash 內建一個 Model Context Protocol(MCP)伺服器,位於 /_emdash/api/mcp,將內容管理操作以工具形式公開給 AI 助手使用。
本頁涵蓋通訊協定詳情:驗證、傳輸、工具規格、OAuth 探索與錯誤處理。
驗證
MCP 伺服器支援三種驗證方式:
| 方式 | 運作方式 |
|---|---|
| OAuth 2.1 授權碼 + PKCE | MCP 用戶端的標準流程。使用者在瀏覽器中核准 scope。 |
| 個人存取權杖(PAT) | 在管理後台建立的長期 ec_pat_* 權杖。 |
| 裝置流程 | CLI 風格流程,在瀏覽器中核准驗證碼。由 emdash login 使用。 |
工作階段 cookie(來自管理 UI)也可使用,但對外部 MCP 用戶端不太實用。
Scope
權杖使用 scope 來限制用戶端可執行的操作。Scope 在 OAuth 授權期間請求,並在每次工具呼叫時強制執行。
| Scope | 授予存取權限 |
|---|---|
content:read | 列出、取得、比較與搜尋內容。列出分類法詞彙與選單。 |
content:write | 建立、更新、刪除、發布、取消發布、排程、複製與還原內容。建立分類法詞彙。 |
media:read | 列出與取得媒體項目。 |
media:write | 更新與刪除媒體中繼資料。 |
schema:read | 列出集合與取得集合 schema。 |
schema:write | 建立與刪除集合與欄位。 |
admin | 所有操作的完整存取權。 |
admin scope 授予所有操作的存取權。基於工作階段的驗證(無權杖)也擁有基於使用者角色的完整存取權。
角色要求
除了 scope 之外,部分工具需要最低 RBAC 角色:
| 操作 | 最低角色 |
|---|---|
| 內容操作 | 無最低要求(由 scope 控制存取) |
| Schema 讀取 | 編輯(40) |
| Schema 寫入 | 管理員(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 特定碼表示 scope 與權限失敗。
工具
伺服器公開 33 個工具,涵蓋七個領域。每個工具以 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 時相關。 |
Scope: content:read | 唯讀: 是
content_get
透過 ID 或 slug 取得單一內容項目。回傳所有欄位值、中繼資料和用於樂觀並行控制的 _rev 權杖。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 內容項目 ID(ULID)或 slug |
locale | string | 否 | 用於 slug 查詢的語系。ID 全域唯一。 |
Scope: 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 |
Scope: content:write
content_update
更新現有內容項目。僅包含你要變更的欄位——未指定的欄位保持不變。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 內容項目 ID 或 slug |
data | object | 否 | 要更新的欄位值 |
slug | string | 否 | 新的 URL slug |
status | string | 否 | 新狀態:draft 或 published |
_rev | string | 否 | 來自 content_get 的修訂權杖,用於衝突偵測 |
Scope: content:write
content_delete
透過移至回收桶來軟刪除內容項目。使用 content_restore 復原,或使用 content_permanent_delete 永久移除。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 內容項目 ID 或 slug |
Scope: content:write | 破壞性: 是
content_restore
從回收桶還原軟刪除的內容項目。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 內容項目 ID 或 slug |
Scope: content:write
content_permanent_delete
永久且不可逆地刪除已移至回收桶的內容項目。項目必須先在回收桶中。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 內容項目 ID 或 slug |
Scope: content:write | 破壞性: 是
content_publish
發布內容項目,使其在網站上線。從目前草稿建立已發布的修訂版。後續編輯會建立新草稿,不影響線上版本,直到重新發布為止。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 內容項目 ID 或 slug |
Scope: content:write
content_unpublish
將已發布的項目恢復為草稿狀態。它將不再在線上網站中顯示,但內容會保留。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 內容項目 ID 或 slug |
Scope: content:write
content_schedule
排程內容項目在未來發布。它將在指定的日期/時間自動發布。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 內容項目 ID 或 slug |
scheduledAt | string | 是 | ISO 8601 日期時間(例如 2026-06-01T09:00:00Z) |
Scope: content:write
content_compare
比較內容項目的已發布(線上)版本與目前草稿。回傳兩個版本以及指示是否有變更的旗標。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 內容項目 ID 或 slug |
Scope: content:read | 唯讀: 是
content_discard_draft
捨棄目前草稿並恢復到最後發布的版本。僅適用於至少發布過一次的項目。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 內容項目 ID 或 slug |
Scope: content:write | 破壞性: 是
content_list_trashed
列出集合回收桶中已軟刪除的內容項目。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
limit | integer | 否 | 最大項目數(1-100,預設 50) |
cursor | string | 否 | 分頁游標 |
Scope: content:read | 唯讀: 是
content_duplicate
建立現有內容項目的副本。副本以草稿建立,標題附加「(Copy)」,slug 自動產生。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 要複製的內容項目 ID 或 slug |
Scope: content:write
content_translations
取得內容項目的所有語系變體。回傳翻譯群組和每個語系版本的摘要。僅在啟用 i18n 時相關。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 內容項目 ID 或 slug |
Scope: content:read | 唯讀: 是
Schema 工具
schema_list_collections
列出 CMS 中定義的所有內容集合。回傳 slug、標籤、支援的功能和時間戳記。
無參數。
Scope: schema:read | 最低角色: 編輯 | 唯讀: 是
schema_get_collection
取得集合的詳細資訊,包括所有欄位定義。欄位描述資料模型:名稱、類型、約束和驗證規則。使用此工具了解 content_create 和 content_update 預期的內容。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
slug | string | 是 | 集合 slug(例如 posts) |
Scope: 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(預設:['drafts', 'revisions']) |
Scope: schema:write | 最低角色: 管理員
schema_delete_collection
刪除集合及其資料庫表。此操作不可逆,會刪除集合中的所有內容。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
slug | string | 是 | 要刪除的集合 slug |
force | boolean | 否 | 即使集合有內容也強制刪除 |
Scope: 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 | 否 | 包含在全文搜尋索引中 |
translatable | boolean | 否 | 此欄位是否可翻譯(預設 true) |
欄位類型:string、text、number、integer、boolean、datetime、select、multiSelect、portableText、image、file、reference、json、slug。
對於 select 和 multiSelect 類型,在 validation.options 中提供允許的值。
Scope: schema:write | 最低角色: 管理員
schema_delete_field
從集合中移除欄位。這會刪除該欄位中的欄和所有資料。不可逆。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
fieldSlug | string | 是 | 要移除的欄位 slug |
Scope: schema:write | 最低角色: 管理員 | 破壞性: 是
媒體工具
media_list
列出已上傳的媒體檔案,支援選用的 MIME 類型篩選與分頁。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
mimeType | string | 否 | 按 MIME 類型前綴篩選(例如 image/、application/pdf) |
limit | integer | 否 | 最大項目數(1-100,預設 50) |
cursor | string | 否 | 分頁游標 |
Scope: media:read | 唯讀: 是
media_get
透過 ID 取得單一媒體檔案的詳情。回傳包括檔名、MIME 類型、大小、尺寸、替代文字和 URL 的中繼資料。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
id | string | 是 | 媒體項目 ID |
Scope: media:read | 唯讀: 是
media_update
更新已上傳媒體檔案的中繼資料。檔案本身無法變更。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
id | string | 是 | 媒體項目 ID |
alt | string | 否 | 無障礙替代文字 |
caption | string | 否 | 說明文字 |
width | integer | 否 | 圖片寬度(像素) |
height | integer | 否 | 圖片高度(像素) |
Scope: media:write
media_delete
永久刪除媒體檔案。移除資料庫記錄和儲存中的檔案。參照此媒體的內容會出現斷裂參照。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
id | string | 是 | 媒體項目 ID |
Scope: media:write | 破壞性: 是
搜尋工具
search
跨內容集合的全文搜尋。集合必須在 supports 列表中包含 search,且欄位必須標記為 searchable。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
query | string | 是 | 搜尋查詢文字 |
collections | string[] | 否 | 限制搜尋的特定集合 slug |
locale | string | 否 | 按語系篩選結果 |
limit | integer | 否 | 最大結果數(1-50,預設 20) |
Scope: content:read | 唯讀: 是
分類法工具
taxonomy_list
列出所有分類法定義(例如分類、標籤)。回傳名稱、標籤、是否階層式,以及關聯的集合。
無參數。
Scope: content:read | 唯讀: 是
taxonomy_list_terms
列出分類法中的詞彙,支援分頁。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
taxonomy | string | 是 | 分類法名稱(例如 categories、tags) |
limit | integer | 否 | 最大項目數(1-100,預設 50) |
cursor | string | 否 | 分頁游標 |
Scope: content:read | 唯讀: 是
taxonomy_create_term
在分類法中建立新詞彙。對於階層式分類法,指定 parentId 以建立子詞彙。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
taxonomy | string | 是 | 分類法名稱 |
slug | string | 是 | URL 安全識別碼 |
label | string | 是 | 顯示名稱 |
parentId | string | 否 | 父詞彙 ID(用於階層式分類法) |
description | string | 否 | 詞彙說明 |
Scope: content:write
選單工具
menu_list
列出所有導覽選單。回傳名稱、標籤和時間戳記。
無參數。
Scope: content:read | 唯讀: 是
menu_get
透過名稱取得選單,包含所有項目的順序。項目具有標籤、URL、類型和選用的父項以進行巢狀。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
name | string | 是 | 選單名稱(例如 main、footer) |
Scope: content:read | 唯讀: 是
修訂工具
revision_list
列出內容項目的修訂歷史記錄,最新在前。集合必須支援 revisions。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 內容項目 ID 或 slug |
limit | integer | 否 | 最大修訂數(1-50,預設 20) |
Scope: content:read | 唯讀: 是
revision_restore
將內容項目還原到先前的修訂版。用指定修訂版的資料取代目前草稿。不會自動發布——如需要請在之後使用 content_publish。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
revisionId | string | 是 | 要還原的修訂 ID |
Scope: 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
}
Scope 與權限錯誤會拋出 MCP 通訊協定錯誤:
{
"jsonrpc": "2.0",
"error": {
"code": -32600,
"message": "Insufficient scope: requires content:write"
},
"id": 1
}
傳輸層錯誤(伺服器設定錯誤、未處理的例外)回傳 JSON-RPC 錯誤碼 -32603(內部錯誤),不會洩漏實作細節。