早上好。我是まさきん。
家里用的聊天机器人,一直没法往购物清单里写东西。原因是它背后运行的 claude -p 每次都会拒绝 MCP 工具。我对照官方文档查了原因和修法,在这里记一笔。
※本文为发布时的信息。最新条件请以官方网站为准。
claude -p的无人值守执行中,需要确认的操作会被拒绝--permission-mode acceptEdits放行的只有文件编辑和一部分文件操作命令- MCP 工具要在
--allowedTools或permissions.allow里明确写出才会放行 - 写法是
mcp__<服务器名>__<工具名>,也可以按服务器为单位指定 - 我只允许了 Notion 的搜索、获取、查询、创建、更新这 5 项操作
购物清单写不进去
我家有一个全家人一起用的聊天软件机器人。它是我自己做的,背后调用的是 claude -p,也就是以无头方式运行 Claude Code。
我想让这个机器人读写购物清单。购物清单是 Notion 里的一个数据库。家人发一句“帮我买一下这个”,机器人就把它加进清单。我设想的就是这样的用法。
可是试了很多次都写不进去。每次调用 Notion 的工具,都一定被拒绝。在我手边的交互式会话里明明能用,只有经过机器人的时候不行。
原因是没有授权
结论很简单。机器人调用的 claude -p 没有拿到 Notion 连接器的许可。
机器人是用 --permission-mode acceptEdits 运行的,文件编辑会自动放行。所以我一直以为“已经交给它不少权限了”。但 MCP 工具并不在这个范围里。
在我的环境里,无人值守执行时 MCP 工具一定会被拒绝,直到用 --allowedTools 明确写出来为止。这就是这次的出发点。
无人值守时没有人来回答
先把机制理一下。Claude Code 在执行操作前,有时会确认是否允许。交互式会话里,确认会显示在屏幕上,由人来回答。
加了 -p 的执行是非交互模式。官方文档在“Run Claude Code programmatically”这一页做了说明。文档写道,在没有准备好回答确认的对象的 -p 执行中,需要确认的操作会被拒绝。
也就是说,不是“被问到然后停住”,而是“没被问就直接被拒”。在机器人的背后,这个差别就表现为“一定被拒绝”。弄懂机制之后,我才恍然大悟。
权限模式对比
接下来是权限模式。官方的“Choose a permission mode”按模式列出了不需要确认就能执行的范围。
| 模式 | 不需要确认就能执行的内容 | 官方列举的用途 |
|---|---|---|
| default | 仅读取 | 每一项操作都要自己确认的工作 |
| acceptEdits | 读取、文件编辑、一部分文件操作命令 | 一边检查代码一边推进的工作 |
| plan | 以读取为主(编辑需要批准) | 修改之前的调查 |
| auto | 由分类器审查操作并判断 | 耗时较长的工作 |
| dontAsk | 仅读取和事先允许的工具 | 范围收得很窄的 CI 和脚本 |
| bypassPermissions | 几乎全部 | 仅限隔离的容器或虚拟机 |
default 在界面上显示的名字是 Manual。作为设置值仍然是 default。
模式是地基。在它上面再叠加允许规则和拒绝规则。官方写道,拒绝规则在包括 bypassPermissions 在内的任何模式下都有效。
acceptEdits 放行的范围
acceptEdits 自动放行的是工作目录内的文件编辑。此外 mkdir、mv 这类文件操作命令也会放行。
另一方面,其他的 shell 命令和网络访问不在范围内。官方写道,这些需要 --allowedTools 或 permissions.allow 的规则。自动批准的列表里没有 MCP 工具。
acceptEdits 是“把编辑交出去的模式”,而不是“把外部服务的操作交出去的模式”。我觉得这样理解比较自然。
bypassPermissions 没有生效
其实我在设置文件里写了 bypassPermissions,位置是 ~/.claude/settings.json。所以我一直认定“应该全部都能通过”。但在机器人那里并没有生效。
原因官方写得很清楚。启动时的模式,采用最先匹配到的那一项。
--permission-mode参数(或--dangerously-skip-permissions)- 设置文件里的
permissions.defaultMode
CLI 参考里也写着同样的内容。--permission-mode 会覆盖设置文件里的 defaultMode。机器人启动时带着 --permission-mode acceptEdits。所以设置文件里的 bypassPermissions 根本没被用上。
参数和设置文件之间的关系,除了模式以外我没有细查。这里就只当作我自己环境里的事实。
MCP 工具名的写法
写在允许规则里的 MCP 工具名有固定的格式。官方“Configure permissions”里给出的写法如下。
| 写法 | 对象 |
|---|---|
mcp__puppeteer | puppeteer 服务器的所有工具 |
mcp__puppeteer__* | 同样是该服务器的所有工具(通配符) |
mcp__puppeteer__puppeteer_navigate | 只有 puppeteer 服务器的 puppeteer_navigate |
mcp__github__get_* | github 服务器中以 get_ 开头的工具 |
可以按服务器指定,也可以按工具指定。不过允许规则里的通配符有条件,只能用在 mcp__<服务器名>__ 的后面。像 mcp__* 这样连服务器名都模糊掉的许可,文档说会带着警告被忽略。
还有一点要注意的是连接器的名字。Claude Code 自己获取的连接器,工具名的形式稍有不同,据说是 mcp__claude_ai_<服务器名>__<工具名>。先确认实际的名字再写比较稳妥。
用 —allowedTools 明确写出
修法就是把要用的工具在 --allowedTools 里列出来而已。官方的说明是,这个参数用来指定“不需要确认就执行的工具”。
写出来是下面这样。服务器名和工具名只是示例。实际的名字因环境而异,请自行替换。
claude -p "把牛奶加到购物清单里" \
--permission-mode acceptEdits \
--allowedTools \
"mcp__notion__search" \
"mcp__notion__fetch" \
"mcp__notion__query" \
"mcp__notion__create_pages" \
"mcp__notion__update_page"
我是把这份许可列表放在机器人的代码里。机器人每次调用 claude -p,都传入同一份列表。
也可以写在设置文件里。在 settings.json 的 permissions.allow 中用同样的格式列出。
{
"permissions": {
"allow": ["mcp__notion__search", "mcp__notion__fetch"],
"deny": ["mcp__notion__delete_page"]
}
}
这里的工具名同样是示例。放在哪一边也许看个人喜好。我觉得能从代码里读出“这个机器人能做什么”更安心,所以放在了代码这一侧。
允许的 5 项操作
如果按服务器整体放行,设置只要 1 行。但我没有这么做。我只允许了 5 项操作 。
| 操作 | 是否允许 | 在购物清单里的用途 |
|---|---|---|
| 搜索 | 允许 | 查找清单和物品 |
| 获取 | 允许 | 读取页面内容 |
| 查询 | 允许 | 按条件筛选数据库 |
| 创建 | 允许 | 添加新的物品 |
| 更新 | 允许 | 修改“下次购买”之类的状态 |
| 删除 | 未允许 | 不使用 |
| 以上 5 项以外的操作 | 未允许 | 不使用 |
购物清单的读写,有这 5 项就够了。删除没有放进去。想去掉某个物品时,更新状态就能解决。
加上许可之后,机器人就能用了。家人提出要买的东西,它能放进购物清单的“下次购买”并回报结果。
把交给工具的权限收到只够用的程度,这种感觉和重新审视固定支出很像。手机费也是一样,按实际用量来配,浪费就容易看出来。
把许可收到最小的思路
为什么要收窄?因为机器人的输入并不只来自我一个人。
家人会随意发来各种文字。有口误的时候,也有被理解成别的意思的时候。这时如果连删除都允许了,就无法挽回。只有创建和更新的话,弄错了还能改回来。
把思路列出来,大致如下。
- 先分成“读的操作”和“写的操作”
- 写的操作再分成“添加、修改”和“删除”
- 删除的操作,在真正需要之前不加进去
- 要意识到按服务器整体放行时,工具一增加范围也跟着变大
官方还写了规则的判定顺序:deny(拒绝)、ask(确认)、allow(允许)。最先命中的那一条就是结果。所以绝对不想让它用的工具,写进 deny 最可靠。也可以把工具名直接写进 --disallowedTools。据说那样 Claude 就看不到这个工具了。
在处理密钥信息时,同样的“不要只看形式就放心”的感觉也很重要。那部分写在了gitleaks 漏掉 2 处的那篇文章里。
dontAsk 这个选项
读官方文档的时候,还有一个模式让我在意,那就是 dontAsk。
dontAsk 是把所有需要确认的操作一律拒绝的模式。能通过的只有读取和事先允许的内容。官方也给出了面向严格限定许可列表的 CI 的例子。
claude -p "run the test suite" --permission-mode dontAsk --allowedTools "Bash(npm test)" "Read"
我的机器人目前还是 acceptEdits,因为有些场景也想让它编辑文件。不过如果只是操作外部服务,dontAsk 也许更合适。
另外,不指定权限模式的 -p 执行需要留意。启动模式会随环境和版本变化。官方也写着要明确指定想用的模式。
设置步骤
下面是今后要做同样事情时的流程。
- 把想让机器人做的操作用文字写出来
- 选出这些操作需要的 MCP 工具
- 按
mcp__<服务器名>__<工具名>的格式确认实际的工具名 - 列在
--allowedTools或permissions.allow里 - 有不想让它用的工具,就写进 deny
- 用
claude -p实际调用,看看有没有被拒绝 - 许可列表只在操作增加时才追加
工具名和拒绝的确认方法
工具名靠猜是写不对的。官方介绍了 system/init 这个事件,它出现在 --output-format stream-json 的最开头。里面有模型、工具、MCP 服务器的信息。
拒绝也能从同一份输出里追踪。拒绝会以 permission_denied 这条系统消息出现。据说最后的结果消息里也会以 permission_denials 列出清单。把它留在机器人的日志里,找原因应该会快很多。
常见的失误
- 认定只要设成 acceptEdits,MCP 工具也会放行
- 认定设置文件里的 bypassPermissions 比参数更强
- 工具名靠猜来写,和实际的名字对不上
- 写了
mcp__*这种宽泛的许可,却没发现它被忽略了 - 嫌麻烦,把整个服务器全部放行
- 在无人值守执行里用 bypassPermissions,变成什么都能通过的状态
前两条正是我自己干过的事。模式名字给人的印象,和实际放行的范围有些出入。
关于 bypassPermissions,官方给了很强的提醒,前提是在隔离的容器或虚拟机里使用。对于家人的输入会原样送达的机器人来说,我觉得不太合适。
开始之前要确认的事
- 机器人是以哪种权限模式启动的
- 模式是由启动参数还是设置文件决定的
- 是否把想让它做的操作用文字写出来了
- 是否确认了 MCP 工具的实际名字
- 是否去掉了删除等无法挽回的操作
- 能否在日志里追踪被拒绝的工具
- 是否把许可列表的存放位置定在一处
常见问题
Q. 为什么 claude -p 会拒绝 MCP 工具?
-p 是非交互的执行。官方写道,如果没有准备好回答确认的对象,需要确认的操作会被拒绝。在我的环境里,在明确允许 MCP 工具之前一定会被拒绝。
Q. 设成 acceptEdits,MCP 工具也会放行吗?
没有放行。按官方的说明,acceptEdits 自动放行的是文件编辑和一部分文件操作命令。其余的需要 --allowedTools 或 permissions.allow。
Q. 在 settings.json 里写了 bypassPermissions 却不生效。
请确认启动时有没有带 --permission-mode。官方写道,这个参数会覆盖设置文件里的 defaultMode。我的机器人也是卡在这里。
Q. 可以按服务器一次性放行吗?
可以。写成 mcp__<服务器名> 或 mcp__<服务器名>__*,该服务器的全部工具都在范围内。不过删除之类的也会包含进去。我是只把需要的操作逐个写出来。
Q. —allowedTools 和 —tools 有什么区别?
--allowedTools 指定的是不需要确认就执行的工具。--tools 是用来限定可用内置工具的参数。官方写道,--tools 不影响 MCP 工具。
Q. 写了允许规则也有通不过的情况吗?
似乎有。官方写道,组织设为 ask 的连接器工具,允许规则不起作用。被要求必须由用户操作的 MCP 工具也一样。在 dontAsk 模式下,这些会被拒绝。
Q. 加上 —bare 会怎样?
--bare 是省略 MCP 服务器等自动加载的模式。官方写道,MCP 服务器只会连接通过 --mcp-config 传入的那些。认证也以 API 密钥等为前提,所以加之前最好先确认一下。
Q. 有办法明确声明没有人回答确认吗?
官方列出了 --permission-prompts none 这个参数。它会拒绝需要确认的操作,并告诉 Claude 不要重试。据说需要 v2.1.259 及以上版本。我还没有用过。
参考的官方信息
- Run Claude Code programmatically(Claude Code Docs)
- Choose a permission mode(Claude Code Docs)
- Configure permissions(Claude Code Docs)
- CLI reference(Claude Code Docs)
- All settings(Claude Code Docs)
- Configure permissions - Agent SDK(Claude Code Docs)
总结
claude -p 拒绝 MCP 工具,是因为没有授权。acceptEdits 是为文件编辑准备的模式。外部服务的操作需要另外明确写出。
许可收到只包含要用的操作比较好。我是从 5 项操作开始的。自制机器人值不值得继续做,这笔账我在Claude Max 使用率的文章里整理过。从通知直接找 AI 商量的做法,也写在了“交给 Claude”按钮的文章里。机器人不动的时候,先看看启动参数吧。
本文包含联盟营销广告。如果您通过本站链接申请相关商品或服务,我们可能会从合作企业获得报酬。此外,运营者是乐天集团的员工,也可能通过员工推荐计划获得报酬。文章内容与评价均基于运营者的真实体验与调查完成,与是否存在广告无关,但请您在阅读前了解上述关系。详情请参阅免责声明与联盟营销说明。 免责声明与联盟营销说明
本文包含机器翻译内容。正式条件请以乐天移动官方网站的多语言页面为准。
如果您对乐天移动的通信区域·信号状况有疑问,可以通过官方的 电波改善调查申请表 进行咨询。