posts/cloudflare-mcp-optional-scopes.md
Cloudflare 给 MCP 加权限勾选,Agent 仍不该拿全权
28 个权限。
一个开发工具想连上 Cloudflare,授权页先摊开这么大一包东西。里面有账户与账单,有开发者平台,还有 Workers、KV、R2、路由这些能直接改生产环境的能力。
好家伙,模型还没开始干活,钥匙串先挂满了。
Cloudflare 在 8 月 22 日发了一条不算长的更新。Wrangler 和 Cloudflare API MCP server 的 OAuth 授权页,现在允许用户关掉不需要的可选 scope,也就是权限范围。必需权限仍然保留,当前任务不需要的读写能力可以先不发给客户端。
页面变化很小,不过多了一个「Edit Permissions」。
我觉得这事比不少 Agent 新功能都重要。因为模型会不会调用工具,决定它能干多少活。凭证允许工具碰哪些资源,决定它翻车时能拆多少房子。

Cloudflare 新授权页会展示权限总数,并提供编辑附加权限的入口。
两个工具背后站着 2500 个接口
MCP 是 Model Context Protocol,中文一般叫模型上下文协议。你可以把它理解成一套让 Claude、Codex、Cursor 之类的 Agent 调用外部服务的统一插座。
插座很方便,权限问题也被它放大了。
Cloudflare 的 API MCP server 有个挺有点子牛逼的设计。它没有把两千多个 API 端点全塞成两千多个工具,而是只暴露 search() 和 execute() 两个工具。模型先搜索 OpenAPI 描述,再写一小段 JavaScript 调用目标接口。
官方给出的数字很有冲击力。传统做法如果把 2594 个端点的完整 schema 全部送进上下文,大约要 117 万 token。Code Mode 只要两个工具,常驻成本约 1000 token。
省得非常漂亮。
但这里有个容易被忽略的错觉。工具列表里只有两个名字,不代表权限也只剩两个格子。execute() 后面仍然连着 DNS、Workers、R2、Zero Trust 以及其他 Cloudflare 产品。界面看起来很克制,凭证可能一点都不克制。
这就是 Agent 工程里一个挺麻烦的错位。我们很容易按「工具数量」感受风险,可系统真正的爆炸半径由 token 能访问的资源和动作决定。一个叫 execute 的工具,只要拿着全量权限,能做的事可能比一整页工具都多。
模型也不需要怀有恶意才会出事。需求写得含糊一点,网页里混进一段提示注入,或者重试逻辑把一次写操作执行两遍,都可能把「能做」变成「真做了」。安全边界如果只靠 prompt 里一句「请谨慎操作」,那跟在生产数据库旁边贴张「不要误删」差不多。
Cloudflare 这次改动补的,正是凭证这一层。
可选 scope 不是新概念,愿意让人少给才是进步
MCP 的授权规范 把远程 MCP server 视作 OAuth 资源服务器,客户端代表资源所有者拿 access token 去访问受保护能力。协议把登录、发 token、带 token 请求这些路线接了起来,但具体给多大权限,仍然要靠授权服务器和产品设计。
OAuth 很早就允许部分授权。RFC 6749 的 scope 章节 写得很清楚,授权服务器可以按照策略或资源所有者的选择,只批准客户端请求的一部分 scope,并把实际授予的 scope 告诉客户端。
标准早就留了门,产品不一定给你门把手。
很多授权页过去只有两个选择,要么全给,要么取消。开发者着急把工具跑起来,通常就一路点确认。权限从「这个任务需要什么」悄悄变成「这个应用将来可能用到什么」。可能两个字,养出了多少常驻全能 token,大家心里都有数。
Cloudflare 更新后的授权说明里,所有请求权限默认仍然选中,但用户可以一键只保留只读权限,也可以按分类或单项关闭可选权限。必需权限不能取消,没有配置成可选的客户端也不会出现编辑入口。
棒棒的,至少「全给」终于不再是唯一能继续往下走的按钮。

