MCP总体架构

  • MCP主机:像Claude Desktop、IDE或AI工具这样的程序,需要通过MCP访问数据
  • MCP客户端:与服务器保持1:1连接的协议客户端
  • MCP服务器:轻量级程序,每个程序都通过标准化模型上下文协议公开特定功能
  • 本地数据源:MCP服务器可以安全访问的您计算机上的文件、数据库和服务
  • 远程服务:MCP服务器可以通过互联网(例如通过API)连接到的外部系统
image-20250709232422765

Transport

  • MCP的Transport是Client和Server数据传输通道,通过JSONRPCMessage传输消息。
  • 它有Stdio、SSE、Websocket等实现。
  • 目前还有Streamable Http,仍在实现中。

Stdio

Stdio Transport只能用于client和LocalServer的通信,LocalServer一般是如文件系统操作、本地数据库访问、GIT OPS等管理本机的工具。

常见使用姿势:

  • 厂商提供本地起stdio server的python/js二方包,用户安装后,动态拉起。
  • Stdio使用操作系统的IPC机制进行通信,如stdio&stdout

目前大部分MCP的desktop软件的MCP插件都是基于STDIO,需求上很多是本地操作需求。

  • 优点:无网络通信,延迟低
  • 缺点:仅用于本地电脑。clienti和server1对1,一个server不能服务多个client.。
image-20250709233003055

SSE Session

SSE

SSE用于什么场景呢?它主要用于客户端与大模型之间的对话。用户输入一个问题,模型会逐字反馈结果。SSE是客户端到服务端的单向数据传输,而服务端的响应则是一个流,可以逐步返回数据。

MCP的SSE Session

MCP宣称其具有双向通信能力,那么它的双向通信是如何实现的呢?我们已经了解到,SSE实际上是单向的流,它并不是双向的流。那么,它是如何实现双向通信的呢?

首先,它会发起一个连接,即相当于我已连接到你的服务器,并且这个连接是长期保持的。这样,服务器可以向我推送消息,但是在我建立连接时发送一个消息后,就不再发送其他消息了。

因此,它创造了一个名为SSE Session的机制。

总结:SSE是单向服务器推送协议,基于HTTP协议。MCP使用SSE Session实现双向流通信。

image-20250709233142696

SSE Session优缺点

  • 优点:具备很好的兼容性,通过SSE Session实现了双向流通信。

  • 缺点:SSE是服务端->客户端的单向流,双向流依赖client永远post message到同个Server IP。服务端做分布式困难。

也就是说,当你下次向服务器推送消息时,它相当于发起了一次临时的POST请求。这会导致明显的连接问题,因为建立连接和后续发请求是两条独立的通路,这在分布式服务中是个大问题。

比如你连接的是服务器A,而下次消息发到服务器B时,服务器B无法响应,因为所有消息都必须通过原会话链接返回。因此,它的一个明显缺陷是难以适应分布式环境。

它的设计初衷是在本地计算机通过STDIO方式进行,而如今人们期望将其扩展到云端,进行远程部署,这就暴露出问题。

集团怎么解决分布式问题?

  1. 不使用域名:每个client使用VipServerf解析得到一个IP,固定访问这个IP。如果两次post请求到不同的Server就无法工作了。集团的VIP挺好用,会在统一接入层转发至分布式后端机器。然而,这也带来了一个问题:作为服务提供者,当服务IP地址被发布后,如果该服务下线,连接将无法维持。
  2. 服务端优化:针对message post到不同的IP,能转发会sse connect的IP,相对复杂。
  3. 社区发现了这个缺陷,已经将Streamable Http提上日程,未来会替换SSE。

Streamable Http

  1. 统一端点设计

将/sse和/message两个端点合二为一,简化接口结构,满足无状态和有状态的需求。

支持断连恢复等多种场景,提升开发效率与灵活性。

核心诉求:可以提供一个无状态的单点,这样每次开始时就不会有问题。此外,即使IP地址发生变化,也可以记住筛选条件,确保上次的复杂任务可以继续运行和传输。这就是Streamable Http的核心需求。(目前社区正在做)

  1. 灵活响应模式

服务器可选择直接返回标准HTTP响应或升级为SSE流,适应不同业务需求。

目前社区已提出issue并正在实现中,推动功能完善与优化。

