☰
MCP真的凉了吗?大厂改用CLI的背后逻辑与选型参考
2026/10/22 11:03:34 网站建设 项目流程

最近这一个月,我在好几个技术群里都撞见同一个话题:MCP(模型上下文协议)是不是凉了?起因是有团队晒出内部架构变更,把 Agent 工具调用从 MCP server 整段换回 CLI(命令行工具),评论区有人叫好,有人说这是开倒车。我前阵子刚陪一个内部平台走完类似的重构,对这个趋势有些自己的判断,趁假期把观察和实操整理成一篇,聊聊大厂这种选择背后的真实原因,也给正在纠结选型的团队一个参考。

先给结论:这波“抛弃”不是把 MCP 批倒批臭,而是生产环境把工具层的优先级狠狠教育了一遍。下面展开说。

1. MCP 的高光时刻:它解决的确实是个真问题

1.1 在 MCP 出现之前,Agent 接工具为什么是一团乱麻

在 MCP 普及之前,要让智能体调用外部工具,最痛苦的事情就是接口碎片化。每个模型平台有自己的一套 function calling 规范,每个 Agent 框架有自己定义的 tool schema,每个内部系统又各有各的鉴权方式。一个 Agent 想查订单、看库存、发通知,每个能力都要从头对接一遍:接口设计、参数映射、错误处理、重试策略,全是重复劳动。

我见过某个团队接入一个内部数据查询服务,前后花了两周,其中大部分时间不是在写业务逻辑,而是在处理连接池、鉴权 token、超时重试这些和业务毫无关系的周边问题。而这种成本只要换一个模型平台就要再付一次。工具接入的碎片化,是当时整个 Agent 生态从 demo 走向生产最大的堵点。

1.2 MCP 的简化逻辑:把工具变成可插拔的 server

MCP 干了一件很聪明的事:把工具抽象成 server,把调用封装成统一的 JSON-RPC 消息。宿主应用通过 client 去连接 server,server 用 list_tools 把自己的能力描述出来,调用时通过 call_tool 统一传参和取结果。对上层模型来说,工具是什么语言写的、部署在哪里、内部什么结构,统统不重要,只要协议对上就能用。

这个思路本身非常漂亮,相当于给工具生态定了一套 USB-C 接口。理论上,任何工具只要挂一个 MCP server,就能被任何支持 MCP 的宿主应用发现和使用。这个想象空间足够大,所以它能在短时间内火起来,我一点都不意外。

1.3 热度与现实的落差:POC 的甜和生产的苦

问题在于,MCP 的 POC 阶段体验太有欺骗性了。官方仓库里现成的 server 一抓一把,连上本地文件、数据库、浏览器,几分钟就能让模型跑起来干活。一个 server、一个 client、一次调用,这就是 POC 的全部。

但生产环境要面对的是几十个 server 的版本管理、断线重连、资源占用峰值、权限隔离,还有像“某个 server 的某个依赖库在特定版本下会阻塞”这种完全没法从协议层面预防的问题。很多团队在 POC 时被“什么都能接”的光环吸引,上线半年后被运维成本打醒,开始重新审视这条路。我认识的几个团队,基本都是在 3 到 6 个月这个时间节点上动了换掉 MCP 的心思,这和我在网上看到的趋势是吻合的。

2. CLI 的回归:不是倒退,而是工程成熟度的胜利

2.1 真正通用的不是协议,而是进程模型

为什么会有人把目光转回 CLI?因为命令行工具才是 IT 世界里最经得起时间考验的通用接口。不管操作系统是什么、不管编程语言是什么,只要跑在类 Unix 的进程模型上,stdout、stderr、exit code 这套约定就是几十年不变的基础设施。

所有 Agent 框架、所有 CI/CD 系统、所有任务调度器,本质上都在做同一件事:拉起一个进程、传参数、等结果、看退出码。与其让模型工具层去适配一套新协议,不如直接站在这套已经被验证过无数次的通用地基上。CLI 不是新技术,但它是最稳的通用技术。

2.2 CLI 能落地,是因为它永远“先有工具,后有协议”

大厂内部早就积累了海量的命令行工具。运维脚本、数据抽取、服务调用、发布工具,全是 CLI。Agent 要具备这些能力,只需要把它们登记进一个可执行清单,而不是为每个工具重新开发一个 MCP server。

