← 返回文章列表

MCP 的使命已经完成

一个被验证的观察

今年参与开发了大量多端应用,得益于 AI Coding 的普及,个体的能动性和效率得到了极大的提升。为了保证各端体验一致性,一个人要开发 Android、iOS、HarmonyOS 三个端加前端的需求。公司给提供了几乎是不限量的 Qoder 服务,Qoder 体验确实非常好。为了支撑终端需求的开发,团队里提供了通用的工作流任务编排执行系统,这在 1M 上下文的 Qoder 里,体验很丝滑,但是在 Claude Code 里,如果是用的 opus 4.6,甚至连一个 Hi 都发不出去。排查下来,才发现原来是启动 Session,仅仅只是加载 MCP 工具,就已经用掉了 180K+ 的上下文,开局就陷入了无限 Compacting 的窘境。

在实际的工程实践中,MCP 比传统的 Function Calling 和 Skill 机制消耗更多的 token。这不是理论推测,而是已经被大量项目验证的现象。更令人深思的是,如今,行业正在脚投票:

  • Perplexity:内部弃用 MCP,仅保留对外 Server。
  • YC / Garry Tan:"MCP sucks honestly"。
  • Thoughtworks:技术雷达警告 token 消耗和上下文污染。
  • Cloudflare:2,500+ API 端点不用 MCP,改用 search() + execute() 两个工具,Agent 写 JS 查询。
  • 新的 AAP(Agent Action Protocol):明确将"成本控制、权限模型、生命周期钩子"列为 MCP 的缺失项。

这不是"技术不成熟",而是设计哲学的根本分歧。

Token 浪费:MCP 最显性的痛点

协议层的结构性开销

MCP 的 token 浪费并非偶然,而是内嵌于其协议设计之中。首先,每个工具的定义都需要携带完整的 JSON Schema,包括参数结构、类型约束和自然语言描述。当工具数量增加时,这部分 schema 文本会作为系统提示的一部分反复送入模型上下文。以 GitHub MCP Server 为例,其 93 个工具的定义加载即消耗约 55,000 个 token,相当于 GPT-4o 一半的上下文窗口——这发生在用户尚未发出任何请求之前。连接 6 个常见 Server(GitHub、数据库、Slack、Jira、云基础设施、监控),工具定义本身就能消耗 60,000 至 90,000 token。在 Opus 模型的定价下,仅 schema 的月度开销可达 40,500 美元(按连接 6 个 Server、日均 10,000 次请求、每次请求均需完整加载 schema 估算)。

其次,MCP 的通信基于 Server-Sent Events 或 stdio,需要维持持续的双向连接。这意味着每次会话都要经历初始化、能力交换、工具列表获取等多轮协商,每一轮都携带大量协议元数据。最后,MCP 的 Resources 机制可以配置为自动注入上下文,容易导致"默认全量加载",进一步加剧上下文膨胀。

与 Function Calling 和 Skill 的对比

Function Calling(如 OpenAI/Claude 原生机制)遵循"按需索取"原则:模型在需要时调用特定函数,获取精简结果后继续推理。其 schema 相对紧凑,结果可控,没有冗余的上下文负担。Skill 机制(如 Kimi 的 Skill 系统)则采用高度封装的设计,预编排的工作流只暴露少量入口参数,内部逻辑对模型完全不可见,token 消耗最为节省。

MCP 则走了另一条路:它追求"通用转接头"式的生态互通,一个 MCP Server 可以被 Claude、Kimi、Cursor 等任意客户端使用。但这种通用性是有代价的——为了兼容所有可能的调用方,协议层必须携带完整的自描述信息,而这些信息每一次请求都要重新加载,无法摊薄。

按请求计费的"固定税"

在生产环境中,MCP 的 token 浪费呈现出"按请求计费"的特征,且服务端几乎无法通过缓存来优化。每个新用户请求都是一张独立的账单:

  • Schema 是固定税 无论用户问什么,只要走模型+MCP 路径,就必须先加载 50,000 至 90,000 token 的工具描述。这部分不会因为"这是第 N 个用户"而减少。
  • 工具结果是变动税 用户意图不可预测,查询参数组合无限,"查上个月的销售额"和"查这个月的销售额"是两个完全不同的查询,返回结果无法缓存复用。
  • 模型没有记忆 即使服务端缓存了 Schema 的文本内容,每次请求仍然需要将其重新塞入模型的上下文窗口,模型必须"重新看到"才能"重新理解"。

