MCP(模型上下文协议)是现在非常火热的一项技术,是构建智能体的一种通用方法,市面上有很多介绍MCP的文章,这篇文章主要集中在如何使用Spring AI来构建MCP应用,并且通过Web接口将服务暴露出来,提供给前端使用。本文提供了三种实现MCP的方式,一种是通过stdio方式构建自己的MCP服务,并通过客户端调用;一种是通过sse方式构建自己的MCP服务,并通过客户端调用;还有一种是调用公开的MCP服务,实现我们需要的功能。

Spring AI 是 Spring 团队推出的一个面向人工智能工程的应用框架,旨在将 Spring 生态系统的设计原则(如可移植性、模块化设计)应用于 AI 领域,为 Java 开发者提供便捷的 AI 集成方案。
Spring AI 通过标准化接口、模块化设计和快速集成,降低了 Java 开发者使用 AI 技术的门槛。开发者无需深入理解不同 AI 模型的底层细节,即可通过统一的 API 与多种 AI 模型交互。
Spring AI 与 Spring Boot、Spring Data 等现有框架无缝集成,支持依赖注入、面向切面编程(AOP)等特性,便于开发者将 AI 功能嵌入企业级应用。
Spring AI支持向量数据库,实现了RAG(检索增强生成)、MCP(模型上下文协议)、日志控制、大模型聊天等功能,几乎覆盖使用LLM开发AI应用的方方面面。
一、使用Spring AI进行大模型对话
使用Spring AI进行应用开发首先要在pom.xml文件中添加spring ai的包:
<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-deepseek</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-autoconfigure-model-chat-memory</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!--Spring AI BOM-->
<!--先添加BOM再添加openai依赖-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在项目的application.yml文件中配置聊天大模型:
server:
port: 8080
spring:
ai:
openai:
api-key: <API KEY>
base-url: https://api.deepseek.com
chat:
options:
model: deepseek-chat
deepseek:
api-key: <API KEY>
chat:
options:
model: deepseek-reasoner
接下来就可以构建一个controller,并在controller中提供聊天的接口,前端通过访问这个接口就可以和大模型进行聊天了。
@RestController
public class OpenAiController {
ChatClient chatClient;
public OpenAiController(OpenAiChatModel openAiChatModel,
ChatMemory chatMemory,
ToolCallbackProvider toolCallbackProvider) {
this.chatClient = ChatClient.builder(openAiChatModel).build();
}
// 普通接口
@RequestMapping(value = "/chat", produces = "text/html; charset=utf-8")
public String chat(@RequestParam(value="message", defaultValue = "你好") String message) {
return this.chatClient.prompt()
.options(DeepSeekChatOptions.builder().temperature(0.9).build())
.user(message).call().content();
}
// 流式接口
@RequestMapping(value = "/chat_stream", produces = "text/stream; charset=utf-8")
public Flux<String> chat_stream(@RequestParam(value="message", defaultValue = "你好") String message) {
Flux<String> result = this.chatClient.prompt()
.options(DeepSeekChatOptions.builder().temperature(0.9).build())
.user(message).stream().content();
//result.toIterable().forEach(System.out::println);
return result;
}
}
二、Stdio模式的MCP服务构建
在springboot工程启动后,我们就可以在浏览器中进行测试了。不过这样构建出来的应用程序只能实现最基本的对话功能,不能让大模型具备更多的能力,而通过增加MCP工具调用的能力,大模型可以帮我实现各种功能,极大的拓展它的应用领域。MCP主要分为三种模式:stdio,sse和streamable http,不过目前stdio和sse用的比较多,所以本文只考虑前两种。
stdio一般是部署在本地的MCP服务,用来拓展大模型的能力,实现某些具体的功能,stdio一般效率会更高,安全性会更好。要使用stdio方式的MCP工具,我们首先需要构建一个MCP本地服务端,并打包成jar文件,然后在需要使用的MCP客户端中调用这个jar提供的MCP工具。这里,我构建了一个MCP本地服务,我会给出一个文件夹,功能是统计这个文件夹中文件的数目。
首先,构建一个工程,包含服务端和客户端,目录结构如下:

