最近好几个技术社群里都在吵同一个话题:MCP是不是要凉了。起因也不难理解,Agent Skills、更原生的Function Calling、各家框架自己封的插件协议,看起来都比MCP更轻、更贴近模型能力,于是“删掉薄封装”成功变成新一轮的技术叙事,标题越起越狠,连“退出历史舞台”都出来了。
作为一个从MCP刚起步就把它接进内部工具链的开发者,我想先泼盆冷水:这个话题一半是技术争论,另一半是流量密码。MCP(Model Context Protocol)本意是把AI Agent和外部工具之间的连接方式标准化,它实实在在地解决了多客户端、多工具、跨语言的集成痛点,但它也确确实实有设计边界。本文我打算把“薄封装”到底指什么、MCP在Agent连接架构里的真实位置、什么时候该保留它、什么时候该换成原生方案,以及我在真实项目中遇到的坑和排查方法,一次性讲透。适合正在做AI Agent集成、手里同时维护多套客户端工具的同学参考,也适合被“MCP已死”言论整到犹豫要不要继续投入的人。
1. 唱衰MCP的三类噪音背后:薄封装到底是什么
1.1 为什么“删掉薄封装”会成为热搜话题
MCP被唱衰,过去一年我至少听过三类叙事。
第一类是“协议过剩论”。很多项目实际只需要让模型调用三五个工具,比如查库存、发邮件、算价格。这种情况下直接把工具列表放进Prompt,用模型自带的Function Calling就完事了,根本不需要引入一套独立的协议层。MCP的Server、Client、Tool、Resource、Transport这些概念对一个小项目来说确实是负担,这就是“薄封装”被吐槽“多余”的直接来源。
第二类是“控制权回归论”。模型厂商和框架方都在推自己的Agent原生生态,比如Anthropic的Agent Skills、OpenAI的Function Calling进阶用法。这些方案和模型内部能力贴合得更紧,能吃到模型厂商的功能更新,比如新的结构化输出、并行调用、内置上下文缓存。相比之下,MCP作为一套独立协议,更新节奏完全跟不上模型能力迭代,自然给人一种“落后半代”的观感。
第三类是“工程债论”。随着MCP生态膨胀,工具数量爆发,问题也开始暴露:鉴权不统一、流式传输支持参差不齐、长连接容易断、跨平台配置混乱。这些吐槽我大部分是认同的,但这不等于“协议本身该消失”。
那“薄封装”究竟是指什么?说穿了,MCP做的事情就是把“模型需要调用工具”这件事拆成固定的消息格式和传输约定:客户端发一个tools/call请求,服务器返回content和isError,中间再加个initialize握手。官方SDK写起来代码量极少,给人感觉就是薄薄一层壳。问题在于,把它往真实业务里一放,你就得处理鉴权、超时、重连、流式、幂等、多租户隔离……真正麻烦的不是协议本身,而是协议之外那层胶水。
1.2 技术噪音之外的几句实话
我对MCP的真实态度是:确有弱点,但罪不至此。
先说不该被忽略的优点。MCP最大的价值是“一处接入、多处可用”。我维护过一套内部运维工具集,包了日志查询、配置变更、发布状态这些能力。换成MCP之后,同一个Server可以被Claude Desktop、Codex、Dify、自研Web客户端连接,不用为每个端写一套适配层。这个收益在客户端数量大于等于三个时是非常显著的,尤其是团队里不同人用不同工具,统一协议能省掉大量重复劳动。
再说确确实实存在的短板。MCP对“流式工具调用”的支持一直不够理想。传统HTTP/SSE传输下,服务器向客户端推流是单向的,做那种“边生成边写文件”的场景,你得自己加回调机制。另外MCP官方规范里工具描述是JSON Schema,但很多模型对Schema的遵循质量不稳,工具一多就容易乱选。这些都是真实痛点,也是“连接架构重选”话题的正确答案来源,只要稍微抬杠一下,就能得出“删掉MCP”的结论。
我觉得更合适的类比是HTTP协议本身。HTTP也是一层薄封装,没人会天天喊“删掉HTTP”,原因是大家清楚它只负责最基础的请求响应,剩下的路由、鉴权、缓存都是上层自己叠的。MCP现在的问题是被一部分人当成了“AI连接万能解决方案”,当期望撑不住时,骂声自然就来了。等情绪退潮,它会回归成一个基础连接层,该用的地方继续用,不适合的地方换成更合适的方案。这跟“退出历史舞台”绝对扯不上关系。
2. MCP在Agent连接架构里的真实位置
2.1 MCP的能力拆解:不只是工具调用
很多被“薄封装”言论带跑偏的人,以为MCP就是个工具调用协议。其实MCP规范里有四个核心能力,只有把四个都理解透,才能做好架构判断。
第一是tools,这个大家最熟悉。模型向服务器发请求,服务器执行并返回结构化结果。适合查询、计算、操作类动作,对应的是“Action”这一层。
第二是resources。这是用来给模型提供上下文内容的,比如项目文档、代码文件、日志片段、上报数据,从机制上更接近一个只读文件系统。模型侧不需要主动调用,客户端可以把Resource内容自动注入到上下文里。项目里把rules、wiki、接口文档暴露成Resource,效果比硬塞Prompt稳定得多。
第三是prompts。本质是预置的提示词模板,服务器端定义,客户端侧选择并填充参数后使用。多客户端统一模板时很省事,避免每个端各维护一套提示词逻辑。
第四是sampling,这是最容易被忽略的能力。它允许服务器反过来向模型发起生成请求,也就是模型—工具之间的双向协作。典型场景是Agent要动态决定要不要让LLM再生成一段文本当中间步骤,服务器侧也能参与采样策略。
只看tools的话,MCP确实薄。但如果把resources、prompts、sampling放进视野,它就是一套完整的上下文传输与交互规范,价值和厚度完全不同。
2.2 传输层选型:stdio、HTTP/SSE与Streamable HTTP怎么选
MCP的传输层直接影响使用体验和架构设计,这块是很多“MCP已死”论据的来源。
早期MCP最常用的是stdio传输。客户端以子进程方式启动Server,通过标准输入输出通信。优点是本地命令型工具接入极快,配置也简单,Claude Desktop这类桌面应用天然适合。缺点也很明显:跨网络不可用、生命周期跟客户端绑死、不方便在远端使用多租户服务。
后来是HTTP+SSE传输。服务器暴露一个HTTP端点,客户端通过SSE接收事件。稍微复杂一点,但摆脱了进程限制,可以部署到服务器,多个客户端同时连。缺点在于SSE是单向的,客户端要向服务器连续POST事件才能真正实现双向流式会话,状态管理也因此变得别扭。
最近MCP在推Streamable HTTP,核心变化是支持双向流式通信,客户端和服务器都能主动发消息。对实时性要求高的工具,比如让Agent边推理边看到日志输出、流式写文件、持续反馈执行进度,这种传输模式明显更顺。
实际选型时,我一般画一个简单象限表:
| 传输方式 | 跨网络 | 流式支持 | 多客户端 | 典型场景 |
|---|---|---|---|---|
| stdio | 否 | 一般 | 弱 | 本地调试、桌面客户端、临时脚本 |
| HTTP+SSE | 是 | 弱 | 中 | 单方向推送、早期服务化部署 |
| Streamable HTTP | 是 | 强 | 强 | 服务化Agent、实时输出、多端共享 |
我自己的经验是:本地工具和调试场景用stdio,凡是准备长期跑的服务,尽量直接上Streamable HTTP。省得后面为了流式需求再重构传输层。
2.3 MCP不是唯一的连接方式:和Function Calling、插件协议的边界在哪
要判断“删掉MCP”,先得搞清楚它和其他连接方案的边界。
原生Function Calling是模型厂商直接支持的能力,定义函数列表、让模型选函数、回传参数,整个流程发生在模型推理内部,延迟低、贴合紧。如果整个系统只有一个模型供应商、两三个内部工具,用Function Calling完全没有问题,加MCP只是徒增层数。
插件协议,比如IDE里的插件机制、Agent框架自带的Action插件,优势在于贴近宿主环境,能吃到宿主本身的能力,比如文件访问、编辑器上下文、生命周期事件。适合单宿主深度集成,可移植性通常较差。
MCP的位置在于“标准化中间层”。它不跟模型绑定,也不跟宿主绑定,给的工具形态是一致的。当一个生态里同时存在Claude Desktop、Codex、Dify、自研Web端,大家要共用同一套工具时,MCP的价值是其他方案替代不了的。
选择逻辑很简单:模型层能力够用且不多端共享,用Function Calling;深度绑定单一宿主,用插件协议;多端复用、跨语言、要做统一权限审计,选MCP。这三者不是互斥关系,一个复杂系统里经常叠加使用,比如MCP Server内部继续调用原生Function Calling接口去驱动模型。
3. 连接架构重选的判断与落地路径
3.1 什么时候保留MCP、什么时候换成轻量方案
前面把概念边界理清了,现在聊实操判断维度。我做架构重选时基本看五个维度。
第一,客户端数量。只有单客户端、单场景,MCP优势不明显。三端以上共享工具,收益立刻拉满。
第二,工具数量与更新频率。工具少且稳定,手工维护列表也行。工具几十上百、天天有人加参数,MCP Server把工具注册集中管理,优势非常明显。
第三,跨语言与团队构成。团队后端是Go、前端是TS、还有一个专门写脚本的Python小子,如果每端各写各的函数调用封装,光对齐Schema就要流失大量时间。MCP统一成一份Schema,各端只要有个Client SDK就能接。
第四,审计与权限需求。MCP的工具调用天然走统一入口,日志、黑白名单、配额都方便集中控制。这对安全合规很关键,后面我会专门展开。
第五,维护成本预期。MCP Server本身也要维护,不能只看接入方便。如果一段时间内只有两个人维护、工具量又在爆炸,MCP是给自己的治理成本减负,不是加码。
我自己见过最典型的反面案例:一个团队只有两个工具、一个客户端、用单一模型,硬是上了MCP,结果光调试配置就花了两天。这种场景我真的支持“删掉薄封装”,原生Function Calling半个小时搞定。但反过来的案例更多:内部工具平台接十几个服务、四五个客户端,没有MCP之前每个端一套自定义适配,每换一次模型就要全部返工。MCP在这里不是多一层,是把原先混乱的N层变成统一的一层。
3.2 重选架构时的五步落地法
如果你正在纠结要不要换掉MCP,或者准备把零散连接改成MCP,我的建议按下面五步走。
第一步,盘点集成面。把所有需要给Agent暴露的能力列出来,标出哪些是工具型调用,哪些是上下文型读取,哪些只是模板复用。这一步会直接决定要用MCP的四个能力里的哪些,避免全部堆上去。
第二步,定义Schema边界。给每个工具写清楚参数、返回值、错误码。这里最容易犯的错是把内部接口原样暴露,让Agent拿着复杂系统DSL当参数。更好的做法是设计“面向任务”的窄接口,每个工具只做一件事,参数尽量扁平。
第三步,选择传输层。本地工具直接stdio,线上服务直接Streamable HTTP。早期图方便全用stdio,后面挪服务器时十有八九返工。
第四步,设计鉴权与审计。MCP Server内部要接好服务端认证,每次调用必须能追溯到发起方。工具级权限要能细到“谁能调谁不能调”,别让所有客户端都一样权限。
第五步,做并发和幂等兜底。Agent很爱并发调工具,尤其是并行调用工具的场景,一个Server扛不住就要做限流。写文件、发消息这类动作必须幂等,否则Agent重试一次就重复下单。
这套流程跑下来,你会发现连接架构重选最后大概率不是“删掉MCP”或“保留MCP”的二选一,而是“哪些服务暴露成MCP工具、哪些直接用原生能力、哪些干脆手动直连”的混合方案。
3.3 从“薄封装”到“厚治理”:架构讨论不该停在协议层
关于“删掉薄封装”,我想再提一个自己的理解:如果有问题,不是在“薄”上,而是在“治理薄”上。
MCP给Agent的工具调用提供了一个标准化入口,这是好事,但入口标准化不等于权限、配额、监控、幂等自动就有了。很多实际事故,比如Agent循环调用写坏数据、高并发打垮DB、越权读到其他租户数据,背后不是MCP协议错了,而是没人给这层做治理。
我的经验是把MCP Server当一个真正的后端服务来治理,而不是一个仅供本地调试的小工具:
- 服务端做超时控制,避免长尾工具调用拖垮整体响应
- 对每个工具定义限流阈值,按客户端维度独立计数
- 所有调用请求和返回值统一结构化日志,方便复盘模型“为什么做了这个决策”
- 关键操作设置人工审批,Agent只能发起请求,人确认后才真正执行
- 敏感资源用独立的Resource路径暴露,只授权给有需要的客户端
做到这些之后,“MCP很薄”这种说法基本就不成立了。它本质上已经从“多出来的一层封装”变成“集中治理的一层厚底座”。唱衰MCP的人如果看到的是没有治理的裸协议,那确实该骂;稍微叠点设计和运维,它立刻变成Agent架构里最稳的一段主动脉。
4. 实操实录:从工具接入到流式输出再到调试排坑
4.1 跑通一个最小可用的MCP Server
理论讲太多容易飘,先看一个最小可用的例子。用Python官方SDK写一个本地计算器工具,走stdio传输。这段代码我实际跑过,可以直接拿去做连接验证。
from mcp.server.fastmcp import FastMCP mcp = FastMCP("demo-server") @mcp.tool() def add(a: int, b: int) -> int: """两数相加""" return a + b if __name__ == "__main__": mcp.run(transport="stdio")然后在Claude Desktop这类客户端的配置里,加一行启动命令,就能把工具暴露给模型调用。注意Windows和macOS下路径写法不同,配置里要把python解释器路径写全,这一点是新手的最大坑。
等这个例子跑通,再往Server里叠各种工具就顺畅了。我自己的经验:最小验证时千万别一上来就接生产数据库,先用一个无副作用工具把链路打通,再逐步加真实依赖,否则排查时很难分清是协议问题、SDK问题还是上游接口问题。
4.2 流式输出内容到文件:一次真实的工程改造
有朋友问过“使用MCP工具流式输出内容到文件”怎么实现,这个场景我正好在CherryStudio里折腾过。
需求本身很简单:模型生成内容的同时,由MCP工具把内容增量写入本地文件。问题在于流式调用和一次性返回的差异很大。
先说工具侧。正常的MCP工具调用是模型先生成参数、客户端发请求、工具一次性返回全文。要实现“边生成边写”,就得让工具承担“增量状态累积”的职责。我的做法是在工具函数里实现一个可追加的Buffer,并对文件句柄做全局管理,避免多次调用互相覆盖。
代码形态大致是这样:
import json from pathlib import Path _write_buffer = [] @mcp.tool() def write_output_chunk(text: str, task_id: str) -> dict: """向指定任务的输出文件追加内容,重复调用会持续累加""" global _write_buffer _write_buffer.append(text) current_text = "".join(_write_buffer) Path(f"output_{task_id}.md").write_text(current_text, encoding="utf-8") return {"status": "ok", "total_chars": len(current_text)}关键点有两个:第一,写文件必须走同一个文件路径,否则每次调用单独写一个文件;第二,写入时用文本追加语义,而不是“覆盖写入”,不然Client重试一次整段内容就废了。
客户端侧也有讲究。在CherryStudio这类工具里配置MCP Server后,要让模型理解“分批调用这个工具”,提示词里就要写明:你是要分多次调用write_output_chunk,每次生成一小段内容后立刻写入,而不是一轮生成完再一次写入。否则模型通常还是会选择一次性返回全部内容。
踩过的坑提醒:大批量流式输出时,文件写频繁会导致锁竞争,尤其同一个文件被多个会话同时写时。我后来加了按task_id隔离文件,再把写盘动作做成异步队列,才彻底解决阻塞问题。还有一个隐藏坑是编码,Windows下要显式传encoding="utf-8",否则默认GBK会打出乱码。
4.3 IDE与逆向场景的MCP插件:Codex接Figma、蓝湖,以及IDA/x32dbg的MCP
跟工具链相关的热搜词里,有很大一块是IDE和调试场景。Codex接Figma MCP、接蓝湖MCP,说到底就是让命令行Agent能拿到设计稿的上下文。
Codex接入Figma的MCP时,最常见的翻车点是授权。Figma MCP要走OAuth流程,会弹浏览器、交换授权码、然后回写到本地配置。我遇过的问题包括:回调地址被系统防火墙拦截、scope权限不足导致读不到文件、本地端口被占用导致回调失败。排查思路很简单,先看MCP Server日志里有没有收到回调参数,再检查配置文件里的access token是否过期。
蓝湖MCP的思路类似,但它更偏“设计稿标注信息”的拉取,工具往往只有“读取标注”和“读取页面列表”几个动作,比较窄但很好用。接这类MCP时,我建议先通过Resource方式暴露上下文,而不是当作工具调用,因为模型多数情况下只需要被动读取设计稿信息,没必要主动“调工具”。
再聊一个更有意思的场景:IDA MCP和x32dbg的MCP插件。这是安全分析圈里越来越火的方向。调试器通过MCP Server把自己的状态暴露给Agent,模型可以直接读取寄存器、反汇编结果、栈回溯,甚至下断点。好处是,以前要自己写脚本批量分析反汇编输出,现在可以让Agent直接基于调试器实时数据做推理。
但这里一定要补一句安全提醒:调试器MCP很强大,也极度危险。一旦Agent被投毒或系统被入侵,它能操作的东西远超普通工具。我只在隔离虚拟机里启用调试型MCP,且配置成只读模式,至少不开放断点和内存写入能力。这里没有例外。
4.4 Dify浏览器MCP与Agent安全的边界
浏览器MCP是一个转变Agent能力边界的工具。它让模型能直接驱动浏览器,打开网页、点击按钮、填写表单、抓取页面数据。结合Dify这类低代码Agent平台,可以实现“Agent自动填报系统、自动抓取页面结果、自动做巡检”的完整流程。
实际落地时,我的经验是把浏览器MCP的动作控制在一个很窄的范围内。每个Agent绑定一个专门的配置文件,指定它可以访问的域名白名单,比如只允许操作内部测试站点。对外的生产环境一律不允许Agent直接点击,要做成套“只读巡查+人工确认”模式。
还要关注两个坑:一个是浏览器MCP操作太快,页面元素还没渲染完就提交,容易把表单填错。解决办法是在动作之间加固定等待,或者工具里内置“元素可见性检测”。另一个是并发窗口,多个Agent同时操作同一浏览器会话会互相干扰,我一般给每个任务起独立的浏览器上下文,用完销毁。
Agent安全不是MCP独有的问题,但MCP把所有工具调用聚合成了一层清晰接口,反而方便做身份认证、操作审计、人审回调。真正危险的做法是把MCP Server当透明隧道直接用,不做任何权限拦截。把不该开放的API暴露给Agent,量再大也撑不住。反过来,在Server入口统一加“允许/拒绝/需审批”三级策略,Agent越权问题就会好控制很多。
5. 常见问题与排查技巧速查
5.1 高频故障:Codex找不到MCP、授权失效、工具不显示
把我在社区和实际项目中见到的典型问题整理成一张速查表,排查时按图索骥即可。
| 问题现象 | 可能原因 | 排查步骤 |
|---|---|---|
| Codex提示找不到MCP Server | 配置文件路径未生效、Server进程启动失败、端口被占用 | 用npx或python手动启动Server看报错;检查客户端加载的是不是你改的那份配置;确认stdio模式的启动命令完整 |
| Figma/蓝湖MCP授权失败 | OAuth回调地址被拦截、scope权限不足、access token过期 | 查看MCP Server日志是否有回调参数;检查OAuth应用配置里的重定向地址;重新授权前先刷新token |
| MCP工具在客户端工具列表里不显示 | Schema解析失败、工具函数未注册、SDK版本过旧 | 用MCP inspector单独连接Server验证工具列表;看返回值是否合法JSON;升级SDK到最新版 |
| 流式输出到文件后内容乱码 | 文件编码不是UTF-8、Windows默认GBK | 写文件时显式传encoding="utf-8";检查客户端输入流是否也按UTF-8解析 |
| 同一个文件被多个会话覆盖 | 没有按会话/任务隔离文件路径 | 文件名插入task_id或session_id;写路径权限控制好,别共享 |
| MCP Server偶发断连 | 长连接超时、心跳没配、反推机制缺失 | 使用Streamable HTTP时配置心跳;进程本身做重启守护 |
| 多个客户端使用同一MCP Server时权限越界 | 客户端等级没有做身份区分 | 在Server入口对客户端来源做认证,不用只看transport是否通 |
这些问题的共性是“链路没透过”。我强烈建议先配上MCP Inspector这一类的调试工具,能看到完整的请求/响应消息流,比在客户端里瞎猜高效得多。
5.2 Agent并发怎么扛:MCP Server只是协议适配,不是业务执行者
“AI Agent怎么扛并发”这个问题几乎每周都有人问。核心答案:MCP Server本身不应该扛并发,它只是一个协议适配层。
现在很多人的做法是,把业务逻辑直接写进MCP工具函数里,一个Server进程内同步计算完再返回。小流量可以,但Agent喜欢并行调多个工具,一旦并发量上来,Server进程就成了瓶颈。
我的实际改造方案:
一是把工具函数变成“提交任务”和“查询结果”两个独立工具。Agent先调用submit_task拿到一个任务ID,再轮询get_task_result获取结果。Server里压入消息队列,后端Worker慢慢消费,本质上把同步调用变成了异步。二是所有写操作都做幂等,比如写入日志时带request_id,同一请求重试不影响数据。三是在服务端做限流,按客户端维度并发控制,超额直接返回“请稍后再试”,不要无限排队。
Alan这层改完之后,MCP Server就从瓶颈变成了稳定入口。我见过最夸张的场景是一个团队用MCP Server接了十几个浏览器伪装头,同时跑几十个抓取任务,Server只有4个副本,照样稳得很。关键就在于后端执行器和协议适配彻底分离。
5.3 调试与避坑心得:日志先行,Schema严格校验
最后分享几条我用血泪换来的调试经验。
第一,日志必须在最初就铺好,别等到问题发生再补。每次工具调用记录:哪个客户端、传了什么参数、返回值是什么、耗时多少。Agent推理是个黑盒,你只有靠调用侧日志才能复原它当时的行动路径。
第二,工具Schema做严格校验。不校验的话,模型一旦传错类型,工具侧拿到NaN、None、异常对象,行为就会难以预测。我一般用Pydantic这类库的schema自动验证,再把错误类型明确抛回给模型,让它知道要修正参数而不是硬着头皮重试。
第三,尽量让每个工具保持无状态或低状态。MCP Server重启后,之前挂在Buffer里的数据全都丢了。凡是需要存的数据,尽早落盘或转给后端存储。我在早期写流式输出工具时,Buffer全在内存,Server一重启,所有输出全得重来。
第四,升级MCP规范时谨慎。Streamable HTTP是好事,但老客户端可能还在用SSE,服务端平滑兼容比一锤子切换更稳。配置里做好版本协商,至少同事的旧工具不会一夜之间全挂。
第五,生产环境的MCP Server全部走独立进程管理,比如systemd或容器调度,配上重启策略。stdio模式下它真的会随客户端退出而退出,线上服务不能用这种方式。
写在最后的个人体会
我从MCP早期就开始接各种内部工具,也一度把它吹成“Agent连接层的万能钥匙”,后来被现实教育过几次,才慢慢找到合理的姿态。现在我的判断很简单:MCP不会因为一句“删掉薄封装”就退出历史舞台,真正应该被删掉的,是那种“不管场景对不对,先套一个协议再说”的偷懒思维。它的价值从来不在厚薄,而在它能把多端、多语言、多工具的连接成本压缩到可以维护的程度。如果你正在被“MCP已死”的讨论带得摇摆,我的建议是拿自己的真实场景做一次对照测试:把MCP接入时间和直接用原生Function Calling的时间比一比,把后续再接入一个新客户端的时间也记录下来。数据会告诉你答案。另外再分享一个我最终踩过坑后固定下来的习惯:所有MCP Server上线前,先跑一遍无副作用的冒烟用例,确认工具列表能完整列出、参数校验能命中、错误能正确回传,再放Agent进去。这个习惯帮我挡掉了后面至少三分之二的线上故障,希望对你也有用。