iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0

MCP 在 2026 年 7 月 28 日發布新版規範,這一版把協定本身從有狀態連線改成無狀態請求,把 Roots、Sampling、Logging 三項功能標為 Deprecated,並改掉 OAuth 的 client 註冊方式。以下整理會動到實作的幾項改動,以及自建 MCP server 要跟著調整什麼。


協定變成無狀態

規範拿掉了兩樣東西:Streamable HTTP 的 Mcp-Session-Id 標頭,以及 initializenotifications/initialized 這組交握。

Day06McpStatelessComparison

拿掉之後,每個請求得自己帶齊過去靠交握建立的資訊,位置在 _meta

_meta 帶什麼 強制程度
io.modelcontextprotocol/protocolVersion 協定版本 每個請求都帶
io.modelcontextprotocol/clientCapabilities client 能力 每個請求都帶
io.modelcontextprotocol/clientInfo client 身分 SHOULD
io.modelcontextprotocol/serverInfo server 身分,放在每個結果的 _meta SHOULD

規範頁上的 tools/call 範例就是新版一個請求的全貌:

POST /mcp HTTP/1.1
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: get_weather

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": { "location": "Seattle, WA" },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": { "name": "ExampleClient", "version": "1.0.0" },
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}

版本對不上時回 UnsupportedProtocolVersionError,回應裡會列出該 server 支援的版本。

新增的 server/discover 是 server MUST 實作的 RPC,用來告知支援的協定版本、能力與身分。Client 可以在其他請求之前先呼叫它選版本,在 STDIO 上也可以拿它當回溯相容的探測。

還有三項連帶移除:

  • tools/listresources/listprompts/list 的結果對每個請求一致
  • pinglogging/setLevelnotifications/roots/list_changed 移除,log 層級改成每個請求用 _metaio.modelcontextprotocol/logLevel 指定,沒帶這個欄位的請求,server MUST NOTnotifications/message
  • SSE 的續傳與重送(Last-Event-ID 與事件 ID)移除,回應串流斷掉就是整個請求作廢,client MUST 用新的 request ID 重送

那需要跨呼叫狀態的 server 怎麼辦?規範的做法是由 server 自己鑄出 handle,當成一般的工具參數傳遞。

狀態從連線移到參數,變成呼叫雙方都看得見的東西


舊 client 打到新 server 會得到什麼

規範為只實作這一版的 server 列出三種舊流量的處置方式:

舊 client 的動作 新 server 的回應
對 MCP 端點發 HTTP GET 或 DELETE 405 Method Not Allowed
請求帶 Mcp-Session-Id 標頭 忽略,並且不鑄造也不回傳 session ID
請求帶 Last-Event-ID 標頭 忽略,串流沒有續傳

方法不存在時回的是 404 Not Found 加上 JSON-RPC 錯誤碼 -32601那個 JSON-RPC 錯誤體正是用來與舊 HTTP+SSE server 的 404 區分開來,新版 client 靠它判斷對方說的是哪一代協定。


標頭與 body 必須一致

這一版要求每個 POST 帶三個標頭,值一律鏡射自 body:

標頭 來源欄位 適用範圍
MCP-Protocol-Version _metaprotocolVersion 每個請求
Mcp-Method method 每個請求
Mcp-Name params.nameparams.uri tools/callresources/readprompts/get

理由寫在規範裡:中介設備(負載平衡器、閘道、可觀察性工具)可以只讀標頭就完成路由與檢查,無須解析 body。代價是兩邊必須對得起來,負載平衡器依標頭路由、MCP server 依 body 執行,兩個元件各自相信不同的真實來源時會產生漏洞。對不上時 server MUST400 Bad Request 與錯誤碼 -32020

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32020,
    "message": "Header mismatch: Mcp-Name header value 'foo' does not match body value 'bar'"
  }
}

伺服器主動說話拆成兩條路

Server 要主動送東西給 client,舊版有幾種零散的機制,新版整理成兩條。

變更通知走 subscriptions/listen。這是一條長時間存在的 POST 回應串流,取代原本的 HTTP GET 端點與 resources/subscriberesources/unsubscribe。Client 明確訂閱需要的類型(toolsListChangedpromptsListChangedresourcesListChangedresourceSubscriptions),server 回覆確認,並在通知上標記 io.modelcontextprotocol/subscriptionId

請求範圍內的通知走另一條路徑,notifications/progressnotifications/message 留在它所屬請求的回應串流上。

要跟 client 索取資訊走 MRTR(Multi Round-Trip Requests)。舊版是 server 主動發出 roots/listsampling/createMessageelicitation/create,新版改成 server 回一個 InputRequiredResult,把需要的東西列在 inputRequests,client 帶著 inputResponses 重送原本那個請求。

因此所有結果都多了一個必填的 resultType

意思
complete 一般結果
input_required MRTR 的中途結果,還要再一輪

舊版 server 不會有這個欄位,client MUST 把缺欄位的結果當成 complete

取消的語意也跟著變:每個請求各有自己的回應串流,關掉串流就是取消那一個請求,server 收到之後 MUST NOT 再為它送出任何訊息。

通訊方向只剩一種,request 由 client 發起、server 回應,server 需要什麼就寫在回應裡等 client 再送一次


Tasks 移出核心成為 extension

