MCP、LSP、ACP三大协议深度解析:AI编程与代理的协作边界
2026/9/13 4:42:01 网站建设 项目流程

先说个现象。2024 年底,MCP(Model Context Protocol)突然火遍整个 AI 开发者圈子,GitHub 上几乎每天都有新的 MCP Server 冒出来;到了 2025 年,大家又发现 LSP(Language Server Protocol)这种已经在编辑器里服役近十年的老协议,反而成了 AI 编程工具绕不开的底座;而 ACP(Agent 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 Server;HTTP 方案适合远程部署,比如把内部系统的数据能力通过 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 之于 Go,clangd 之于 C/C++,pyright 之于 Python,rust-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 往往一起跑,一个问题可能出在任何一层。排查的关键是逐层隔离,我的常用顺序是:

  1. 先确认 LSP 没问题:打开编辑器的协议日志,或直接用命令看语言服务器的日志;
  2. 再单独验证 MCP:写一个不带 AI 模型的测试客户端,直接调用 MCP Server 的某个 Tool,看返回是否正常;
  3. 最后才怀疑代理编排层:打开代理运行时的 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 代理走向产品化时绕不开的问题。协议之争远没有结束,但与其押注哪家胜出,不如先把三者的边界和用法吃透——因为它们下一步大概率不是互相取代,而是像今天这样,在同一条调用链上各守一段。这也是我写这篇长文的核心动机:让你在动手选型前,先把它们之间的关系想清楚。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询