最近在技术社群里看到一条挺扎眼的发言:“MCP不就是一层薄封装吗?把它删掉,直接让Agent调函数不就行了?”
当时群里立刻分成了两派,一派赞同“薄封装该删”,另一派则觉得“删了只会更乱”。争论到最后,真正的问题已经不再是要不要删MCP,而是:在Agent愈发复杂的今天,连接架构到底应该怎么重新选型?
我做了几年Agent相关的东西,从早期的工具原型到后面接入各类代码库、调试器、PCB设计软件、游戏引擎,MCP和“自己写工具调用”这两条路都走过。这篇想把我看到的现象、踩过的坑、真实项目里验证过的边界和取舍写清楚。如果你正在Agent项目里纠结“要不要上MCP”,或者正在考虑把现有MCP拆掉换成别的方案,这篇应该对你有用。
1. 「薄封装」的批评到底批评了什么
1.1 MCP那层皮确实薄,薄到一眼能看穿
先说个客观事实:MCP本身的协议实现,本质上就是JSON-RPC 2.0加上一套资源抽象。你定义一个tool,给一个名字、一段描述、一个JSON Schema入参,然后MCP server注册一下,Agent就能通过MCP客户端调用它。
从代码量看,一个最小的MCP server可能只需要一两百行。对比一下gRPC你要生成stub、写proto、配拦截器;对比一下完整的SDK你要管序列化、鉴权、重试策略——MCP确实“薄”。曾在IDA Pro里见过有人用MCP插件把反汇编结果直接暴露给大模型,实现方式就是读寄存器、读内存、翻反汇编窗口,然后包成tools,代码不复杂,效果却很直接。
这个“薄”也正是很多批评的来源。有人会问:既然就是一层JSON-RPC转发,那我直接用FastAPI起一个HTTP接口,把我的函数列成JSON Schema,不也一样吗?Agent拿到的还是一个个可调用的function,模型照样能根据描述决定调哪个。什么Tools、Resources、Prompts,不就是换个名字的增删改查吗?
单看协议文本,这个说法我认。MCP的协议设计刻意保持了简单,没做太多“重量级”的事,这也是它能快速扩散的原因之一。
1.2 批评者的合理部分:多一层连接,就多一层成本
MCP带来的额外成本是实实在在存在的。最明显的就是进程管理:你用stdio方式启动一个MCP server,Agent要负责拉起子进程、管理生命周期、读取stdout、写stdin,任何一个环节不稳定,工具就神秘失联了。我在本地接x32dbg的MCP插件时就遇到过进程僵死的情况,Agent调一次断点没响应,整个对话流就卡在那,最后只能手动杀进程重启。
HTTP模式的MCP也好不到哪去。SSE那套传输层在早期确实有各种连接保持的问题,后来社区又推streamable HTTP,版本迭代频繁,客户端和server的版本匹配问题成了新的摩擦点。
对于一个只需要调用两三个工具的Agent来说,这些摩擦完全是可以避免的。你可能只需要一个能查数据库的函数,直接让Agent框架里的工具节点去调用就行,没必要为此引入一个MCP server。这也是“删掉薄封装”派的核心立场:当连接数很少且完全可控的时候,MCP的保护作用体现不出来,成本却实打实地摆在那。
我自己的项目里也删过MCP。有一个内部查询系统,总共就五个接口,之前我照着MCP规范包了一层,后来发现Agent经常把参数名搞混,调试时要同时看MCP日志、Agent日志和业务日志,效率反而低。最后把那五个接口写成普通的JSON Schema工具函数,问题立刻少了一半。这种场景下,删MCP是正确的。
1.3 但“薄”不等于“可以随便删”
不过,“薄”和“没价值”是两码事。我见过太多人因为一段代码看起来简单,就低估了它背后的约定。
MCP薄,但薄的地方是协议本身的实现复杂度;它厚的地方,是一整套工具发现、调用、解析和权限边界的标准化约定。你看到的JSON-RPC确实只有几十行,但在这个基础上,大家一起约定“工具长什么样”“参数怎么描述”“错误怎么返回”“谁有权调用哪个工具”——这才是协议存在的意义。
“删掉薄封装”在单一项目内部完全可行,因为你自己就是唯一的调用方和实施方,约定写在文档里没人管得着你。但只要跨出项目边界,哪怕只是从一个人用到两个人用,从本地工具变成远程服务,从一次调用变成二十个Agent共享——那个你以为能删掉的“薄封装”,就会以另一种姿势长回来。
我个人的判断是:**MCP退不退场,不取决于协议薄不薄,而取决于Agent生态还要不要跨主体共享工具。**只要还要共享,就必须要有一层统一的描述契约,只是这层契约叫不叫MCP的问题。
2. MCP真正的贡献不在协议本身,而在生态契约
2.1 一次实现、处处调用:长尾工具的救命稻草
如果你只在自研系统内部接Agent,MCP的优势确实不明显。但一旦你面对的是“一篮子别人造的工具”,MCP的价值就完全不一样了。
举个直观的例子。逆向工程里有IDA MCP、x32dbg的MCP插件,装了之后,Agent可以直接询问当前函数的反汇编代码、读取寄存器、设置断点。没有MCP之前,这些工具各有各的脚本接口,有的用Python API,有的用插件SDK,有的靠窗口自动化。你要让Agent用上它们,就得给每个工具单独写一套适配代码,而且换一个Agent框架就要重写一遍。有了MCP之后,IDA那边一次封装,任何支持MCP的客户端都能直接对接。
再比如Altium Designer(PCB设计软件)出了AI接口,可以直接以MCP的方式让大模型读取原理图、检查布线规则。游戏引擎那边,Unreal引擎的MCP接口也出来了。这些场景有一个共同特点:**工具本身是长尾生态,市场规模不足以让每个Agent厂商都去做原生适配。**MCP用一个相对温和的协议约定,把长尾工具的对接成本从“定制开发”降到了“写一个适配器”。这个价值,恰恰是“薄”才带来的——太重的协议长尾工具根本懒得接。
2.2 三类原语的语义边界:为什么Tools不是全部
MCP里定义了三种核心原语:Tools(工具)、Resources(资源)、Prompts(提示词模板)。很多人觉得这只是换了个名字的API分类,实际用起来差别还是挺大的。
Tools是“执行动作”——调接口、改数据库、发送消息,有副作用,需要明确的权限控制。Resources是“读取信息”——获取一段文档、一份配置、一段代码片段,本质上是大模型上下文里的可查询资料。Prompts则是“引导行为”——把某个场景下的最佳实践包成一个可复用的提示词模板,有点像给Agent的配套说明书。
这三者分开设计,不是闲得慌,而是因为它们的权限模型和调用逻辑完全不同。Resources可以被Agent选择性拉取,不会产生副作用;Tools则必须被谨慎授权。如果你把所有东西都定义成函数调用,就很容易让Agent在“读取信息”时误触发“执行动作”,这在生产环境里是很危险的事情。
我在Dify上接浏览器MCP的时候感受特别明显。浏览器MCP同时暴露了“读取页面内容”和“点击按钮/填表单”两类能力,前者是Resources,后者是Tools。当我允许Agent自由调用全部工具时,它偶尔会在只该读取的步骤里试图去点按钮(虽然最后没真点,但日志里能看到意图)。后来把读取类操作显式归类为Resources、把执行类操作归类为Tools,才把这种误触倾向压下来。这就是协议语义带来的实际价值。
2.3 传输层之争:stdio不优雅,但它管用
MCP的传输层经历过一波讨论和迭代。早期最常用的方式是stdio——MCP server作为子进程,通过标准输入输出与客户端通信。很多从Web开发转过来的朋友第一反应是:为什么不用HTTP?为什么不用WebSocket?
实际在本地工具场景里,stdio反而是最优解。以IDA MCP为例:本地调试器进程、本地MCP server、本地Agent客户端,三者都在同一台机器上,用stdio就不需要开端口、不需要处理CORS、不需要担心防火墙拦截。开一个端口虽然不难,但在企业内部网络上,每多一个端口就多一个安全隐患和运维负担。
远程场景则更适合HTTP类传输。社区后来的streamable HTTP方案补上了早期SSE的不足,支持流式输出、请求取消、连接池管理这些实际需求。所以现在MCP的传输层选择慢慢形成了共识:本地优先stdio,远程用streamable HTTP,两者不冲突。
有一类问题值得单独提醒,就是“MCP用起来慢”到底是不是协议的问题。很多批评MCP性能的文章,把调一次工具的延迟都归咎于协议本身。但实际排查下来,一大半的延迟发生在MCP server内部的业务逻辑里——比如数据库查询本身慢、外呼API本身慢,又或者server要做认证鉴权。协议层的开销其实很小,JSON-RPC的序列化/反序列化基本可以忽略不计。分享一个我实测过的数据:本地stdio方式调用一个纯内存计算工具,MCP协议带来的额外耗时大约是几毫秒级,真正慢的是计算本身和日志输出。所以别一慢就让MCP背锅。
3. Agent连接架构的重选:MCP不是唯一答案,也不该是唯一答案
3.1 什么场景下MCP确实是多余的
既然标题说“连接架构重选”,就不能只讲MCP的好处,也得坦率承认它的不适场景。结合我的实操经验,大致有这么几类:
- 工具数量极少(≤5个)且调用逻辑简单:直接写在Agent框架的工具列表里更省事。比如一个只需要查天气、发邮件的轻量Agent,引入MCP完全是自我感动。
- 工具与Agent部署在同一代码库、同一进程:同进程函数调用是最低成本的实现方式。MCP的进程隔离优势在这里体现不出来,反而多了一层编解码损耗。
- 有成熟的企业API网关:如果公司已有完备的服务发现、鉴权、限流体系,那么Agent直接调用网关上的API,比再立一套MCP server更贴合现有架构。
- 对延迟极其敏感的场景:虽然MCP协议本身开销不大,但MCP server进程的启动、加载、连接建立依然有不可忽视的时间。高频低延迟的工具调用(比如股票行情的高频查询)在进程内直接调用能省下几个数量级的开销。
这些场景有一个共同特征:**调用方和实现方之间没有信息不对称,也没有多主体协作的需求。**MCP解决的是“多个客户端对接多个服务端”的标准化问题,当你只有一个客户端对接一个服务端,而且两边都是自己人时,标准化就是个伪需求。
3.2 替代方案的真实形态:Function Calling、Agent Skills、上下文注入
现在市面上已经有不少替代或共存路线,值得一一分析。
**Function calling(函数调用)**是目前最广泛的能力抽象,OpenAI、Anthropic、各大模型平台都有自己的函数调用格式。它的思路很直接:把工具描述成JSON Schema,让模型根据用户意图选择调用哪个函数并生成参数。Function calling解决的是“模型怎么理解并调用工具”的问题,但它不解决“工具怎么被发现、怎么被多个客户端共享、怎么跨进程通信”的问题。所以function calling是Agent内部机制,MCP是Agent与工具之间的连接协议,两者不在一个层面,也不矛盾。Codex接入Figma MCP、蓝湖MCP这类场景就是典型例子——Codex本身用function calling建模,但连接外部工具时依然需要MCP来统一描述。
**Agent Skills(技能包)**是这两年兴起的路线,Anthropic的Claude也在这方面发力。它的核心是把一些通用能力打包成“技能”,让Agents把技能当作“教学说明+脚本”来执行。Skill与MCP的边界在于:Skill更像教给Agent的一套方法论(背景知识+操作步骤+推理规则),MCP更像给Agent提供的一个现成遥控器(直接可调用的动作)。实际使用中两者可以混用——Skill描述流程,MCP提供底层工具操作。Spring AI那边也在往这个方向靠,把Agents当成可组合的Skill单元来处理。
上下文注入是另一条被讨论得比较多的路线。即不通过工具调用,而是把业务数据直接塞进系统提示词里。它的优点是模型对“工具”的依赖降到最低,推理链路更直接;缺点是上下文窗口有限、静态注入无法实时获取变化数据。这条路线适合低频、小数据量的场景,在大规模实时数据处理上不如工具方案灵活。
框架内建工具图则是LangChain、Semantic Kernel等框架主推的方式。框架直接维护一个“工具图”,Agent内部按图调用工具,不需要外部服务介入。它的好处是开发体验丝滑、调试方便;坏处是工具图和Agent强绑定,换一个框架就要重新组织一遍。MCP与工具图的关系更像是“外部数据源接入工具图的统一适配层”——你不是二选一的关系,而是MCP可以作为工具图的一个节点类型出现。
3.3 “协议下沉”与“编排上移”:两条路径的权衡
观察这几年的Agent架构演进,能明显看到两个方向的运动。一个是协议下沉:本来属于应用层的工具调用逻辑,逐渐被标准化成基础设施层的协议(MCP就是在做这件事);另一个是编排上移:本来需要在代码里写死的工具调用流程,逐渐被上移到Agent自己的推理编排里(模型自己决定调什么、调几次、什么时候调)。
这两条路径看似相反,其实是同一个趋势的两个侧面——**“连接”本身被标准化、抽象化,“决策”本身则被赋予Agent。**你不再需要为每个工具写一套定制调用逻辑,只需要把它们按标准接入,然后让Agent在这一层标准基础设施上自由编排。这是Agent连接架构从“工程驱动”走向“智能驱动”的关键一步。
所以在做架构选型时,不该问“要不要用MCP”,而该问:**我的Agent需要连接多少外部工具?这些工具是否会被多个客户端复用?我的Agent对工具调用的控制粒度要到什么程度?**答案会自然指向不同的方案组合:少量自研工具直接用function calling;多样外部工具、跨客户端复用选MCP;需要复杂指令组合的场景叠加Agent Skills;低延迟强一致性的场景考虑进程内调用。
下面这张表是我自己项目中最终沉淀下来的选择参考:
| 场景特征 | 推荐方案 | 理由 |
|---|---|---|
| 工具量少(≤5)、逻辑简单、单客户端 | function calling直接调用 | 省掉进程管理、协议编解码,链路最短 |
| 工具类型多、涉及第三方工具 | MCP server | 一次封装,多Agent复用,生态适配好 |
| 需要工具组合成复杂流程 | MCP + Agent Skills | Skill负责流程编排,MCP负责底层操作 |
| 低延迟、强一致、同进程 | 直接函数调用 | 无进程切换开销,调试简单 |
| 工具量中等,且有现成API网关 | 网关API + function calling | 复用已有鉴权、限流能力,避免重复造协议 |
| 长尾工具、生态丰富但无原生Agent接口 | MCP(推荐) | 接入成本最低,社区适配器多 |
这张表对我自己最大的指导作用,就是别把MCP当成Agent架构的全部——它只是连接层里的一个选项,而且是在“跨主体共享”这个前提下才最优的选项。
4. 从实际项目踩坑看MCP的价值边界
4.1 一个由三个工具涨到二十个工具的亲测过程
我做过一个小项目,最初只接三个内部API。那时我采用了“直接函数调用”的方案,代码很清爽,没有引入任何额外依赖。后来业务方提了新需求:要接公司的知识库、要查线上日志系统、要连几个外部SaaS服务、甚至要跑一些模型自检的脚本。工具数量从三个涨到二十个。
当时如果还是靠function calling一个个写工具描述,光维护JSON Schema就会让人崩溃。更要命的是,每个工具的参数定义风格、错误处理逻辑都不一样——有的返回标准JSON,有的返回文本,有的一失败就抛非标准异常。我需要为一个统一的Agent写二十段互不兼容的适配代码,那才是真正的灾难。
后来我做了决定:把工具划分为几组,每组起一个轻量MCP server,用统一的方式暴露Tools和Resources,Agent只需要对接这几个server。整体改造时间不到一周,但后续加工具的成本降到了每次只写一个几十行的注册函数。这算是MCP价值最典型的一次验证——当工具数量少,手写是效率;当工具数量多,标准协议才是效率。
4.2 Agent安全模型:MCP server的信任边界不能拍脑袋定
接入MCP之后,最让我神经紧绷的不是功能实现,而是安全模型。热搜词里“Agent安全”热度很高,说明这不是我一个人的问题。
MCP的权限机制本质上是一个“Server级信任边界”:你信任某个MCP server,就信任它所有暴露的工具。这个粗粒度在标准协议层面目前没有解,只能在设计层面用工程手段去补。
我的做法是把MCP server拆成不同的信任级别:本地只读型server(比如读取文档的Resources)可以给多数Agent开放;本地写操作型server(比如改文件、执行脚本)只给经过授权的Agent开放;远程型server则一律放在隔离沙箱里,agent对工具的调用行为要经过一层统一审计。开发那段时间,我建了一个很简单的日志审计机制:对每个工具的调用记录时间、参数、Agent身份、返回状态。后来有一次Agent在调试时被带偏,想直接往生产环境写数据,正是审计日志第一时间定位到了这个越权意图,避免了一场事故。
要注意的是,这些问题并非MCP独有——任何远程调用框架都需要处理权限边界。但MCP因为接入成本低、工具暴露很容易,反而更容易让你在安全设计上偷懒。如果你决定引入MCP,安全模型必须在第一天就设计进去,不能等工具多了之后再补。
4.3 并发能力:别让MCP server成为Agent吞吐的瓶颈
另一个高频问题是“AI Agent怎么扛并发”。说实话,我见过很多Agent项目把并发能力问题归咎于MCP,其实大部分情况是MCP server实现得太粗糙。MCP server如果按单个Agent会话独占方式跑,那并发自然上不去;如果改造成无状态服务放到连接池后面,并发能力会显著提升。
一个比较有效的改造做法是:**本地工具用stdio模式保证隔离性,远程工具用streamable HTTP模式,后端挂多实例负载均衡。**这样本地操作不占网络资源,远程操作可以横向扩容。同时要注意MCP的请求/响应对之间如果没有做好超时控制和熔断,一个慢请求会拖跨整个Agent的调用链。我在线上环境里给MCP server加过超时保护:超过3秒未返回的调用直接判失败,Agent会自动尝试二次调用或放弃该工具。这个改动对整体响应稳定性帮助很大。
另外还有一点容易被忽略:**MCP server要尽量保持无状态设计。**有状态的server(比如保存会话状态、维护内部缓存)在并发扩容时会产生各种隐蔽问题,而MCP协议本身并不强制状态管理方式,这个决定权完全在server实现方手里。如果你想把Agent跑上生产规模,MCP server就当作普通服务来设计:可水平扩展、无持久状态、依赖外部存储。
4.4 那些被误归为MCP的问题
根据我这几年做Agent项目的经验,跟风吐槽MCP的开发者往往忽略了一点:相当一部分所谓的“MCP问题”,其实是“不合理的MCP实现方式”问题。
节奏夸张的例子:有人把MCP server做成进程阻塞式的重IO处理,结果一个Agent并发调几个工具就崩溃,然后得出结论“MCP扛不住并发”。还有人让MCP server承担了本不该它承担的业务逻辑,把整个AI应用的智能核心都塞进MCP那层薄封装里,结果越来越重、越来越难调试,然后得出结论“MCP是反模式”。
这些归因都偏了。MCP的设计定位是工具连接层,不是业务逻辑层,更不是Agent框架。它只负责“让Agent可以调到这个工具”以及“让工具可以返回给Agent”,至于Agent如何决定调用、如何编排多个工具、如何处理复杂的业务逻辑,那是Agent框架和业务层的事。我不止一次在社区里强调:保持MCP server薄而纯粹,让Agent的智能留在Agent层,是最稳妥的架构姿势。
5. 未来走向:MCP会褪色,但不会退场
5.1 MCP的终点形态更像“基础设施协议”
我不是老派守旧者,我相信MCP在未来几年会经历一轮明显的“认知降温”——它不会再是每个Agent文章里必提的流量密码,甚至会从很多轻量项目的技术栈里消失。但我也确信,MCP不会真正退场,它更可能沉淀成一种“你不一定感知得到、但确实在运行”的基础设施协议。
类比一下HTTP:现在谁还会在技术分享里大讲HTTP协议本身?它存在于每一个网络请求里,但已经不再是话题。MCP如果发展顺利,同样会走上这条路——协议层足够稳定,稳定到大家不再讨论它值不值得用,只管通过它连接工具。过程里的“讨论热度下降”和“协议被广泛使用”,完全可以是同时发生的两件事。
5.2 从MCP协议到MCP语义:名字会变,内核会留
更重要的一点是,MCP提出的那一组语义——Tools(动作)、Resources(信息)、Prompts(模板)——可能会比协议本身走得更远。即便有一天标准MCP被另一种协议取代,这三类原语的区分逻辑仍然会内嵌到Agent框架、API网关甚至IDE插件里。
IDE里现在有通义灵码这类工具通过MCP连接Oracle数据库,本质就是让Agent读取表结构、生成SQL、执行查询的计划。以后即便不叫MCP,这类“Agent连接数据库资源”的能力也会成为IDE的标配能力。再比如ADK.dev这类Kotlin框架里跑Agent,也在默认支持类似MCP的对接模式。这些都是在验证同一件事:Agent连接外部世界必须有一层统一描述,而这层描述的语义内核比具体协议名更加持久。
5.3 Agent连接架构的未来决策标准:以我的经验给你一份参考
如果你正在做Agent架构选型,我给不了“万能答案”,但可以给一套我一直在用的判断标准:
- **先数工具数量,再定连接方案。**少于5个自研工具,直接函数调用;超过10个且包含外部工具,优先MCP;落在中间地带,取决于是否会跨团队复用。
- **先想清楚信任边界,再讨论安全细节。**MCP server的信任级别要从第一天就分好,不然工具越多越失控。
- **区分“连接”和“编排”两个问题。**连接层用标准协议(如MCP),编排层交给Agent框架和Skill机制。混在一起是后续灾难的根源。
- **别用单一方案包打天下。**同一套Agent系统里,可以同时存在直接函数调用、MCP server和Skill技能包。架构的健康度在于组合的合理性,不在于“只用某一种方案”。
我记得自己最早做Agent连接的时候,也犯过“把MCP供上神坛”的毛病。后来删过、重构过、再引回来过几轮,现在的心态反而平静很多:MCP说到底只是一个让Agent和工具能说上话的约定,它薄,但好用,够用,而且在很多场景下是最不坏的选择。删掉它之前,先想清楚你要用什么来替代那套约定;如果替代品只是另一个约定,那它本质上就是MCP换了个名字。
工具会变,协议会迭代,名字也可能被替代,但Agent连外部世界的需求是长期存在的。方向的终点,大概率不是某个协议的胜利,而是“连接”这一层彻底变成每个人都能顺手使用的基础能力。到那时候,我们今天争论MCP是否退场,可能就像争论当年谁先定义了JSON-RPC一样,已经没那么重要了。