query() 会话里能做什么。它可以限制模型可见的工具,设置默认授权策略,在工具执行前交给宿主应用审批,也可以在用户授权后把新规则应用到当前会话。
权限控制不是一个单独的 API,而是一组放在 query({ options }) 里的配置。通常你会先决定本次会话允许模型使用哪些工具,再决定这些工具在什么情况下可以执行,最后按需要接入运行时审批、动态规则更新、settings 或 hooks。
Read、Grep、Bash,其中 Read 和 Grep 预授权,Bash 禁止执行。实际项目里,你可以继续加上 canUseTool,把未预授权的操作交给自己的产品 UI、审批系统或风控服务判断。
快速开始:让宿主应用审批工具调用
当你需要把工具调用接入自己的审批逻辑时,使用canUseTool。SDK 会在运行时把工具名、工具入参和一组可展示的审批信息交给你的 callback。callback 返回 allow 时工具继续执行,返回 deny 时工具被拒绝。
read_order 是一个 SDK MCP 工具。模型调用它时,完整工具名会是 mcp__orders__read_order。canUseTool 只允许这个工具执行,并把原始入参作为 updatedInput 返回。返回 toolUseID 可以让运行时把审批结果和本次工具调用准确对应起来。
控制默认策略:permissionMode
permissionMode 决定会话的默认权限策略。它适合表达“这次会话整体处于什么模式”,例如先计划、自动接受编辑、不询问直接拒绝,或者在受控环境里跳过权限检查。
plan 模式适合让模型先产出计划,再进行变更。
需要在同一个会话里切换模式时,可以使用返回的
Query 对象:
bypassPermissions 和 yolo 都是高风险模式。SDK 要求显式传入 allowDangerouslySkipPermissions: true,避免调用方误把普通会话变成跳过权限检查的会话。
控制工具范围:tools、allowedTools、disallowedTools
工具控制回答的是“模型能看到哪些工具,以及哪些工具默认允许或禁止”。这三个字段经常一起出现,但语义不同。Read、Grep、Bash 三个工具;其中 Read 和 Grep 预授权;Bash 被禁止,即使模型想调用也不会执行。
当同一个工具同时匹配 allow 和 deny 时,deny 优先。这能确保禁止规则不会被更宽泛的允许规则绕过。
MCP 工具也使用完整工具名匹配。例如 SDK MCP server 名为
orders,工具名为 read_order,完整工具名就是 mcp__orders__read_order。
运行时审批:canUseTool
canUseTool 适合宿主应用需要参与审批的场景。比如你要把权限请求展示在自己的 UI 里,让用户点“允许一次”“始终允许本会话”或“拒绝”;或者你要调用企业风控服务判断某个命令是否可执行。
canUseTool 的签名如下:
返回
allow 表示继续执行工具:
updatedInput 是工具最终收到的参数。你可以原样返回,也可以在审批通过后修改参数。例如给查询增加租户 ID、把路径改写到安全目录,或者去掉不允许的字段。
返回 deny 表示拒绝工具:
deny.message 必填,它会成为拒绝原因的一部分,供模型、日志或宿主应用展示。SDK 收到 CLI 的授权请求但没有配置 canUseTool 时,会返回错误,不会默认放行。
当权限系统直接拒绝工具调用时,消息流中可能出现结构化的权限拒绝消息:
permissionMode: 'dontAsk'、自动拒绝或规则拒绝等场景。宿主应用可以用它更新 UI 状态或写审计日志。
会话内更新权限:PermissionUpdate
PermissionUpdate 用于在一次审批之后更新当前会话里的权限规则。最常见的场景是用户在审批 UI 里选择“始终允许本会话”。这时你可以把运行时给出的 suggestions 原样返回,也可以自己构造明确的规则。
推荐把动态权限更新写入当前会话:
session 只影响当前 query 会话后续的权限检查。需要持久化到本地、项目或用户级配置时,优先使用 settings 管理流程,而不是依赖单次工具审批回调里的动态更新。
访问额外目录:additionalDirectories
默认情况下,会话以cwd 作为主要工作目录。模型需要读取或修改 cwd 之外的目录时,应显式传入 additionalDirectories。
/repo/app,同时允许模型访问 /repo/packages/shared。这适合 monorepo、跨仓库调试、共享库排查等场景。
运行过程中也可以通过 PermissionUpdate 调整目录授权:
additionalDirectories 作为通用默认值;更稳妥的做法是按任务需要添加最小目录集合。
外部授权工具:permissionPromptToolName
permissionPromptToolName 用于把权限请求交给运行环境中的 permission prompt tool,而不是在 SDK host 中实现 canUseTool。它适合已有外部审批工具、远程运行环境或统一权限网关的场景。
permissionPromptToolName必须是当前运行环境可以识别的 prompt tool 名称。permissionPromptToolName与canUseTool互斥,不能同时传入。- SDK host 自己要决定审批时,优先使用
canUseTool。
allow.updatedInput 是最终执行工具时使用的入参。如果希望保持原始入参,应该原样返回收到的 input。deny.message 必填。interrupt: true 表示拒绝后中断当前 Agent 流程。
用 settings 提供权限规则
settings 适合在会话启动前提供静态权限配置。它比 canUseTool 更适合表达“这个项目默认允许什么、拒绝什么、额外目录有哪些”。
如果你的应用会读取并应用 settings 中的默认权限模式,建议在执行高风险模式前做自己的产品级确认。
bypassPermissions、yolo 这类模式应该只出现在明确受信任的环境中。
用 hooks 做高级拦截和审计
Hooks 适合已经接入 SDK hooks 体系,并希望在工具生命周期里做更细粒度控制的场景。和canUseTool 相比,hooks 更适合横切逻辑,例如审计、告警、统一拦截、记录拒绝原因。
PreToolUse 可以返回:
PermissionRequest 可以返回类似工具审批的权限结果:
PermissionDenied 通常用于观察结果,不负责放行工具。它的输入会包含被拒绝的工具名、工具入参、工具调用 ID,以及拒绝原因。
MCP Tool Policy
如果权限策略天然属于某个 MCP server,也可以直接在 MCP server config 里声明 tool-level permission policy。这样策略跟随 MCP server 配置,而不是散落在全局allowedTools 或 disallowedTools 中。
name 可以是 MCP tool 的原始名称,也可以是完整工具名,例如 mcp__repo_tools__search。实际匹配时,运行时会把策略名称映射到当前 MCP 工具调用。