
MCP 是一个开放协议,它标准化了应用程序向 LLM 提供上下文的方式。可以把 MCP 想象成 AI 应用程序的 USB-C 端口。正如 USB-C 提供了一种将设备连接到各种外设和配件的标准化方式一样,MCP 也提供了一种将 AI 模型连接到不同数据源和工具的标准化方式。
—— Anthropic
我希望这到头来会是我自己的技能问题,也希望我遗漏了一些东西。
在过去的一段时间里,MCP(模型上下文协议)——它可以让 LLM 成为代理并与世界互动——真的火了起来。这个想法很简单:让我们为 LLM/ 代理标准化一个 API,让它们与世界互动,并定下将这些信息告知 LLM/ 代理的方式。
事情发展得非常快,IBM 最近发布了他们自己的 MCP“正交标准”,称为代理通信协议 (ACP),紧随其后,谷歌发布了 Agent2Agent (A2A)。
MCP 服务器和客户端每天都有新的构建和发布,可以在 mcp.so 和 pulsemcp.com 等网站上找到。
然而,让我惊讶的是成熟工程实践实在太少了。所有主要参与者都花费了数十亿美元来训练和微调他们的模型,但据我所知,他们最后却让实习生编写文档,提供的 SDK 质量低劣,而且几乎没有提供任何实现指导。
这种趋势似乎在 MCP 中延续了下来,导致了一些非常奇怪的设计决策、糟糕的文档,以及更糟糕的实际协议规范。
我的结论是,提案的整个 HTTP 传输设置(SSE+HTTP 和 Streamable HTTP)都应该被抛弃,取而代之的是模仿 stdio 的 Websockets。
大约三周前,我决定投身 MCP 的潮流尝试一下,看看它在我们自己的环境中如何应用。我非常希望在使用抽象之前先了解底层工作原理。现在我们有了一个可以在不同传输协议上运行的新协议——真是令人兴奋!
Anthropic 是 MCP 标准化工作的幕后推手,而之所以 Anthropic 首席执行官认定大多数代码将在一年左右的时间内转由 LLM 编写,MCP 似乎就是主要原因之一。对编程工具的重视似乎是其标准化工作的指导原则,其核心在于使用体验。
简而言之,它是一个 JSON-RPC 协议,带有预定义的方法 / 端点,旨在与 LLM 结合使用。这并非本文的重点,但该协议本身确实存在一些需要批评的地方。
与 2005 年之后的许多应用程序号称是“本地优先”(很讽刺)一样,MCP 似乎也是如此。查看传输协议,你就能了解它们源自何方——大概他们的目的是构建在笔记本电脑上编程的 LLM 工具。他们可能正在研究本地 IDE(或者更现实地说,Cursor 或 Windsurf),以及如何让 LLM 与本地文件系统、数据库、编辑器、语言服务器等进行交互。
这里主要有两种(或三种)传输协议:
-
stdio
-
“得通过 HTTP 传输,Web 似乎是我们应该支持的东西。”
使用 stdio 本质上意味着启动一个本地 MCP 服务器,连接从服务器到客户端的 stdout 和 stdin 管道,并开始发送 JSON 并使用 stderr 记录日志。这在某种程度上打破了使用这些流进行双向通信的 Unix/Linux 管道范式。当需要双向通信时,我们通常会使用 socket、Unix socket,甚至是网络 socket。
不过,socket 有简单易懂,在所有操作系统中开箱即用,不需要额外处理等优势。所以即使有人提出批评,我也理解。
HTTP 传输则是另一回事。同样的一个错误有两个版本:HTTP+SSE(服务器发送事件)传输,它正在被“Steamable HTTP”(一个杜撰的术语)取代,后者将 REST 语义与 SSE 结合使用。但这又带来了许多额外的困惑和极端情况。
总结下来就是:“由于我们喜欢用 SSE 进行 LLM 流式传输,所以我们不使用 WebSocket。相反,我们实际上是在 SSE 之上实现 WebSocket,并将其称为‘Steamable HTTP’,让人们认为这是一种被接受 / 已知的处理方式。”
他们在这个 PR:modelcontextprotocol/pull/206 中讨论了 WebSockets 的问题(以及 Steamable HTTP 的原因),并提出了一些非常奇怪的扭曲和不切实际的论点来反对使用 WebSockets。该帖子中至少还有一个人似乎同意我的观点:modelcontextprotocol/pull/206#issuecomment-2766559523。
我打算用 Golang 实现一个 MCP 服务器。目前没有官方的 Go SDK,而且我想了解这个协议。结果证明,这是个会影响心理健康的错误……
我查看了 https://modelcontextprotocol.io,发现其文档写得很糟糕(所有 LLM 供应商似乎都在内部竞争,争相编写令人困惑的文档)。该规范掩盖或忽略了协议的一些重要方面,并且没有提供任何对话流程的示例。事实上,整个网站似乎都不是用来阅读标准规范的;相反,它引导你去学习如何实现他们的 SDK 的教程。
所有示例服务器都是用 Python 或 JavaScript 实现的,目的是让你下载并使用 stdio 在本地运行它们。如果你想在别人的电脑上运行程序,Python 和 JavaScript 可能是最糟糕的语言选择之一。作者似乎意识到了这一点,因为所有示例都以 Docker 容器的形式提供。
说实话……你上次运行 pip install 而没有陷入依赖地狱是什么时候?我是不是太自命不凡 / 武断了,认为人工智能领域的从业者只懂 Python,而且“嗯,它在我的电脑上能用就行”这种做法仍被认为是可接受的?对于任何尝试过运行 Hugging Face 某一功能的用户来说,这一点都应该是显而易见的。
如果你想在本地运行 MCP,难道你不想选择 Rust、Go 这样的可移植语言,或者像 Java 或 C# 这样基于虚拟机的语言吗?
当我开始实现该协议时,我立刻就觉得必须对其进行逆向工程。文档中缺少 SSE 部分的重要内容,而且似乎还没有人实现“Steamable HTTP”;甚至连他们自己的工具,例如 npx @modelcontextprotocol/inspector@latest,都没有。(公平地说,这可能是我自己搞出来的技术问题,可能是拉错了版本,因为几周后我再次检查时它已经可用了。你也可以在 inspect.mcp.garden 上找到版本,这可能更方便。)
一旦你掌握了架构,很快就会意识到实现 MCP 服务器或客户端可能是一项繁重的工作。问题在于 SSE/Streamable HTTP 实现试图像 socket 一样工作,模拟标准输入输出 (stdio),但实际上并非如此,它们会试图同时在任何地方执行所有操作。
modelcontextprotocol.io/specification/2024-11-05/basic/transports
在 HTTP+SSE 模式下,为了实现全双工,客户端会建立一个 SSE 会话,例如通过 GET /sse 来读取。第一次读取会提供一个可以提交写入操作的 URL。然后,客户端会继续使用指定的端点进行写入操作,例如发送 POST /a-endpoint?session-id=1234 的请求。服务器会返回 202 Accepted 状态码,且不包含任何正文,此时应该从 /sse 上预先存在的打开的 SSE 连接读取该请求的响应。
modelcontextprotocol.io/specification/2025-03-26/basic/transports
在 “Streamable HTTP”模式下,他们意识到无需在第一个请求中提供新的端点,而是可以使用 HTTP 标头作为会话 ID,并使用 REST 语义作为端点。例如,GET 或 POST /mcp 可以打开一个 SSE 会话并返回 mcp-session-id=1234 的 HTTP 标头。要发送数据,客户端会向 POST /mcp 发出请求,并添加 mcp-session-id=1234 的 HTTP 标头。响应可能:
-
打开一个新的 SSE 流并发布回复
-
返回 200 状态码,并在正文中包含回复
-
返回 202 状态码,表示回复将被写入任意一个现有的 SSE 流
要结束会话,客户端可以发送或不发送带有 mcp-session-id=1234 标头的 DELETE /mcp 消息。服务器必须维护状态,除非客户端正常结束会话,否则无法明确知道客户端何时放弃了会话。
这是一个问题百出的设计,我都不知道该从何说起。
虽然 SSE 模式的一些关键特性尚未编写文档,但只要对其进行逆向工程,就会发现它相当简单。但这仍然会给服务器实现带来巨大且不必要的负担,服务器实现需要在调用之间“join”连接。实际操作几乎都会迫使你使用消息队列来回复任何请求。例如,以任何冗余方式运行服务器都意味着 SSE 流可能从一个服务器发送到客户端,而请求却被发送到完全不同的服务器。
Steamable HTTP 方法将其提升到了另一个层次,带来了一系列安全问题和令人困惑的控制流。 Streamable HTTP 虽然保留了 SSE 模式的所有缺陷,但它似乎更像是 SSE 模式的复杂扩展集。
就实现而言,我只是略知皮毛,但根据我对文档的理解……
可以通过 3 种方式创建一个新会话:
-
一个空的 GET 请求
-
一个空的 POST 请求
-
一个包含 RPC 调用的 POST 请求
一个 SSE 可以通过 4 种不同方式打开:
-
一个用于初始化的 GET 请求
-
一个用于加入先前会话的 GET 请求
-
一个用于初始化会话的 POST 请求
-
一个包含请求并使用 SSE 响应的 POST 请求
一个请求可以通过 3 种不同方式响应:
-
一个作为对包含 RPC 调用的 POST 请求的 HTTP 响应
-
一个作为对 POST RPC 调用的响应而打开的 SSE 中的事件
-
一个作为之前打开的任何 SSE 的事件
由于它有多种方式来发起会话、打开 SSE 连接和响应请求,因此带来了显著的复杂性。这种复杂性有几个普遍的影响:
-
复杂性提升:执行同一件事(会话创建、SSE 开启、响应传递)的多种方式增加了开发人员的认知负担。代码的理解、调试和维护变得更加困难。
-
不一致的可能性:由于实现同一结果的方式多种多样,不同服务器和客户端之间实现不一致的风险更高。这可能导致互操作性问题和意外行为。客户端和服务器只会实现它们认为必要的部分。
-
可扩展性问题:虽然 Streamable HTTP 旨在提高效率,但从另一方面来说,其复杂性将带来需要克服的可扩展性瓶颈。服务器可能难以管理大量机器上的各种连接状态和响应机制。
Streamable HTTP 的“灵活性”带来了一些安全隐患,以下仅列举其中几项:
-
状态管理漏洞:跨不同连接类型(HTTP 和 SSE)管理会话状态非常复杂。这可能导致会话劫持、重放攻击或 DoS 攻击等漏洞,因为服务器会创建需要管理并保存的状态,直到会话恢复。
-
扩大攻击面:会话创建和 SSE 连接的多个入口点扩大了攻击面。每个入口点都代表着一个攻击者可能利用的潜在漏洞。
-
困惑和混淆:发起会话和传递响应的多种方式可用于混淆恶意活动。
最新版本的协议包含一些关于如何进行授权的非常主观的要求。
modelcontextprotocol.io/specification/2025-03-26/basic/authorization
使用基于 HTTP 的传输方式的实现应该符合此规范。
使用 STDIO 传输的实现不应遵循此规范,而应从环境中获取凭据。
我理解的意思是,对于 stdio,随便你。对于 HTTP,你最好还是去实现 OAuth2 吧。如果我使用 HTTP 作为传输方式,为什么还需要实现 OAuth2,而 stdio 用 API 密钥就够了?
我不知道,只是有点难过……目前业界似乎无计可施——“现在还凑合,但以后处理起来会很困难。”
JSON RPC 协议只有一个,而 Stdio 显然是首选的传输协议。那么我们应该尽量让 HTTP 传输方式接近 Stdio,只有在真的非常需要的情况下才引入变化。
-
在 Stdio 中我们有环境变量;在 HTTP 中我们有 HTTP 标头。
-
在 Stdio 中我们有类似 socket 的行为,包含输入和输出流;在 HTTP 中我们有 WebSocket。
就是这样。我们应该能够在 WebSocket 上完成与在 Stdio 上相同的操作。WebSocket 是通过 HTTP 进行传输的理想选择。我们可以省去会话中复杂的跨服务器状态管理。我们可以消除大量的极端情况,等等。
当然,有些事情,比如授权,在某些情况下可能会更复杂一些(而在某些情况下则更容易);有些防火墙可能会阻止 WebSocket;小型会话可能会有额外的开销;恢复中断的会话可能会更困难。但正如人们所说:
客户端和服务器可以根据其特定需求实现额外的自定义传输机制。该协议与传输无关,可以在任何支持双向消息交换的通信通道上实现。
modelcontextprotocol.io/specification/2025-03-26/basic/transports#custom-transports
作为一个行业,我们应该针对最常见的用例进行优化,而不是只优化一些特殊情况。
如上所述,似乎有更多协议正在涌现。MCP 实际上是“向 LLM(可以创建代理)公开 API 的协议”。IBM 和谷歌的较新协议(ACP 和 A2A)实际上是“向 LLM(可以创建代理的代理)公开代理的协议”。
纵观 A2A 规范,似乎对它们的需求非常有限。尽管它们声称是正交的,但 A2A 中的大多数功能都可以使用 MCP 原样或通过少量添加来实现。
归根结底,它们就是两个完整的协议,它们也可以作为 MCP 服务器中的工具。甚至 IBM 似乎也承认他们的协议并非真正必要:
“代理可以被视为 MCP 资源,并进一步作为 MCP 工具调用。这种 ACP 代理的视角允许 MCP 客户端发现并运行 ACP 代理……”
—— IBM / agentcommunicationprotocol.dev/ecosystem/mcp-adapter我一开始的感觉是,ACP 协议更像是 IBM 推广其“代理构建工具”BeeAI 的一种尝试。
这两个 A** 协议都提供了一个合理的传输层和一种发现代理的方法。

原文链接:
https://raz.sh/blog/2025-05-02_a_critical_look_at_mcp
6 月 27~28 日的 AICon 北京站将继续聚焦 AI 技术的前沿突破与产业落地,围绕 AI Agent 构建、多模态应用、大模型推理性能优化、数据智能实践、AI 产品创新等热门议题,深入探讨技术与应用融合的最新趋势。欢迎持续关注,和我们一起探索 AI 应用的无限可能!

今日荐文
别被MCP的包装骗了!重构系统、向智能体转型,CEO亲述:关键时刻还是RPA兜底?
王兴兴回应比赛风波:挣到钱了,但现在的机器人别指望它能干活
13 年苦熬到 170 亿市值,一夜间被用户抛弃!一封“AI吹”全员信让网友“不喷不行”
天塌了,Claude 全面断供Windsurf!CEO喊冤控诉也挡不住开发者退订,祸起OpenAI收购?
0粉丝狂卷数十亿播放,靠AI流量欺诈获利近亿!网友:这“刑”得离谱

你也「在看」吗?👇
(文:AI前线)