博客 • AI / Agent
Claude Managed Agents 2026 新功能解析:AI Agent 如何自动判断 Tool Call 是否允许?JSON 权限策略与 MCP Security 完整教程
2026 年 9 月 10 日,Anthropic 给 Claude Managed Agents 的权限策略加了一种新类型:auto。同一天,agent.tool_use和agent.mcp_tool_use事件开始带evaluation字段,和原来的evaluated_permission并排。
模型提出 Tool Call,并不等于这次调用会被执行。真正拍板的是服务器上的策略评估:它读你写进 Agent 配置的 JSON policy,再对这一次调用的工具名、输入和会话内容给出 allow、deny 或 ask。
本文将介绍:
- 三种 permission policy 各自拦在哪一层
auto按次评估时看什么、三种结果分别留下什么 JSON- MCP toolset 为什么默认
always_ask,和 auto 怎么叠 - 会话停在
requires_action之后,user.tool_confirmation怎么写 - 怎么用 JSONNote 把策略、事件和审批请求拆开核对
先记住这一点:auto不是「全开」,也不是人工审批。服务器认为安全时,调用会在你看见之前跑完;认为高风险时,客户端连推翻 deny 的机会都没有。下面按「三种策略 → 按次评估 → 事件 JSON → MCP → 审批流」拆开。
三种策略:always_allow、always_ask、auto
Permission policy 只管服务器代执行的工具:内置agent_toolset_20260401,以及你挂上的 MCP toolset。自定义工具由你的应用执行,不走这套策略。请求要带 beta 头managed-agents-2026-04-01。官方说明见
Claude Managed Agents Permission policies。
策略决定的是「这次调用何时跑」,不是「这个工具在不在目录里」。要从 Agent 拿掉一个工具,用 disable,不要指望策略替你藏工具。
| 策略 | 服务器做什么 | 客户端还要做什么 |
|---|---|---|
always_allow |
直接执行,不等人 | 读事件即可,没有确认步骤 |
always_ask |
发出 tool_use 事件后停住 | 对每个阻塞事件发user.tool_confirmation |
auto |
按这一次调用评估:跑、拒,或停下来问你 | 只处理结果为 ask 的事件;deny 不能推翻 |
默认值两边不一样。Agent toolset 默认always_allow。MCP toolset 默认always_ask。没有一个 toolset 默认开auto,要自己写进 JSON。
已经在跑的 session 继续用创建时那份 toolset 配置。你改 Agent 之后,新 session 才吃到新策略。发布说明见
Claude Platform release notes(2026-09-10)。
auto 到底看什么
以前只有「这个工具永远放行」或「这个工具永远问人」。auto把判断从工具级改成调用级。
官方写得很具体:评估会看工具本身、这一次的 input,以及到此刻为止的会话内容。所以同一个bash,两条不同的command,结果可以一个 allow、一个 deny。
-
1
调用被放行
服务器认为这次安全,工具按
always_allow那样执行。没有暂停,也没有人工窗口。 -
2
调用被拒绝
服务器把它评成高风险,工具不跑。Agent 收到一条错误 tool result:
Permission to use {tool_name} has been denied.,并且is_error: true。会话继续。你的客户端不能改这个 deny。 -
3
调用停下来等你
服务器给不出确定结论,会话按
always_ask那样暂停。你再用确认事件放行或拒绝。
意图只从你发出的user.message读。工具结果、抓回来的网页、MCP Server 的返回、线程之间的消息,服务器会评估内容,但不会把它们当成指令。有些调用无论谁开口都评成高风险。
如果你把不可信的最终用户原文原样塞进user.message,服务器也会把它当成你的意图,可能因此放行一次调用。这种入口上的工具,应单独配always_ask。
策略写在哪一段 JSON
策略出现在两个位置:toolset 的default_config.permission_policy,以及configs里某一条工具的覆盖。下面这份配置把 Agent toolset 和 GitHub MCP 都设成auto,再把bash单独钉成always_ask。
{
"name": "Ops Agent",
"model": "claude-opus-5",
"mcp_servers": [
{
"type": "url",
"name": "github",
"url": "https://mcp.example.com/github"
}
],
"tools": [
{
"type": "agent_toolset_20260401",
"default_config": {
"permission_policy": { "type": "auto" }
},
"configs": [
{
"name": "bash",
"permission_policy": { "type": "always_ask" }
}
]
},
{
"type": "mcp_toolset",
"mcp_server_name": "github",
"default_config": {
"permission_policy": { "type": "auto" }
}
}
]
}
mcp_server_name必须和mcp_servers里那一项的name对上。MCP 侧按工具名覆盖时,name用 Server 报告出来的工具名,不是你自己起的别名。
省略default_config时,Agent toolset 会以always_allow启用。这是省事的默认值,不是安全默认值。
每次调用留下的 evaluation
不管策略是哪一种,agent.tool_use和agent.mcp_tool_use都会带顶层字段evaluated_permission,取值是allow、ask或deny。大多数事件再带一个evaluation对象,用type标明是哪条策略做出的结论。
在auto下,对象里还会写下服务器的判定;结果是 ask 或 deny 时,再带reason_code。官方例子:bash走 auto,一次高风险调用被拒。
{
"type": "agent.tool_use",
"id": "sevt_01pqr...",
"name": "bash",
"input": {
"command": "rm -rf /workspace/reports"
},
"evaluated_permission": "deny",
"evaluation": {
"type": "auto",
"evaluated_permission": {
"type": "deny",
"reason_code": "high_risk"
}
},
"processed_at": "2026-03-25T14:05:12Z"
}
| evaluation | 顶层结果 | 含义 |
|---|---|---|
{"type":"always_allow"} |
allow | 解析后的策略是 always_allow,调用已执行 |
{"type":"always_ask"} |
ask | 解析后的策略是 always_ask,会话在等你 |
{"type":"auto","evaluated_permission":{"type":"allow"}} |
allow | auto 认为这次安全,已经跑了 |
{"type":"auto","evaluated_permission":{"type":"ask","reason_code":"indeterminate"}} |
ask | auto 给不出结论,停下来问你 |
{"type":"auto","evaluated_permission":{"type":"deny","reason_code":"high_risk"}} |
deny | auto 评为高风险,已经拒绝 |
reason_code是给你的客户端做分支和审计日志的,不是给人看的文案。官方目前写明的有indeterminate和high_risk。客户端必须能容忍以后多出来的type或reason_code。
有两种情况没有evaluation。Agent 点了会话里没启用的工具:事件只有evaluated_permission: "deny"。字段出现之前记下的旧事件也没有它:当时 allow 按 always_allow 读,ask 按 always_ask 读。
这和「JSON 是安全边界」是同一层东西,但切口不同。那边讲的是模型发出去的 arguments 必须先被校验;这边讲的是平台自己会再写一份评估结果,而且这份结果你推不翻。前一篇见
MCP Tool Call 和默认 always_ask
MCP 把工具目录从你的仓库挪到了外面的 Server。Server 用 JSON-RPC 暴露 tool,每个 tool 带inputSchema。Host 把目录喂给模型,再把模型的调用转成tools/call。规范见
Managed Agents 对这件事的默认态度很保守:MCP toolset 默认always_ask。新工具被加进某个你已经连上的 Server 时,不会在你的应用里悄悄执行。这是 MCP Security 在平台侧能落地的第一道闸,比「相信 Server 自己的 description」可靠。
你仍然可以改。信任某个 GitHub MCP、希望它少打断,就把该 toolset 的default_config.permission_policy改成always_allow或auto。改的是「何时执行」,不是「Schema 还要不要验」。
| 层 | 它回答什么 | 它不回答什么 |
|---|---|---|
| JSON Schema | 参数字段、类型、必填、枚举对不对 | 这次调用该不该发生 |
| Tool Calling | 模型选出了哪个工具、填了什么 arguments | Host 会不会执行 |
| permission policy | 这次调用 allow / ask / deny | payload 是否符合 schema、description 有没有带偏模型 |
三层叠在一起才像一扇门。只开 auto、Schema 仍然是{"sql":{"type":"string"}},评估器看到的输入面会宽到无法判断,更多调用会掉进indeterminate,也就是 ask。收紧 schema,是在帮 auto 做出能写进日志的结论。谁负责哪一层,见
MCP 安全:为何 Schema、Tool Calling 和权限不能互相替代。
ask 之后的 JSON 审批流
一次调用评成 ask,只可能来自always_ask,或来自auto的indeterminate。后面的事件顺序是固定的。
-
1
先出 tool_use 事件
会话发出
agent.tool_use或agent.mcp_tool_use,里面已经有evaluated_permission: "ask"。 -
2
再出 idle
会话暂停,
session.status_idle的stop_reason.type是requires_action。被堵住的事件 id 在stop_reason.event_ids。它会一直等。 -
3
你回确认事件
对每个阻塞 id 发
user.tool_confirmation,tool_use_id填那个事件 id,result填allow或deny。拒绝时可用deny_message解释。一次请求可以带多条确认。 -
4
会话回到 running
全部阻塞解开后,被允许的工具执行;被拒绝的不跑,Agent 会收到带你
deny_message的 tool result。
{
"events": [
{
"type": "user.tool_confirmation",
"tool_use_id": "sevt_01ask...",
"result": "allow"
},
{
"type": "user.tool_confirmation",
"tool_use_id": "sevt_01mcp...",
"result": "deny",
"deny_message": "Do not push to main from this session."
}
]
}
如果事件的evaluated_permission不是 ask,你再发确认,API 会回 400。这包括 auto 已经 deny 的调用:客户端没有复议通道。交互式处理可以用ant beta:sessions connect,终端里看到等待中的调用再允许或拒绝。
自己搭审批队列、把 deny 写回 Agent、以及如何在 Host 里落一份可回放的策略,留给后一篇讲实现。本篇只把平台已经替你评估完的那一段 JSON 说清楚。
auto 不是检查点
官方有一句不宜略过:auto不是人类检查点。服务器认为安全时,调用会在任何人看见之前执行,效果可能不可逆。必须有人看的工具,给它配always_ask。
自定义工具也不在这套门里。agent.custom_tool_use既没有evaluated_permission,也没有evaluation。你的应用收到事件,自己决定执行还是拒绝,再回user.custom_tool_result。平台不会替你评这一跳。
所以「AI Agent 如何自动判断 Tool Call 是否允许」这句话,范围其实很窄:只覆盖服务器代执行的 Agent 工具和 MCP 工具,而且只在你显式把 policy 写成auto之后。其余要么永远放行,要么永远问人,要么根本不归平台管。
用 JSONNote 核对策略和事件
策略 JSON、tool_use 事件、确认请求,三份结构长得像,字段却不是同一层。调试时不要靠眼睛扫。
-
1
先格式化策略
把 Agent 的
tools配置丢进JSON 格式化,确认default_config和configs里的permission_policy.type没有写错、没有被覆盖吃掉。 -
2
再校验事件形状
用JSON Schema给
evaluation写一份最小 schema:type枚举always_allow/always_ask/auto,auto 时要求嵌套evaluated_permission。未知的reason_code用additionalProperties兼容,不要直接拒掉。 -
3
对比两次调用
同一工具一允一拒时,用JSON Diff对齐两次
input和两次evaluation。差别几乎总在 command、path 或会话里刚刚发生的那一步,不在工具名。 -
4
留一份可分享的复盘
策略和打码后的事件可以用Hash 分享递给同事,数据不过服务器。密钥和生产 token 不要放进去。
常见问题
auto 会不会把所有 Tool Call 都放行?
不会。auto 是按次评估:同一工具的两次调用,输入和会话不同,结果可以不同。判定为 high_risk 会直接 deny,客户端不能用 user.tool_confirmation 推翻。
JSON Schema 合法是否等于允许执行?
不等于。Schema 只回答参数长得对不对。permission policy 回答这次调用能不能跑。形状合法的 bash 命令,auto 仍可能写成 deny。
MCP Tool Call 默认走哪条策略?
MCP toolset 默认 always_ask。新工具加进 Server 时不会在你的应用里自动执行。信任某个 Server 再把 default_config.permission_policy 改成 always_allow 或 auto。
自定义工具受不受 permission policy 管?
不受。Custom tools 由你的应用执行。事件是 agent.custom_tool_use,没有 evaluated_permission 和 evaluation。你自己决定跑不跑,再回 user.custom_tool_result。
auto 能代替人工审批吗?
不能。官方写明 auto 不是人类检查点。服务器认为安全时,调用会在任何人看见之前执行,副作用可能不可逆。必须人看的工具,单独配 always_ask。
小结
9 月 10 日加上的auto,把「这个工具能不能用」改成了「这一次调用能不能跑」。判断依据是你写进 Agent 的 JSON policy,加上这一次的工具、输入和会话;判断结果写回事件里的evaluated_permission和evaluation。
模型负责提出调用。策略引擎负责允许、拒绝或停下来问人。MCP 默认先问人。自定义工具你自己管。客户端推翻不了 deny。
把策略 JSON 和事件 JSON 当成两份契约来读,不要把 Schema 合法误认成已经授权。需要人盯的工具继续 always_ask;需要少打断、又能留下审计字段的工具,再打开 auto。
把策略和 tool_use 事件拆开看