
如果你最近下载过任何一款AI编程工具大概率会被几个长得差不多的缩写绕晕MCP、ACP、LSP。我把它们同时装进一个IDE里折腾了一圈之后一度以为这三者又是什么三选一的“标准大战”——就像当年VHS和Betamax争录像带格式一样。后来把三方的协议日志同时打开跟踪了一轮真实任务才发现这个“三足鼎立”完全是我脑补出来的。它们不仅不互斥反而像三根接力棒在一套AI应用里各跑各的赛段。这篇文章想把这三根接力棒到底怎么传的讲清楚顺便聊聊各自容易踩的坑。如果你正在用Claude Code、Codex这类Agent工具或者你在给团队搭AI辅助开发环境又或者你只是想搞明白“MCP是什么”“LSP在AI编程里有什么用”“ACP为什么要存在”这篇应该能帮你把这些碎片拼起来。1. 三个高频缩写三件完全不同的事先说结论MCP、ACP、LSP虽然都叫Protocol但它们解决的是三个完全不同层面的通信问题。我在很多讨论帖里看到有人问“MCP会不会取代LSP”或者“ACP是不是MCP的升级版”说实话这类问题本身就问错了方向。就好比问“USB接口会不会取代方向盘”——这俩根本不解决同一个问题。1.1 一张表看明白三者的定位差异协议全称提出方与时间核心问题传输/消息格式典型场景LSPLanguage Server ProtocolMicrosoft2016年编辑器与语言智能如何通信JSON-RPC 2.0通常走stdio代码补全、跳转、诊断、悬停提示MCPModel Context ProtocolAnthropic2024年11月开源大模型与外部工具/数据源如何互通JSON-RPC 2.0stdio或Streamable HTTPAI调用数据库、文件、API、Figma等ACPAgent Client ProtocolSourcegraph与Block发起2025年兴起客户端与AI Agent之间如何完成会话控制与事件交互JSON-RPC 2.0可走stdio/网络传输IDE连接Codex CLI、Claude Code这类Agent从这个表就能看出来它们根本不是同一次比赛里的对手。LSP是“编辑器—语言”的接口MCP是“模型—工具/数据”的接口ACP是“客户端—Agent”的接口。三者的“协议”都是形容词但修的对象完全不同。1.2 一个容易令人混淆的原因它们都在处理AI应用中的“上下文”为什么大家会把三者放在一起比较我琢磨了一下因为它们都在回答同一个大问题AI程序需要的信息/动作到底怎么在进程之间传递LSP传递的是代码语义信息这个符号在哪里定义、这段代码有没有语法错误、当前函数有哪些引用。MCP传递的是模型与外部世界的调用模型需要查订单表就通过MCP去调用数据库工具拿回查询结果。ACP传递的是用户与Agent之间的任务信息用户发来一句话Agent在后台思考并执行然后把思考进度、工具调用请求、最终结果回传给前端。理解了这个区别你就会明白为什么我强烈反对把它们看成替代关系。真正合理的视角是它们各自处于AI应用协议栈的不同层位相互之间还有协作接口。接下来逐个拆开看。2. LSP八年前终结编辑器插件乱局如今成了AI读懂代码的“视觉皮层”LSP可能是三者中最“老古董”的一个但在AI编程时代它的价值反而被重新放大了一轮。不夸张地说现在你用的AI补全、AI问答工具多半在后台偷偷踩在LSP的肩膀上。2.1 2016年之前每个编辑器都要为每种语言写N套插件回到2016年之前做过编辑器插件的人应该都懂那种痛苦。VS Code要支持Python得写一套Python插件Vim要支持Python又得写一套Python插件Emacs、Atom、Sublime各自再来一套。对语言作者来说更痛苦他发布一门新语言光是给主流编辑器各写一遍语法高亮、补全、诊断的适配就能耗掉一个团队半个月。LSP的破局思路很有意思把“语言能力”单独抽成一个进程——language server编辑器只负责当好客户端。两者约定一套统一的JSON-RPC 2.0消息从此语言作者只需要写一次server所有遵循LSP的编辑器都能直接用。这等于把所有编辑器拉进了同一个“通用插座”。2.2 LSP的一次握手initialize到shutdown的生命周期LSP的生命周期控制得相当严格核心流程可以简单理解为编辑器启动一个语言服务器进程通常通过stdio连接。编辑器发送initialize请求跟服务器做能力协商——服务器告诉编辑器“我支持补全、诊断、跳转但我不支持重命名。”双向确认之后编辑器发initialized通知表示“可以开始干活了”。用户打开文件时编辑器发textDocument/didOpen编辑时发textDocument/didChange。编辑器按需发textDocument/completion、textDocument/definition、textDocument/references这类请求。结束阶段编辑器发shutdown和exit服务器退出。一个典型的initialize请求长这样{ jsonrpc: 2.0, id: 0, method: initialize, params: { processId: 12345, rootUri: file:///home/user/my-project, capabilities: {} } }服务器返回它支持的能力范围比如textDocumentSync、completionProvider、definitionProvider等等。这些消息全是JSON-RPC 2.0格式统一边界清晰。2.3 AI编程时代LSP为什么反而更重要了很多人以为AI编程工具是“大模型直接看代码”其实不完全对。LLM直接吃纯文本有个致命问题它分不清一个标识符到底是本地变量、类成员还是系统API它也不知道某个符号在整个工程里的引用关系。如果只把文件原文塞给模型它经常把同名变量搞混。这时候LSP的价值就体现出来了。现在的AI代码补全和AI问答工具很多会作为LSP客户端接入语言服务器通过textDocument/references拿到“这个函数的所有调用方”通过textDocument/definition拿到“这个变量在哪里定义”通过textDocument/diagnostic拿到“当前文件的编译错误”。这些语义级上下文被拼进prompt之后模型的理解准确率会提升一个档次。我实测过对比不给LSP上下文让AI直接解释一个跨文件的函数调用链它经常一本正经地编出一个不存在的调用关系给了LSP返回的符号表、引用集合之后解释基本能对应上真实代码。可以这么说LSP在AI时代变成了“AI读懂代码的视觉皮层”——模型自己看不见代码结构是LSP替它看见了。2.4 LSP的局限它是为“人看IDE”设计的不是为“Agent跑任务”设计的但LSP不是万能的。它返回的消息是给编辑器UI渲染用的——组件hover内容、跳转目标位置、诊断列表。AI Agent想要的是“可以作为一条指令执行的结构化动作”比如“把文件里所有排序接口的入参校验逻辑统一重写”。LSP给不了这个它只是一个语义管道不负责任务编排。另外语言服务器吃资源是个老问题。rust-analyzer索引一个大型monorepo内存经常几个GB起步TypeScript语言服务器在超大前端工程里也容易卡。这个我放到后面“踩坑”部分专门说这里先记住一个观点LSP是必要的底层设施但它是“工具”不是“统治者”。3. MCP把大模型变成一台可以外接设备的主机如果说LSP是八年前埋下的基础设施那MCP就是过去一年里AI应用生态最大的变量。从热度和生态上看MCP几乎是火箭式增长甚至一度让人觉得“不会MCP就不配叫AI工具”。3.1 MCP出现之前每接一个数据源都要写一套胶水代码两年前想让大模型查一次数据库是个什么体验你至少得经历这些环节选一个模型后端拿它的function calling接口写工具定义把SQL语句作为参数传入然后再写回调处理返回结果。换一个模型平台这套定义方式可能全变换一个数据源又得重写一套。你写的不是“业务代码”而是无穷无尽的适配层。Anthropic在2024年11月开源MCP目标非常明确让模型和外部工具/数据源之间的连接变成标准化的“插座”。这个思路被很多人称作“AI应用的USB-C接口”。有了MCP之后工具提供方只需要写一次MCP Server任何支持MCP的客户端都可以调用它而不是为每个模型单独做适配。3.2 MCP的架构与三个核心原语MCP的架构分三层Host宿主应用比如Claude Desktop、一个IDE插件、Client宿主内部维护的MCP客户端连接、Server独立的工具/数据服务进程。在协议内容上MCP定义了三个核心原语我分别打个比方Tools这是模型可以主动“调用”的行动。好比给模型装了一双手它能按按钮、拉杆、拿东西。典型例子是执行SQL、读文件、调API。Resources这是模型可以“读取”的数据。好比给模型开了几扇窗户让它能看到数据库里的记录、配置文件内容、外部文档。Prompts这是可复用的提示词模板。好比给用户准备了一套标准化表单用户勾选几个选项就能生成一段结构化的指令。其中Tools是大家用得最多、也最容易理解的。下面是一个简化的MCP请求/响应演示“AI调用数据库查询工具”这个动作// 客户端 → MCP Server { jsonrpc: 2.0, id: 1, method: tools/call, params: { name: query_orders, arguments: { sql: SELECT count(*) FROM orders WHERE statusfailed AND created_at now() - interval 7 days } } } // MCP Server → 客户端 { jsonrpc: 2.0, id: 1, result: { content: [ { type: text, text: {\count\: 137} } ] } }这个流程里模型不需要知道你的数据库密码不需要了解你的内网拓扑它只是通过MCP这个“公用车钥匙”向Server发出了一个经过授权的请求。3.3 MCP的传输方式stdio和Streamable HTTPMCP早期主推的是stdio传输也就是客户端直接启动一个本地Server进程通过标准输入输出进行JSON-RPC通信。这种方式好处是安全、隔离、简单尤其适合本地的文件操作、命令行工具类MCP Server。你现在在Claude Desktop或各种IDE插件里配置一个本地MCP Server绝大多数走的就是stdio。后来随着云端Agent和远程服务增多MCP支持了Streamable HTTP传输Server部署成一个HTTP端点客户端通过网络请求访问。配置MCP Server时填“stdio类型”需要给出启动命令填“http类型”需要给出URL和鉴权信息这两者千万别搞混——我在后面踩坑章节会详细说。3.4 为什么MCP能迅速被Figma、数据库、蓝湖等接走MCP生态能爆核心原因是它太“省事”了。对工具方来说我只要写一个标准的MCP Server所有支持MCP的客户端都能调用我不用为OpenAI写一套、为Anthropic写另一套。对模型应用方来说我只要实现MCP Client协议就能接上所有生态里的工具不用每个工具定制开发。Figma MCP就是典型的例子设计稿的结构、图层、样式都通过MCP暴露给大模型AI就能直接分析设计稿并生成前端代码。蓝湖、各类数据库MCP Server也纷纷跟进。你甚至能看到很多文章在教“Java将REST接口发布为MCP”本质上就是给老服务套一层MCP外壳让它能被AI调用。很多人问“MCP怎么被调用的”其实可以简单理解成模型生成一个符合MCP协议的tools/call请求发到MCP ClientClient转发给对应的MCP ServerServer执行完毕后把结果原路返回。模型本身不需要关心Server内部的实现细节它只需要知道“有一个名叫query_orders的工具参数是SQL字符串”。3.5 MCP和function calling的区别这里顺便把另一个高频问题说透MCP不是function calling的替代品两者根本不在一个抽象层级。Function calling是模型API内部的一个特性它让模型学会在回复中夹带“工具调用标记”由应用层去执行。它解决的只是“模型怎么把调用意图表达出来”这一小段。MCP解决的是“工具怎么被描述、怎么被发现、怎么被调用、怎么被授权”这一整条链路。你可以把function calling看成是一个具体实现把MCP看成是一套完整的“工具协议生态”。4. ACP给Agent装一套“方向盘与仪表盘”如果说MCP让模型“长了手”那ACP就是让Agent“有了驾驶舱”。ACP目前名气不如MCP大但如果你用IDE去连接Codex CLI或Claude Code这类Agent你其实已经间接在用它的逻辑了。4.1 ACP要解决什么问题Agent CLI进IDE的适配之痛2025年Agent命令行工具开始爆发Codex CLI、Claude Code、Gemini CLI……它们能在终端里自主完成读文件、改代码、跑测试、提交PR这一串动作。但问题也来了用户并不总想待在终端里。如果我想在VS Code里选中一段代码让Claude Code去分析并修改怎么办最原始的做法是为每个Agent CLI写一套IDE插件适配器。Codex接入VS Code写一套Claude Code接入VS Code再写一套Codex接入JetBrains又得写一套。这跟LSP出现前编辑器插件各自为政的混乱几乎一模一样。ACP的目的就是把客户端应用IDE、Web UI、移动端和Agent之间的通信方式标准化。ACP的几位关键推手是Sourcegraph和Block原Square随后得到了包括OpenAI在内的生态支持。它被设计成一套基于JSON-RPC 2.0的双向协议一个ACP会话里可以承载Agent的完整生命周期从初始化、创建会话、发送用户提示到Agent返回状态事件、发起工具调用请求、客户端执行并把结果回传。4.2 一次ACP会话的简化消息流下面这个流程我做了简化不同实现会有方法名差异但不影响理解整体结构客户端启动Agent进程通过ACP的initialize握手协商双方能力。客户端发送session/newAgent返回一个唯一的sessionId。这一步相当于“开了一条独立的对话车道”。客户端发送session/prompt把用户选中的代码、上下文和指令交给Agent。Agent开始工作后持续返回事件流包括状态更新“正在搜索定义”、消息内容、以及工具调用请求。当Agent想修改文件或执行命令时它不直接做而是通过ACP向客户端发送一个“工具调用请求”。这一步是整个ACP的核心设计——真正的环境操作权保留在客户端。客户端弹窗让用户确认用户同意后客户端执行真正的写文件/跑命令动作再把结果通过ACP回传给Agent。任务完成后可以继续发session/prompt或者发session/close回收会话。换句话说ACP的“Agent”本身是很克制的它规划任务、生成决策但实际动手必须让客户端来。这么做的好处是安全可控坏处是如果你直接用一个纯CLI去连Agent不经过任何客户端适配那ACP根本没用——你缺了一个“驾驶舱”。4.3 “failed to initialize acp session”这类报错背后是谁在作妖很多人在IDE里配置Agent时会碰到形如failed to initialize acp session. error: internal error: already initialize这种报错我排查过好几次问题几乎都出在会话生命周期的管理上。ACP的session/new跟LSP的initialize不一样它不是一次性握手死了就完事而是在一个长连接里可以创建多个会话。常见踩坑原因有几个客户端代码在每次发消息前都调用了一次初始化逻辑结果第二次初始化时发现“你已经有session了”于是报already initialize。某个插件在IDE窗口加载和激活时被调用了多次导致同一个transport上重复new session。Agent进程其实已经异常退出过但客户端的会话缓存没清导致恢复连接时拿着旧sessionId又去初始化撞上了“already initialize”的内部状态。我的经验是先把transport和session分开看待。Transport是长连接进程活着就一直复用Session是“一次对话任务”的容器复用一个session去继续对话是合理的但没有必要反复初始化。代码里如果要写Agent连接层应该保证初始化逻辑只执行一次后续发prompt都往同一个session里塞。4.4 ACP与LSP、MCP的分工带状态的LSP还是带方向盘的外设总线ACP经常被拿来和LSP类比因为它俩确实像都是“客户端—服务端”架构都用JSON-RPC 2.0都有清晰的协议边界。但两者有个本质差异。LSP处理的是无状态的查询你问我一个符号在哪里定义我回答你位置这中间没有“改代码”的动作。ACP处理的是有状态的持续任务你让我修复一个bug我需要读文件、改文件、跑测试、看到测试结果、再迭代修改。这个循环里有状态、有上下文、有多次工具调用的反馈。跟MCP的区别也很明显。MCP的“工具调用”是模型发起的、面向外部系统的一次性数据/动作请求它不管谁在驾驶全局ACP的“工具调用”是Agent把具体的环境操作请求提升到客户端让客户端负责执行和授权。放一起看ACP更像“方向盘与仪表盘”MCP更像“USB-C集线器”LSP则像“后视镜和车窗”。5. 一条真实链路一次AI改bug任务里三条协议的分工纸上谈兵没什么意思。我拿一个我曾经反复配置过的真实场景完整走一遍三条协议怎么配合。场景是这样我在IDE里接了一个Agent类型的编程助手这个Agent能自主规划并修改代码。Agent侧配置了一个MCP Server用来查询团队业务数据库。IDE本身还挂着语言服务器比如Pyright或rust-analyzer。用户选中一个函数然后输入指令“找出get_order()的所有调用方顺便查一下最近7天失败订单数量最后把结论追加到运行日志里。”整个过程可以拆成这样IDE通过ACP的session/prompt把选中的代码、文件路径、用户指令发给Agent进程。Agent内部开始规划它第一步要搞清楚get_order()到底被哪些地方调用了。它不能靠肉眼扫它向IDE的LSP客户端发起一个textDocument/references请求。LSP语言服务器在后台建立代码索引返回所有引用位置列表。Agent拿到这些位置之后把它们作为上下文继续推理——它终于知道改动会影响哪些地方。Agent发现还需要查数据库于是通过MCP Client调用配置好的“订单查询”MCP Server发送tools/call请求带上SQL参数。数据库MCP Server执行查询把失败订单数量返回给Agent。Agent综合代码引用和数据库结果生成总结并通过ACP事件流把“写运行日志”的工具请求返回给IDE客户端。IDE弹出审批框用户点击允许后IDE真正执行文件追加操作再把结果通过ACP回传给AgentAgent收尾结束。是不是发现这三条协议其实互不打扰但缺了谁都会出事如果LSP没配好Agent会拿不全引用关系它修改get_order()调用方时漏改一两个地方bug照样在原处。如果MCP Server超时Agent拿不到订单数据它可能会在日志里写一段“看起来很像真的”的猜测数字。如果ACP会话断开最直观的体验是Agent实际还在后台跑但IDE界面上没有任何响应像卡死了一样。所以我的选型建议其实很简单想让编辑器里的AI工具“看懂代码”先检查LSP接口通不通想让模型拿到外部数据或调用外部系统去配MCP想让Agent能被任意前端接入、被好好管理生命周期再考虑ACP。三者不存在互相替代的关系只存在你需不需要的问题。6. 协议栈里的坑session初始化失败、server超时、LSP吃内存协议这块我踩过的坑不算少。下面挑三类最有代表性的问题给出我自己的排查路径不一定全但能帮你在踩坑时省点时间。6.1 MCP Server超时或“连接不上”症状一般是AI在回答时提到“工具调用失败”或者面板里直接报MCP Server connection closed。排查步骤我会从三层递进传输层如果你配置的是stdio确认启动命令里的路径是绝对的虚拟环境路径别写错工作目录也要配对。Windows下尤其注意Python环境路径。如果你配置的是Streamable HTTP确认URL没漏掉版本前缀例如/mcp这类路径。协议层确认传输类型没选反。stdio对应的是本地进程http对应的是远程端点。见过很多人把本地MCP Server填成http://localhost然后请求一直pending其实类型选错的话请求根本发不到对的地方。业务层MCP Server进程本身有没有崩溃最简单的方式是用MCP Inspector这类调试工具直接手动发起tools/list如果手动调用都失败那就是Server自身的问题跟AI客户端无关。我遇到过的最高频原因是stdio配置里没有写--stdio参数导致Server以某种待机模式启动后既不接受输入也不输出客户端等半天超时。6.2 ACP session重复初始化前面提到的failed to initialize acp session...already initialize我给出一个可复现的排查链路打开Agent进程的日志看是哪个模块触发了第二次初始化。检查客户端代码里session/new的调用点是否在“每次发送消息”的执行路径上。如果是把它挪到连接建立之后只执行一次。检查IDE插件或客户端工具是否在“窗口加载”和“命令面板激活”两个时机都执行了一遍初始化。这种情况常见于插件开发者没有做幂等保护。如果Agent进程本身卡在异常状态重启进程再试别想着复用旧session。这类问题的根源通常是“状态管理不严谨”。LSP时代大家习惯了无状态查询到了ACP这种有状态协议很多人还按老思路在每次交互前初始化一遍不出错才怪。6.3 LSP服务器内存吃满、启动慢用rust-analyzer或者TypeScript语言服务器的人应该都见过内存飙到几个GB的场面。解决方案不一定是一味加内存我常用的几个有效手段缩小工作区LSP的workspace越窄索引越快。如果项目是monorepo试试只加载跟你当前代码相关的子工程。配置语言服务器的文件排除规则把vendor、node_modules、target这类目录排除在索引范围外。按需启动改成平时不启动语言服务器等AI工具或用户主动需要语义信息时才启动。这样一来很多“后台吃内存”的情况就消失了。在AI编程的场景里LSP吃内存的痛点会被放大因为AI工具可能会在后台频繁请求语义上下文。我的建议是给语言服务器单独设一个较高的资源上限同时把不相关的排除项配好别让它在无关目录上白白建索引。6.4 通用排查法先分传输层、再查协议层、最后看业务层这三类问题的排查思路其实是通用的。我建议你在面对任何“协议相关”的问题时都按下面的三层清单过一遍层级排查问题举例常用手段传输层进程起来了没有端口/管道通不通进程有没有正常握手看进程列表、看日志、用curl/Inspector手动连接协议层消息格式对不对JSON-RPC的id是否匹配请求方法名是否存在抓协议日志逐条对照规范业务层Server/Agent内部业务逻辑有没有异常权限够不够数据源连通吗查业务日志手动执行一次同样操作大方向上协议对接的问题九成出在传输层和协议层业务层反而没那么容易出问题。因为MCP、ACP、LSP这类协议的消息格式基本都是JSON-RPC 2.0结构不难难的是“哪个进程在维护那个连接”“生命周期谁在管”“路径有没有写对”。7. 三足鼎立会变成一统天下吗开发者当下怎么选写到最后这部分很多朋友关心的是这三种协议会不会统一成一种现在学哪个最划算我的判断是短期不会出现“大一统”协议替代三者。原因不复杂——三者绑定的上下文完全不同硬塞到一起只会让协议变得无比臃肿。LSP如果你的目标是做一款编辑器插件那LSP直接给AI提供语义上下文MCP如果你是给AI应用接数据源和工具MCP是一等公民ACP如果你想把Agent接入不同的前端并且需要完善的会话管理那值得花时间深入研究。7.3 标准格局与生态现状老邻居、新基建、新玩家从标准化进程来看LSP已经稳定多年版本迭代虽然不快但生态相当扎实所有主流编辑器、语言服务器都按它来。MCP在2024年底开源后迅速得到OpenAI、Google等官方生态支持2025年基本坐实了“模型—工具”层的实际标准。ACP起步最晚但方向明确——它瞄准的是Agent基金会与可移植性的空白已经在Codex CLI等实际产品中出现了落地案例。这三者就像是城市交通里的“老路网”、“地下管道”和“自动驾驶调度系统”老路网LSP为所有车辆提供基础通行能力地下管道MCP为城市供能送水自动驾驶调度系统ACP则让车辆能自主决策、和指挥中心通信。三条系统各自进化但谁也取代不了谁。我个人的体会是协议这种东西真正让人放心的不是“标准”这个词而是“调试入口”。MCP你可以用Inspector手动试ACP你可以用日志跟踪session生命周期LSP你可以开trace看每次请求耗时。这三个“入口”比背规范更有用。所以如果你现在有点被这些缩写搞晕我的建议很简单不要急着读全规范先在自己最常用的AI工具里打开它的协议日志窗口跑一个任务看看MCP、ACP、LSP各发了几条消息。那个画面一亮起来你瞬间就懂了这些协议到底是什么。