先说个现象。2024 年底MCPModel Context Protocol突然火遍整个 AI 开发者圈子GitHub 上几乎每天都有新的 MCP Server 冒出来到了 2025 年大家又发现 LSPLanguage Server Protocol这种已经在编辑器里服役近十年的老协议反而成了 AI 编程工具绕不开的底座而 ACPAgent Client Protocol这个名字随着 Claude Code 的更新逐步走进视野把“AI 代理在应用里到底怎么跑”这个之前没人统一回答的问题正式摆上了台面。这篇文章我想从一个每天都在跟协议打交道的开发者视角把 MCP、ACP、LSP 这三者的分工边界讲清楚它们各自解决什么问题、底层机制有什么不同、在真实调用链里怎么协作、以及落地选型时应该怎么判断。不堆概念尽量说人话最后附带我实际踩过的一些坑。1. 三种协议各自的“身位”解决的是哪一层问题要搞清楚三个协议之间的关系第一步不是背定义而是先看它们各自站在哪一层。我经常用一个餐厅的类比MCP 解决的是“后厨能从外部采购什么食材”LSP 解决的是“菜品的加工过程是否标准”ACP 解决的是“前厅和后厨、服务员和顾客之间怎么交接”。听着抽象下面一个个拆开讲。1.1 MCP模型与外部世界之间的“万能插座”MCP 是 Anthropic 在 2024 年底开源的协议目标非常直接让大语言模型用统一的方式调用外部工具、读取外部数据。在 MCP 出现之前你想让模型查数据库、发 HTTP 请求、操作文件只能写一大堆胶水代码把每个工具手动封装成 function calling 的格式。换一个模型厂商格式可能就变了代码重写一遍。MCP 把这件事标准化成了三层结构宿主应用Host比如 Claude Desktop 或 Cursor、协议客户端Client宿主内置、协议服务器Server外部能力的提供者。模型在 Host 里发起调用Host 通过 Client 把请求翻译成 JSON-RPC 消息发给对应的 MCP Server拿回结果后再交给模型整合成自然语言回复。这套设计最大的价值是“插拔”。今天你的应用接的是一个天气查询 Server明天换成公司内部的订单查询 Server只要两边协议实现正确模型层和业务层都不用改。这也是社区里把 MCP 类比成“AI 界的 USB-C”的原因——接口统一设备随便接。MCP 不止支持工具调用Tools还定义了资源Resources类似只读文件、提示Prompts可复用的指令模板和服务端采样Sampling服务端反过来向模型请求生成结果这几个原语基本覆盖了 AI 应用的数据交互场景。1.2 LSP一个老协议凭什么成为 AI 编程的地基LSP 是微软在 2016 年随 VS Code 推出的解决的是“编辑器怎么读懂代码”的问题。在这之前每种语言都要给每个编辑器单独写插件语言生态和编辑器生态互相绑定LSP 把语言分析能力抽出来放进独立进程编辑器只负责发请求、收结果。于是任何支持 LSP 的编辑器都能立刻获得某种语言的补全、跳转、格式化、诊断能力不用重复开发。LSP 现在听上去“老”但恰恰是这种成熟稳定让它成了 AI 编程工具的地基。AI 编程助手在编辑器里看到光标位置、读取符号定义、拿到当前文件的诊断信息底层绝大多数走的是 LSP。你在 Cursor、VS Code、Zed 里让 AI 补全代码时模型能“看到”你正在写的函数签名和上下文就是 LSP 在背后默默提供结构信息。不少刚接触 AI 编程的人误以为“AI 是直接读源码”其实不是。AI 编辑器通常是把 LSP 提供的符号表、语义信息、诊断结果连同当前文件内容一起拼进上下文窗口模型再基于这些素材做判断。换句话说LSP 是 AI 编程助手“眼睛”的信息来源之一而且是最稳定可靠的那一路。1.3 ACP代理与运行环境之间的“通信契约”ACP 是三者里最年轻、也最不稳定的一个。全称 Agent Client Protocol近几年在 Claude Code 的更新里被反复提及核心要解决的问题是当一个 AI 代理不是孤零零跑在命令行而是嵌在某个宿主应用IDE 插件、网页聊天窗、企业应用里时代理和宿主之间到底怎么通信。以前这个问题没人在意因为早期代理就是“一个循环调用模型直到任务完成”输出用完就结束。现在代理应用复杂多了代理要流式输出思考过程和中间工具调用结果要停下来等用户确认某个危险操作要在运行中被暂停、恢复、取消甚至要支持多个子代理协同工作。这些都不是“模型自己跑自己的”能解决的需要一套宿主和代理共同遵守的协议来约定。我的理解是如果说 MCP 是模型与工具之间的协议那么 ACP 就是代理与客户端/宿主之间的协议。它约定的是会话建立、消息流式传输、工具调用审批、代理状态同步这些“运行时编排”环节。因为还处于快速迭代期规范细节变得很快如果你发现某些接口定义和我描述的不一致完全正常以官方最新文档为准。2. 协议机制拆解传输、数据模型与生命周期概念说完了看技术层面。三个协议虽然都基于 JSON-RPC 消息格式但传输选择、数据模型、生命周期管理差别很大这些细节直接决定了它们各自适合什么场景。2.1 传输层的选择逻辑stdio、HTTP 与进程间通信LSP 从一开始就走“编辑器主进程 语言服务器子进程”的架构最常用的传输方式是 stdio。编辑器把 JSON-RPC 消息写到子进程的标准输入从标准输出读回结果简单、隔离、没有端口冲突非常适合本地开发。后来 LSP 也支持了基于 TCP 的传输但实际用得不多。MCP 同时提供 stdio 和 Streamable HTTP 两类传输。stdio 方案和 LSP 思路一致适合本地运行比如在 Claude Desktop 或本地终端里连接一个 MCP ServerHTTP 方案适合远程部署比如把内部系统的数据能力通过 HTTP 暴露给远端的大模型客户端。这个双轨设计让 MCP 既能服务本地效率工具也能进入企业级集成场景。ACP 的设计更偏向“代理嵌入应用”的场景通信双方天然跨进程更强调基于流式通道的双向通信。它不像 LSP 那样有个“编辑器”作为天然宿主也不像 MCP 那样主要靠 stdio 把 Server 挂在本机而是更像一个会话协议一开始就要把连接、鉴权、消息分帧、断开重连这些网络通信才有的问题都考虑进去。这也是它看着复杂的原因——它要托管的场景本身就复杂。举个例子。你在终端里跑一个 AI 代理背后其实有几个进程在协作CLI 主体、模型 API 客户端、工具调用器。ACP 要管的就是这些进程之间如何“对话”模型推理时如何让 CLI 去调用一个工具工具结果回来时如何流式推给用户用户中断时如何让代理优雅退出。没有这套约定每个应用都得自己实现一遍而且互不兼容。2.2 数据模型设计三家怎么定义“一条消息”LSP 的数据模型是编辑器交互事件的集合。它按方法划分能力textDocument/completion 表示请求补全textDocument/hover 表示请求悬停文档initialize 表示建立连接。核心概念是“文档”和“位置”几乎所有方法都围绕这两个概念展开。这和 LSP 的定位完全匹配——它就是为代码编辑而生的。MCP 的数据模型归纳成四个原语Tools、Resources、Prompts、Sampling。Tools 是模型可调用的动作入参用 JSON Schema 描述Resources 是模型可读的上下文数据类似文件系统里的只读文件Prompts 是可复用、可预置的提示词模板Sampling 允许 Server 请求模型生成内容形成一个反向通道。这四个原语组合起来几乎能覆盖 AI 应用的所有数据交互场景。MCP 能快速火起来很大程度上就是因为它把“模型侧和工具侧本来就得这么通信”这件事标准化了。ACP 的数据模型坦白说还没有 MCP 那么家喻户晓但从定位能推断它一定会重点定义“会话”“消息”“工具调用审批”“代理状态”这几类东西。MCP 的消息偏向“一次调用、一个结果”的短事务而 ACP 的消息更像“持续对话中的一帧”——一条消息可能包含文本片段、工具调用请求、工具调用结果、状态变更事件等多种内容消息之间还有时序关系。这个差异很像 HTTP 和 WebSocket 的差异一个偏请求-响应一个偏长连接流式。2.3 生命周期管理从握手到断线重连LSP 的生命周期最成熟也最简单启动语言服务器、发 initialize 握手、换发 initialized 通知、正常处理文档事件、关闭时发 shutdown/exit。这套流程被所有主流编辑器实现过无数次稳定得几乎没人再讨论。MCP 的初始化流程类似同样是 initialize 到 initialized但多了一层“能力协商”客户端和服务器在握手时互相声明支持哪些协议版本、支持哪些原语从而决定连接后能做什么。这个设计很关键因为 MCP 生态太杂有的 Server 只支持 Tools有的还支持 Resources不协商的话客户端很可能发起一个对方完全不支持的请求。ACP 的生命周期要复杂一档。代理不是“等请求再响应”的进程而是会主动执行多步操作的主体所以协议会话管理必须处理代理开始运行、代理请求用户输入、代理执行工具调用、代理暂停等待审批、代理完成或失败、用户取消等状态。这些状态之间有合法流转路径协议得把流转规则定义清楚否则宿主应用没法安全地托管一个代理。从复杂度看LSP 最简MCP 居中ACP 最复杂。但复杂度往往对应能力边界ACP 之所以复杂是因为它要管的场景本身是最复杂的。3. 站在完整调用链上看三者的边界前面是分开看这一节把它们放进同一条真实调用链里你会发现边界其实很清晰。一个典型的 AI 编程助手场景是这样工作的VS Code 或 Zed 启动后先通过 LSP 连接语言服务器拿到补全、诊断、符号表信息你向 AI 助手提问“帮我改一下这个函数的实现”助手先把 LSP 提供的上下文打包给大模型模型在推理过程中决定调用一个外部工具比如读取项目配置文件这个请求通过 MCP Client 转发给对应的 MCP Server工具结果返回模型继续推理最后输出回答。如果这个助手以“代理”形态嵌入编辑器那么整个过程还要通过 ACP 与宿主保持状态同步——把中间步骤流式推送到界面或在执行危险操作前暂停等你确认。三个协议在一条调用链上各管一段并不冲突。LSP 管代码理解MCP 管外部能力接入ACP 管代理的运行编排。这就是为什么我叫它“三足鼎立”而不是“三国大战”——它们分别占了三块相邻的领地而不是在同一块地上争抢。3.1 最容易搞混的重叠区工具调用最容易让人迷惑的是“工具调用”这件事。MCP 有工具调用LSP 里也有 codeAction、executeCommand 这类执行性能力ACP 还要管理工具调用的生命周期。看起来三者在做同一件事其实完全不同。LSP 的工具/命令是编辑器层面的代码操作比如“重构这段代码”“应用修复建议”操作对象是代码文本。MCP 的工具是模型层面的外部动作比如“查询订单”“发送邮件”操作对象是业务系统。ACP 的工具调用管理是流程层面的监管比如“这个工具调用需要用户确认吗”“执行到第几步了”。一句话概括LSP 管代码动作MCP 管外部动作ACP 管代理执行过程的控制。3.2 谁在下游谁在上游另一种看清边界的方式是看调用方向。LSP 是编辑器主动请求语言服务器的能力方向是“编辑器指向语言服务器”语言服务器永远是被动响应方。MCP 的常规方向是“模型/客户端指向 MCP Server”但 Sampling 原语提供了反向通道Server 可以请求模型生成内容。ACP 则是双向的宿主可以给代理发指令和审批结果代理也向宿主推送状态和数据。这个差异对架构设计影响很大。你可以把 LSP 当作“读能力”MCP 当作“调能力”ACP 当作“托管能力”。读能力是只读、低风险、高频的调能力是双向、高风险、低频的托管能力是整个运行时的地基风险最高收益也最大。3.3 生态现状谁已经全面上车LSP 的生态最成熟几乎所有主流编辑器和语言都有对应实现gopls 之于 Goclangd 之于 C/Cpyright 之于 Pythonrust-analyzer 之于 Rust这些名字在开发者社区里比协议本身还出名。MCP 的生态最热闹。Anthropic、OpenAI、微软都公开支持或兼容了 MCP社区里的 Server 数量增长极快设计工具的 Figma MCP、建模软件的 Blender MCP、工业软件 NXOpen MCP几乎每个热门应用都有人做适配。连一些传统软件厂商都开始把“支持 MCP”当产品卖点。ACP 的生态还在早期。目前主要和 Claude Code 及它对嵌入场景的支持绑定第三方实现还不多规范也还在调整。我的判断是ACP 属于那种“现在看着没什么动静、但有了它很多应用形态才真正跑得起来”的协议。等 AI 代理真正变成行业基础设施它的价值会越来越明显。4. 实战选型什么场景优先用哪个协议讲了这么多原理最后得落到实操。如果你现在要做技术选型面对 MCP、ACP、LSP到底怎么选我的建议是先看你最痛的问题是什么再选协议不要反过来。4.1 做编辑器扩展绕不开 LSP 和 MCP如果你是在 IDE 里做功能比如给 VS Code、Cursor 写扩展只要功能需要“理解代码结构”——补全、跳转、诊断、重命名LSP 就是最省力的标准路径。自己从头解析 AST 不是不行而是太亏语言服务器已经把这些做完了你只需要打通协议。如果你做的是 AI 功能比如让模型读项目文件、调第三方 API、操作数据库MCP 是目前最标准的选择。虽然社区里还在争论 MCP 和 function calling 哪个好但主流做法已经变成内部用 MCP Server 封装能力再通过 MCP 暴露给模型代码改动比手工维护 function schema 少得多。4.2 做独立代理或人机协同应用多关注 ACP如果你的产品形态是“代理”特别是嵌在某个宿主界面里的代理IDE 内 AI 助手、网页对话助理、企业工作流代理ACP 值得重点跟踪。它规范的是代理运行时的编排问题如何流式展示执行步骤、如何暂停请求用户审批、如何同步多代理任务状态。不过提醒一句ACP 目前还在快速变化直接上生产要承担不小的兼容性风险。团队如果要做长期代理类产品可以把 ACP 纳入调研范围但不要把所有业务逻辑都绑死在协议实现上留一层适配器协议变更时方便平滑迁移。4.3 团队选型决策清单分享一份可以拿来直接用的决策清单要给编辑器加代码智能优先看 LSP要让 AI 模型调外部工具/数据源先看 MCP要做嵌入宿主应用的代理需要处理人工审批、步骤流式展示盯紧 ACP模型是私有化部署工具调用全部自己实现MCP 的 Streamable HTTP 支持跨网部署不用局限于本机 stdio团队现在什么协议都还没用从 MCP 入手成本最低、社区资料最多、见效最快三个协议不互斥它们在一条调用链上完全可以共存别被“二选一”“三选一”的思维框住。5. 落地实践我踩过的坑和一个最小可跑示例最后分享几个实际项目中踩过的坑外加一个最快能跑起来的 MCP 示例。这些内容在协议规范文档里基本找不到但对动手实现很有帮助。5.1 别小看 JSON-RPC 的细节差异三个协议都基于 JSON-RPC 2.0但具体实现里有很多“约定俗成”的细节差异非常容易中招。比如 LSP 对响应 id 的要求、MCP 初始化方法名是否携带完整版本号、ACP 对消息分帧的处理——每个官方 SDK 都把这些细节封装好了但一旦你想绕过 SDK 自己写裸协议这些细节全都会冒出来。我的建议是除非有特别强的理由否则别自己实现协议客户端或服务器直接用官方 SDK。MCP 的 TypeScript SDK、Python SDK 已经能覆盖绝大多数场景LSP 可以直接用 vscode-languageserver 这类现成库。自己写裸 JSON-RPC 的坑远比想象的多。5.2 工具调用的结果会占上下文窗口使用 MCP 时最容易忽略的问题工具调用结果会计入模型上下文。如果一个 MCP Tool 的返回结果很庞大而模型上下文窗口有限一次看似无害的调用可能直接撑爆上下文导致后续对话质量断崖式下降。我遇到过类似情况一个集成数据库查询的 MCP Server 返回了整表全量数据模型上下文直接超限后面的回答完全“失忆”。解决思路有两个一是在 MCP Server 侧做结果裁剪或分页只返回模型真正需要的那部分二是在 Host 侧配置工具返回内容上限超出部分截断或摘要。具体策略得根据业务场景调没有万能方案但一定要提前想到这个问题。5.3 三协议联调时的高效排查方法实际项目里LSP、MCP、ACP 往往一起跑一个问题可能出在任何一层。排查的关键是逐层隔离我的常用顺序是先确认 LSP 没问题打开编辑器的协议日志或直接用命令看语言服务器的日志再单独验证 MCP写一个不带 AI 模型的测试客户端直接调用 MCP Server 的某个 Tool看返回是否正常最后才怀疑代理编排层打开代理运行时的 trace 日志检查代理状态流转是否和预期一致。另外建议养成一个习惯开发早期就把协议日志可视化。MCP 和 LSP 的 SDK 都支持输出协议日志调试阶段开着日志能省下大量盲猜时间。5.4 十分钟搭一个最小 MCP Server空谈不如动手。如果你还没接触过 MCP我建议花十分钟跑一个最小的示例感受协议的工作方式。下面是一个基于 TypeScript SDK 的代码import { McpServer } from modelcontextprotocol/sdk/server/mcp.js; import { StdioServerTransport } from modelcontextprotocol/sdk/server/stdio.js; const server new McpServer({ name: demo-server, version: 1.0.0 }); server.registerTool( add, { a: { type: number }, b: { type: number } }, async ({ a, b }) ({ content: [{ type: text, text: String(a b) }] }) ); const transport new StdioServerTransport(); await server.connect(transport);跑起来之后在任意支持 MCP 的客户端里添加这个本地 Server然后问模型“1 加 2 等于多少”。模型会调用 add 工具而不是自己猜测结果。这个过程能很直观地看到三件事模型如何知道有这个工具tools/list如何决定调用它tools/call结果如何被整合为最终回答。提示注册工具时参数描述越详细模型正确调用工具的概率越高。MCP 的入参用 JSON Schema 描述规则和 OpenAPI 一样把 type、description、required 几个字段写清楚就够。关于这三个协议我现在的判断是LSP 已经是地基短时间内不会被动摇MCP 正在快速成为模型连接外部世界的默认接口ACP 还在早期但它解决的是 AI 代理走向产品化时绕不开的问题。协议之争远没有结束但与其押注哪家胜出不如先把三者的边界和用法吃透——因为它们下一步大概率不是互相取代而是像今天这样在同一条调用链上各守一段。这也是我写这篇长文的核心动机让你在动手选型前先把它们之间的关系想清楚。