長時間任務原本是核心裡的實驗功能,新版移到官方 extension io.modelcontextprotocol/tasks

  • 阻塞式的 tasks/result 換成輪詢式的 tasks/get
  • 新增 tasks/update,讓 client 在任務執行中把輸入送進去
  • 移除 tasks/list

同時 ClientCapabilitiesServerCapabilities 多了 extensions 欄位,核心以外的功能從此有正式的宣告位置


授權:CIMD 取代動態註冊

改動集中在 client 怎麼跟授權伺服器表明自己是誰。規範列出三種註冊機制,並給了選用順序:

  1. 已經有預先註冊的資訊就用它
  2. 授權伺服器的 metadata 帶 client_id_metadata_document_supported 就走 CIMD
  3. registration_endpoint 才退回動態註冊(DCR)
  4. 最後由使用者自行填入

CIMD(Client ID Metadata Documents) 是拿一個 HTTPS URL 當 client_id,URL 指向一份至少帶 client_idclient_nameredirect_uris 的 JSON,文件裡的 client_id 與該 URL 完全相同。授權伺服器看到 URL 形式的 client_id 就去解析它,兩種做法的差異在可攜性:

基於 Client ID Metadata Documents 的 client ID 可跨授權伺服器攜帶,因為它們是自行託管、由授權伺服器按需解析的 HTTPS URL,授權伺服器更換時不需要重新註冊

反過來,預先註冊與 DCR 取得的憑證綁在發行它的授權伺服器上,client MUST 以 issuer 識別碼為鍵保存,授權伺服器換掉時 MUST 重新註冊,不得沿用舊憑證。


棄用與生命週期政策

這一版同時把「棄用」本身定成規則,三個狀態與時程寫進政策:

狀態 意思
Active 屬於現行版本
Deprecated 仍在規範內並仍可運作,已排定移除,新實作改用替代方案
Removed 已從 draft 刪除,下一個現行版本起消失

從 Deprecated 到 Removed 至少十二個月,窗口從標為 Deprecated 的那一版發布起算,窗口過後的第一個現行版本才具備移除資格。唯一的例外是已有公開資安通報或在野利用且無法就地緩解的功能,縮短仍需保留至少九十天。

登記表把每一項的替代做法與時程列得很明確:

功能 改用什麼 Deprecated 最早移除
Roots 工具參數、resource URI 或 server 組態傳遞目錄與檔案 2026-07-28 2027-07-28 之後的第一個版本
Sampling 直接接 LLM provider 的 API 2026-07-28 2027-07-28 之後的第一個版本
Logging stdio 走 stderr,或改用 OpenTelemetry 2026-07-28 2027-07-28 之後的第一個版本
DCR(RFC 7591) CIMD 2026-07-28 2027-07-28 之後的第一個版本
includeContextthisServerallServers 省略該欄位或填 none 2025-11-25 跟隨 Sampling
HTTP+SSE 傳輸 Streamable HTTP 2025-03-26 SEP-2596 定案後三個月

登記表的 Removed 區目前是空的,這套政策上路以來還沒有任何功能真的被移除。


對自建 MCP server 的影響

把上面的改動對到實作,需要動的地方是這幾項:

改動 要做什麼
無狀態 確認 server 的狀態全部由參數傳入,需要跨呼叫狀態時改鑄 handle 當工具參數
server/discover 新增這個 RPC,回傳支援的協定版本、能力與身分
resultType 所有結果補上這個欄位
_meta 改成從每個請求讀協定版本與 client 能力
標頭驗證 比對 MCP-Protocol-VersionMcp-MethodMcp-Name 與 body,不符時回 -32020
快取欄位 tools/listprompts/listresources/listresources/readresources/templates/list 五個方法的結果要帶 ttlMscacheScope
舊流量 GET 與 DELETE 回 405Mcp-Session-IdLast-Event-ID 一律忽略
授權 client 側改走 CIMD,憑證以 issuer 為鍵保存
棄用功能 有用到 Roots、Sampling、Logging 的先規劃替代路徑

這幾項的急迫程度不同:

  • 無狀態與 resultType 是協定層的硬改動:跟上之後才與新版 client 相容
  • 快取欄位與 server/discover 影響的是效率與相容性:可以排在後面
  • 棄用的三項還有一年以上:最早移除落在 2027-07-28 之後

心得

自建的環控 MCP server 在組態裡開了 FASTMCP_STATELESS_HTTP=true,時間點早於這次改版。

先前維持 session 的組態跑起來會這樣:連續呼叫幾次之後,agent 端收到 Session terminated,接著進重連,重連後停在逾時,整個工具呼叫的結果停在空白,錯誤訊息同樣停在空白。改成每次呼叫獨立之後,這個現象消失。

新規範把 session 從協定層拿掉,方向與這件事一致。跨呼叫的狀態一旦綁在連線上,連線的存活就成了工具呼叫的隱藏前提,而這個前提只在連線持續存在時成立,網路抖動與伺服器重啟都會打斷它,這兩件事在長期運作的系統裡都會發生。


明天

三者的選型理由、安裝流程與組態檔的結構。


上一篇
【Day 5】2026 Agent 生態系:協定、擴充機制與框架的分工
系列文
打造具備記憶與執行能力的常駐 AI Agent:Hermes Agent × Gemini × MCP 的 Harness 設計6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言