5 个 MCP server,55 个工具,约 16,500 tokens。
这个数是 Ryan Palo 在七月三号那篇《Choosing the Right Tooling Layer for Your Agent》里顺手摆出来的。他在算全量挂载 MCP 的账——不是运维的账,是上下文的账,server 的 schema 只要挂着就一直占着窗口。整条讨论线里这是唯一一个能上秤的量,剩下的全是判断、类比、经验。一笔能算的账落在一堆判断中间,位置本身就说明点什么。
那篇转述的是 Nikita Kothari 在 AI Engineer World's Fair 上的一场演讲,讲的就是 MCP、CLI、技能三者在 agentic development 里的工具层选择。正文结论:看运行环境、看任务类型、看有没有现成 CLI、看组织的认证和治理要求。MCP 更安全更易治理,CLI 更快更可靠,多数用例落在两者中间。评论区六条。其中一条,我认为比正文重。
我把这条线从上到下梳了一遍,落下来的判断是:这场辩论被摆在了一根错的轴上。「MCP 还是 CLI 还是技能」,这是在问三个不同楼层的东西选哪个。不会有答案——三者不是同一个槽位里的三个候选。真正决定这套东西你写不写得动、上不上得了生产的,是三根别的轴:上下文里的常驻成本、操作契约的归属、执行路径的可见性。前两根讨论里都碰到了,第三根只有一个人在评论里问了一句就沉下去了。
四个区:先拆「选哪一层」这个问法本身,说清这三样东西各自在栈的哪一层;然后算账——常驻税贵在哪、什么时候从成本问题变成可行性问题;再往下走执行面,看 CLI 便宜在哪个角落、代价收在哪;最后摊开契约层。那是这张图上最大的一块空白。
一、「选哪一层」这个提法本身就不对
MCP 是一套协议。它同时规定了两件事:工具怎么被描述(schema),工具怎么被调用(传输)。CLI 是执行面,存在了几十年,和 agent 没有任何关系,只是恰好被 agent 用上了。技能是描述层,一份按需被感知的说明,告诉 agent 该用哪些工具、怎么用。
三样东西,三层栈。把一层的协议、一层的执行面、一层的说明文档塞进同一个「选哪个」的问题里,得到的必然是「看情况」。不是这些问题没有答案,是这个问法本身没有答案。
Palo 那篇开头拿软件工程里的抽象层级选择做类比。这个类比成立,但方向他没走到底。选抽象层级,本质上是在选谁持有接口契约:你封装成一个高层 API,是因为你想把底层字段的所有权和变更自由收到一个人手里;你裸调命令行,是因为你不在乎这层封装,或者你需要保留手动兜底的能力。放到 agent 工具层上,同一个问题——只不过这次,能绕过坏抽象的那个人不在了。
我把这三层摊成一张图,后面所有讨论都挂在这张图上:
模型面对层 技能 / 工具清单 / 路由视图 ← 该薄,该按需加载
──────────────────────────────────────────
契约层 副作用类别 · 审批 · 幂等 · 预算 ← 这一层没人占
──────────────────────────────────────────
执行面 MCP server · CLI 进程 · 窄包装脚本
这张图是我画的,不是 Palo 的。他把三层摊开了,但没明说中间那层是空的——而那一层恰恰决定了这套东西能不能上生产。全文下来,只有评论区一条最短的评论碰到了它。
先把执行面那层的账算清楚。因为它能算。
二、常驻税:唯一能算的一笔账
全量 MCP 方案的动机很好理解(Palo 写得很清楚):启动时把所有可能用到的 MCP 都挂上,发现性好、灵活、能并行组合多类工具,你不用提前判断这次任务需要哪些工具。工具就在那儿。
代价是 schema 常驻。不是调用时加载、用完释放,是只要这个 server 挂着,schema 就一直在上下文窗口里。5 个 server、55 个工具、约 16,500 tokens。摊到每个工具大概 300 token,这个量级不离谱,我见过更胖的 schema。
评论区里 Nazar Boyko 给这笔账起了个我看一次就记住的名字:运行税。每一轮都得付的那种。这个命名比 Palo 原文里「隐蔽问题」那个说法准得多——它不是一个坑,是一笔持续支出,而且是和你的任务内容抢位置的那种支出。你多挂一个 server 的边际成本,不是多一份运维负担,是每轮多一份 schema,并且这份 schema 是从你的推理预算里扣的。
扣多少要看任务。如果你的 agent 一轮里要展开很长的中间步骤,那 16,500 不是一个占 8% 的固定开销,是从剩下的那部分里再切一块。这个差别在做技术选型的时候经常被平均掉。
更重的是 CAI 那条评论。他说超过大约 10 个 MCP server 之后,schema 占用会决定上下文窗口是否可用,并且 16,500 这个示例不是最坏情况。
这句话被严重低估了。它把 schema 从「性能开销」抬成了「可行性开关」。五个 server 的时候这是个成本问题,十五个 server 的时候这是个能不能跑的问题——而且不是线性变坏,是过了某个点之后整件事的性质变了。
客户端那边有缓解手段。Palo 提到现代客户端在 schema 过大时可能不会把完整 schema 放进上下文,会用缓存、压缩或索引,按需加载工具 schema;他给的建议是把 MCP 调用封装进技能,用技能精确描述所需工具及用法,让客户端只解包相关的那部分。CAI 追了一句:按需加载依赖客户端支持,而当时不是所有客户端都支持这一模式。
这一条是整张图上最该被单独钉住坐标的位置。它意味着「用不用 MCP」这个问题的一部分根本不由你决定,由你选的客户端决定。同一套配置,在支持按需解包的客户端上是一份索引,在不支持的客户端上是一张 16,500 token 的账单。你在技术选型会上把这件事当成自己的决策在处理,其实是把上游客户端厂商的路线图当成了你的架构前提。
顺带说一句我自己的推论,评论区没人这么讲,我标一下这是我的:工具面变宽除了烧 token,还会稀释路由。55 个工具的候选集里选一个,和 8 个工具的候选集里选一个,不是同一道题。前者模型要在更长的清单里做区分,而清单里大部分条目和当前这一步无关。常驻的 schema 是每轮在付的显性税,路由准确率下降是隐性税,两笔加在一起才是全量挂载的真实成本。这一步是推的,没有数据支撑,放在这儿等反驳。
技能加 CLI 那条路本质上是同一个动作的两面:把「可能用到的工具说明」从常驻上下文里挪出去,挪进按需加载的描述层。Palo 说得很直接——CLI 工具在上下文和速度上明显优于 MCP 工具,因为不产生额外网络调用、几乎不占上下文、输出比较可预测。这三条不是小事,它们是 agent 循环频率的直接决定因素。
但便宜是收在别处的。下一节。
三、CLI 便宜在哪,代价收在哪
先说便宜这侧。三条:不额外走网络、几乎不占上下文、输出可预测。
CAI 从延迟角度把这件事说透了:MCP 每次工具调用会增加一次网络往返,对需要快速循环执行大量小操作的 agent 不利;CLI 在延迟上占优,但表达力较低。这一对取舍很干净——你要的是每秒能转多少圈,还是单个动作能表达多复杂的东西。跑测试、读文件、grep、改一行配置,这类动作高频、简单、结果短,走 MCP 是拿一次网络往返换一个本来就在本地的动作,账算不过来。
Palo 还提了一条我认为被严重低估的好处:如果 agent 在本地跑,你可以利用自己对这套环境的熟悉,在它卡住的时候手动介入。
这不是便利性问题,是故障恢复路径的有无。CLI 那条路天然留了一个人兜底的口子,因为人也在同一个 shell 里,agent 卡在哪条命令上、那条命令当时的环境是什么样,你能直接复现。MCP 那条路一旦调用语义出错,你手里通常只有一份日志和一份 schema——你得先进到那个 server 的进程里,才谈得上复现它的行为。
然后是代价。Palo 写得很直:能访问 CLI 工具通常意味着能访问 shell。这句话得掰开看——shell 不是一个工具,是一整个权限面,agent 拿到它之后能动的东西比你打算给它的多得多。
沙箱化和权限控制能压住一部分,但 Palo 往下追了一层,那一层是整篇里最实操的一句:还要关注 agent 能访问哪些凭据文件,以及那些凭据的角色是否配得上它要做的事。沙箱管的是它能跑什么,凭据管的是它跑起来之后是以谁的身份在说话。这两件事经常被一句「我们上了沙箱」盖过去。一个 agent 被沙箱关在一个目录里,手里却拿着一份能读整个对象存储的凭据,那沙箱管的是它的脚,不是它的手。
再往下是 Mykola Kondratiuk 那条评论,我认为是整条讨论里最锋利的一句:类比成立,但有一点不同——开发者能绕过坏抽象,agent 大多不能,错误边界会在每次调用中累积,代价更高。
这句话把 Palo 那个软件工程类比的隐含前提打掉了。抽象层级选择之所以在软件工程里是个可管理的决策,是因为底下站着一群会不耐烦的人:API 难用,人就绕过去,写个脚本,问题暴露得很快,坏抽象会被市场淘汰。agent 不会不耐烦。它会照着你给的那份技能描述,一个 token 一个 token 地把错误的用法执行完,然后在第五步报一个和第一步真实原因隔了三层的错误。所以同一个决策搬到 agent 工具层上,代价不是「抽象选得不好」,是「抽象选得不好,而且没人会告诉你」。这个差别足以让「反正先用着,不好再换」这套在软件工程里屡试不爽的策略失效。
Nazar Boyko 给了中间解,我认同这个方向:CLI 的安全问题和 MCP 的上下文问题方向相反,实际设计常常需要在不交出整个 shell 的前提下拿到 CLI 的速度,窄包装脚本能覆盖不少场景。
窄包装脚本是这条线上最少被讨论、性价比最高的一块。它一个动作一个脚本,脚本自己固定参数形状、自己检查要动的东西、自己不接受任意输入——agent 拿到的是几十个窄口子,不是一个 shell。代价很直白:这几十个脚本得有人写、有人维护,每加一个能力就多一个。抽象选择省下来的成本,最后在这里付出去。软件工程里没有免费的抽象,这句话在 agent 工具层上一样成立。
CAI 还提了 MCP 在这一侧的对称优势:MCP server 作为独立进程有它自己的权限面,比给 agent 任意 shell 访问更容易沙箱化;如果组织已经有一套 Web API 的认证基础设施,MCP 更容易接进去。这条把我前面「CLI 更便宜」的印象拉回来了——便宜是在 token 和延迟上便宜,治理上它是最贵的那一端。而治理这件事的账单,通常不会出现在选型那一刻。
四、契约层:这条线上最重要的一句话藏在评论区
Armorer Labs 那两条评论,我认为比正文重。
第一条:关键问题不是哪一层最好,而是哪一层拥有操作契约。第二条给了具体做法:对可改变状态、花钱、接触客户数据或触发重试的工具,由运行时层统一管理输入 schema、副作用类别、审批策略、幂等键、超时或预算、输入来源和回执这几样东西;模型面对层保持轻量,运行时层先给一个路由视图,只有在候选工具真正参与进来的时候才去绑定完整契约。
我读到这儿停了很久。因为它把前面所有「MCP 还是 CLI」的讨论重新归了一次类:那些都在讨论执行面长什么样,而这两条说的是执行面之上那一层的所有权。两者的关系很清楚——你怎么选执行面,是一道性能和运维题;谁拥有契约,是一道事故责任题。前者决定你跑得快不快,后者决定你出事的时候找谁。
把那份字段清单展开,每一项挡的是什么故障就清楚了:
| 契约字段 | 它挡的是 |
|---|---|
| 输入 schema | 模型编出字段名或类型,调用在服务端 400,或者更糟——静默写错字段 |
| 副作用类别 | 一次「查询」实际上写了库;重试一次变成写两次 |
| 审批策略 | 花钱、发信、改客户状态这类动作没人拦,agent 自己觉得该做就做了 |
| 幂等键 | 超时重发、循环重试、并行分支撞车,同一个动作被执行多次 |
| 超时或预算 | 单次调用挂住整个循环;或者一个 agent 整晚把钱烧在同一件事上 |
| 输入来源 | 参数是用户直接给的,还是从某个网页或工具回执里来的——后者是注入面 |
| 回执 | 调用发出去了但没人知道状态变到哪,失败了下游无法判断能不能重试 |
这张表里没有一个字段属于「工具描述」。它们是运行时元数据。这就是为什么把契约塞进 schema 里是错的——schema 是要放进上下文的东西,契约是不该进上下文的东西。契约该在执行层被强制,不是被模型读到然后「遵守」。模型读到副作用是 high 就谨慎一点,这叫劝导,不叫控制。评论区没人这么说,这句是我加的。
有人会反驳:模型不知道这个动作危险,它怎么判断该不该做。我的回答是,那属于另外两样东西——路由视图告诉模型「这个工具干什么、大概什么代价」,审批策略在运行时决定「这一步要不要人签、有没有幂等保护」。前者是描述,后者是强制,两样都要有,但不能混成一样塞进上下文。Armorer Labs 说的「模型面对层保持轻量,运行时层只在候选工具参与时才绑定完整契约」,就是这个结构的实现方式。
这个结构其实不新。你已经认识它——它就是 API 网关和限流中间件那一套:schema 校验、幂等键、超时、审计、审批流,二十年前就在挡一模一样的故障。新的是两个东西:一个是副作用分类,网关不关心你这一步是读还是写,agent 的工具层必须关心;另一个是输入来源,网关不区分参数是用户填的还是模型从某个网页回执里抄来的,而 agent 世界里这个区别就是注入攻击和正常调用的分界线。
所以这块地图的空白不是「没有解法」,是「已有的解法和新的需求没接上」。网关那一半是成熟的、可复用的;agent 特有的那一半是零散的、散在各个博客和评论里的。中间那根接缝现在没人焊。
回到 MCP 的位置。CAI 那条评论里藏着一个我认同的重新定位:MCP 的价值不在于它是不是更好的工具调用方式,在于它是一个现成的治理挂载点。
Palo 那篇其实说到了(MCP 更安全、更易治理),但他把它放在结论里当一个并列项,没抬到「选 MCP 的第一理由」这个位置。我认为它就是第一理由。在一个已经有 API 网关、有认证体系、有审计的组织里,MCP 是一条把 agent 动作接进现有治理面的现成接口;CLI 是一条绕过整个治理面的近路。近路更快,代价是你得从头造一套新的治理,而这套新治理的质量上限,取决于你团队里有没有人真的把凭据角色这件事当回事。
五、摊开这张表
把前面三节压成一张对比表,这张是本文的图例,建议直接截图。
| MCP(全量挂载) | 技能 + CLI | MCP 封进技能(混合) | |
|---|---|---|---|
| 上下文驻留 | 55 工具 / 5 server ≈ 16.5k tokens 常驻,每轮支付 | 几乎为零,技能按需感知 | 理论上最低,依赖客户端按需解包 |
| 调用延迟 | 每次多一跳网络往返,小操作密集时吃亏 | 无额外网络调用,延迟最低 | 通常保留 MCP 那一跳 |
| 表达力 | 结构化 schema,表达力强 | 输出是文本,表达力弱 | 折中 |
| 沙箱难度 | server 是独立进程,权限面可切 | 等于给 shell,权限面最宽 | 看你把拦截点放在哪一层 |
| 契约承载 | 契约和执行混在一层,难分开 | 靠包装脚本自己写,弱 | 契约可以放在封装层,强 |
| 治理接入 | 组织已有 API 认证时最顺 | 要重造一套 | 同 MCP |
| 配置成本 | 一次性配置,之后基本不动 | 每加一个能力写一份技能 | 最高,技能和封装都要维护 |
横向看一条规律:这张表里没有一列是全面占优的。MCP 在治理和契约承载上强,CLI 在延迟和上下文上强,混合方案的强项全建立在两个前提上——客户端支持按需解包、你养得起持续写技能和封装的人。第一个前提不在你手里。
纵向看另一条:上下文和延迟是「运行时成本」,契约和治理是「事故成本」。这两类成本的决策周期完全不同。运行时成本你上线第一天就能测出来,事故成本要等到第一次出事才知道自己欠了多少。选型时人天然偏向能测的那一侧,这就是全量 MCP 和裸 CLI 两个极端都很有市场的原因——它们各自把一类成本藏起来了。
再补一条时间轴上的观察,这条是我对这条线整体重心的读法,不是谁的原话:讨论的重心从「接不接得上」挪到了「接不接得起」。前半段大家在争协议标准化、客户端支持、生态里有多少 server;现在争的是上下文预算和治理成本。Palo 那篇从抽象层级切入、落点却落在 token 和治理这两个词上,本身就是这次重心挪动的证据。
按任务特征切一张决策表,我自己在用的版本,仅供参考:
| 任务特征 | 我更倾向 |
|---|---|
| 可改变状态、花钱、碰客户数据、会触发重试 | 契约层优先,执行面用 MCP 或窄包装脚本,不做裸 CLI |
| 高频、小动作、循环密集(读文件、跑测试、grep) | CLI,包装越窄越好 |
| 需要实时结构化数据、参数形状复杂 | MCP |
| 一次性探索脚本 | CLI,别写技能,跑完就扔 |
| 组织已有 API 认证和审计体系 | MCP 接进去,别自建 |
| agent 跑在本地、你能盯着 | CLI 加人兜底 |
这张表没有一行写「看情况」。这是有意的。看情况是一句真话,但它不是一张地图。
六、地图上还空着的几块
第一块,执行可见性。Raju Dandigam 那条评论问了两件事,第一件是:一旦 agent 有多层工具可用,你就需要执行可见性,来知道它选了哪条路径、以及为什么选这条。
这个问题比它看起来难。你手上有一个 MCP 工具、一个同名能力的 CLI 包装、一份技能把两者都提到了,agent 选了其中一条——日志能告诉你它调了哪个(前提是它如实上报了),但告诉不了你「它本来还可以调哪个、为什么没调」。因为选择发生在模型的隐状态里,不在日志里。
要做这个可见性,得先把路由视图落成一个可审计的对象——每一次候选集是怎么构成的、哪些工具被排除了、排除的依据是什么。也就是说,可见性问题其实是契约层问题的下游,不是一件事。这块我不敢说我看清了,先标在这儿。
第二块,默认工具面最小化还是最大化灵活性。Raju Dandigam 那条评论的第二问:团队应该优先优化灵活性,还是尽量缩小默认工具面。
我的判断很明确:默认面尽量小,灵活性靠按需加载补。理由就是第二节那笔账——常驻成本每轮都付,灵活性一年用上几次。但这里面有个反直觉的地方:按需加载把成本从 token 挪到了发现性上。工具不进上下文,模型就不知道去找它,于是你需要一层描述来兜住发现性。技能这个东西在这两年冒出来,我认为一半是在给发现性补位,不只是给上下文省钱。这一点如果成立,那技能的写法就有一个硬指标:它得让模型在不知道工具存在的前提下,也能判断出「这件事该去查一下有没有现成的」。这跟写一份好 README 是两种手艺。
第三块,契约的自动生成和强制。这是我落子的位置,下一节细说。
第四块,混合方案的那个隐形前提。Palo 说混合方案在值得付出额外配置成本的时候通常是最佳选择。我抬一句杠:这个「最佳」带着两个前提,一个是你的客户端支持按需解包 schema(CAI 明确说当时不是所有客户端都支持),另一个是你养得起持续写技能和维护封装的人。第一个前提不在你的控制范围内,第二个前提是要按季度持续付的。所以「混合方案最佳」这句话在演示环境里永远成立,在生产里成立与否,取决于两件和方案本身无关的事。这是我的判断,不是共识——你不同意,可以拿你们线上的数据来挪这块坐标。
七、交代一下哪儿没画全
按我自己的规矩,得说清楚这张图的边界,不然你会以为它是完整的。
我只梳了这条线:Palo 那篇加它的六条评论,加上那篇转述的一场演讲。Palo 在文末建议想深入研究的读者去看 Firecrawl 的博客,说那里对各方案的差异、优势和劣势有更全面的分析——那篇我没读,所以这个领域里别的立场我这里没有覆盖。如果那边的梳理和这里不一致,以我这张图为准是错的。
评论只有六条,样本极小。我把 Armorer Labs 和 CAI 两条的权重给得特别高,这个权重是我自己拍的,没有依据。四舍五入,这一节的地图是拿六个人的观点画的。
记忆层和规划层我一个字没碰。工具层只解决「能不能动」,记忆和规划解决「该不该动、动完记不记得住」。把一个 agent 的工具层设计得再干净,规划那一层烂着,它照样会拿一把好工具把事办砸。那块我打算单独画一张图。
这篇里没有引用任何一篇论文,全是工程博客、会议演讲和评论区。这条线上确实还没有论文可引——谁要是把它做成一个可被引用的东西,这本身就是一块空地。我现在能给的坐标,精度只到「谁在什么场合说了什么」,再往下我核不动。
落子
摊开这张地图,我的落子是:agent 工具层现在站在「从接得上转到接得起」的那个拐点上,这一层的重心已经从执行面挪到了契约层。
还空着的是两块,而且我认为它们是同一块的两面:契约的自动生成和强制,以及执行可见性。你要能看见 agent 选了哪条路径,前提是那条路径上的每一步都带着可审计的契约;你要能自动生成契约,前提是每个动作的副作用已经被分类过一次。顺序上,契约在前。
所以下一颗钉子,我押在「把工具执行的运行时契约做成一层独立、可审计、能从工具实现里反推出来的东西」上。它不会出现在任何一份 MCP 还是 CLI 的技术选型文档里,因为选型文档问的是用哪个,而这件事问的是谁来管。这两问答完,才是同一张图上的前后脚。
MCP 会留在这张图上,但它的位置不是「更好的工具调用方式」,是「治理挂载点」。CLI 也会留在图上,位置是「最快、最窄、最需要人兜底的那一层」。技能留在描述层,负责发现性和按需加载。三者不打架——打架的是把它们塞进同一个选型问题的那个问法。
这个判断可以被证伪:如果接下来半年到一年,这条线上的讨论重心还停在「MCP 还是 CLI」上,契约和可见性还是只出现在评论区的一两句话里,那说明两种情况之一——这一层还没到要上生产的时候,或者管这层的活已经被 API 网关那边悄悄接走了。两个结果都会让这张图重画一次。错了我改坐标,比端着一句「看情况」有用——后者看着稳,其实等于没画。