返回资料库
MCP

MCP Events:当订阅变成无法撤销的凭据

最后更新:2026年10月3日

核心要点

  • 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 改变了智能体的触发模型,这才是真正的架构转变。但凭据寿命缺口才是最先咬到生产部署的部分。协议让服务器无状态;事件扩展又让服务器重新有状态 —— 而它持有的状态,是一份没有规定撤销节奏的凭据。

下图梳理订阅生命周期、凭据寿命缺口,以及不对称的撤销面:

MCP Events:订阅生命周期与凭据缺口 2026-07-28 无状态规范之后首个新的 MCP 传输原语 1 订阅 —— events/subscribe ChatGPT 携事件名、过滤参数、回调 URL、签名密钥(HMAC)调用你的服务器 服务器通过挑战握手验证回调,存储订阅:拥有者、过滤器、URL、密钥、过期时间 要求 MCP 2.0,协议版本 2026-07-28 · 面向 12 亿 ChatGPT 周活用户 2 凭据缺口 —— 订阅比令牌活得更久 访问令牌:短寿命,每次请求校验作用域,过期返回 401 订阅:以 (principal, url, name, arguments) 为键 —— 键中无令牌、作用域或过期时间 ttlMs: null 请求永不过期 · refreshBefore: null 获准 · WorkOS:"一份无人能看见的凭据" 令牌:约 1 小时 TTL 每次请求校验 订阅:可达永远 SHOULD "定期" —— 无间隔 3 交付 —— 签名 webhook 至回调 URL Standard Webhooks:webhook-id、webhook-timestamp、webhook-signature · 上限 256 KiB · 每次请求一个事件 交付时执行 SSRF 检查:仅 HTTPS,屏蔽私有网段,不跟随重定向 · 载荷 = 注入面 写入幂等(事件乱序到达) · 收到事件 ≠ 行动授权 4 撤销 —— 在 ChatGPT 中不对称 草案:签名 {"type":"terminated"} 信封 POST 至回调 → 智能体立即得知"已停止及原因" ChatGPT:支持 webhook 模式,不支持 terminated 信封 草案撤销路径 terminated 信封 → 智能体立即收到通知 ChatGPT 撤销路径 TTL 到期 → 刷新失败 → -32012 Forbidden(仅存信号) ttlMs: null 永不过期 → 刷新永不触发 → 智能体永远不知情 5 工作组 —— SEP 尚未提交 负责人:Clare Liguori(AWS)+ Peter Alexander(Anthropic) · 章程变更记录:一条,2026-03-24 活跃工作项:"SEP: Events in MCP v1 RFC" —— 状态:Ideating · 目标:End April · 负责人:TBD 设计草图已存在(2026-02-19,草案) · 实现者提交实战报告 · 无 SEP = 无合规测试 订阅生命周期明确在范围内,也明确未完成 上线前必须由你做出的三个决定 1. 授予较短的有限 TTL —— 拒绝 ttlMs: null 2. 以一句能说清的日程重新检查访问 3. 保留按用户的订阅索引 —— 离职时确认,而非假设

Related reading


一家中型 SaaS 公司运营着一个客服 MCP 服务器 —— 把 ChatGPT 连接到工单系统和知识库的那种 —— 希望增加事件驱动触发器,以便在新的高优先级工单到达时由智能体起草回复。工程团队实现 events/subscribe,存储订阅,交付 webhook。三周后,一名客服人员离职。其访问令牌一小时后过期,但以该令牌创建的事件订阅仍在向 ChatGPT 推送 webhook —— 因为没有人授予有限 TTL,按用户的订阅索引也不存在。本应在集成中告诉 ChatGPT "一切已停止" 的 terminated 信封并不受支持。智能体继续处理离职员工在源系统中已无权查看的工单。

申请范围明确的交付。为期一周的调研。你将获得系统清单、工作流地图和固定范围 —— 无论是否与我们共建。

想为您的系统构建这个吗?

这里的每份文档都来自真实的生产工作。如果您有目标系统和工作流想法,我们可以在一周内确定范围。

申请定制开发

为期一周的发现阶段。您会拿到系统清单、工作流地图和固定范围——无论您最终是否与我们合作开发。