服务端的pom文件核心要配置:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server</artifactId>
</dependency>
客户端的pom文件核心要配置:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-deepseek</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-client-chat</artifactId>
</dependency>
在服务端,只需要把具体的MCP工具功能实现,并通过ToolCallbackProvider将工具暴露出来即可:
@Service
public class FileService {
@Tool(description = "获取文件夹内文件的数量")
public String getFileCount(String folderPath) {
File folder = new File(folderPath);
// 检查路径是否存在且是文件夹
if (folder.exists() && folder.isDirectory()) {
// 获取文件列表(不包括子目录)
File[] files = folder.listFiles(File::isFile); // 仅文件
// File[] files = folder.listFiles(); // 文件 + 目录
if(null==files) {
return "读取出错";
}
return String.valueOf(files.length);
} else {
return "路径不存在或不是文件夹";
}
}
}
@SpringBootApplication
public class App
{
public static void main( String[] args )
{
SpringApplication.run(App.class, args);
}
@Bean
public ToolCallbackProvider fileTools(FileService fileService) {
return MethodToolCallbackProvider.builder().toolObjects(fileService).build();
}
}
之后,就可以将MCP服务端打包成jar文件。
在客户端,我们只需要在之前的普通聊天程序基础上,在ChatClient中加入toolCallbackProvider就可以了。主要是需要在配置文件中配置一下这个MCP服务。
this.chatClient = ChatClient.builder(openAiChatModel)
.defaultAdvisors(new SimpleLoggerAdvisor()) // 日志拦截器
.defaultSystem("请讲中文")
.defaultToolCallbacks(toolCallbackProvider) // MCP工具
.build();
在application.yml中指出我们的MCP服务配置地址:
spring:
ai:
mcp:
client:
request-timeout: 50000
stdio:
# 1.单独放在一个json文件(推荐)
servers-configuration: classpath:/mcp/mcp-servers-config.json
openai:
api-key: <API KEY>
base-url: https://api.deepseek.com
chat:
options:
model: deepseek-chat
logging:
level:
org:
springframework:
ai:
chat:
client:
advisor:
SimpleLoggerAdvisor: DEBUG
server:
port: 8080
之后在mcp-servers-config.json中给出我的jar包地址和启动参数即可。
{
"mcpServers": {
"mcp-server-file": {
"command": "java",
"args": [
"-Dspring.ai.mcp.server.stdio=true",
"-Dlogging.pattern.console=",
"-jar",
"D:\\work\\2025AI项目\\code\\stdio-mcp\\mcp-server\\target\\mcp-server-1.0-SNAPSHOT.jar"
]
}
}
}
下面是聊天的测试结果,可以看到,可以正常返回我们的文件夹内文件的数量。

三、SSE模式的MCP服务构建
利用Spring AI构建sse模式的MCP服务其实跟构建stdio的模式的MCP服务非常像,主要区别就在于引入的包不同,application.yml的配置项有点区别。
在sse模式的MCP Server项目中,需要在pom.xml中配置:
<dependencies>
<!-- MCP Server -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>
</dependencies>
server端的application.yml无需特殊配置
spring:
ai:
mcp:
server:
name: weather
version: 1.0.0
type: async
server:
port: 8088
核心MCP工具代码,我这个通过RestTemplate来获取天气接口的数据,实现了根据城市获取天气的功能:
@Service
public class UserToolService {
@Autowired
private RestTemplate restTemplate;
public String getWeatherData(String city) {
return restTemplate.getForObject("https://api.openweathermap.org/data/2.5/weather?q={city}&appid=d82113f3af7c2d7e142828449d5efc0a", String.class, city);
}
@Tool(description = "根据城市获取天气信息")
public String getWeather(String city) {
return getWeatherData(city);
}
}
同时和stdio模式类似,要通过ToolCallbackProvider把MCP工具暴露出去。
在客户端,需要在pom.xml中做如下配置:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-deepseek</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-client-chat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
在application.yml中需要声明sse模式的连接地址:
spring:
ai:
mcp:
client:
toolcallback:
enabled: true
enabled: true
request-timeout: 60000
sse:
connections:
UserSSEInfo:
url: http://localhost:8088
openai:
api-key: <APK KEY>
base-url: https://api.deepseek.com
chat:
options:
model: deepseek-chat
server:
port: 8080
其余代码和stdio模式的客户端代码几乎一样了,在controller中构建ChatClient,声明一下toolCallbackProvider即可。下面是我测试一下获取北京的天气,可以看到回复还是不错的。

四、公开MCP服务的调用
MCP服务还有一个很有意思的应用,就是通过接入公开发布的各种MCP服务,极大的拓展我们的应用程序能力边界,从而实现很多非常复杂的功能。接入公开MCP服务,我们不需要再开发服务端,直接开发一个MCP的客户端即可。我们只需要在application.yml中声明我们的MCP配置信息,或者将配置信息写在一个文件中,并在MCP配置文件中声明MCP的调用参数即可。我这边是接入了百度地图的公开MCP服务。
pom.xml和普通的MCP服务客户端差不多,主要看一下application.yml:
server:
port: 8080
spring:
ai:
mcp:
client:
request-timeout: 5000
stdio:
# 配置信息单独放在一个json文件中
servers-configuration: classpath:/mcp/mcp-servers-config.json
openai:
api-key: <API KEY>
base-url: https://api.deepseek.com
chat:
options:
model: deepseek-chat
deepseek:
api-key: <API KEY>
chat:
options:
model: deepseek-reasoner
下面,我在mcp-servers-config.json中配置了百度地图公开MCP服务的信息:
{
"mcpServers": {
"baidu-map": {
"command": "cmd",
"args": [
"/c",
"npx",
"-y",
"@baidumap/mcp-server-baidu-map"
],
"env": {
"BAIDU_MAP_API_KEY": <百度地图API KEY>
}
}
}
}
其余和前面两种MCP模式的代码几乎一致,controller甚至可以不改,直接搬过来用。测试结果如下:

可以看到通过百度地图公开的MCP查询到了我们需要的路线情况,其实通过百度地图还可以获取到天气等等信息。
MCP确实极大的提升了系统的应用能力,甚至可能改变应用程序开发的模式,结合增强检索生成(RAG)等技术,可以实现很多功能强大的AI应用。