图解源码:万字解析 Spring AI 到底是怎么实现 MCP 的
一、前言:Spring AI 与 MCP
在过去的一年里,大模型生态的一个明显趋势是从模型调用走向模型协作。不仅仅是怎么让大模型回答问题,更是怎么让模型具备执行、协同与插件化能力。Spring AI 正是在这一背景下诞生的,它试图以 Spring 的方式,将 AI 能力融入现有的企业级应用体系中。
Spring AI 本质上是一个为 Java 生态设计的 AI 集成框架。它统一了不同模型(如 OpenAI、Anthropic、Ollama 等)的调用方式,并提供了 Prompt 模板、输出解析、工具调用(Tool Invocation)等上层抽象,让开发者可以像使用 RestTemplate 一样优雅地调用大模型。
Spring AI 在 2024 年引入了对 MCP(Model Context Protocol)的支持,这一机制旨在标准化模型与外部系统(插件、数据库、API、文件系统等)之间的上下文通信协议,使模型具备理解和调用外部资源的能力。换句话说,MCP 规范了模型与外部世界之间的通信,使模型能够在受控、安全、可扩展的环境下访问外部资源并执行任务。
在理解了 Spring AI 与 MCP 的背景之后,本文将从源码角度出发,系统解析 Spring AI 是如何实现 MCP 协议的。我们将依次梳理其整体架构设计、核心交互过程、关键组件源码以及运行时的执行机制,并通过断点演示还原客户端与服务端的实际协作路径。
二、架构解析
在 Spring AI MCP 中,客户端与服务端的设计呈现出高度的对称性与分层化特征,其架构的核心思想是分层解耦、职责清晰、对称可扩展。无论是客户端还是服务端,每一层都只负责单一维度的功能。下图为 MCP 客户端和服务端的分层架构图:

在 Spring AI MCP 中,客户端和服务端的架构是十分接近的,自上而下包含入口层、运行层、会话层、传输层,不同之处在于服务端架构会多出一层,即会话管理层,下面是各层的作用:
- 入口层
这一层是 MCP 客户端/服务端对外的统一入口,对应的接口为 McpClient/McpServer。只需通过其工厂方法,并提供配置信息(如超时时间、能力配置等),就能以同步或异步模式创建运行层的客户端/服务端实例。入口层对下层的复杂实现进行了封装,对上层提供统一、简洁的构建入口,使得调用者无需关心传输方式与消息机制的差异。 - 运行层
这一层是 MCP 客户端/服务端的核心控制中心,对应的类为 McpAsyncClient/McpSyncClient、McpAsyncServer/McpSyncServer。其实现了具体的业务行为,包括初始化、工具注册、工具调用等操作,并使用响应式编程模型来处理异步流程。 - 会话管理层
这一层是 MCP 服务端特有的部分,用于管理多个客户端会话,对应的接口为 McpServerTransportProvider。其用于管理活跃会话的生命周期、向所有客户端广播消息、统一关闭与清理连接资源等,使得服务端可以同时维护多个客户端连接。 - 会话层
这一层是 MCP 客户端与服务端之间通信的上下文载体,对应的类为 McpClientSession/McpServerSession。每一个会话代表一次完整的逻辑连接,其负责管理客户端与服务端之间的消息上下文,包括请求、响应与通知。该层基于 JSON-RPC 协议,实现了通信数据的统一封装与传递,使业务逻辑与底层传输机制相互解耦。 - 传输层
这一层负责实际的数据收发与序列化,对应的接口是 McpClientTransport/McpServerTransport。其屏蔽了底层 I/O 的复杂性,为上层提供消息发送、对象反序列化等操作,并提供了不同协议的实现,如 Stdio、HTTP + SSE、Streamable HTTP。
三、核心交互过程
上一章我们从架构层面梳理了 Spring AI MCP 的整体设计思路:客户端由入口层、运行层、会话层与传输层构成,服务端则在此基础上增加了会话管理层,用以协调多会话场景下的资源与上下文。但理解分层结构只是第一步,要真正掌握 MCP 的运行机制,还需要深入到“层与层之间”,也就是它们如何建立连接、初始化、交换消息、调用工具的核心交互过程。
本章将以 SSE 为示例,串联起 MCP 在真实运行中的三条主线,分别是客户端与服务端的构建与连接过程、初始化过程、工具发现与调用过程。通过这三个阶段,我们将从源码层面以图的形式还原 MCP 的交互逻辑,理清每一层的职责边界与协作方式。实际上源码中对于其他协议的处理也是非常类似的,只是传输层的实现上会略有不同,但整体结构都是一致的。
在解析三个阶段之前,先要讲述一下 Spring AI MCP 的 SSE 实现中客户端和服务端中是哪些层次完成消息收发的:
|
|
|
|---|---|
|
|
|
3.1 客户端/服务端构建、连接过程
首先讲解客户端/服务端的构建和连接过程,这是他们交互的第一步,其中比较特殊的是,客户端向服务端发起连接的过程是发生在客户端的构建过程的,因此下面会将客户端构建与连接过程一起讲解。
- 服务端构建过程
服务端的构建过程比较简单,在入口层中配置了服务端的所有信息(如超时时间、能力配置)后,调用其工厂方法就能构建出一个服务端运行层实例。 - 客户端构建过程
与服务端类似,在入口层中配置了客户端的所有信息(如超时时间、能力配置)后,调用其工厂方法就能构建出一个客户端运行层实例。但有所区别的是,客户端还需要创建出其会话层对象。在配置完会话层对象后(需要配置超时时间、传输层对象等),还需要调用传输层方法来建立与服务端的连接,此时会向客户端发送 GET 请求来建立并监听 SSE 连接。服务端的会话管理层接收到后,会开启 SSE 连接,并为客户端创建一个会话层对象,最后再返回客户端消息端点地址(之后客户端需要向这个地址发送业务交互消息)。在客户端收到响应后,会保存这个消息端点地址,至此客户端的构建过程才算结束。
详细的交互流程如下图所示:

