Agent 工具能力目录:分页发现、Generation 冻结与调用准入
工具列表能拉取成功,不代表 Agent 看到的是完整且仍获授权的能力集合。本文把分页发现、描述符验证、策略过滤和调用绑定组成版本化 catalog generation,阻断半份目录与迟到变更进入执行面。
本文要点
- 主题聚焦:AI Agent、MCP、DevOps
- 适合人群:独立开发者、全栈工程师、AI 应用开发者
- 核心价值:快速理解背景、实践路径、常见误区和工程建议
把 Server 启动时返回的工具列表拼进系统提示,看起来已经完成“能力发现”,实际留下了三个时间窗口:分页只拿到一半时进程重启,管理员在会话中撤掉写权限,以及工具描述更新后旧计划仍按原参数调用。此时模型选择正确也可能调用一个已经不存在、尚未完整发现或不再属于当前主体的工具。
MCP 工具 Schema 设计讨论单个工具的参数如何可预测,本篇处理多个动态工具何时构成一份可使用的目录。MCP Server 鉴权边界区分用户、Server 与下游身份;目录只能反映某个授权视图,不能把管理员看到的全集当成所有用户的能力。
目录是快照制品,不是可变数组
发布 toolCatalogSnapshot.v1,固定 serverIdentity、传输端点摘要、协议版本、audienceClass、发现开始时间、策略 epoch、catalog generation、页集合、工具描述符摘要和过期时间。audienceClass 只能是服务端可证明的权限类别,不能包含 bearer token,也不能让不同租户共享缓存。每个工具记录稳定 ID、名称、input/output schema digest、风险类别、是否可能产生副作用,以及来源原文;模型友好的短描述是派生字段,不能覆盖来源合同。
schema: toolCatalogSnapshot.v1
server: inventory-mcp@sha256:7c1...
catalogGeneration: 184
audienceClass: tenant-admin.policy-42
policyEpoch: 917
protocol: mcp-2025-11-25
pageRoot: sha256:6a0...
tools:
- id: inventory.reserve@3
descriptor: sha256:51e...
effectClass: RESERVATION
state: COMPLETE
MCP 的 tools/list 支持 cursor 分页,Server 也可声明 listChanged 并发送 notifications/tools/list_changed。但通知只是非事务性的失效提示,协议既未保证每次变化必有通知,也未提供通用的跨页快照 token。连续两次结果相同仍可能经历 A-B-A 变化,不能证明完整。要进入准入目录,适配器必须取得 Server 提供的单调 catalogRevision 或 snapshot token,并让每页及末尾复核都绑定同一代;也可以由代理所有变更的网关从线性化存储签发该代。只有普通 MCP 分页的来源只能标为 UNVERSIONED_OBSERVATION,用于候选展示,不能给自主写调用生成资格。OpenAPI 文档同样只是来源,operation 是否可调用仍由策略层计算。
发现状态限定为 DISCOVERING -> VALIDATING -> SNAPSHOT_PROVEN -> ELIGIBLE,缺少来源 generation 时进入 UNVERSIONED_OBSERVATION,异常进入 INCOMPLETE 或 QUARANTINED,被替代后进入 RETIRED。只有 SNAPSHOT_PROVEN 才能继续校验工具名唯一、schema dialect、引用闭包、大小上限和风险注解。JSON Schema 的 dialect 与 vocabulary 必须显式固定;MCP annotations 也是不可信提示,readOnlyHint 不能单独授予无确认执行权。
只有一次目录接受点
唯一接受点是目录注册表对 (serverIdentity, audienceClass) 的 active pointer 做 CAS:候选必须为 SNAPSHOT_PROVEN,所有页面与末尾复核绑定同一 source catalog revision,策略 epoch、来源身份和信任配置仍未变化,才把 generation 从 183 指向 184。source revision、page root、pointer 与 catalog receipt 同事务写入;缓存、Prompt builder 和 planner 只能读取该 pointer。旧 generation 保留到所有绑定运行排空。
计划节点保存 catalog generation 与 descriptor digest。真正调用时,网关再次检查 active/兼容 generation、当前主体、策略 epoch、工具是否撤销及参数 schema;通过后签发短时、限定工具和资源的执行能力。Agent 短期能力租约负责这一步的不可转移授权。MCP 多租户隔离中的租户上下文也必须进入目录缓存键和调用 receipt。目录命中只证明“曾被准入”,绝不替代调用时授权。
用漂移和乱序攻击完整性
故障套件要在第 2 页后注入 list_changed、A-B-A 目录变化、扫描结束后迟到通知、跨页 source revision 改变、重复 cursor、cursor 环、工具同名异 schema、Server 身份换证、策略撤权与 pointer CAS 竞争;还要让旧 planner 迟到调用。预期无 source generation 的自主写工具进入 ELIGIBLE 为 0,半份页集合准入为 0,跨租户缓存命中为 0。Tool Calling 失败分类可把 STALE_CATALOG、INCOMPLETE_DISCOVERY 和 POLICY_REVOKED 分开观测。
验收门要求十万轮随机分页与通知交错中,完整集合与独立 oracle 一致率 100%;未知 schema dialect 接受为 0;撤权传播 p99 小于 30 秒;每次执行 receipt 绑定 catalog、descriptor 与 policy epoch 的覆盖率 100%;目录刷新失败时旧 generation 仅在未过期且授权仍有效的情况下继续服务。上线先 shadow 构建并比较现有静态清单,再对只读工具开放 5% 会话,最后扩大到写工具。若缺工具率上升或出现一次越权,CAS 把 active pointer 回切上一份仍新鲜的 generation,并停发新 lease;若旧目录也无法证明当前授权,则关闭该 Server,而不是回退到陈旧全集。
Related