对于大型项目,这种成本是毁灭性的。假设一个日活 10 万的中型 SaaS、10% 的请求走模型+MCP 路径(AI 渗透率偏乐观取值),按 GPT-4o 定价计算,月度成本约在 40-80 万元区间。实际成本取决于请求频率、schema 大小和结果截断策略。而传统 RPC 路径的同等请求,计算成本几乎为零,延迟仅为 10 至 100 毫秒。

有状态连接:与云原生架构的根本冲突

什么是有状态连接

MCP 的通信模型要求客户端与服务器之间维持一条持续的、双向的、有记忆的连接。这与传统的无状态 HTTP 请求截然不同:

  • 无状态 HTTP 每个请求独立处理,服务器不记住之前的交互,响应完成后连接即可关闭,请求可以任意分发到后端节点。
  • MCP 有状态连接 整个会话期间连接必须保持打开,服务器记住"你是谁、你有什么权限、你之前调用了什么、当前上下文是什么"。

生产环境中的具体冲突

这种设计假设与云原生架构存在多层面的冲突:

云原生组件核心假设MCP 的冲突
负载均衡器请求无状态,可任意分发到后端节点MCP 连接必须粘滞到同一节点,否则状态丢失
自动扩缩容根据 QPS 动态增减实例长连接导致实例无法优雅下线,缩容时连接中断
Serverless(Lambda/Cloud Functions)函数执行完即销毁,按调用计费MCP 要求进程常驻,"冷启动"变成"热保持"成本
容器编排(K8s)Pod 可任意重启、迁移连接断开后,会话状态全部丢失

会话重建的灾难性成本

当连接意外断开(网络抖动、节点重启、超时),客户端必须重建整个会话环境:重新 TCP/TLS 握手、重新初始化、重新获取工具列表(再次加载 55,000 token 的 schema)、重新订阅资源、重新建立认证上下文。这不是"重试一次请求",而是"重建整个会话环境"。

在多实例部署场景下,问题更加隐蔽:如果请求路由到不同实例,MCP 会话无法共享;如果强制请求粘滞到同一实例,就回到了负载均衡的老问题;如果每个实例都独立维护会话池,那就是 N 条有状态连接乘以 M 个实例,内存占用随用户数线性增长,连接泄漏风险持续累积。

可组合性差:数据被迫流经模型

什么是可组合性

在软件工程中,可组合性指的是多个小组件可以像乐高一样直接拼接,不需要通过第三方中转。Unix 管道是最经典的可组合性设计:

cat log.txt | grep "ERROR" | awk '{print $1}' | sort | uniq -c | sort -nr

每个命令的输出直接成为下一个命令的输入,数据不经过用户空间的中转站。

MCP 的数据流瓶颈

MCP 的数据流却强制所有中间数据经过模型:

工具 A(查数据库)→ 模型(中转站)→ 工具 B(发邮件)
                      ↑
                      │
              所有中间数据必须经过模型

这带来了四个层面的效率损失:

1. 数据必须"流经模型"。如果工具 A 返回 10,000 行数据库查询结果,工具 B 只需要其中第 3 列的汇总统计,MCP 的标准流程要求工具 A 把全部结果返回给模型,模型将其塞进上下文,"理解"后提取关键信息,再调用工具 B。即使两个工具完全知道如何直接对话,它们也被强制通过模型中转。

2. 工具之间无法直接引用。MCP 没有"工具链"或"管道"的概念。每个 tool_call 是独立的,工具 A 返回的 resource_uri 对工具 B 来说只是一个字符串,无法直接读取内部状态或临时文件。

3. 无法并行组合。真正的可组合系统允许独立任务并行执行再合并结果,但 MCP 的架构是串行、单线程、模型协调的:模型决定调用工具 A,等待返回,再决定调用工具 B,再等待返回。即使工具 A 和 B 完全独立,也无法并行执行,因为调度权被垄断在模型手中。

4. 缺乏中间表示。Unix 有文本流,Docker 有容器镜像,WASM 有二进制模块,但 MCP 没有定义工具之间的通用数据格式。每个工具返回的结构由自己定义,模型必须在运行时动态理解这种格式,才能传递给下一个工具——JSON 转 CSV、图片 URL 转 base64,这些转换都靠模型完成。