这个差别是决定性的。MCP 的路径是“先定协议,再造工具”,每个工具都要额外维护一个 server 壳;CLI 的路径是“先有工具,再造协议”,用一个统一的执行器把已有的命令包起来即可。接入成本从“每个工具开发维护一个服务”变成“注册一行元数据”,这个差距在工具数量上百之后会无限放大。

我当时的账是这样算的:一个普通业务工具,写 MCP server 加上部署联调,一个版本迭代至少要投入三天;改造一个已有 CLI,半天都不到。工具越多,CLI 路线节省的人天越可观。

2.3 可调试、可隔离、可审计:生产环境的三座大山,CLI 天然过关

命令行工具的调试体验是碾压级的。一条命令报错,在终端里直接跑一遍就能复现,报错堆栈就在 stderr 里。MCP 调用出了问题,你得先确认 client 和 server 两边的版本,再翻协议层日志,运气不好还得抓包看 JSON-RPC 的握手过程。这种排障成本在一个几十个工具的系统里会被放大到让人崩溃。

隔离和审计也是一样。CLI 是围绕“单次调用”设计的,天然适合放进容器、seccomp、只读文件系统这些沙箱机制里,跑完就销毁,不残留任何状态。MCP server 是常驻进程,只要有那么一两个 server 出现内存泄漏或僵死,整个宿主应用都要跟着遭殃。

维度MCP serverCLI
接入成本需要开发并维护 server已有命令,注册元数据即可
运行形态常驻进程,保持长连接一次调用一个进程,用完即清
调试手段协议日志、抓包、版本排查本地直接跑命令,看 stderr
资源占用每个 server 固定吃内存仅在进程存活期间有开销
安全边界依赖 server 自身实现平台可做沙箱、超时、白名单
模型理解JSON Schema 描述,token 消耗大--help 文本,自然语言,token 消耗小

2.4 一个被严重低估的点:CLI 对模型更友好

最后说一个很多人没想到的角度:LLM 本质上是文本模型,它的训练语料里最不缺的就是命令行用法、man page、脚本示例。你对模型说“用 curl 访问某个地址”,它理解起来毫无压力;你给它一个工具,附带一段 --help 文本,它很容易猜出这个工具能干什么、参数怎么填。

MCP 的工具描述虽然结构化,但代价是 token。一个稍微复杂一点的工具,其 JSON Schema 描述轻松吃掉几千 token,工具一多,每次对话都要重复携带这一大堆描述,上下文很快被撑爆。CLI 工具只要一行说明、一段 --help,模型就能理解,token 开销小一个量级。对于追求低延迟和高吞吐的大厂 Agent 平台,这个差异是实打实的。

3. 生产环境里,MCP 最让我劝退的四道坎

3.1 常驻 server 进程:省事还是埋雷

MCP 的设计核心是 server 作为常驻进程和 client 保持连接。这在本地开发时没啥问题,但放到大厂的生产环境,尤其是容器和 Serverless 混合部署的环境里,就成了最大的隐患。

常驻进程意味着每次拉起成本高、生命周期长、资源占用固定。一个负责查数据库的 server 要维持连接池,一个负责调内部 API 的 server 要占内存跑完再去处理请求。当 Agent 平台要挂十几个甚至几十个 server 时,光是内存开销就很可观。更糟的是,宿主应用一旦重启,所有 server 都要重新握手,重连逻辑稍有瑕疵,就会看到一群半死不活的游离进程。我在生产环境里亲眼见过一个 server 失联后反复尝试重连,把日志刷爆的场景。

3.2 工具描述膨胀:协议结构化反而加重了上下文负担

MCP 要求每个工具都提供完整的 JSON Schema 描述:description、properties、required、枚举、示例,一个都不能少。协议本身要结构化,这没毛病,但工具数量一多,把这些描述全塞进上下文就成了噩梦。

假设你的 Agent 平台挂了 200 个工具,平均每个工具的描述占 2000 token,那 total 就是 40 万 token。这还不算业务知识的上下文。模型在思考选哪个工具时,必须把一部分描述加载到上下文里,token 消耗直接爆炸。CLI 方案只需要给每个工具有一个名字加一行用法说明,模型选定后再把对应的 --help 完整文本按需加载,这个设计在工程上要合理得多。

