跳到主内容

MCP 工具注解详解:readOnlyHint 与 destructiveHint 怎么帮客户端做决策

100%
MCP 工具注解详解:readOnlyHint 与 destructiveHint 怎么帮客户端做决策

一句话结论

MCP 工具注解(ToolAnnotations)是服务端给工具贴的四张「行为提示」标签——readOnlyHint 、 destructiveHint 、 idempotentHint 、 openWorldHint,帮客户端决定「调之前要不要问用户」,但它们只是提示不是安全机制,来自不可信服务器时应当整个忽略。

写 MCP 服务端的人大多见过注册工具时的 annotations 参数,但真正用对的不多:要么全留空让客户端按最坏情况处理,要么乱标 readOnlyHint 反而把自己工具的风险掩盖掉。 2026 年 3 月 MCP 官方博客专门发文梳理了注解的现状与边界,这篇按「是什么、默认值、怎么用、什么时候不可信」四步讲清(还不了解 MCP 协议本身的,先看我们的 MCP 入门教程)。

四个提示分别管什么

注解随 2025-03-26 版规范落地,当前接口一共五个字段(含纯展示用的 title):

注解回答的问题默认值
readOnlyHint工具会不会修改环境?false(默认会改)
destructiveHint如果会改,是破坏性的还是追加性的?true(默认破坏性)
idempotentHint同一参数重复调用是否无副作用?false(默认不幂等)
openWorldHint与封闭域交互还是开放的外部世界?true(默认开放)
title给 UI 看的人类可读名称无

默认值的设计原则是「未声明即按最坏情况」:没有注解的工具被视为会改环境、可能破坏、不幂等、开放世界。这套悲观默认让漏标的服务端不会获得危险的高估。

前三个提示回答的基本是同一个前置问题:客户端要不要在调用前向用户确认。第四个 openWorldHint 不一样——它描述工具的触达范围和输出可能带回什么,这在调用之后同样重要,且对部署环境高度敏感(「外部」指公司内网之外还是本机之外,取决于服务器跑在哪)。

代码里怎么标注

Python SDK 的装饰器写法(官方文档示例的工具):

@mcp.tool(
    title="Search the catalog",
    annotations={
        "readOnlyHint": True,      # 只读:不改任何东西
        "openWorldHint": False,    # 封闭域:只查这个目录,不碰开放网络
    },
)
def search_books(query: str) -> str:
    ...

destructiveHint 和 idempotentHint 只对「会写」的工具才有意义——规范定义它们仅在 readOnlyHint == false 时有效,一个纯查询工具标这两个字段没有语义。一个删除接口的合理标注是 destructiveHint: True;一个追加日志的接口则是 destructiveHint: False 加 idempotentHint: False。

核心纪律:提示不是担保

规范原文说得毫不含糊:所有注解属性都是 hints,不保证忠实描述工具行为(包括 title 这种描述性字段);客户端绝不应基于来自不可信服务器的注解做工具使用决策。这段话的来源是规范评审时的真实争论——MCP 联合创始人 Justin Spahr-Summers 当时就提出:如果信息不可信,客户端拿它有什么用?最终的折中方案是:全部叫 hint 、默认按不可信对待、由每个客户端根据自己对服务器的了解决定采信程度。 Basil Hosmer 的立场更激进:对不可信服务器的注解应该整个忽略,包括 title 。

落成实践守则就是一句话:

服务端:如实标注,宁可悲观。客户端:只对自己信任或审计过的服务器采信注解;对第三方市场的工具,注解一律按默认值处理。注解防的是误操作,不防恶意——安全边界永远要在 OS 权限与沙箱层做。

现状:覆盖率不均,社区仍在演进

官方博客披露,注解推出以来社区已提交五份独立 SEP(规范增强提案)试图新增注解,背后是对「智能体工作流里风险到底在哪」的共识仍在深化。同时大量存量服务器根本没标注解,各家客户端对悲观默认的执行宽严也不一——这正是当前波 SEP 想收敛的差距。另外早年讨论过的一些方案(stateless 、 streaming 、 async 注解、安全类注解)有的被否决,有的换了形态(taskHint 最终以 Tool.execution 落地),如果看到旧资料提到这些,以现行规范为准。

工具注解要和另外两件事配合看:一是工具描述(description)写给模型读、注解写给客户端读,两者互补;二是真实风险控制要落在审批点设计上——客户端把 readOnlyHint 为 true 的工具设为静默执行、其余弹确认,是目前的常见实现。更系统的防泄漏与防投毒思路可以参考我们的 MCP 安全风险清单,动手写服务端则从 MCP Server 搭建教程起步。


不写注解会怎样?
客户端按最坏情况处理:当作会改环境、可能破坏、不幂等、开放世界。功能正常,但用户可能被不必要的确认弹窗打扰——纯查询工具建议至少标 readOnlyHint: True 。

readOnlyHint: True 能保证工具真的只读吗?
不能保证。它只是服务端的自述,规范明确客户端不应基于不可信来源的注解放行。真正的保证来自权限配置、沙箱与审计。

openWorldHint 有什么实际用途?
帮客户端评估输出风险:开放世界工具(如网页搜索)可能把外部不可信内容带进上下文,客户端可以对其结果做额外的注入检测;封闭域工具(如内存存取)则可以放宽。

注解和工具的 description 有什么区别?
description 主要是给大模型看的自然语言说明,影响模型选不选这个工具;注解是结构化字段,给客户端程序用来决定审批策略。两者都写、各司其职。

这篇有帮助吗?
云上的幻象
云上的幻象查看主页

七彩云博客,分享 WordPress 建站实战与 AI 工具测评,覆盖服务器运维、站长工具、软件资源与电商运营干货,专注原创实用的主题插件、网站加速与安全优化教程。

847文章4评论

相关文章

评论 (0)

欢迎你,新朋友,感谢参与互动!文明发言,理性交流 · 首次评论将在审核后展示