Tool、MCP 与安全:把模型意图变成受约束的现实动作

1. 第一性原理:Tool 是副作用边界

模型输出的是意图,Tool 执行的是真实动作。读文件、修改代码、发请求、运行命令和部署服务的风险完全不同,所以 Tool 不是“给模型增加几个函数”,而是把副作用放进一个有合同、有权限、有审计的执行边界。

每个 Tool 都应明确:输入 Schema、输出 Schema、所需权限、可访问资源、超时、重试语义、幂等键、取消方式、审计字段和验证方法。

2. Tool Gateway 的职责

不要让模型直接连接任意外部服务。Tool Gateway 位于模型和执行环境之间,负责:

解析 → Schema 校验 → 权限判断 → 风险分级 → 资源隔离
→ 执行/超时/取消 → 结果归一化 → 审计与轨迹记录

MCP 可以统一工具发现和调用协议,但协议统一不代表权限自动安全。每个 Server、Tool 和资源仍需独立授权,租户、Session 和用户身份不能只由模型参数传递。

3. 输入安全与提示注入

提示注入的本质是:不可信数据试图改变控制指令。网页、Issue、README、代码注释和 Tool 返回都可能包含“请忽略之前规则”之类文本。

第一性原则是分离数据和指令:不可信内容默认是证据,不是授权;Tool 返回应带来源和信任级别;系统规则和用户任务合同要放在更高优先级层;危险动作必须通过策略检查,而不是让模型自行判断。

可以维护一个风险矩阵:低风险读取、可回滚的局部编辑、不可逆文件删除、外网写操作、凭据使用和生产部署。风险越高,越需要显式审批、沙箱、双重验证和更细的审计。

4. Tool 错误为什么不能直接重试

错误分类先于重试。至少区分:

  • 参数错误:修正输入后重试,不能原样重试。
  • 权限错误:请求授权或换用合法能力。
  • 资源不存在:重新探索或更新目标。
  • 超时/限流:指数退避,并检查动作是否已经提交。
  • 服务端错误:有限次数重试,超过预算后降级。
  • 部分成功:读取真实状态,执行补偿或继续剩余部分。
  • 未知错误:停止自动化并保留证据。

重试必须携带幂等键。对于创建资源、发消息、提交订单这类动作,“请求超时”不代表没有成功,直接重试可能造成重复副作用。更稳妥的流程是查询状态,再决定重试、确认或补偿。

5. 幂等、取消与排空

幂等不是让函数永远返回同一个结果,而是同一个逻辑操作重复提交不会产生额外副作用。幂等键应由 session_id + turn_id + tool_call_id 等字段组成,并有过期时间和状态记录。

取消也不是简单杀掉进程。Runtime 要先阻止新的 Tool Call,通知正在执行的工具,等待可安全取消的阶段,记录已提交动作,最后把 Session 置为可恢复状态。对于无法取消的动作,应进入排空和补偿流程。

6. 结果验证与最小权限

Tool 返回的成功状态只能证明接口调用成功,不能证明任务成功。文件修改要检查 diff 和测试;数据库写入要读取结果;部署要检查健康状态;研究任务要检查证据覆盖和来源可信度。

最小权限应按 Session、Tool、资源和动作拆分。只读任务不应持有写权限;某个 Skill 的权限不能自动扩散给嵌套 Skill;凭据尽量由 Gateway 代持,不能直接放进模型上下文。

7. MCP 的工程化边界

MCP Server 是能力提供者,Gateway 是策略执行者,Sandbox 是运行环境,Verifier 是结果裁判。四者职责要分开:Server 不应替调用方做最终授权,Sandbox 不应替业务验证结果,模型也不应替策略系统授予权限。

协议演进需要版本化 Schema 和兼容策略。新增字段应允许旧客户端忽略,改变字段语义要升级版本;Tool 的错误类型、分页、流式结果和取消事件都应写入契约测试。

8. 审计与学习者练习

一条可审计的 Tool 记录应关联任务、Turn、调用者、参数摘要、权限决定、执行环境、结果摘要、重试和验证证据。敏感参数要脱敏,但不能让审计失去定位能力。

练习:设计三个 Tool——读文件、编辑文件、运行测试。为每个 Tool 写 Schema、权限、超时、重试和验证策略;注入一个恶意 README;再模拟一次超时但实际已经提交的写操作,验证系统是否会重复副作用。