用户可以按类别或单项关闭可选 scope,必需权限仍会保持选中。
不过,勾选框没有自动解决后面的工程问题。
客户端拿到缩水后的 token,必须知道自己实际得到了什么。如果 Agent 搜索计划时仍能看见一堆无权执行的动作,它就会认真规划一条终点必然撞墙的路线。前面读了日志、改了配置、创建了资源,走到收尾步骤才收到权限错误,留下的不是一个红色报错,而是半套已经生效的系统状态。
权限粒度和任务粒度也不总能对齐。截图里的 Workers Write 描述覆盖 zones、KV、R2、scripts 和 routes。某个任务也许只想更新一段 Worker 脚本,却不得不面对一个跨多类资源的权限包。scope 比全局管理员小很多,但离「只够完成眼前这一步」还可能差一截。
还有重新授权。Cloudflare 的规则是,如果命令需要此前拒绝的 scope,客户端就得重新走授权。短任务里多点一次还能接受。一个跑了四十分钟、已经产生副作用的长任务被卡在这里,怎么暂停、怎么恢复、会不会把前半段再跑一次,都是运行时要回答的问题。
所以,可选 scope 是好消息,却不是可以把权限设计从待办里划掉的理由。
权限不足要在计划阶段报,不要在生产阶段报
假设一个常见场景,Agent 要发布预览环境。它需要读取项目配置,上传 Worker,创建一个 KV namespace,再绑定路由。需求里没有改 DNS,也没有碰账单。
如果直接给全量 token,任务大概率很顺。代价是任何错误指令都能顺手越过项目边界。
如果人工凭感觉砍权限,另一种麻烦会冒出来。Agent 前三步都成功了,绑定路由时才发现缺少写权限。Worker 和 KV 已经存在,路由没接上。用户看到「失败」,云端看到一堆孤儿资源。
嘶,这就不是补一个 scope 再重试那么简单了。
更稳的做法,是先把任务翻译成权限清单,再开始产生副作用。下面只是示意,不是 Cloudflare 的真实配置格式。
task: deploy-preview
allow:
- workers.read
- workers.write
- kv.write
approval_required:
- routes.write
deny:
- dns.write
- billing.write
token_ttl: 30m
Agent 先输出计划,运行时根据计划算出所需权限,再和 token 实际拿到的 scope 做差集。缺权限就停在零副作用阶段,告诉人类「还需要 routes.write,用十分钟,完成后撤销」。权限齐了再执行。
这一步很像编译。自然语言需求是源代码,工具计划是中间表示,scope 清单是类型检查。类型没过,程序别跑。
坦率讲,这比让模型记住一百条安全提示靠谱得多。模型可能漏看 prompt,资源服务器不会因为它语气诚恳就放过一个缺 scope 的 token。
工具发现也要跟着实际权限收缩。无权调用的工具,要么不出现在搜索结果里,要么明确标成不可用,并在规划时给出缺少的 scope。别让 Agent 花十分钟写出一套漂亮方案,执行器再冷冷回一句 403。权限错误越早,修复成本越低。
写操作还应该有独立确认。读日志、列资源可以在只读 token 下自动跑。更新 Worker、修改 route、删资源这种动作,进入执行前展示目标资源、预期 diff 和回滚动作,让人确认一次。确认记录要绑定 run_id、tool_call_id 和具体资源,不能拿一句模糊的「允许本次操作」给后面所有写请求当通行证。
再往下是幂等和审计。一次写请求因为网络超时没有返回,Agent 不知道服务端到底成功没成功。它若原样重试,可能创建第二份资源。每次写入都该有幂等键,审计日志至少要记下调用身份、实际 scope、目标资源、请求摘要、结果和回滚状态。Cloudflare 本身也提供专门的 Audit Logs MCP server,拿它做事后查询挺方便,但真正的运行记录仍然要能从一次 Agent 任务追到每个 API 调用。
短期 token 是另一层保险。授权只覆盖任务预计时长,到期后自动失效。长任务需要续期时,不要静默换成更大的凭证,更不能失败后偷偷回退到环境变量里的全局 API key。不是哥们,前面费劲砍掉权限,异常分支又把万能钥匙掏出来,那前面是在表演安保吗。。
一把 token 不够描述一次任务
OAuth scope 描述的是客户端被允许触碰的能力,它并不知道 Agent 此刻为什么要碰,也不知道这次任务结束后还该不该继续碰。
这两个问题看起来接近,放到生产里差得很远。
一个 token 可以只带 Workers Write,不算宽。可如果十个 Agent 运行共享它,任何一条运行都能代表另外九条运行去写。如果它能活九十天,今天批准的预览发布,三个月后还可以拿同一把钥匙改生产。如果它覆盖整个账户,任务只想动一个 Worker,却仍然可能碰到旁边二十个项目。
scope 变少了,身份、资源和时间边界仍然可能很大。
我更愿意把一次授权判断看成六个字段。谁在调用,代表哪次任务,要操作哪个资源,准备做什么动作,权限能活多久,哪位人类批准了哪一步。
下面同样只是运行时记录的示意。
principal: agent-run-8f21
task_id: deploy-preview-174
resource: workers/my-preview
action: update-script
granted_scope: workers.write
expires_at: 2026-08-24T15:30:00+08:00
approval_ref: approve-6c02
这份记录里,token 只回答「能不能」。任务策略还要回答「该不该」。
身份要细到一次 Agent run,而不是笼统记成某位员工登录。员工完成 OAuth 同意后,运行时可以为当前任务派生一个短生命周期会话身份,并把它和 run_id 绑在一起。两个并发任务即使来自同一个人,也不该在审计日志里糊成同一个调用者。
资源边界要尽量贴近目标对象。授权服务器如果只能给到产品级 scope,执行层还得再加账户、zone、Worker 名称或资源标签的 allowlist。scope 说你能写 Workers,不代表这次任务能写账户里所有 Workers。
动作也不能只分读和写。创建、更新、删除的风险完全不同。读配置可以自动,生成 diff 可以自动,应用 diff 要确认,删除资源除了确认还应要求可恢复方案。把它们全塞进一个 Write,省了策略代码,出事时会把省下的代码连本带利还回来。
时间边界不是简单填一个过期时间。运行时要在开始长步骤之前检查 token 剩余寿命。预计上传加部署需要十二分钟,token 还有两分钟,就该在产生副作用前续期。续期只能延长原有范围,不能顺手把拒绝过的 scope 补回来。
人类确认也得可验证。确认页展示的资源、动作和 diff,要生成不可混用的 approval reference。执行器收到确认后再检查计划哈希是否变化。模型如果在确认后改了目标资源,旧确认立即失效,重新展示。
这些字段看着有点像给一次工具调用办签证,麻烦吗,确实麻烦一点。可 Agent 一旦能操作云资源,模糊的「用户已经授权」已经不够用了。它只能证明门开过,证明不了进门的人现在应该去哪个房间。
还有恢复问题。
每个写步骤执行前,系统要保存检查点和补偿动作。创建 KV 成功,就记下资源 ID 和删除方案。更新 Worker 成功,就保存上一版引用。绑定路由失败,运行时可以停在明确边界,补权限后从未完成步骤继续,或者按补偿动作退回去。
这不一定要做成重量级分布式事务。很多场景里,一个稳定的幂等键、一份步骤状态表、写前版本号和清晰的补偿函数已经够用。关键是别让重新授权等于整条任务重新跑。
真正该验收的是拒绝之后会发生什么
权限系统最容易在顺风局里显得很安全。只读 token 执行只读任务,当然一切都好。要测,就得故意拒绝它。
我会把下面几种情况放进上线门禁。
-
只读 token 收到写请求时,任务要在计划或执行前检查阶段停止,不能先改一半资源。
-
用户关掉某个可选 scope 后,Agent 的工具搜索与计划必须反映实际授权,不能继续假装那项能力可用。
-
运行中需要补权限时,系统要从检查点恢复,只执行尚未完成的步骤,不能把前面的写操作整段重放。
-
token 被用户撤销或过期后,所有调用都要失败关闭,并留下清晰审计记录,不能回退到另一把更大的钥匙。
-
工具返回内容里出现诱导指令时,模型可以被骗,token 不能被扩大。授权边界必须在模型之外。
-
写操作的确认要绑定具体资源和 diff。把确认范围从「允许 Agent」缩到「允许这次改这个对象」。
这些测试不花哨,也不会在演示视频里让人惊呼厉害了。可它们决定了 Agent 是一个能进生产的执行系统,还是一个拿着管理员 token 的聊天窗口。
验收时还可以顺手记四个数字。一次任务授予了多少 scope,真正使用了多少。权限拒绝发生在计划阶段还是产生副作用之后。补权限后有多少任务能从检查点恢复。失败任务留下了多少孤儿资源。
这几项会比「授权成功率」诚实很多。授权成功率高,可能只是大家都拿了全量权限。真正健康的系统,应该让未使用权限越来越少,让权限错误越来越早,让重新授权越来越不需要人工收拾残局。
也别迷信把权限利用率做到百分之百。某些只读 scope 会作为诊断备用能力保留,硬追满分反而逼着团队拆出一堆难维护的 token。指标的作用是暴露异常。一个只改 Worker 脚本的任务,最终用了两个权限却拿了二十八个,这种落差值得追。一个故障处理任务预先声明会读取日志、回滚版本,实际都用上了,多拿一两项只读权限未必需要大动干戈。
权限治理不是比谁的 scope 最少,而是每一项多出来的能力都能解释,每一次扩大范围都有人知道,每一次任务结束都真的把钥匙收回去。
Cloudflare 的 Wrangler 登录流程已经把授权、设备码与权限选择放到用户能看见的位置,Cloudflare One 的 MCP 安全接入文档也在处理身份和受保护资源之间的连接。下一步更值得期待的是,客户端和 Agent 运行时把「实际获得了哪些 scope」变成规划、工具发现、暂停恢复和审计里的第一等数据。
我对这次更新的评价很直接。方向对,而且早该做。
但 28 个权限不该只是一页你懒得看的授权说明。它们应该变成任务可编译、运行可观测、失败可恢复的一份合同。
勾选框只是门把手,门后还得有锁。