MCP 服务器提供的 Tools、Prompts、Resources 并不是连接后就一成不变的。用户登录后可能解锁新工具,管理员可能随时启用或禁用某些 prompt 模板,资源的可用性也可能因为各种原因发生变化。
如果客户端只在初次连接时调用一次 tools/list、prompts/list、resources/list,那么后续的变化就无法感知。新增的工具看不到,已经下线的工具还留在列表里,状态不一致只能靠重连或重启来修复。
list_changed 就是用来解决这个问题的。服务器通过一条标准通知告知客户端"列表变了",客户端收到后重新拉取列表,完成同步。
本文基于 MCP 官方规范(2025-11-25 版本),说明 list_changed 的字段与方法名,并记录 Claude Code 2.1.0 对该机制的支持情况。
为什么需要 list_changed
核心需求很简单:服务器端的可用列表变了,客户端需要在不断开连接的情况下感知到这个变化。
listChanged 能力声明
MCP 服务器在初始化阶段会声明自身的能力(capabilities)。如果服务器打算在列表变化时主动通知客户端,就需要在对应的能力字段里把 listChanged 设为 true。
Tools
{
"capabilities": {
"tools": {
"listChanged": true
}
}
}声明后,服务器会在工具列表发生变化时向客户端发送通知。
Prompts
{
"capabilities": {
"prompts": {
"listChanged": true
}
}
}Resources
{
"capabilities": {
"resources": {
"listChanged": true
}
}
}Resources 的能力声明里还有一个 subscribe 字段,用于订阅单个资源的内容变化,跟这里讨论的"列表变化"是两回事。
通知的 JSON-RPC 格式
list_changed 是 JSON-RPC 的 notification,只有 jsonrpc 和 method 字段,没有 id。
工具列表变化
{
"jsonrpc": "2.0",
"method": "notifications/tools/list_changed"
}客户端收到后,调用 tools/list 重新获取工具列表。
提示列表变化
{
"jsonrpc": "2.0",
"method": "notifications/prompts/list_changed"
}客户端收到后,调用 prompts/list 重新获取。
资源列表变化
{
"jsonrpc": "2.0",
"method": "notifications/resources/list_changed"
}客户端收到后,调用 resources/list 重新获取。
客户端如何响应
以工具为例,整个流程分三步:
- 服务器端工具列表发生变化
- 服务器发送
notifications/tools/list_changed通知 - 客户端收到通知,调用
tools/list拉取最新列表并更新本地状态
Prompts 和 Resources 同理。
需要注意的是,通知本身不携带列表内容,它的作用仅仅是告诉客户端"该重新拉取了"。
总结一下命名规律:
| 类型 | 能力声明 | 变更通知 | 列表拉取 |
|---|---|---|---|
| tools | capabilities.tools.listChanged | notifications/tools/list_changed | tools/list |
| prompts | capabilities.prompts.listChanged | notifications/prompts/list_changed | prompts/list |
| resources | capabilities.resources.listChanged | notifications/resources/list_changed | resources/list |
Claude Code 2.1.0 的支持
Claude Code 从 2.1.0 版本开始支持 MCP 的 list_changed 通知。实际效果是:服务端 Tools/Prompts/Resource 列表发生变化后,客户端能自动刷新,不再需要通过重连来同步状态。
典型应用场景
以下场景都可能触发列表变化:
- 认证状态变化:用户登录后可用工具变多,退出后变少
- 配置更新:管理员启用或禁用了某些工具或 prompt 模板
- 资源可用性变化:某类资源上线或下线,导致资源列表变化
- 权限变更:用户角色变化带来可见性变化
MCP 协议本身不关心这些业务层面的原因,它只负责在变化发生后提供标准的通知机制。
小结
list_changed通知只表示"列表可能变了",具体变成什么样,客户端还是要调用对应的 list 方法获取notifications/resources/list_changed是资源列表的变化通知,不是某个资源内容的更新通知- 只有在 capabilities 里声明了
listChanged: true,服务器才会发送对应的通知