3.2 客户端/服务端初始化过程
然后讲解客户端/服务端的初始化过程,这是他们交互的第二步。整个初始化过程可以分为两个阶段:初始化建立、初始化完成通知。初始化建立指的是客户端在向服务端发起初始化请求,服务端向客户端响应服务端信息的过程。这个过程完成后,服务端存储的状态仅是初始化中,即还未结束初始化过程,之后还需要客户端向服务端发送初始化完成通知,服务端存储的状态才会设置为初始化完成,这才标志着双方正式完成初始化交互。这样做的意义在于双方能通过两次消息交换完成状态确认,确保初始化过程完整可靠。
- 初始化建立
上层服务在调用客户端运行层对象的初始化方法后,就能开启这一过程。运行层对象会构建初始化请求方法、参数(包含客户端版本、配置信息),然后调用会话层对象发送请求。会话层对象将请求转换为 JSON-RPC 格式的消息,然后就调用传输层对象发送消息。传输层对象则向服务端的消息端点发送 POST 请求,并携带刚才构建的 JSON-RPC 消息。
服务端的会话管理层接收到后,会取出连接过程时创建的会话层对象,然后让其来处理这个消息。会话层对象会保存客户端消息,并设置状态为初始化中,之后构建 JSON-RPC 响应消息(内容包含服务端版本、信息等),再调用传输层对象发送消息给客户端。最后传输层对象则通过 SSE 连接向客户端发送这个 JSON -RPC 消息。
客户端传输层对象接收到这一响应后,会一直向上传递到运行层,之后运行层对象会存储响应中服务端的配置信息。
- 初始化完成通知
在初始化建立后,客户端运行层对象还需要调用会话层对象来通知服务端初始化完成,会话层对象则会构建 JSON-RPC 通知消息,并调用传输层对象发送这一通知。传输层对象则向服务端的消息端点发送 POST 请求,并携带刚才构建的 JSON-RPC 消息。
服务端的会话管理层接收到后,会取出连接过程时创建的会话层对象,然后让其来处理这个消息。会话层对象则将状态设置为初始化完成,并返回成功信息给会话管理层。最终会话管理层会向客户端的 POST 请求做一个简单的响应。
客户端传输层对象接收到这一响应后,会一直向上传递到运行层,最后运行层会将客户端的状态标记为初始化完成。至此整个初始化过程才算结束。
详细的交互流程如下图所示:

3.3 工具发现、调用过程
最后讲解工具发现、调用的过程,这个过程属于 MCP 的业务交互流程。其他的过程都是很类似的,因为源码对整个业务交互进行了非常好的抽象,所以每个业务流程在层次走向上都是非常类似的。
- 工具发现过程
上层服务在调用客户端运行层对象的工具发现方法后,就能开启这一过程。运行层对象会调用会话层对象发送请求,来获取工具列表,会话层对象将请求内容转换为 JSON-RPC 格式消息后,调用传输层对象发送消息。最后,传输层对象则向服务端的消息端点发送 POST 请求,并携带这一消息。
服务端的会话管理层对象接收到后,会取出连接过程时创建的会话层对象,然后让其来处理这个消息。会话层对象则会构建 JSON-RPC 响应消息,内容包含服务端的可用工具列表,再调用传输层对象发送消息给客户端。最后,传输层对象会通过 SSE 连接向客户端发送这一消息。
客户端的传输层对象在接收到后,会将返回的内容一直向上传递到运行层对象,然后再返回给上层的调用者,
-
工具调用过程:
整个过程其实和工具发现过程非常类似,这里就不再赘述。唯一的区别在于服务端的会话层对象执行逻辑不同,此时其会调用相应的工具并等待调用结果,最后再把这个结果通过传输层返回给客户端。
详细的交互流程如下图所示:

四、核心组件源码剖析
在上一章中,我们深入解析了 MCP 客户端与服务端在 SSE 模式下的核心交互流程,从构建与连接、初始化,到工具的发现与调用,全流程呈现了分层架构下各模块的协作机制。理解了交互逻辑之后,本章将以 Spring AI MCP 的源码为基础,剖析其核心组件的实现细节,以更好地理解其内部的运作方式。
这里先给出 MCP 客户端、服务端的完整类图,后续会逐层拆分这个类图,自上而下地讲解各个层次涉及到的源码。这里我使用的源码版本为 0.10.0(github.com/modelcontex…),对应 Spring AI 1.0.0 版本内使用的 mcp 版本。

