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 信封并不受支持。智能体继续处理离职员工在源系统中已无权查看的工单。
申请范围明确的交付。为期一周的调研。你将获得系统清单、工作流地图和固定范围 —— 无论是否与我们共建。
想为您的系统构建这个吗?
这里的每份文档都来自真实的生产工作。如果您有目标系统和工作流想法,我们可以在一周内确定范围。
申请定制开发为期一周的发现阶段。您会拿到系统清单、工作流地图和固定范围——无论您最终是否与我们合作开发。