MCP Events:當訂閱變成無法撤銷的憑證
核心重點
- MCP Events 為代理新增了第三種喚醒觸發器 —— 除了排程任務與人類訊息之外,MCP 伺服器現在可以在連線應用程式發生變化時,向 ChatGPT 推送簽名的 webhook。
- 訂閱的壽命超過建立它的存取權杖 ——
ttlMs: null會請求一個永不過期的訂閱,而用以識別訂閱的元組不含權杖、範圍與到期時間。 - ChatGPT 支援 webhook 傳遞模式,但不支援草稿中的
terminated撤銷信封 —— 僅存的撤銷訊號是一次失敗的重新整理,回傳-32012 Forbidden。 - 工作小組自己的成功準則 —— 提交一份 SEP —— 尚未交付 —— 章程表格仍顯示 "Ideating",負責人為 "TBD",且僅有 2026 年 3 月 24 日的一筆變更紀錄。
- WorkOS 將訂閱界定為一份憑證 —— 一筆在某個使用者的存取權杖下建立的持久紀錄,即使權杖早已過期,它仍授權你的伺服器把該使用者的資料推送給代理。
在此之前,AI 代理的喚醒只有兩種原因:排程任務觸發,或人類輸入訊息。2026 年 9 月 29 日,OpenAI 在 DevDay 上宣布支援擬議的 MCP Events 規範,讓外掛能在連線應用程式中發生某件事時啟動自動化。官方文件描述了 MCP 伺服器如何向 ChatGPT 推送更新 —— 依頻道篩選的 message.created 事件,或依文件篩選的 comment.created 事件 —— 讓代理在錯誤報告送達或審閱留言發布時立即行動,而不是等你想起来才去問。在 Notion 擔任產品設計的 Nathan Baschez 於 10 月 3 日發文表示:「事件驅動觸發器是一件大事」,而他從未見過如此少的熱情。
本文梳理 MCP Events 實際上實作了什麼、其核心的憑證壽命缺口,以及生產級 MCP 伺服器在發送 webhook 前必須儲存與驗證的內容。本文承襲 MCP 2026-07-28: What the Stateless Protocol Means for B2B Agent Deployments 一文,該篇涵蓋了無狀態核心;此處聚焦事件驅動擴充,以及工作小組尚未定稿的訂閱生命週期問題。
ChatGPT 實際上實作了什麼
MCP Triggers and Events 工作小組章程僅列出一個進行中的工作項目:"SEP: Events in MCP v1 RFC",狀態 "Ideating",目標日期 "End April",負責人 "TBD"。章程只有一筆變更紀錄,日期為 2026-03-24:"Initial charter"。工作小組由 AWS 的 Clare Liguori 與 Anthropic 的 Peter Alexander 領導。
孵化儲存庫呈現了另一番景象。其中有一份標注 "Status: Draft proposal" 的設計草圖,作者 Peter Alexander,日期 2026-02-19。README 的措辭很直接:內容屬探索性質,「不代表 MCP 的官方規範或建議」。實作者已針對它提交實戰回報。但並不存在已提交的 SEP —— 也就是章程自己聲明的成功準則:「一份被接受的 SEP,定義觸發/回呼機制及其訂閱生命週期。」
ChatGPT 實作了這份未完成文件的一部分。OpenAI 的 MCP Events 指南要求 MCP 2.0、協定版本 2026-07-28,並支援草稿中的 webhook 傳遞與回呼驗證。輪詢、串流,以及草稿的 gap 與 terminated 控制通知皆不支援。最後這一點至關重要。
機制本身很直接。伺服器在 server/discover 回應中宣告 events 能力。使用者告訴 ChatGPT 要監測什麼以及如何回應。ChatGPT 呼叫 events/subscribe,附上事件名稱、篩選參數、回呼 URL 與簽名密鑰。伺服器以一次性挑戰驗證回呼,儲存訂閱,然後把符合條件的事件以簽名 webhook 推送出去。三個方法 —— events/list、events/subscribe、events/unsubscribe —— 與工具運行在同一個經過驗證的端點上。
訂閱是一份憑證
值得警惕的是草稿要求你的伺服器儲存什麼。正如 WorkOS 的分析所界定的:事件訂閱是一份憑證 —— 一筆在某個使用者的存取權杖下建立的持久紀錄,即使建立它的權杖早已過期,它仍授權你的 MCP 伺服器把該使用者的資料推送給代理。
把訂閱與授權這次呼叫的權杖比較。依 2026-07-28 授權規範,伺服器必須驗證存取權杖是專為它簽發的,授權必須包含在每個 HTTP 請求中,而無效或過期的權杖必須收到 401。壽命短、範圍窄、每個請求都重新檢查。訂閱則完全不同。設計草圖以元組 (principal, delivery.url, name, arguments) 作為 webhook 訂閱的鍵 —— principal 是伺服器為受驗證主體設定的規範識別碼。該元組不含權杖本身、其範圍或到期時間。而且壽命可以協商到永遠:ttlMs: null 請求一個不過期的訂閱,同意它的伺服器回傳 refreshBefore: null。
| 存取權杖 | 事件訂閱 | |
|---|---|---|
| 壽命 | 短,固定到期 | 由你授予的 TTL 決定,乃至永不過期(ttlMs: null) |
| 綁定到 | 你的伺服器作為受眾,外加範圍 | (principal, url, name, arguments) —— 無權杖、範圍或到期時間 |
| 檢查 | 每個 HTTP 請求,過期回傳 401 | 訂閱時必須(MUST);之後「應該」(SHOULD)定期,但無間隔 |
| 終止於 | 權杖過期或授權伺服器撤銷 | TTL 到期、用戶端退訂,或你的伺服器終止它 |
存取權杖會過期。它建立的訂閱卻持續遞送。
在 ChatGPT 中,撤銷是不對稱的
草稿對義務說得很清楚,對節奏卻含糊其詞。訂閱時,主體必須通過驗證與授權。遞送時:「伺服器應該(SHOULD)定期重新驗證權限。若使用者的存取遭撤銷(例如被移出 Slack 頻道),」伺服器便終止訂閱。OpenAI 的指南重申了同樣的義務:「在訂閱生命週期內重新檢查使用者存取,若存取遭撤銷則停止遞送。」
「定期」一詞在這句話裡承擔了太多。沒有間隔,沒有 MUST,背後也沒有一致性測試。
接著是訊號本身。在草稿中,每種傳遞模式都有自己的「停止」方式。對 webhook 而言,是一個簽名的 {"type":"terminated"} 信封,以 POST 傳送到回呼 URL。此後訂閱不復存在,若終止原因仍然成立,後續重新整理會回傳 -32012 Forbidden。這個信封就是協定告訴代理「已經停止,原因如下」的方式。它也是 ChatGPT 整合不支援的兩種控制通知之一。
| 傳遞模式 | 草稿如何說「停止」 | 在 ChatGPT 中 |
|---|---|---|
| 輪詢 | 下次輪詢出錯 | 模式不支援 |
| 推送串流 | notifications/events/terminated |
模式不支援 |
| Webhook | 簽名的 terminated 信封 POST 至回呼 |
模式支援,信封不支援 |
| 任何模式 | 下次重新整理失敗,回傳 -32012 Forbidden |
僅存的訊號 |
在 ChatGPT 的整合中,僅存的撤銷訊號是一次失敗的重新整理。若使用者存取遭撤銷而你的伺服器停止了遞送,代理只會在訂閱 TTL 到期、重新整理失敗時才得知。若你授予了 ttlMs: null,代理永遠不會知情。
你的伺服器必須驗證什麼
草稿與 OpenAI 指南共同規定了一個真實的安全面。其中不可協商的部分:
- 要求經過驗證的主體。
events/subscribe與events/unsubscribe必須以經過驗證的主體呼叫;授權失敗的呼叫回傳-32012 Forbidden。 - 在首次真實遞送之前驗證端點。 HMAC 防偽造,不防洪水。在確認端點接收遞送的意願之前 —— 透過挑戰握手、允許清單或事先帶外驗證 —— 伺服器不得開始向回呼 URL 遞送。
- 在遞送時執行 SSRF 檢查。 回呼 URL 必須使用 HTTPS。每次連線時皆須解析並驗證目標位址,阻擋私有與本地網段,絕不跟隨重新導向,驗證請求與遞送一視同仁。
- 保持酬載最小。 事件酬載與工具結果具有同樣的注入風險。OpenAI 指南要求發送摘要並提供一個讀取工具以取得完整紀錄,把使用者撰寫的文字當作資料處理,不得在酬載內加入指示模型如何行動的指令。
- 讓寫入具備冪等性。 事件可能亂序送達,重複呼叫不得重複變更。遞送上限 256 KiB,410 與 413 回應不重試。
- 在行動時授權,而非接收時。 收到事件不等於取得行動授權。代理回應事件所發起的工具呼叫,仍要經過你的例行檢查 —— 也就是在 OAuth 範圍之外把關 MCP 工具呼叫的那些檢查。
以上內容都寫在文件裡。文件裡沒有的兩件事:你以多高的頻率重新檢查存取,以及使用者或管理員如何查看自己的帳戶正在推送什麼。
三個必須由你自己做出的決定
訂閱生命週期正是工作小組在章程中為自己設定、卻尚未提交 SEP 的事項。在此之前,三個決定只能由你來做,而預設值會做出糟糕的決定。
第一,授予較短的有限 TTL,拒絕 ttlMs: null。TTL 就是被撤銷的訂閱對用戶端可見的間隔。一個永不過期的訂閱,等於一份無人能見的 OAuth 授權。
第二,以一句能說清的日程重新檢查存取 —— 而不是「定期」。如果你說不出「我們每 15 分鐘重新檢查一次」並指出執行它的排程作業,你依賴的就是一個沒有間隔、沒有一致性測試的 SHOULD。
第三,保留按使用者的訂閱索引。沒有它,為員工辦理離職意味著假設其訂閱已消亡,而不是確認這一點。當一名員工離開,撤銷問題不是「他們的權杖過期了嗎」 —— 而是「他們授權的每一個 webhook 都停止了嗎」。
MCP Events 改變了代理的觸發模型,這才是真正的架構轉變。但憑證壽命缺口才是最先咬到生產部署的部分。協定讓伺服器無狀態;事件擴充又讓伺服器重新有狀態 —— 而它持有的狀態,是一份沒有規定撤銷節奏的憑證。下圖梳理訂閱生命週期、憑證壽命缺口,以及不對稱的撤銷面:
Related reading
- MCP 2026-07-28: What the Stateless Protocol Means for B2B Agent Deployments — 母文章:無狀態核心被 MCP Events 以事件驅動能力加以擴充;無狀態協定讓伺服器無狀態,事件擴充又讓它重新有狀態
- MCP Security Hardening Checklist for Production Deployments — 治理模組論以及適用於事件訂閱的安全控制:SSRF、酬載注入、密鑰輪換、回呼驗證
- A2A vs MCP: Choosing the Right Protocol — MCP Events 為 MCP 增加事件驅動能力後,協定對比有何變化
一家中型 SaaS 公司營運著一個客服 MCP 伺服器 —— 把 ChatGPT 連接到工單系統與知識庫的那種 —— 希望新增事件驅動觸發器,讓代理在高優先級新工單送達時起草回覆。工程團隊實作 events/subscribe,儲存訂閱,並交付 webhook。三週後,一名客服同仁離職。其存取權杖一小時後過期,但以該權杖建立的事件訂閱仍持續向 ChatGPT 推送 webhook —— 因為沒有人授予有限 TTL,按使用者的訂閱索引也不存在。本可在整合中告訴 ChatGPT「一切已停止」的 terminated 信封並不受支援。代理持續處理離職同仁在來源系統中已無權檢視的工單。
申請範圍明確的交付。為期一週的深度評估。你將取得系統清單、工作流程地圖與固定範圍 —— 無論是否與我們共建。
想為您的系統建構這個嗎?
這裡的每份文件都來自真實的生產工作。如果您有目標系統和工作流程想法,我們可以在一週內確定範圍。
申請客製開發為期一週的發掘階段。您會拿到系統清單、工作流程地圖和固定範圍——無論您最終是否與我們合作開發。