MCP 权限分级的关键不是“Agent 能不能调用某个工具”,而是“这次工具调用会造成什么后果”。同一个工具集里可能同时包含查询、修改、发送、删除、支付等动作,如果只按工具集授权,Agent 很容易从只读越界到高风险操作。
更稳的做法是按动作风险分级:只读权限允许读取上下文;可操作权限允许有限、可追踪、可修正的状态变更;高风险动作涉及外部触达、资产、隐私、权限或生产环境,必须保留人的强确认。
我们最早做 MCP 工具接入时,权限不是按风险分级的,而是按“工具集”来管理的。
一个用户,或者一个 Agent,只要拿到了某个工具集,就默认拥有这个工具集里的一组能力。这个设计在早期很方便:接入快、管理简单、业务也能跑起来。
但后来,随着 Agent 调用工具越来越频繁,问题开始暴露出来。
它不再只是偶尔查一下资料,而是开始主动创建、修改、发送、同步、更新。工具越多,边界越模糊。原来按工具集授权看起来足够清楚,但放到 Agent 高频自主调用的场景里,就开始不够用了。
后来我们意识到,MCP 权限不能只按“工具属于哪个集合”来分,更应该按“这次动作会造成什么后果”来分。
也就是:
MCP 权限的关键,不只是 Agent 能不能调用某个工具,而是调用之后会发生什么。
这就是我们后来整理 MCP 三级权限策略的起点。
工具集权限的问题
按工具集授权,本身没有错。
它适合早期,也适合做粗粒度管理。比如一个“订单工具集”、一个“文档工具集”、一个“消息工具集”、一个“知识库工具集”。从平台管理视角看,这种方式很直观。
但问题在于:一个工具集里,往往混着不同风险等级的动作。
比如同样是订单相关能力:
- 查询订单状态,风险很低;
- 修改订单备注,已经改变了业务状态;
- 取消订单、发起退款,则可能带来真实损失。
再比如同样是消息相关能力:
- 查询联系人,是读取信息;
- 生成消息草稿,是辅助操作;
- 直接发送给客户,就是对外触达。
如果这些能力都因为“属于同一个工具集”而被同等授权,Agent 就很容易越界。
这里的越界,不一定是恶意的。更多时候是 Agent 在执行任务时,把“可以看”的边界,顺手推进到了“可以改”;把“生成草稿”的边界,推进到了“直接发送”;把“处理一个对象”的边界,扩展到了“批量处理一组对象”。
所以,工具集是管理视角,权限分级是风险视角。两者可以同时存在,但不能只保留工具集视角。
这一点我们在 agent-runtime-lab 里就是这么落地的:工具集(base / knowledge / apikey)作为管理视角保留,每个工具集再标一个敏感度;但具体权限不看工具集,而是看动作落在哪一档风险。这样平台管理员可以按工具集授权,风险控制却始终按动作来。
| 工具集 | 敏感度 | 只读 | 可操作 | 高风险 |
|---|---|---|---|---|
base | low | get_current_time | — | — |
knowledge | medium | search_knowledge | ingest_knowledge | delete_knowledge_document |
apikey | high | list_api_keys | — | create_api_key、revoke_api_key |
这张表本身就在回答本文一直在追问的问题:同一个工具集里,哪些动作只读、哪些可操作、哪些高风险,必须分开看。
还有一点:这三层不是互斥的开关,而是有包含关系——拿到高风险那一档,自然就包含只读和可操作。这在我们的实现里就是 dangerous ⊇ write ⊇ read,背后的逻辑很简单:能承担更严重后果的角色,不该再被只读权限卡住。继承具体怎么实现,我放在了 权限码那篇。
真正要分的不是工具,而是动作
我们后来更倾向于用动作后果来判断权限等级。
一个工具本身不一定天然属于某个等级。同一个工具,不同参数、不同目标、不同执行方式,风险可能完全不同。
读取一个文件列表,可能只是只读权限。创建一个临时文件,可能是可操作权限。删除整个目录,就一定是高风险动作。
查询客户信息,可能是只读权限。更新客户标签,可能是可操作权限。批量导出客户手机号并发送到外部系统,就已经是高风险动作。
所以 MCP 权限的最小判断单位,不应该只是工具,而应该是动作。
更准确地说,是:
工具 + 参数 + 目标对象 + 影响范围 + 执行后果。
这个判断方式,会比“这个 Agent 有没有某个工具集权限”更贴近真实风险。
第一级:只读权限
第一级是只读权限。
它的定义很简单:只读取信息,不改变业务状态,不触发外部动作。
典型动作包括:
- 查询知识库;
- 搜索文档;
- 读取任务列表;
- 查看订单状态;
- 查询配置;
- 获取公开数据;
- 读取某个对象的基础信息。
只读权限解决的是:Agent 能不能看见上下文。
在很多场景里,如果 Agent 连上下文都看不到,它就只能靠用户反复复制粘贴信息,实际效率会很低。所以只读能力通常可以相对宽松一些。
但“只读”不等于“无限读”。
只读权限仍然要控制数据范围。比如用户只能看自己有权限看的文档,只能查询自己业务范围内的客户,只能读取当前任务相关的信息。对于敏感字段,也应该考虑脱敏、最小化返回,或者按需返回。
所以只读权限的默认策略可以是:
- 用户授权后允许 Agent 自动调用;
- 重点限制数据范围;
- 避免一次性返回过多敏感信息;
- 不允许产生业务副作用。
一句话概括:
只读权限让 Agent 理解上下文,但不能改变上下文。
第二级:可操作权限
第二级是可操作权限。
它的定义是:会改变业务状态,但通常影响范围有限,可追踪、可撤销,或者至少可以人工修正。
典型动作包括:
- 创建任务;
- 新建文档;
- 更新标签;
- 修改备注;
- 生成草稿;
- 发送内部通知;
- 更新非关键配置;
- 提交一条可被人工复核的记录。
可操作权限解决的是:Agent 能不能替我推进一件事。
这一级和只读权限最大的区别,是它已经开始改变系统状态了。
比如,Agent 帮我新建一个待办事项,这不是简单读取;Agent 帮我把客户打上某个标签,也不是简单读取。它们不一定高风险,但已经是业务动作。
所以可操作权限不能完全静默执行。至少需要满足几个条件:
- 用户意图要明确;
- 执行动作要能被解释;
- 关键字段不能靠模型猜;
- 操作结果要可追踪;
- 最好支持撤销或人工修正。
比如用户说“帮我整理一下这个客户的跟进事项”,Agent 创建待办前,最好能展示一下它准备创建什么任务、任务标题是什么、截止时间是什么、关联到哪个客户。
这不是为了增加流程,而是为了防止 Agent 把一个模糊意图直接落成错误动作。
一句话概括:
可操作权限让 Agent 能推进业务,但动作必须清楚、可解释、可修正。
第三级:高风险动作
第三级是高风险动作。
它的定义是:一旦执行,可能造成不可逆影响、资产损失、外部传播、权限变化、隐私泄露或生产事故。
典型动作包括:
- 删除数据;
- 支付、退款、转账;
- 对外发送邮件、短信、企微消息;
- 发布内容;
- 导出敏感数据;
- 修改权限;
- 执行生产环境操作;
- 批量修改核心业务数据。
高风险动作解决的不是“Agent 能不能做事”,而是“Agent 不能擅自替人承担后果”。
这一级的默认原则应该很明确:不能自动执行。
哪怕用户之前已经授权了某个工具集,只要这次动作属于高风险动作,也应该重新进入强确认流程。
强确认至少要展示这些内容:
- 要操作什么对象;
- 会改变什么字段;
- 影响范围有多大;
- 是否会触达外部对象;
- 是否涉及金额、权限、隐私或生产环境;
- 执行后能不能撤回。
如果参数缺失,Agent 不能自行脑补。比如收件人不明确、金额不明确、删除范围不明确、生产环境目标不明确,都应该停下来确认,而不是“推测一个最可能的值”。
对于更高风险的动作,还应该进入人工审批,而不是只靠一次弹窗确认。
一句话概括:
高风险动作必须把最终决定权留给人。
强确认,强在哪里
前面反复说高风险动作“要强确认”,这句话值得再展开一点:强确认到底强在哪里?
如果只是在工具调用时弹个确认框、用户点一下就过,那其实算不上强——事后既说不清当时确认的是哪个参数,也防不住参数被悄悄改掉,更没法追溯。
所以我们在 agent-runtime-lab 里,把高风险动作的确认做成了有状态的审批流程,而不是一次性的 yes/no:第一次调用不会执行,只会创建一条待审批记录,告诉审批人这次具体要删什么、影响什么;审批人在控制台看到之后才决定批准;批准后 Agent 必须用完全相同的参数再调一次才真正执行。而且这条审批绑定了参数哈希、绑定了当前 API Key、只能消费一次、还会过期。
这些细节背后,想表达的还是同一个原则:
高风险动作要回答的,不是“要不要确认”,而是“确认的是哪一次具体动作、由谁负责、能不能追溯”。
这条状态机的完整设计,我在权限码那篇里详细写过。
一个简单的分级判断表
如果要快速判断一个 MCP 动作属于哪一级,可以先问几个问题。
| 判断问题 | 倾向等级 |
|---|---|
| 只是读取信息吗? | 只读 |
| 会改变业务状态吗? | 可操作 |
| 是否可以撤销或人工修正? | 可操作 |
| 会对外发送、发布或通知吗? | 高风险 |
| 涉及钱、权限、隐私、生产环境吗? | 高风险 |
| 执行后是否难以撤回? | 高风险 |
| 影响范围是否从单个对象扩大到批量对象? | 通常升一级 |
这个表不复杂,但它能帮助团队从“工具权限”切换到“动作风险”。
很多时候,权限问题不是因为没有规则,而是因为规则太粗。粗到只看工具,不看动作;只看是否授权,不看后果。
权限分级不是为了限制 Agent
我们后来整理 MCP 三级权限,不是为了让 Agent 少做事。
相反,是为了让 Agent 能在明确边界内放心做事。
只读权限让 Agent 理解上下文,可操作权限让 Agent 推进流程,高风险动作则提醒我们:有些动作必须由人最终确认。
如果没有分级,系统往往会在两个极端之间摇摆。
要么太松,Agent 很容易越界;要么太紧,Agent 什么都要确认,最后用户觉得它根本不好用。
三级权限的价值,就是把不同风险的动作拆开处理。
低风险的,让它自动化;中风险的,让它可解释、可修正;高风险的,让人保留最终决定权。
MCP 的核心价值是连接工具。但当工具开始改变业务状态、触达外部对象、影响真实资产时,权限就不能只停留在“能不能调用”。
它必须升级为:
这次调用会发生什么,影响谁,能不能撤回,谁来承担最终责任。
这才是 MCP 权限分级真正要解决的问题。
这些不是空想
这篇文章讲的分级,在 agent-runtime-lab 里是可运行的。运行 pnpm seed 会拿到四档 API Key:只读、可写、可申请危险动作、以及专门负责审批的一档。换不同 Key 去连同一个 MCP Server,能看到的工具、能执行的动作完全不同——这正是“按动作风险分级”最直观的证明。
至于分级之后,权限码具体怎么设计、审批状态机怎么运转,可以看 MCP 工具权限码怎么设计?read、write、dangerous 三层模型。
完整源码
这篇文章讲的权限分级不是空想,对应的工具声明、权限校验、审批与审计,都开源于 agent-runtime-lab。