教程

Stateless MCP 是什麼?2026 MCP 無狀態架構、JSON-RPC 與 Remote Server 完整解析

2026-07-28 版 MCP 把協議層改成無狀態:每個 JSON-RPC 請求自帶版本與能力,Remote Server 可以跑在普通 HTTP 負載均衡後面。工具參數仍是 JSON,落地時仍要本地校驗。

Model Context Protocol(MCP)讓 AI 客戶端能發現工具、資源和提示詞,並把它們接到模型上下文裏。2026 年最大的架構變化,是把 MCP 從「先握手、再帶 Session ID 的雙向有狀態協議」,改成「每個請求自描述、可獨立路由的無狀態 JSON-RPC」。如果你已經在用 Claude Desktop、Cursor 或自建 Agent 調 Remote MCP Server,這次變更直接影響你怎麼部署、怎麼擴縮容、怎麼在網關層限流。讀完你可以分清協議無狀態和應用有狀態,並知道工具參數裏的 JSON 仍然要本地校驗。

MCP 與 Stateless 在解決什麼

MCP 解決的是「模型怎麼安全、可發現地調用外部能力」。客戶端(Claude、ChatGPT、IDE Agent)需要一份標準方式列出你的工具、讀資源、拉提示詞模板;服務端(GitHub、數據庫、內部 API 的 MCP 適配層)需要一份標準方式暴露這些能力,而不必爲每個客戶端寫定製插件。

早期 MCP 在傳輸層保留了會話:客戶端先initialize,服務端回能力清單,後續請求還要帶Mcp-Session-Id,把流量釘在同一臺實例或共享 Session Store 上。這對本地 stdio 進程沒問題;一旦 Remote Server 要水平擴展、跑在 Cloud Run / Lambda、或經 API 網關做按工具限流,會話粘性就成了瓶頸。

2026-07-28 規範(Release Candidate)把協議層改成無狀態:處理任意請求所需的元數據都在請求本身裏,任意實例 behind 普通 round-robin 負載均衡都能接。官方說明見MCP 2026-07-28 規範公告與Statelessness 章節。

有狀態時代留下了什麼

舊流程裏,Streamable HTTP 客戶端通常要先走一遍握手:

  1. 發送initialize,交換協議版本與 client/server capabilities。
  2. 收到initialized通知,服務端下發Mcp-Session-Id響應頭。
  3. 之後的tools/call、resources/read都要帶上同一個 Session ID,否則網關或實例內存裏找不到上下文。

生產上的典型代價:負載均衡要開 sticky session;多副本之間要 Redis 存 Session;Serverless 冷啓動後舊 Session 失效;GitHub MCP 等熱門 Server 一度不得不維護 Redis 層。Google 在Scaling AI Agent Infrastructure裏把這次變更稱爲「自 MCP 發佈以來最大的規範改動」——核心就是去掉傳輸層會話管理。

維度 有狀態時代(2025 及更早) 無狀態核心(2026-07-28)
握手 initialize / initialized必填 已退役;可選server/discover
會話標識 Mcp-Session-Id響應頭 已移除(SEP-2567)
能力協商 連接建立時交換一次 每個請求的_meta攜帶
水平擴展 粘性路由 + 共享 Session Store 普通 round-robin 即可

2026-07-28 無狀態核心

規範對「無狀態」的定義很硬:服務端不得依賴同一連接上的先前請求來推斷協議版本、客戶端身份或 capabilities;每個請求必須在_meta裏自帶這些信息。多個任務、線程或對話的請求可以交錯在同一傳輸上;連接或 stdio 進程本身不是會話邊界。

客戶端在每個請求的params._meta(或等價位置)裏攜帶:

  • io.modelcontextprotocol/protocolVersion— 必填,例如2026-07-28。
  • io.modelcontextprotocol/clientCapabilities— 必填;空對象表示不支持可選能力。
  • io.modelcontextprotocol/clientInfo— 建議填寫,用於日誌與調試(服務端不應據此做安全決策)。