目前,需求还在开发中,社区已经提出了这个规范。例如,像比较快的TypeScript语言,它已经提前release出来了。而我们所需的Python和Go语言仍在开发中。

MCP与普通RPC的区别

基本概念对比

MCP常被误解为仅是Tool调用的HSF协议。

如果仅从天气查询等简单场景看,二者确实相似,但实际远不止于此。

阿里的RPC系统具有一个特点,即发现彼此间的调用关系并不需要鉴权。只要知道对方的版本和地址,就可以进行调用。这正是我们集团内部最广泛使用的调用机制——没有鉴权,但只要不让你知道,那么几乎无人能调用。

例如,如果你是我的业务合作方,我告诉你我的接口地址,你就可以进行调用。

而相比之下,MCP则不同,你只需要知道一个end point,它会自动帮你列出其中的所有tools,这是在发现性上一个很关键的差别。

强大功能特性

MCP具备发现性、动态性、双向通信能力等,能实现极其丰富的工具调用能力。

如:tool的变更通知、长时间任务的进度通知、human-in-the-loop(风险识别干预等)。

扩展协作能力

除了工具调用,MCP还提供Prompts、Resources能力;

还可与A2A等协议协作,实现更丰富的交互方式和功能扩展。

MCP转化到RPC的思考

大家都在谈论如何迅速将现有的服务转化为MCP。想要快速构建一个丰富的tools市场,你可能会考虑将存量的HSF进行转化,例如中间件团队也做个转化的中间件,通过一定的配置化过程,可以将存量服务转变为HSF,进而成为MCP。这种方法确实有效、可行,并且迅速。

然而,这只是个临时方案呢?这是因为许多服务非常基础,并且过去的设计并未考虑大模型。例如,如果一个服务有多个参数,其中一些参数还嵌套了复杂的逻辑,那么在大模型中传递这些参数几平是不可能的。如果你的服务是核心且重要的,那么未来你很可能会选择使用native服务的方式,重新开发MCP native版本。

另一个问题是,虽然HSF可能只是一个简单的流快速response。但在构建agent应用时,情况就远非如此简单。在这种场景下,tool 可能需要与系统进行交互,例如处理隐私数据或包含LLM的情况下需要流式输出。这些丰富的功能是传统的RPC协议无法表达的。

因此,我认为未来Al native的agent开发将倾向于采用符合这种native标准协议的编程方式,而不仅仅是简单地将现有存量进行转换。

MCP生命周期

image-20250710000545913

观察MCP的完整生命周期,可以发现它并非无状态,而是具有状态的。

这是因为存在多个版本的MCP和server。为了确保不同版本之间的正确交互,它们之间存在着协商协议。例如,连接建立后会进行初始化。

在初始化阶段,客户端会通知服务端自身所具备的能力以及所需能力,而服务端则会反馈其版本信息和能力。完成这一交互后,客户端和服务端便能使用正确的协议进行通信。这一过程与我们日常的Java开发中server类的初始化有些类似,包含一个初始化阶段,随后是不断的执行(execute)操作,直至最后关闭。

MCP初始化

那么,它们之间协商的内容是什么呢?

image-20250710001058642

协议版本协商

首先是版本信息,互相告知对方所持版本的详情,以及是否兼容。

客户端在初始化请求中发送其支持的协议版本,服务器必须以相同版本或其支持的其他版本进行响应。

这一过程确保双方在协议版本上的兼容性。

例如,服务端会告知客户端是否提供了tools、prompts和resource等信息。如果这些内容发生了变更,服务端会通知客户端。

能力声明

客户端和服务器在Initialize阶段会明确声明它们各自支持的能力。

这些能力决定了在会话期间可以使用哪些协议特性。

其他

此外,服务端还会分享其专用能力,如sampling能力,以及其它特定功能、root的能力,这些特殊的能力需要通过server与客户端协商确定

示例

  • 客户端请求示例

请求中包含协议版本、客户端能力及客户端信息,示例展示了JSON格式的具体内容。

image-20250710001245230

  • 服务器响应示例

响应包含协议版本、服务器能力及可订阅资源变化信息,提供JSON格式的详细说明。

image-20250710001237546

Tool发现

Tool发现机制

tool list协议是MCP Serveri让客户端感知工具的关键协议

请求结构

首先客户端需要发送一个tools list请求cursor用于分页,一般来说我们不大用这个功能,都是全量返回。