一个具体场景的对比

场景:从数据库查询销售数据,生成图表,发送邮件报告。

Unix/CLI 方式:

psql -h db.company.com -c "SELECT * FROM sales WHERE date > '2026-01-01'"   | python generate_chart.py --type bar   | mutt -s "月度销售报告" manager@company.com -a /dev/stdin

数据以文本流传递,每个工具独立运行,不需要任何协调者,可以并行优化。

MCP 方式:

模型调用 query_database,等待 10,000 行 JSON 进入上下文; 模型调用 generate_chart,传递 10,000 行数据; 等待 base64 图片进入上下文; 模型调用 send_email,传递 base64 图片。

每步都必须等待模型决策,10,000 行数据在上下文中来回传递,三个工具无法并行,如果第 3 步失败,第 1 步的结果已经丢失上下文位置,需要重新查询。

生产架构中的 MCP:被关在服务端内部

实际部署模式与设计初衷的错位

在真实的生产环境中,MCP 很少以原生设计的方式使用。更常见的架构是:C 端客户端应用发起请求,到服务端后先过一层任务编排,如果无法准确识别意图,才交给模型决策,再由模型返回结果下发给客户端。MCP 的角色被限制在服务端内部,C 端无感知。

这与 MCP 的原生设计假设——客户端直连、长连接维持、有状态会话——形成了鲜明的错位。在这种架构下,MCP 的某些问题确实被缓解了:有状态连接发生在服务端内部,可以走内网直连或本地进程通信;工具 schema 不会暴露给 C 端;会话重建在内部网络中更快。

但核心问题并未消失

然而,token 浪费这个最致命的问题并未因为这种部署方式而减少:

  • Schema 仍然每次都要加载 即使只有一条 MCP 连接,每次用户请求都要重新将 50,000 至 90,000 token 的 schema 塞进模型上下文。
  • 工具返回仍然要中转 数据库返回的 10,000 行数据仍然要经过模型上下文,才能生成回复。
  • 效率仍然低下 用户点击"查看销售额"按钮,传统前端调 API 查库返回 JSON 渲染,延迟小于 100 毫秒;走模型+MCP 路径,需要模型理解意图、选择工具、生成查询、等待返回、理解数据、生成回复,延迟数秒,且是概率性的——可能选错工具、生成错误查询。

MCP 把"确定性操作"变成了"概率性推理",这是效率低的根本原因。用户点击按钮时意图是明确的,但通过自然语言走模型+MCP,意图需要被"重新理解"一次。

服务端压力的真相

在这种架构下,"服务端压力非常大"的压力来源并非连接数,而是每次请求的上下文膨胀:模型必须"看到"工具描述才能选择工具,必须"看到"返回结果才能生成回复——这两步的 token 消耗是 MCP 的结构性成本,无论把 MCP 放在客户端还是服务端,这个成本都在。

更隐蔽的是,如果服务端是多实例部署,MCP 的有状态问题会以另一种形式存在:每个实例都独立维护 MCP 会话池,请求路由到不同实例时会话无法共享,强制粘滞则回到负载均衡困境,MCP Server 内部的数据库连接池、缓存、事务状态在实例重启时全部丢失。

优化策略:为什么大型项目都无法接受

面对这些问题,业界提出了若干优化策略,但在大型生产项目的尺度下,每一项都触及了不可接受的天花板:

策略小型项目效果大型项目的不可接受之处
精简 Schema少写描述,省 20% token工具从 50 个膨胀到 200 个,触及天花板;描述变模糊导致模型准确率下降
动态加载工具3 个场景分类,准确率 90%100+ 场景边界模糊,意图识别本身需要另一个模型,引入二次推理延迟和成本
结果截断/摘要用户问"总结",丢摘要没问题用户问"找出第三行数据的异常值",截断直接丢信息
意图识别先行已作为架构核心,挡住确定性请求大型项目中真正需要模型灵活处理的复杂请求比例更高,这些请求绕不过 MCP,token 税照交

越大的项目,工具越多、场景越复杂、用户意图越不可预测,MCP 的"按请求固定税"就越沉重,而优化空间却越狭窄。最终,团队会自然地问:"既然我都关在服务端了,为什么不直接用更高效的调用方式?"。