若客戶端想先了解服務端能力,可以調用新的server/discoverRPC,但不是必須——任何請求都可以作爲第一個請求打到任意實例。服務端還可以給tools/list等響應加ttlMs,讓客戶端在 TTL 內緩存工具列表,減少重複發現調用。

需要跨多次工具調用保留的業務狀態(購物車、瀏覽器會話、工單草稿)不應藏在傳輸 Session 裏,而應像普通 HTTP API 一樣:工具返回顯式 handle(basket_id、draft_id),模型在後續tools/call的參數 JSON 裏把它傳回來。模型能看見 handle,比黑盒 Session 更容易調試。

JSON-RPC 在 MCP 裏怎麼跑

MCP 消息層始終是 JSON-RPC 2.0:每條請求有jsonrpc、id、method、params;響應帶result或error;通知沒有id。這和你在 Apple Agent 文章裏看到的「工具名 + 參數對象」是同一套形狀——MCP 只是把方法名標準化成tools/call,參數裏再嵌name與arguments。

一次典型的無狀態tools/call長這樣(HTTP 頭在下一節展開):

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

{
  "jsonrpc": "2.0",
  "id": 42,
  "method": "tools/call",
  "params": {
    "name": "searchInvoices",
    "arguments": {
      "status": "unpaid",
      "limit": 10
    },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {},
      "io.modelcontextprotocol/clientInfo": {
        "name": "jsonvue-demo",
        "version": "1.0.0"
      }
    }
  }
}

成功時result裏通常是帶content數組的工具輸出(多爲type: text的 JSON 字符串或結構化塊)。失敗時 JSON-RPCerror帶code與message;Streamable HTTP 下若 HTTP 頭與 body 裏的 method/name 不一致,規範要求返回-32020類 header mismatch 錯誤。

對 JSONVue 讀者來說,最值得盯的是arguments:外部 Agent 更容易把數字發成字符串、漏掉必填鍵。MCP 無狀態化不會替你校驗業務 JSON——這和 Structured Output 管模型輸出、MCP 管工具調用的分工一致。站內Apple AI Agent 與 JSON一文已說明:同一領域函數可以服務 App Intent、Foundation Models Tool 和 MCP,差別只在適配層。

Remote Server 與 Streamable HTTP

Remote MCP Server 指客戶端經 HTTPS 訪問的 MCP 端點,而不是本地 stdio 子進程。Streamable HTTP 是當前 Remote 部署的主傳輸:單 POST 可以完成一次 RPC;長任務可以返回開放的通知流,但狀態仍 scoped 到該請求,而不是連接級 Session。

2026-07-28 起,Streamable HTTP 請求必須攜帶與 body 一致的三個頭(SEP-2243),方便網關、WAF、限流器在不解析 JSON body 的情況下路由:

  • MCP-Protocol-Version— 須與_meta裏的 protocolVersion 一致,否則 400。
  • Mcp-Method— 對應 JSON-RPCmethod,如tools/call。
  • Mcp-Name— 工具、提示或資源名,如searchInvoices。

部署形態因此變簡單:同一 Docker 鏡像多副本 + 普通 ALB/nginx round-robin;Cloud Run / Cloud Functions 按需伸縮,不必爲 MCP 單獨掛 Redis Session;按Mcp-Name做 QPS 配額也比深包檢測 body 便宜。GitHub MCP Server 等生產服務已在向無狀態規範升級。

stdio 本地 Server 仍然可用,但規範明確:同一 stdio 進程上可以交錯無關請求,Server 不得把進程身份當成會話 ID。本地開發與雲端 Remote 應共用同一套工具實現,只是傳輸適配不同。

應用仍可帶狀態

「協議無狀態」不等於「你的業務無狀態」。購物車、多步審批、瀏覽器自動化裏未完成的表單,仍然可以、也應該有狀態——只是狀態要顯式,而不是綁在Mcp-Session-Id上。

推薦模式:

  1. 第一個工具調用創建資源,返回{ "draftId": "dr_8k2", ... }。
  2. 工具描述裏寫清楚:後續步驟必須傳入draftId。
  3. 服務端用draftId查 DB 或緩存;丟件時返回 JSON-RPC 業務錯誤,而不是 mysteriously 404 Session。