image-20250710001602233

响应结构

服务端会回复工具集合,返回的tools描述是openai schema规范。

因此tool schema是可以直接发送给openai的function call的

image-20250710001552497

存在的问题

然而,在实际应用中,业务人员通常对这一机制感到困惑,因为他们希望系统具有更好的动态性。

  • 性能不佳:我们知道默认的发现机制制,即在server开发时注册了一系列的tools,这可能导致性能不佳。具体来说,如果一个server返回了100个tour,那么当这些tool被传递给大模型时,其上下文质量会非常差,性能也会大幅下降。此外,错误率会增加,导致大模型的识别准确性显著降低。

  • 动态性支持不够高:另外,作为一个统一的服务mcp提供方,面对业务的个性化需求,传统的做法是针对A、B、C三个不同业务需求部署三套不同的解决方案,这不仅导致维护复杂度高,而且在协议中无法天然提供动态性支持。

ListTool动态优化方案

MCP协议里允许所有的Request和Response的params里带上meta字段,即业务可以透传元数据。

在MCP Server实现的时候,自定义listToolHandler即可根据meta做些业务逻辑区分。

比如:指定使用的tool、或者设置权限问题,哪些tool是没有权限的,不同业务实现不同权限控制

image-20250710001918281

如业务希望给返回的tool增加元信息,同样可通过Meta实现。

但是这个Meta只能加到Result层级,不能加到每个Tool层级,在应用端可以做一下整合。

image-20250710001941799

CallTool机制

CallTool机制中,Client发送CallToolRequest,Server返回CallToolResponse。

默认情况下,应用要阻塞等待Tool的响应结果。

image-20250710002724967

进度通知

MCP Server支持运行长耗时任务,并通过Http SSE向客户端推送通知流

此功能需要客户端发送progressToken启用能力,建议使用uuid作为唯一标识

  • 客户端配置

客户端需在请求中设置progressToken,它与jsonrpc的id不同,业务方无法直接获取系统递增
生成的id。

示例中展示了如何在params字段中添加progressToken。

image-20250710003216793

  • 服务端实现

同时需要MCP Server配置实现report,即Server开发者可以在某个运行点位,把进度通知到client。

*total可以理解为总步数,process是当前进度,process必须小于等于total,且每次发送process要变大。如果不能准确判断总步数,可以只递增发送process,不设置total,即total=null。

image-20250710003649727

Tool流式能力

  • 流式能力的重要性

Tool默认只能同步输出一次,而流式输出对于包装LLM或Agent非常重要。通过流式接收返回值,可提升对话体验。

  • Notification机制扩展

Notification机制提供了meta能力,可通过_meta追加业务增量消息。这为流式输出提供了技术支持。

image-20250710003843686

多模态支持

  1. TextContent

大部分工具基于TextContent,返回类型为文本数据,包含”type’字段为”text”,以及对应的文本内容。

image-20250710002924873

  1. ImageContent

支持图像返回,如生成二维码,使用base64编码传递数据,指定”type”为”image”,并提供数据和mimeType。

image-20250710002939337

  1. AudioContent

支持音频返回,通过base64编码传递音频数据,指定”type”为”audio”,并标明mimeType。

image-20250710002952274

  1. EmbededContent

可返回指向Resourcel的内容,Resource即MCP提供的另一种能力。包含”type”为”resource”,以及资源的URl、mimeType和文本内容。

image-20250710003000089

错误处理

  • 协议层错误

当协议层出现问题(如request schema错误),MCP会返回通用的jsonrpc error.

image-20250710004127551

  • 工具调用内部错误

工具开发者可构建Error Result来处理内部错误。

image-20250710004142012

Human in the Loop

image-20250710004310679

Sampling的作用

Sampling(采样)能力是连接服务器与LLM的关键技术通过客户端控制模型访问和内容生成,实现安全高效的智能交互。

交互流程详解

MCP Serveri通过Sampling请求发送对话历史等参数。确保隐私,客户端确认内容后返回Server。

安全与隐私保障

Sampling机制提供了安全性与隐私性手段,避免敏感信息在LLM调用过程中被泄露。


refer

-

声明:

  1. 若文章存在错误,望诸君不吝指正^

  2. blog仅供个人记录学习所用

  3. 部分笔记由于年代久远,做的笔记找不到最初是引用谁的,若是不允许引用转载,请联系我