五、运行时断点追踪
在前面的章节中,我们从架构、交互流程、核心源码三个角度剖析了 Spring AI MCP 的整体设计与关键实现,理清了各层之间的职责划分与调用关系。为了让大家能直观地看到 MCP 在实际运行时的交互过程,这一章将通过断点调试的方式,以服务端源码的视角,深入演示 SSE 模式下客户端与服务端初始化的过程。在理解了初始化这个比较复杂的过程后,其他的过程也是非常类似的,感兴趣的同学可以按照下面的步骤搭建好环境后自行调试。
5.1 环境搭建
pom 依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>io.modelcontextprotocol.sdk</groupId><artifactId>mcp</artifactId><version>0.10.0</version></dependency>
工程代码:
import org.springframework.boot.web.servlet.ServletRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.EnableWebMvc;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import com.fasterxml.jackson.databind.ObjectMapper;import io.modelcontextprotocol.server.transport.HttpServletSseServerTransportProvider;@Configuration@EnableWebMvcpublicclassMcpServerConfigimplementsWebMvcConfigurer {@Beanpublic HttpServletSseServerTransportProvider servletSseServerTransportProvider() {return HttpServletSseServerTransportProvider.builder().objectMapper(newObjectMapper()).messageEndpoint("/mcp/message").build();}@Beanpublic ServletRegistrationBean customServletBean(HttpServletSseServerTransportProvider transportProvider) {returnnewServletRegistrationBean(transportProvider);}}import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.ConfigurableApplicationContext;import io.modelcontextprotocol.server.McpServer;import io.modelcontextprotocol.server.McpServerFeatures;import io.modelcontextprotocol.server.McpSyncServer;import io.modelcontextprotocol.server.transport.HttpServletSseServerTransportProvider;import io.modelcontextprotocol.spec.McpSchema;@SpringBootApplicationpublicclassMcpServerApplication {publicstaticvoidmain(String[] args) {ConfigurableApplicationContextcontext= SpringApplication.run(McpServerApplication.class, args);HttpServletSseServerTransportProvidertransportProvider= context.getBean(HttpServletSseServerTransportProvider.class);varschema="""{"type" : "object","id" : "urn:jsonschema:Operation","properties" : {"operation" : {"type" : "string"},"a" : {"type" : "number"},"b" : {"type" : "number"}}}""";varsyncToolSpecification=newMcpServerFeatures.SyncToolSpecification(newMcpSchema.Tool("calculator", "Basic calculator", schema),(exchange, arguments) -> {Stringoperation= (String) arguments.get("operation");doublea= Double.parseDouble(String.valueOf(arguments.get("a")));doubleb= Double.parseDouble(String.valueOf(arguments.get("b")));double resultValue;switch (operation) {case"add":resultValue = a + b;break;case"subtract":resultValue = a - b;break;case"multiply":resultValue = a * b;break;case"divide":if (b == 0) {returnnewMcpSchema.CallToolResult("Error: Division by zero", true);}resultValue = a / b;break;default:returnnewMcpSchema.CallToolResult("Error: Unknown operation '" + operation + "'", true);}Stringresult= String.valueOf(resultValue);returnnewMcpSchema.CallToolResult(result, false);});McpSyncServersyncServer= McpServer.sync(transportProvider).serverInfo("my-server", "1.0.0").capabilities(McpSchema.ServerCapabilities.builder().resources(true, true).tools(true).prompts(true).logging().completions().build()).build();syncServer.addTool(syncToolSpecification);}}
之后就可以运行 main 方法启动服务:

这里我使用的 MCP 客户端是 MCP Inspector,它是一个用于调试、测试和可视化交互的工具,相当于一个图形化的 MCP 客户端,可以直观地查看、调用和调试 MCP Server 的各种能力。安装了 Node.js 后,就可以用下面的命令启动 MCP Inspector:
npx @modelcontextprotocol/inspector
启动后的界面如下所示:

5.2 断点演示
在第三章讲解初始化过程时,提到初始化过程包含两大步骤:初始化建立、初始化完成通知,而对于这两个步骤,客户端都会发送 POST 请求,因此这里首先需要把断点设置在服务端会话管理层HttpServletSseServerTransportProvider 中接收 POST 请求的方法 doPost()。在 MCP Inspector 中触发这一步骤的方式就是点击 Connect 按钮,在连接完成后,就会发送 POST 请求触发初始化过程。
5.2.1 初始化建立
初始化建立过程如下所示,可以看到客户端发送了 POST 请求,请求路径为 /mcp/message(对应于服务端设置的消息端点地址),且通过请求参数中的 sessionId(这个 id 是客户端在连接过程得到的)获得到对应的会话对象,然后再通过会话层对象处理 JSON-RPC 消息。

会话层对象在 handle() 方法里判断了消息的类型,这里为请求类型,之后走入 handleIncomingRequest() 方法。如下所示。
handleIncomingRequest() 这个方法会修改服务端的状态为 STATE_INITIALIZING(初始化中),然后再让请求处理器处理这个请求。如下所示。