3.3 鉴权、多租户、速率限制:协议层没有答案的必答题

MCP 协议定义的是工具交互机制,但没有定义授权模型。每个 server 自己决定怎么做鉴权:有的用 token,有的用 API key,有的啥也不做。在大厂内部, Agent 平台要同时服务多个业务方,这就要求平台统一控制身份映射、权限判定、限流、审计。

在 CLI 方案里,命令是平台侧执行的,平台天然可以在这个执行器的外层做统一鉴权:用户身份、令牌映射、命令白名单、资源配额,全都在这一层解决。MCP 的方案里,用户身份怎么传、token 怎么换、不同租户怎么隔离,每个 server 都要各自实现一遍,实现的还很不一样,最后只能靠人工审计去查漏补缺。这在一个讲安全合规的环境里是不可接受的。

3.4 排障黑盒:一线开发最真实的挫败感

我不是反对协议,但 JSON-RPC 封装带来的排障成本,是任何一线开发都会想骂人的地方。一次 MCP 调用失败,你看到的可能只是一个 error code 或者一段难以定位的消息。想继续查,你得开 DEBUG 日志、抓 stdin/stdout、比对 client 和 server 的版本、查两边依赖库的差异。

CLI 没有这一层黑盒。命令跑挂了,复制粘贴跑一遍,异常的堆栈就在那里,该什么原因就什么原因。这种确定性的排障体验,在高压生产环境里价值连城。我一度在内部交流里放话:只要你负责维护的那套 Agent 服务上挂着几十个 MCP server,你就迟早会理解“黑盒协议”比“慢但直接”更让人崩溃。

4. 一次真实的迁移实录:某内部 Agent 平台的工具层重写

4.1 迁移前:为什么决定动刀

我之前参与维护过一个内部 Agent 平台,最初选型时很自然地用了 MCP。理由和大家一样:生态新、看着标准化、SDK 齐全。但随着接入工具从十几个涨到一百多个,问题开始密集出现。

首先是资源问题。有的 server 用 Node 写,有的用 Python 写,平均一个占用 200 到 400 兆内存,在测试环境还好,一上生产,几十个 server 一起跑,内存直接告急。其次是稳定性,业务方反馈某个工具调用隔三差五超时,查到最后是某个 server 的内部依赖在特定网络环境下的 DNS 解析阻塞。这种问题修起来没头没尾,因为问题不在业务逻辑,而在被隐藏起来的底层依赖。最终团队达成共识:这一层抽象的收益已经抵不上运维成本,决定动刀。

4.2 迁移目标:以 CLI 为核心的网关架构

我们要的不是“让模型随便跑 shell 命令”,那太危险。改造后的架构是这样:Agent 平台维护一份允许调用的命令清单,每条命令对应一个规范化的 JSON 输出格式,平台侧有一个安全执行器,负责命令解析、参数白名单、超时 kill、沙箱隔离、审计日志。

运行流程也很清晰:模型根据工具注册表里的说明选择工具并输出调用意图,平台校验参数合法性和权限,然后以子进程方式启动 CLI,强制超时后读取 stdout 和 stderr,最终把解析结果回传给模型。这个流程的每一步都可以用现有运维手段监控和模拟,这比调试 MCP 的黑盒链路舒服太多了。

4.3 迁移路上的三个坑

第一个坑是参数注入。最早图简单,用 shell 拼接命令,结果发现参数里的特殊字符、换行、以横杠开头的字符串都可能被解析器误读。后来我们统一规则:不用 shell 做拼接,参数以数组形式直接传给执行器,同时还要求所有新工具支持通过 --json 参数接收结构化输入。参数注入这个问题在任何写 agent 工具层的人那里都会遇到,早立规矩早省心。

第二个坑是无状态改造。原来的 MCP server 内部会维护连接池或临时缓存,换成 CLI 后,每次调用都从零开始,原本一些“上次调用的状态”失效了。我们被迫把所有 CLI 改成无状态模式:需要缓存的写到临时目录,用调用 ID 做隔离;需要共享状态的,干脆把状态挪到远端的共享服务上。

第三个坑是幂等性。Agent 是会重试的,一条命令执行成功后因为网络问题让模型以为失败了,于是又跑一次,结果订单重复、通知重复。所有写操作的命令都必须接受一个幂等键参数,平台在日志里保留去重记录。别小看这条规范,迁移之后因为这避免的事故远比想象中多。