通用性的迷思:协议层通用性是否是正确的抽象

通用性 ≠ 协议层通用性

MCP 的困境本质上是一个抽象层次错位的问题。通用性本身对 Agent 很重要,但 MCP 追求的是"协议层通用性"——任何工具都能插的 USB-C 口——而 Agent 真正需要的是"语义层通用性":理解意图、规划步骤、控制成本、保证安全。

层面内容是否必要
能力层(What)Agent 能做什么:查询数据库、发邮件、部署代码必须有
调用层(How)如何触发:REST API、CLI、MCP、函数调用可以多样
治理层(Whether)能不能做、花多少预算、需不需要审批MCP 完全缺失

MCP 定义了"怎么调用",但完全不定义"是否该调用"。Agent 拿到数据库连接就能删表,协议层没有任何预算、权限、动作严重性的概念。这也是为什么新的 Agent Action Protocol(AAP)会明确将"成本控制、权限模型、生命周期钩子"列为 MCP 的缺失项。

真正被验证的通用性

2026 年的行业实践正在指向更务实的方向:

CLI 的隐性通用性:LLM 在训练数据中见过数百万次 git、curl、jq、kubectl 的使用。一个 git log --oneline -10 命令只需 200 token,而等价的 MCP 初始化需要 10,000+ token——50 倍差距。CLI 的通用性不是来自协议标准,而是来自训练数据的覆盖。

渐进式加载(Progressive Disclosure):Anthropic 和 Cloudflare 证明不需要一次性加载所有工具。Cloudflare 的 API 有 2,500+ 端点,如果每个都做成 MCP tool 需要 117 万 token。但他们只暴露 search() 和 execute() 两个工具,Agent 写 JavaScript 查询 API 规范,总成本降到 1,000 token——99.9% 的削减。

分层架构:最合理的演进方向不是"非 MCP 即 CLI",而是 MCP 负责能力发现和安全接入(认证、OAuth、权限范围),CLI/代码沙盒负责实际执行(组合、管道、过滤、调试)。

是否存在"没有 MCP 就不行"的场景

经过逐层剖析,我们可以直面最初的问题:是否存在"没有 MCP 就不行"的场景?

答案是:在当前的工程实践中,几乎没有。

MCP 能做的事都有替代方案,而且替代方案往往更成熟、更高效:

MCP 能力替代方案优势
查询数据库直接 SQL/ORM、GraphQL类型安全、编译期检查、无 schema token 开销
调用外部 APIHTTP client、gRPC、OpenAPI 生成标准化、可追踪、可缓存、错误处理成熟
文件系统操作OS 调用、对象存储 SDK无中间层、权限控制原生
执行代码/脚本Docker、WASM、serverless沙箱更成熟、资源隔离、冷启动可控
知识库检索向量数据库、Elasticsearch检索质量更高、延迟更低、成本可预测
多工具编排Temporal、Airflow、BPMN确定性执行、可重试、可观测、无幻觉风险

MCP 的真正独特之处不是技术能力,而是"让模型自己发现和调用工具"这个交互模式。它的价值在于:人描述目标,模型自己看工具列表、决定调用什么、处理结果——人只需要说"做什么",不需要知道"怎么做"。

但这个模式的价值边界非常清晰:只有当任务本身不可预定义,且执行者需要实时决策时,才可能有用。即便如此,替代方案仍然存在:专用 research agent 用更紧耦合的工具链,可观测平台用规则加异常检测,IDE 用代码补全加终端执行保留人的控制权。

真正接近"不可替代"的边界,可能是"有一个全新的、模型训练时没见过的工具,需要模型在零样本情况下学会使用,且人不能预先写适配代码"。但即使这里,用文档生成 OpenAPI spec、代码生成客户端、RAG 辅助生成代码片段等人 review 后执行,都是更可控的路径。

MCP 不是基础设施(如 TCP、HTTP),不是最佳实践(如 Docker、K8s),更像是一个实验性工具——探索模式,等待被更专精的方案取代。

另一个方向

WebSocket + 自定义 RPC(MCP 之前的路径)

