如果 MCP 變成 Stateless,那購物車放哪裡?

瀏覽器 agent 已經開了 12 個頁籤,下一次 tool call 怎麼知道該接哪個 browser context?一個做到一半的 workspace,又怎麼在下一個 request 繼續?

這幾個問題比「Stateless 比 Stateful 更好擴展」更值得先弄懂。因為只要把 Stateless 誤解成「Server 不能記住任何東西」,後面的 Serverless、Load Balancing、Failover,甚至 MCP Gateway 都會一起理解歪掉。

MCP 在 2026-07-28 做的事,是拿掉 protocol-level sessioninitialize / initialized 握手與 Mcp-Session-Id 離開新協議核心,每一個 Request 改成攜帶自己需要的 protocol context。這讓 Request 不必回到建立 Session 的那一台 Server。[1]

如果 client 想在正式呼叫前先看 server 的 capabilities,可以選擇呼叫 server/discover;它不是 initialize 的新替代 handshake,也不是 modern request 的必經步驟。一般 modern request 本身已帶著完成這次呼叫所需的 protocol context。[1]

但應用程式仍然可以保存狀態。

這篇要處理的就是這條邊界。

版本範圍:本文以 MCP 2026-07-28 為準,最後核對日期為 2026-08-18。舊版 Client / Server 的 compatibility 與 migration 留到 Part 03。

先把四種常被混在一起的 State 拆開

談 Stateful / Stateless 時,第一個麻煩通常出在用詞:大家嘴裡的「State」根本不是同一件事。

可以先分成四層:

例子2026-07-28 後怎麼處理
Protocol contextprotocol version、client info、capabilities隨 Request 攜帶,不再靠 protocol session 保存
Application / workflow statebasket_idbrowser_idworkspace_id可用 explicit state handle 傳遞/定位,真實狀態由應用程式後端保存
Domain dataGoogle Sheet、CRM record、issue、invoice、database row繼續留在原本的資料真實來源(source of truth)
Identity / authorization使用者、token、principal、permission和 Handle 分開判斷,需要時每次 Call 重新驗證

這四層一拆開,Stateless MCP 就沒有那麼玄。

協議不再替你維持一張看不見的「這個 Client 現在是哪個 Session」表。Application 如果需要跨 Request 記住事情,就自己把那個狀態變成可指向、可傳遞的東西。

Stateless MCP 的 State 邊界:Protocol Session 消失,但 Application State 改成 Explicit Handle

Figure 1-1|Stateless 拿掉的是 protocol session。Application state、domain data 與 authorization 仍然存在,只是責任邊界變得更明確。

2026-07-28 到底拿掉了什麼?

先看舊模式。

2025-11-25 的 Streamable HTTP 模式下,Client 會先做 initialize,Server 可以建立一個 Mcp-Session-Id。後面的 Requests 帶著這個 Session ID 回來。[5]

如果 Server 把很多東西掛在這個 Session 上,例如:

  • 這個 Client 已經初始化過哪些 Capability
  • 現在的 Browser Context 是哪一個
  • 目前購物車裡有什麼
  • 正在編輯哪個 Workspace
  • 某個中間流程跑到哪一步

那 Load Balancer 就會開始有壓力。

因為下一個 Request 如果跑到另一台完全不知道這個 Session 的 Instance,事情就斷了。

常見處理方式有兩種。

第一種是 sticky routing,同一個 Session 一直送回原本那台 Instance。

第二種是把 Session State 放到共享儲存,例如 Redis 或其他 Session Store,讓所有 Instance 都讀得到。

這兩種都能做,只是它們讓 protocol session 開始滲進 deployment architecture。

2026-07-28 把這個 coupling 拿掉。現在每個 JSON-RPC Message 以獨立 HTTP POST 為基本單位,Request 帶著自己的 protocol version 與 client metadata,不再要求 Protocol Session。[1][3]

因此,從 MCP Protocol 本身 的角度,下一個 Request 可以落到另一台 Instance。

