ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

MCP 事件模型:通知类型、消息格式、幂等性

MCP 事件模型:通知类型、消息格式、幂等性

1. 为什么需要 MCP 事件

到目前为止,ChatGPT 与你的后端之间的交互几乎都是 RPC:模型调用工具,工具做点事并返回结果——搞定。对于 200–500 ms、最多几秒的短操作,这很方便。

但一旦出现长耗时任务——例如为 GiftGenius 分析一份很大的员工偏好文件、从一堆外部 API 聚合推荐、重算一个庞大的 feed——事情就变得不那么美妙。HTTP 超时、函数重启、永远转的加载动画,用户坐在那里猜:“它还活着,还是已经挂了?”

这时事件模型就该登场了。与其维持一次长时间的工具调用,不如启动一个任务,拿到 jobId,接下来由服务器主动推送事件:已开始、进度更新、完成、失败。MCP 中的这些事件实现为 JSON-RPC notifications——单向消息,没有 id,不期待响应。

重要的一点:事件不是“线上 console.log”。它是具有固定模式的协议消息,你的 UI(小部件)和/或代理必须像处理工具调用结果那样严谨地处理它。

回顾:MCP 中的消息类型

在继续之前,先简要回顾一下 MCP 里到底有哪些消息类型。

撇开营销层不谈,MCP 基于 JSON-RPC 2.0。它有三类基础消息:请求、响应和通知。

不赘述列表,我们直接看一张小对比表:

类型字段 id谁发起是否期待响应?MCP 中的示例
Request有通常为客户端(ChatGPT)是调用工具 tools/call
Response有MCP 服务器这本身就是响应tools/call 的结果
Notification无客户端或服务器否notifications/progress、resources/updated、logging/message

MCP 事件正对应第三行:notifications。其特征:

  • 顶层没有 id——不会有 result 或 error 作为回应;
  • 发起方不等待 ACK——在协议层面“发射即忘”;
  • 可靠性不是靠确认,而是靠处理器的幂等性与重试策略来构建。

重要限制:MCP 事件不会“随时随地在太空中乱飞”。它们存在于已建立的 MCP 连接之内,承载在具体的传输之上。最常见的是类似 SSE 的流(传输细节及其变体我们会在单独一讲中讨论)。

2. 什么是“实际的 MCP 事件”

从形式上说,MCP 事件就是 JSON-RPC notification,即如下对象:

{ "jsonrpc": "2.0", "method": "notifications/job/progress", "params": { "jobId": "job_123", "percentage": 30, "stage": "在目录中查找备选", "eventId": "evt_abc123", "timestamp": "2025-11-21T10:15:00Z" } }

这里有几个要点:

  1. 在 method 字段中,我们编码事件类型及其“命名空间”。MCP 已经定义了一些标准的 notifications/... 方法用于日志、进度与资源变更,但你可以、也应该添加自己的业务专用方法,比如 notifications/job/progress 或 notifications/job/completed。
  2. 所有业务数据位于 params。我们会在那里保存任务标识(jobId)、事件唯一 ID(eventId)、时间(timestamp)、人类可读的消息等。
  3. 顶层没有 id 字段——这正是它是 notification 的原因。协议不提供对此的响应。如果服务器想知道“对方是否理解了”,可以再发一个事件,或等待客户端的后续反应(例如新的请求)。但就 JSON-RPC 而言,没有 ACK。

在心智模型上可以这样理解:工具调用 tools/call 是“你等待回复的信件”,而事件则是“来自 Slack 机器人的通知:“后台任务 #123 已完成””。

3. 事件分类:有哪些通知

如果只是放开“随便把 JSON 当 notifications 发”,两周后系统就会变成垃圾场:事件名称各不相同、字段到处漂移、UI 不知道如何处理。因此最好先约定一个小而清晰的分类法。

下面是一种与 MCP 规范以及 ChatGPT Apps 实际用例非常契合的分类方式。

作业生命周期事件(Job Lifecycle)

这类事件反映任务状态的关键跃迁。通常任务有一个状态机(state machine),如 pending → running → (completed | failed | canceled)。

典型事件:

  • job.created —— 任务已注册;
  • job.started —— worker 已开始执行;
  • job.completed —— 任务成功完成;
  • job.failed —— 任务失败并带错误;
  • job.canceled
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进