如果放弃 MCP 的"协议层通用性"追求,最直接的选择是回到 MCP 之前的路:WebSocket 保持长连接,工具调用走 gRPC 或自定义 RPC,由代码路由而非模型选择。

┌─────────┐    WebSocket    ┌─────────┐
│  客户端  │  ←────────────→  │  服务端  │
│ (Agent) │   (双向字节流)   │ (工具集) │
└─────────┘                 └─────────┘
                              │
                              ▼
                        ┌─────────────┐
                        │  gRPC/自定义  │
                        │  直接调用    │
                        └─────────────┘

这本质上不是"MCP 的替代方案"——它是放弃了 MCP 要解决的问题。工具调用由代码硬编码路由,类型安全在编译期保证,不需要模型"理解"JSON Schema。工具描述不在模型上下文里,token 开销为零。

代价也很清楚:新增工具需要改代码、走部署流程,失去"模型动态发现"的能力。编排层(Harness)承担了工具调度的职责,模型退出工具选择路径——这让执行回归确定性的同时,也意味着 Agent 失去了自己探索未知工具的可能。

这是一个取舍,不是升级。对于工具集稳定、场景边界清晰的大型项目,这个取舍通常合理。正是这个原因,现在我们越来越重视编排层:让确定性执行回归编排层,模型只负责它擅长的判断和理解。

WebSocket + Agent 间对话协议(另一个范式)

"双向协作、主动对话"基本已经成为 AI Agent 设计的共识。如果彻底放弃协议层通用性的追求,另一种思路是:不要 MCP 的工具描述 + 调用语义,而是让 Agent 之间通过 WebSocket 用自然语言直接协商。

┌─────────┐    WebSocket    ┌─────────┐
│ Agent A │  ←────────────→  │ Agent B │
│ (用户侧) │                 │ (服务侧) │
└─────────┘                 └─────────┘
     │                            │
     ▼                            ▼
帮我查销售数据          收到,我需要调用数据库
     ↑                            │
     │                            ▼
结果是什么?            正在查询...
     ↑                            │
     │                            ▼
用户说预算 5 万          收到,继续执行...

这不是 MCP 的进化,而是对协议层通用性的彻底放弃——用 LLM 本身的语义理解能力来谈判协作,不再通过结构化工具协议做中介。它的优势和劣势来自同一个根源:没有 Schema 开销,但也没有 Schema 的确定性和契约保障。

这套思路的更远未来是 WebTransport——基于 QUIC 协议,原生支持多路复用和连接迁移,彻底解决队头阻塞。但 WebTransport 解决的是传输层问题(更快、更可靠),不是应用层问题(如何发现和调用工具)。它和 MCP 不是在同一个维度竞争。

架构选择的本质

MCP 的困境揭示了一个更深层的工程真理:通用性在协议层往往是反生产力的。

当 MCP 被关在服务端内部使用时,它的"通用协议"价值被架空了——C 端无感知、生态互通无从发挥、工具发现变成内部硬编码。与此同时,它的"模型上下文膨胀"成本却一分不少——每次请求都要交 Schema 入场费,每次结果都要经模型中转。既不够高效,也没发挥通用性。

大型生产项目的最终选择,不是"用不用 MCP",而是"在哪些边界情况下,愿意牺牲效率和可靠性,换取开发速度"。这个边界在成熟团队里通常被压得很窄:80% 的确定性请求走规则引擎(零 token),15% 的半复杂请求走小模型分类(低 token),只有 5% 的真正复杂/未知请求才交 full token 税给大模型加 MCP。

Agent 需要的不是"任何工具都能插的 USB-C 口",而是"知道该插什么、什么时候插、插进去之后怎么控制"的智能层。MCP 提供了前者,但后者才是生产环境的刚需。2026 年的趋势正在验证这一点:模型退居决策层,执行层回归标准编排——Temporal 做工作流、CLI 做数据管道、WASM 做沙箱执行,只在需要"判断"或"理解"的时候才调用模型。

这不是对通用性的否定,而是对通用性层次的重新定位:从"协议层的万能转接头",转向"语义层的意图理解",最终落实到"执行层的确定高效"。MCP 的探索是有价值的,它让我们更清楚地看到了 Agent 架构中真正需要被抽象的是什么——不是工具调用的协议格式,而是任务分解、成本控制、权限治理和可靠性保障这些更高阶的编排能力。