這裡要特別把一句話框起來:

「不再需要 shared protocol-session store」和「Application 不再需要 shared state」是兩件不同的事。

假設你的工具真的在維護一個多人共用 Workspace,那個 Workspace 的資料還是要存。假設你有 Idempotency Record、Job Queue、Database Transaction 或 Lock,那些基礎設施也不會因為 MCP Stateless 就蒸發。

協議少背了一個責任;業務真正需要的記憶仍由應用程式保存。

Explicit State Handle:把隱藏的 Session State 變成工具資料

MCP 官方在 SEP-2567 裡給了一個很實用的模式:Explicit State Handle。[2]

假設你有一個購物流程。

舊做法可能是:

Session abc123
└── basket = [shoe, sock]

後面的 add_item 不需要告訴 Server 自己操作哪個 basket,因為 Server 默認「這個 Session 的 basket」。

新的做法會比較像:

create_basket()
→ basket_id = bsk_a1b2c3

add_item(
  basket_id = "bsk_a1b2c3",
  sku = "shoe"
)

basket_id 就是一個普通 Tool Result 裡的欄位,之後再當普通 Tool Argument 傳回去。

它不是 MCP 新增的 handles/* RPC,也沒有特殊的 Handle Type。對 Protocol 來說,它就是一段 Tool Data。[2]

這個差別看起來很小,實際上很有用。

同一個 Agent 可以同時持有多種 State Scope

假設一個 Parent Agent 開了三個 Subagents 幫忙買東西。

三個 Subagents 應該共用同一個 Shopping Basket,但每個 Subagent 又要有自己的 Browser Context。

只有一個 Session Scope 時,這件事很尷尬:

  • 共用 Session,Basket 對了,但 Browser State 可能互相踩掉
  • 各自 Session,Browser State 對了,但 Basket 又被切成三份

Explicit Handle 可以直接表達:

shared basket_id
browser_id_A
browser_id_B
browser_id_C

State 的共享邊界不再被一個 transport session 強迫決定。Orchestrator 可以按資料本身決定哪些要 share,哪些要 isolate。[2]

這也是 Stateless MCP 不只影響擴展性的地方。

它把一部分原本藏在 Transport 裡的狀態,逼回 Application Design 裡。

Handle 後面的 State 存在哪裡?

Handle 只是地址,不是房子。

basket_id = bsk_a1b2c3 本身通常不會裝下整個購物車。Server 收到這個 ID 之後,還是要到自己的應用程式後端找出真正資料。

那個 Backend 可以是:

  • relational database
  • key-value store
  • object store
  • Durable Object
  • workflow engine
  • application service 本身管理的 durable resource

MCP 不替你指定其中一種。

這裡也不要把「External State Store」理解成新規範要求。SEP-2567 明確把 Handle 定義成 Tool Design Pattern,而不是新的 Protocol Primitive。Server 要怎麼存真正的狀態,是應用程式架構的問題。[2]

另外有一條安全邊界很容易漏掉:

Handle 不能自動等於 Authorization。

如果 Server 有登入與權限模型,就不應該因為 Request 知道一個 basket_id,就直接假設它可以操作那個 Basket。官方 guidance 是在每次 Call 重新驗證 (handle, auth_context)。[2]

這和一般 Web API 很像。知道 /orders/12345 不代表你有權讀 Order 12345。

Cloud Architecture 為什麼因此變簡單?

把 Protocol Session 拿掉後,Remote MCP Server 的 deployment model 會靠近一般 stateless HTTP service。

以前如果 Session 綁 Instance:

Client

Load Balancer
  ↓ sticky route
MCP Server A

Protocol Session State

Server A 掛掉時,Failover 不只是「找另一台 Server」。另一台還得知道剛剛那個 Session 發生過什麼。

或者你得改成:

MCP Server A ─┐
MCP Server B ─┼→ Shared Session Store
MCP Server C ─┘

2026-07-28 之後,Protocol 層可以變成:

Client

Round-robin Load Balancer

MCP Server A / B / C

任何 instance 都可以處理新的 request。應用程式如果真的需要 durable state,再讓各 instance 去讀同一個應用程式後端。[1][3]

MCP 從 Session-affine Deployment 轉成 Stateless HTTP Topology

Figure 1-2|新的 MCP Protocol 不再要求 Sticky Session 或 Shared Protocol Session Store。應用程式後端是否共享,取決於你的業務狀態,而不是 Protocol 強迫。

這讓幾件事變得比較普通:

  • Round-robin load balancing
  • Instance replacement
  • Rolling deployment
  • Autoscaling
  • Serverless / edge hosting
  • Failover

Netlify 在 2026-07-28 的官方文章裡直接把新 MCP Server 描述成 ordinary HTTP workload,重點也是不再需要圍著 Session Management 設計 hosting。[4]

但這裡還是要留一條界線。

Stateless MCP 不等於 Serverless MCP。

Serverless 是託管/執行模式。Stateless 是協議屬性。

你完全可以把 Stateless MCP 跑在長駐 VM、Kubernetes、Container Service,也可以跑在 Function / Worker 類平台。Stateless 只是讓後者不必先解決 Protocol Session Affinity,所以適配得更自然。

一個 Google Sheets MCP 的例子:資料到底存哪?

假設有一個很簡單的 Tool:

append_row(sheet_id, values)

Agent 要求 MCP Server 幫忙往 Google Sheet 新增一列。

一個 Serverless 部署可以長這樣:

Agent / MCP Client

   MCP Request

Serverless MCP Handler

 Google Sheets API

    Google Sheet

這個例子裡,至少有三種完全不同的「資料」:

1. 這一次 MCP Request

它在 Request Lifecycle 裡存在。Handler 處理完就可以消失。

2. Google Sheet 裡的資料

它真正存放在 Google Sheets。下一次 Serverless Instance 換了一台,Sheet 裡那列資料還是在。

3. 如果流程本身還有跨 Call State

例如你不是單純 append_row,而是建立了一個「尚未提交的批次匯入工作區」。Server 可以回傳:

workspace_id = ws_7f29

之後 Tool Call 再把 workspace_id 傳回來,而 ws_7f29 背後真正的資料放在 Database、Durable Object 或其他 Application Store。

因此,「MCP 連 Google Sheet,資料是不是存在 MCP?」這個問法本身就少了一層。

比較準確的問法是:

這筆資料是 protocol context、workflow state,還是業務資料?誰是它的 source of truth?

這個示意只在畫責任邊界;實際的 hosting 與 storage design 可以不同。

如果資料不想被記錄呢?Stateless 也不會替你自動解決

另一個常見誤會是:既然 Protocol Stateless,是不是代表資料「用完就沒了」?

不一定。

Stateless Protocol 只保證 Protocol 不需要依賴跨 Request 的隱藏 Session。以下這些地方仍然可能留下資料:

  • Tool 背後的 Business System
  • Application Database
  • Log / Trace / Audit System
  • Queue / Workflow Backend
  • Explicit State Handle 指向的 Durable State
  • Client 自己保存的 Chat / Tool Result

所以資料保留政策仍然要逐層定義。

如果一筆資料不應該被持久化,你要問的是:

  • Tool 有沒有真的寫入 source of truth?
  • 應用程式後端有沒有保存?
  • Log / Trace 是否收到了 Payload?
  • Handle 的 State 何時 Expire / Destroy?
  • Client 是否保存 Tool Result?

「Stateless」不應被當成 Data Retention Policy 的替代品。

Enterprise Gateway 為什麼更容易做,但不是 MCP 規定

Stateless Core 還帶來另一個架構效果。

當 Request 不再需要 Session Affinity,而且重要 operation metadata 可以在 HTTP 邊界被看見,Load Balancer、Gateway、WAF、Rate Limiter 與 Observability tooling 就比較容易用既有 HTTP infrastructure 處理 MCP traffic。[1][3]

這會讓企業常見的 MCP Gateway / Registry / Control Plane pattern 更好落地,例如把:

  • Identity
  • Routing
  • Rate Limit
  • Policy
  • Audit
  • Registry / Discovery
  • PII handling

集中在比較明確的 platform boundary。

不過這個 topology 不該被寫成 MCP 的標準架構。

MCP Spec 沒有要求「企業一定要有 Gateway」,也沒有因為 Stateless 就自動得到 Tenant Isolation、Authorization 或 Audit。

比較精確的說法是:

新 Wire Semantics 降低了 Gateway 對 Protocol Session 的 coupling,企業既有的 HTTP Control Plane 因此更容易理解與治理 MCP。

至於 Mcp-MethodMcp-Name、cache hints、Trace Context 到底怎麼工作,Part 02 再拆。

實作時,先沿著這幾個邊界檢查

如果你現在有一個 Remote MCP Server,先不用急著換成 Worker 或 Function。

比較值得先沿著這些邊界檢查:

  • Failover: 某台 instance 掛掉後,下一個 request 能不能由另一台接?不能的話,先找出依賴的是 protocol session,還是 application state。
  • State identifier: 跨 tool call 的 state 有沒有明確 identifier?如果只存在某個 process memory 裡,failover 還是會斷。
  • Handle storage: Handle 背後真正的資料在哪裡?workspace_id 有了,不代表 durability 問題自動解決。
  • Authorisation boundary: Handle 和 authorization 有沒有分開?知道 ID 不應自動等於有權操作。
  • Lifetime: State lifetime 誰定義?Browser context、basket、workspace、transaction 不一定該活一樣久。Expiry / cleanup 最好成為 tool contract 的一部分。

其中第二點尤其容易做出「假的 Stateless」。

HTTP Request 看起來沒有 Session ID,Application 卻把 current_workspace 偷放在某台 Instance 的 global memory。平常 Demo 完全正常,Autoscaling 或 Restart 一來,State 就跟著 Process 一起蒸發。

Protocol stateless 讓這種架構更容易落地,但 durability、lifetime 與 cleanup 仍由應用程式自己處理。

回到最初的問題:State 到底去哪了?

MCP 2026-07-28 把 State 的責任重新畫了一次。

Protocol 不再持有跨 request session。需要延續的 application state,可以用普通 tool data 表達成 explicit handle;真正資料交給應用程式後端;業務資料繼續待在原本的 source of truth;authorization 仍然是另一條獨立邊界。

這個改變帶來的好處,不只是「少一個 Session ID」。

它讓 Load Balancing、Failover、Autoscaling 與 Serverless Hosting 不必再先配合一個隱藏的 Protocol Session Scope。也讓 State 的 Sharing、Isolation、Lifetime 與 Authorization 變成 Application 必須明講的設計決策。

下一篇會接著處理另一個問題:

沒有長駐 Session 之後,MCP 怎麼做 Human-in-the-loop、多輪輸入、長時間工作、Gateway Routing、Caching 與 Tracing?

這時才會進到 MRTR、HTTP Headers、Tasks Extension 與 Trace Context。

參考資料

  1. Model Context Protocol, The 2026-07-28 Specification, 28 July 2026. https://blog.modelcontextprotocol.io/posts/2026-07-28/
  2. Model Context Protocol, SEP-2567: Sessionless MCP via Explicit State Handles. https://modelcontextprotocol.io/seps/2567-sessionless-mcp
  3. Model Context Protocol, Streamable HTTP: 2026-07-28 Specification. https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http
  4. Netlify, MCP goes stateless and extensible, 28 July 2026. https://www.netlify.com/blog/mcp-goes-stateless-and-extensible/
  5. Model Context Protocol, The 2026-07-28 MCP Specification Release Candidate, 21 May 2026. https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/