EmDash 在 /_emdash/api/mcp 提供內建的 Model Context Protocol(MCP)伺服器,將內容管理操作以工具形式公開給 AI 助手。
本頁說明通訊協定內容:身分驗證、傳輸、工具規格、OAuth 探索與錯誤處理。
身分驗證
MCP 伺服器支援三種身分驗證方式:
| 方式 | 運作方式 |
|---|---|
| OAuth 2.1 授權碼 + PKCE | MCP 用戶端的標準流程。使用者在瀏覽器中核准權限範圍(scope)。 |
| 個人存取權杖(PAT) | 在管理後台建立的長期有效 ec_pat_* 權杖。 |
| 裝置碼流程 | 類似 CLI 的流程,在瀏覽器中核准驗證碼。由 emdash login 使用。 |
管理後台產生的工作階段 Cookie 也可使用,但對外部 MCP 用戶端不實用。
權限範圍(Scopes)
權杖透過 scope 限制用戶端可執行的操作。scope 在 OAuth 授權時申請,並於每次工具呼叫時強制檢查。
| Scope | 授予的權限 |
|---|---|
content:read | 列出、取得、比較與搜尋內容。列出分類法、分類詞彙與選單。 |
content:write | 建立、更新、刪除、發布、下架、排程發布、取消排程、複製與還原內容。為相容在拆分出下列 scope 之前簽發的權杖,隱含 taxonomies:manage 與 menus:manage。 |
media:read | 列出並取得媒體項目。 |
media:write | 登記(建立)、更新與刪除媒體中繼資料。 |
schema:read | 列出集合並取得集合結構(schema)。 |
schema:write | 建立與刪除集合及欄位。 |
taxonomies:manage | 建立、更新與刪除分類詞彙。 |
menus:manage | 建立、更新與刪除導覽選單及其項目。 |
settings:read | 讀取網站層級設定。 |
settings:manage | 更新網站層級設定。 |
admin | 對所有操作的完整存取。 |
admin scope 可存取一切。以工作階段為基礎的驗證(無權杖)也會依使用者角色擁有與其角色相符的全部權限。
content:write 隱含 taxonomies:manage 與 menus: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
在集合中列出內容項目,支援選用篩選與分頁。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
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_unschedule
取消已安排的排程發布。項目保持目前狀態;僅清除 scheduledAt 時間戳記。冪等:對未安排發布的項目呼叫無效果。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
collection | string | 是 | 集合 slug |
id | string | 是 | 內容項目 ID 或 slug |
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
建立新內容集合。會建立資料庫表與結構定義。slug 須為小寫英數字加底線,且以字母開頭。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
slug | string | 是 | 唯一識別(/^[a-z][a-z0-9_]*$/) |
label | string | 是 | 顯示名稱(複數,例如 “Blog Posts”) |
labelSingular | string | 否 | 單數顯示名稱 |
description | string | 否 | 集合說明 |
icon | string | 否 | 管理後台使用的圖示名稱 |
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
向集合結構新增欄位,即在資料表中新增欄。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
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_create
登記已上傳至儲存空間的媒體檔案。呼叫方須負責將檔案放到 storageKey(通常使用管理後台或獨立 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 | 否 | 主色十六進位色值 |
Scope: media:write | 最低角色: 作者
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 建立子項目。父層祖先鏈深度不得超過 100 層。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
taxonomy | string | 是 | 分類法名稱 |
slug | string | 是 | URL 安全識別碼 |
label | string | 是 | 顯示名稱 |
parentId | string | 否 | 父詞彙 ID(階層式分類法) |
description | string | 否 | 詞彙說明 |
Scope: 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 | 否 | 新說明 |
Scope: taxonomies:manage | 最低角色: 編輯
taxonomy_delete_term
從分類法永久刪除詞彙。曾打上該標籤的內容將失去關聯。若詞彙仍有子項目則不可刪——須先刪除子項目。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
taxonomy | string | 是 | 分類法名稱 |
termSlug | string | 是 | 要刪除詞彙的 slug |
Scope: taxonomies:manage | 最低角色: 編輯 | 破壞性: 是
選單工具
menu_list
列出全部導覽選單。回傳名稱、標籤與時間戳記。
無參數。
Scope: content:read | 唯讀: 是
menu_get
依名稱取得選單及其有序項目。項目含標籤、URL、類型及選用父級以支援巢狀。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
name | string | 是 | 選單名稱(例如 main、footer) |
Scope: content:read | 唯讀: 是
menu_create
建立新導覽選單。name 為網站範本使用的穩定識別碼;label 為管理後台顯示名稱。項目稍後透過 menu_set_items 新增。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
name | string | 是 | 穩定識別碼(/^[a-z][a-z0-9_]*$/) |
label | string | 是 | 管理後台顯示名稱 |
Scope: menus:manage | 最低角色: 編輯
menu_update
更新選單的標籤。穩定識別碼 name 不可變更。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
name | string | 是 | 要更新的選單名稱 |
label | string | 是 | 新顯示標籤 |
Scope: menus:manage | 最低角色: 編輯
menu_delete
刪除選單及其全部項目。無法復原。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
name | string | 是 | 要刪除的選單名稱 |
Scope: menus:manage | 最低角色: 編輯 | 破壞性: 是
menu_set_items
單次呼叫取代選單的全部項目。原子操作:先刪舊項目,再依給定順序插入新清單。比逐筆增刪更清楚,順序與父子關係明確。
項目位置由陣列索引決定。巢狀透過 parentIndex 表達——parentIndex: 0 表示巢狀在索引 0 的項目下。父項目須出現在清單較前位置。無 parentIndex 者為頂層項目。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
name | 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 | 否 | 父項目在陣列中的索引;頂層項目省略 |
Scope: menus:manage | 最低角色: 編輯
修訂工具
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
設定工具
網站層級設定——標題、標語、Logo、網站圖示、標準網址、預設分頁大小、日期與時間格式、社交帳號及 SEO 預設值等。
settings_get
取得全部網站層級設定。媒體參照(logo、favicon、seo.defaultOgImage)在回應中含解析後的 URL 及底層 mediaId。未設定的值不出現在回應中。
無參數。
Scope: settings:read | 最低角色: 編輯 | 唯讀: 是
settings_update
更新一項或多項網站層級設定。部分更新:僅修改提供的欄位;未提供的保持不變。回傳更新後的完整設定物件。
設定媒體參照(logo、favicon、seo.defaultOgImage)時傳入含 mediaId(及選用 alt)的物件。媒體項目須已存在——請先 media_create。
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
title | string | 否 | 網站標題 |
tagline | string | 否 | 標題旁簡短描述 |
logo | MediaRef | 否 | Logo 媒體參照({ mediaId, alt? }) |
favicon | MediaRef | 否 | 網站圖示媒體參照 |
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 | 內容無圖時的預設 Open Graph 圖片 |
robotsTxt | string | 自訂 robots.txt 內文。省略則使用 EmDash 預設。 |
googleVerification | string | Google Search Console 驗證權杖 |
bingVerification | string | Bing 網站管理員工具驗證權杖 |
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(內部錯誤),且不洩露實作細節。