4.4 迁移后的对比数据

改造完成后的数据变化非常直观。这里放一组来自当时压测和线上监控的对比,可以供参考:

指标MCP server 方案CLI 网关方案
P99 调用耗时约 1.8 秒约 0.6 秒
单节点并发支撑约 50 路200 路以上
单工具常驻内存200-500MB调用期间约 10-20MB
故障恢复等 server 重启和重连调用失败立即重试,进程退出即清理
新增工具接入时间数天级小时级

我自己看这份数据时,最意外的其实是 P99 耗时下降那么多。后来复盘发现,主要原因是绕过了 MCP 客户端层和 server 之间的长连接状态与内容协商开销,对高频工具来说,每次调用减少几十毫秒的握手和空转延迟,累积起来非常可观。

5. 我的选型建议:不是二选一,而是以 CLI 为地基、让 MCP 做补充

5.1 什么场景继续用 MCP

我不认为 CLI 会完全替代 MCP。有些场景 MCP 依然是最顺手的选择。

第一类是宿主应用需要与工具保持交互会话的场景,比如桌面端助手、IDE 插件这类工具,需要在一个会话内反复调用并且互相传递状态。第二类是工具本身需要主动推送数据,比如监控告警、消息订阅,这种 server 侧主动下发的事件流,CLI 的一次性进程模型不太好实现。第三类是面向外部生态开放的能力接入,你希望第三方合作方能按照一份公开协议来接入,MCP 作为行业标准协议有自己的生态价值。

在这些场景里强行用 CLI 反而别扭,硬套 CLI 会让状态管理、事件推送、会话保持都变成一堆补丁。技术选型永远要看场景适配,不是跟风。

5.2 什么场景优先上 CLI

反过来,如果是服务端 Agent 平台的内部工具调用,我现在的默认选择永远是 CLI。

具体来说:高频批量调用、并发要求高、安全审计严格、工具数量多、需要跨语言跨版本稳定运行的场景,CLI 都有明显优势。还有一类是工具本身就是命令行程序或脚本,这时候硬包一层 MCP server 属于画蛇添足。

我在内部团队定的规则就一条:默认 CLI,只有当工具确实需要会话状态或事件推送时,才启用 MCP 做补充。实际运行半年下来,这个规则帮团队避免了很多无谓的复杂度。

5.3 给 CLI 工具层定一套“可被 Agent 消费”的规范

如果决定走 CLI 路线,团队最好及早定一套规范,否则所有命令的格式五花八门,Agent 解析起来一样痛苦。我这里给出实际在用的几条核心规范,可以直接抄作业:

  • 所有工具必须支持--format json或--json参数,stdout 只输出结构化结果,stderr 只输出错误和日志。
  • 必须有--help,且--help文本要写清楚用途和参数,因为这份文本会直接被模型消费。
  • 工具必须无状态运行,临时文件写到以调用 ID 命名的独立目录,不依赖历史调用留下的任何状态。
  • 退出码要规范:0 是成功,非 0 是业务失败,128 以上保留给平台超时和资源限制。
  • 平台侧必须有全局超时,默认 30 秒,特殊工具可以申明更长,但绝不无限等。
  • 写操作必须支持幂等键参数,防止 Agent 重试造成重复副作用。

下面是一个简单的调用示例,order_cli get --id ORDER-001 --format json,输出形如:

{ "code": 0, "data": { "order_id": "ORDER-001", "status": "DELIVERED", "updated_at": "2025-06-01T10:22:13Z" } }

平台执行器拿到这份输出后,只需要做一个统一解析:code非 0 就把message回传给模型作为错误信息,等于把“需要模型看自然语言日志”降级成“结构化结果确认”。这套规范看起来简单,但真正跑起来之后,你会发现它把工具接入和调试成本压得非常低。

说实话,CLI 也不是完美方案,冷启动延迟、状态保持、事件推送确实是它天生的弱项,这也是我始终强调“以 CLI 为地基、MCP 做补充”的原因。但就目前大厂的生产环境压力来说,工具层的复杂度每降低一分,稳定性和可维护性就能实打实提高一截。这也是为什么我会在下一次需要重做工具层时,毫不犹豫地再次选择这条路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询