可缓存结果
服务器 MUST 在以下操作返回的结果中包含缓存提示:server/discovertools/listprompts/listresources/listresources/templates/listresources/read
缓存模型
MCP 中的可缓存结果使用两个字段向客户端提供缓存提示:- 生存时间 (TTL) 字段
ttlMs是以毫秒为单位的整数值,指定客户端 MAY 将结果视为新鲜的时长。 - 缓存作用域字段
cacheScope指示缓存响应的预期作用域,可以是"public"或"private"。
Time-to-Live (TTL) 字段
ttlMs 字段是服务器给出的提示,表示客户端 MAY 将结果视为新鲜的毫秒数。其语义类似于 HTTP Cache-Control: max-age。
- 如果
ttlMs为0,响应 SHOULD 被视为立即过期。客户端 MAY 在每次需要结果时重新获取。 - 如果
ttlMs为正数,客户端 SHOULD 在收到响应后的相应毫秒数内将结果视为新鲜。 - 如果缺少
ttlMs,客户端 SHOULD 假定默认值为0(立即过期),并依赖自身缓存启发式规则或通知。这只应出现在较旧的服务器版本中。 - 如果
ttlMs为负数,客户端 SHOULD 忽略它并将其视为0。
>= 0 的 ttlMs 值。
TTL 是新鲜度提示,不是保证。服务器 MAY 在 TTL 过期前更改底层数据。
TTL 告诉客户端它可以合理地避免重新获取多久,而不是保证数据会保持不变多久。
新鲜度计算
客户端记录收到响应时的本地时间(t_received)。当满足以下条件时,响应被视为新鲜:
缓存作用域字段
cacheScope 字段控制谁可以缓存响应,类似于 HTTP Cache-Control: public 与 Cache-Control: private。
选择缓存作用域
- 当工具、提示和资源模板列表对所有用户都相同时,
"public"是合适的。 - 对于依赖已认证用户的
resources/read结果,或按用户变化的过滤列表结果,"private"是合适的。
与通知的交互
TTL 与服务器推送通知互为补充:- 服务器 MAY 在其能力中不公告
listChanged: true的情况下提供ttlMs。在这种情况下,客户端完全依赖基于 TTL 的新鲜度。 - 服务器 MAY 同时公告
listChanged: true并提供ttlMs。在这种情况下,客户端可以使用 TTL 来避免在通知之间进行不必要的重新获取,而通知则作为立即失效信号。
与分页的交互
当列表结果被分页时,每一页都是可独立缓存的响应,这与 HTTPCache-Control 处理分页资源的方式一致。
- 每个页面响应都携带自己的
ttlMs值。每页的新鲜度时钟从收到该页的时间开始。 - 服务器 MAY 在不同页面上返回不同的
ttlMs值(例如,对稳定列表的早期页面使用较长 TTL,对最后一页使用较短 TTL)。 - 当缓存页过期时,客户端 SHOULD 使用其游标重新获取该页。
- 不保证跨页面一致性。如果底层数据在页面获取之间发生变化,客户端可能会观察到重复或缺口。
- 需要完整列表一致快照的客户端 SHOULD 从头开始重新获取(不带游标)。
- 如果游标变为无效(例如,服务器对先前有效的游标返回错误),客户端 SHOULD 丢弃所有缓存页并从头开始重新获取。
cacheScope。例如,如果 tools/list 响应的第一页具有 cacheScope: "private",则该请求的所有后续页面也 MUST 是 "private"。
安全注意事项
cacheScope 为 "public" 表示响应不包含用户特定数据,可以安全共享。服务器 MUST 意识到,即使结果来自已认证端点,具有 "public" cacheScope 的响应也可能在调用方之间共享。例如,带有 "public" cacheScope 的已认证 tools/list 调用结果可能被客户端缓存,并可能在初始请求授权上下文之外共享。(即,不同访问令牌可以利用同一缓存。)
服务器实现者:
- 应确保
cacheScope正确反映原语的预期可见性。 - MUST 应用适当的逐原语访问控制,且 MUST NOT 仅依赖
cacheScope来防止对原语的未授权访问。