处理器的实现对应于 asyncInitializeRequestHandler() 方法(这个方法的定义在运行层 McpAsyncServer 中,以 lambda 的方式传给了会话对象),这个方法会构建给客户端的返回结果,即服务端的基本信息、协议版本等。如下所示。

最后则调用传输层 HttpServletMcpSessionTransport 的 sendMessage() 方法通过 SSE 连接发送结果消息给客户端。如下所示。

5.2.2 初始化完成通知
初始化完成过程通知的过程与前面初始化建立过程非常类似,也是会话管理层接收 POST 请求后转发给会话层处理,区别在于会话层的处理逻辑不同,下面的演示仅展示不同之处。
在会话层的 handle() 方法中,此时的消息类型为通知类型,因此会走入 handleIncomingNotification() 方法,如下所示。

handleIncomingNotification() 方法会将服务端的状态设置为 STATE_INITIALIZED(初始化完成),然后再让通知处理器处理这个请求。
而这个处理器实际上并没有做任何事情,在运行层 McpAsyncServer 构造方法中 lambda 设置为 Mono::empty,即不做任何事。如下所示。

六、总结与思考
整体来看,Spring AI 对 MCP 的实现体现出高度的架构一致性与抽象优雅性。无论是客户端还是服务端,其都以分层化、接口化的方式将核心协议能力抽离出来,使得通信、会话、工具调用等功能可以在统一模型下协同运作。这种设计既延续了 Spring 体系一贯的“以接口驱动框架”的哲学,也让 MCP 能够以极低耦合的方式嵌入到更广泛的 AI 应用场景中。
从源码层面看,Spring AI MCP 的关键特征在于“对称与解耦”。客户端与服务端的类结构几乎是镜像式的存在,这种对称设计不仅提升了理解与调试的便利性,也为未来的扩展(如自定义 Transport、工具注册机制或新能力声明)提供了天然的空间。而在运行时,通过事件流与异步机制,系统实现了协议层与执行层的彻底分离,使开发者能够在保持高抽象层的同时,精确掌握底层交互细节。
更深层次地,Spring AI 对 MCP 的实现并非简单的协议落地,而是一种“开发者可控的 AI 接口体系”的探索。它将“模型上下文协议”转化为可编程的交互骨架,让语言模型不再是黑盒,而成为可管理、可调度的服务端实体。
这种思路的价值,不仅在于当前的 Agent 应用,更可能成为未来 AI 平台化、模块化发展的关键基石。可以预见,随着 MCP 标准的不断完善以及 Spring AI 的生态扩展,这一体系将从“实验性框架”走向“基础设施级组件”。在那之前,理解其源码设计与运行原理,正是开发者掌握下一代 AI 系统构建方式的最好起点。
参考资料
-
Spring AI MCP 浅析_springboot mcp如何告诉大模型参数含义-CSDN博客 -
SpringAI(GA):MCP源码解读 -
github.com/modelcontex… -
深度挖掘MCP协议底层架构,单步跟踪细节一览无遗_哔哩哔哩_bilibili -
modelcontextprotocol.io/sdk/java/mc…
相关内容:https://mcpcn.com/
如喜欢本文,请点击右上角,把文章分享到朋友圈如有想了解学习的技术点,请留言给若飞安排分享
因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享
·END·
相关阅读:
一张图看懂微服务架构路线 基于Spring Cloud的微服务架构分析 微服务等于Spring Cloud?了解微服务架构和框架 如何构建基于 DDD 领域驱动的微服务? 微服务架构实施原理详解 微服务的简介和技术栈 微服务场景下的数据一致性解决方案 设计一个容错的微服务架构
作者:小璐乱撞
来源:juejin.cn/post/7570935965435641871
版权申明:内容来源网络,仅供学习研究,版权归原创者所有。如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!
我们都是架构师!

关注架构师(JiaGouX),添加“星标”
获取每天技术干货,一起成为牛逼架构师
技术群请加若飞:1321113940 进架构师群
投稿、合作、版权等邮箱:admin@137x.com
夜雨聆风