長任務方面,規範通過 Tasks 等擴展支持 MRTR(Multi-Request Task Routing):工具可以先返回status: input_required,客戶端把用戶補答附在後續請求的_meta裏繼續。這仍是無狀態協議上的請求/響應模式,只是響應可能跨多輪交互。

和 Structured Output 的關係

MCP 與 Structured Output 解決不同層的問題,但 JSON 形狀經常在同一條 Agent 流水線裏碰面:

層 機制 約束什麼
模型輸出 Structured Output + JSON Schema 模型最終答覆或抽取結果的字段與類型
工具調用 MCP tools/call+ 工具 inputSchema 傳給 Server 的arguments對象
業務 API REST / GraphQL JSON body Server 內部或下游 HTTP 的真實載荷

最佳實踐是維護一份字段表,生成 MCP 工具的 inputSchema、REST OpenAPI 與給模型的 Structured Output Schema。站內Gemini API JSON 輸出教程講模型側;Gemini Structured Output 教程有云端示例。MCP 無狀態化後,工具列表可能被客戶端緩存——Schema 版本變了要 bump 工具名或協議版本,避免舊緩存把錯誤形狀發進arguments。

落地時怎麼看 JSON

聯調 Remote MCP Server 時,把三份 JSON 並排看最省時間:客戶端發出的tools/call參數、你的領域服務收到的 HTTP body、工具返回給模型的result.content。形狀不一致時,問題幾乎總在適配層,而不是「模型不夠聰明」。

建議在瀏覽器裏走一遍:JSON 格式化確認能 parse;JSON 校驗抓尾逗號與類型錯誤;用JSON Schema校驗工具 inputSchema 與 API body 共用字段;JSON Diff對比「模型 arguments」與「實際 HTTP 請求體」。固定三份夾具:mcp-args.valid.json、http-body.valid.json、mcp-tool-error.json,CI 裏跑同一套 Schema。

常見問題 FAQ

無狀態 MCP 還需要 WebSocket 長連接嗎?

Remote 部署以 Streamable HTTP 爲主:單次 POST 完成 RPC,長通知流也是請求級響應流,不是舊式「先握手再綁 Session」的連接狀態。本地 stdio 仍是長壽命進程,但協議語義上每個請求獨立。

舊客戶端帶 Mcp-Session-Id 還能連新 Server 嗎?

2026-07-28 Server 不再識別協議級 Session ID。客戶端需升級到在每條請求的 _meta 裏帶 protocolVersion 與 clientCapabilities,併發送必需的 HTTP 頭。混跑版本時應在網關按 MCP-Protocol-Version 分流。

tools/list 每次都要調嗎?

不是。Server 可在響應裏給 ttlMs,客戶端在 TTL 內緩存。工具或 Schema 變更時應縮短 TTL 或變更工具名/版本,避免 stale 列表。

MCP 會替 Server 校驗 arguments 嗎?

工具可聲明 inputSchema,但 Server 仍必須做服務端校驗。外部 Agent 常發錯類型;無狀態協議不會減少這類錯誤。返回結構化 JSON-RPC error 比靜默 500 更利於模型重試。

總結與下一步

Stateless MCP 把 2026 年的 Remote Server 拉回了普通 HTTP 運維模型:JSON-RPC 2.0 承載方法,_meta承載協議上下文,Mcp-Method / Mcp-Name頭讓網關能看懂流量。initialize 與 Mcp-Session-Id 退場,換來的是任意實例可接任意請求、Serverless 友好、按工具限流更簡單。

業務狀態用顯式 ID 在 arguments 裏傳遞;JSON 契約仍要本地校驗。下一步:對照 2026-07-28 規範檢查你的 Remote 端點是否發送完整 _meta 與 HTTP 頭;把 MCP arguments 與 REST body 用同一份 Schema 釘死;用 JSONVue 工具在瀏覽器裏驗一遍往返 JSON。