Spring AI + MCP 将后端服务改造成 MCP 服务实践
本文主要介绍 Spring AI 与 MCP 的集成实践。
一、SpringBoot 版本要求
接下来介绍如何将我们的后端服务改造成 MCP 服务,首先,SpringAI 对 SpringBoot 版本有要求,需要 SpringBoot 3.4.x 及以上版本,本文案例使用 3.4.12 版本。如果原有服务版本不是 3.4.x 的,需要升级,JDK 版本最低需要 JAVA 17。我们可以先创建一个简单的项目来帮助我们了解 MCP 的落地效果,然后再慢慢升级已有的服务。
二、服务端(Server)开发
看过 MCP 文档的都知道,MCP 主要包含 服务端(Server)和 客户端 (Client),我们先创建一个服务端的 springboot 项目 spring-ai-mcp-server,注意 springboot 的版本需要 3.4.x 或以上。
1. 在 pom.xml 中添加 Maven 依赖和 spring-ai 相关配置
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<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>
2. 在 application.yml 中配置项目信息
spring:
application:
name: spring-ai-mcp-server
ai:
mcp:
server:
name: spring-ai-mcp-server
version: 1.0.0
server:
port: 8888
3. 编写 Service,并标注为 MCP 工具
这里的 Service 和我们后端服务的 Service 一样的,就是多了 MCP 工具标注@Tool。
package com.example.springaimcpserver.service;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Service;
import com.example.springaimcpserve.pojo.param.EmployeeQueryParam;
import com.example.springaimcpserve.pojo.vo.EmployeeVO;
@Slf4j
@Service
public class MyMcpService {
@Tool(name = "get-company-info", description = "获取公司全称")
public String getCompanyInfo() {
log.info("获取公司全称");
return "xxx 有限责任公司";
}
@Tool(name = "get-dep-info", description = "获取部门列表")
public List<String> getDepList() {
log.info("获取部门列表");
return List.of("研发部", "人事部", "销售部", "广告部", "......");
}
@Tool(name = "get-all-employee-list", description = "获取所有员工列表")
public List<String> getAllEmployeeList() {
log.info("获取所有员工列表");
return List.of("张三", "李四", "小明", "小红", "小花", "小军", "小勇", "小兰");
}
@Tool(name = "get-dep-employee-list", description = "获取部门员工列表")
public List<EmployeeVO> getDepEmployeeList(EmployeeQueryParam param) {
log.info("获取{}部门员工列表", param.getDepartment());
Map<String, List<EmployeeVO>> map = new HashMap<>();
map.put("研发部", List.of(new EmployeeVO("张三", "研发部"), new EmployeeVO("李四", "研发部")));
map.put("人事部", List.of(new EmployeeVO("小明", "人事部"), new EmployeeVO("小红", "人事部")));
map.put("销售部", List.of(new EmployeeVO("小花", "销售部"), new EmployeeVO("小军", "销售部")));
map.put("广告部", List.of(new EmployeeVO("小勇", "广告部"), new EmployeeVO("小兰", "广告部")));
return map.get(param.getDepartment());
}
@Tool(name = "get-employee-count", description = "获取员工数量")
public Integer getEmployeeCount() {
log.info("获取员工数量");
return 8;
}
}
为了演示方便,这里的数据都是虚构的,实际应用中直接从数据库获取,上述代码中涉及到的实体类如下:
员工信息实体 EmployeeVO
package com.example.springaimcpserver.pojo.vo;
import lombok.Data;
import org.springframework.ai.tool.annotation.ToolParam;
@Data
public class EmployeeVO {
@ToolParam(description = "姓名")
private String name;
@ToolParam(description = "部门")
private String department;
//构造函数
public EmployeeVO(String name, String department) {
this.name = name;
this.department = department;
}
}
员工信息查询参数 EmployeeQueryParam
package com.example.springaimcpserver.pojo.param;
import lombok.Data;
import org.springframework.ai.tool.annotation.ToolParam;
@Data
public class EmployeeQueryParam {
@ToolParam(description = "部门")
private String department;
}
上面的 Service 和相关实体仅仅只是比我们平常开发多了 MCP 的相关注解,不影响 Controller 的调用,也就是可以同时使用接口直接调用,也可以通过 MCP 调用,后面继续讲解如何实现 MCP 方式调用。
服务编写好之后,我们需要将该服务里面的方法配置成可以调用的 MCP 工具,可以理解成工具注册。
4. 编写配置类,将 Service 里面的工具暴露出来
package com.example.springaimcpserver.config;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.example.springaimcpserver.service.MyMcpService;
@Configuration
public class ToolCallbackProviderConfig {
@Autowired
private MyMcpService myMcpService;
@Bean
public ToolCallbackProvider toolCallbackProvider() {
//这里可以添加多个服务类,多个的时候直接在 toolObjects 里面传多个即可
return MethodToolCallbackProvider.builder().toolObjects(myMcpService).build();
}
}
上面的代码都编写好以后,我们的 MCP 的服务端就开发好了,接下来开发客户端。
三、客户端(Client)开发
创建一个新的 springboot 项目 spring-ai-mcp-client,注意 springboot 的版本需要 3.4.x 或以上。MCP 架构是大模型驱动的,所以我们还需大模型的支持,这里使用的是 deepseek。
然后去 API keys 里面创建一个 key,用来调用 deepseek 的接口(Spring AI 自动调用,我们不需要手动调用,只需要配置到我们的项目中即可,后面会讲到配置在什么地方)。
1. 在 pom.xml 中添加 Maven 依赖和 spring-ai 相关配置以及 deepseek 的依赖配置
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<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>
2. 在 application.yml 中配置项目信息以及 deepseek 配置
spring:
application:
name: spring-ai-mcp-client
ai:
mcp:
client:
name: spring-ai-mcp-client
version: 1.0.0
toolcallback:
enabled: true
type: sync
sse:
connections:
server1:
url: http://localhost:8888
deepseek:
api-key: "这里替换成你的 API key"
server:
port: 8880
上面配置了我们的 MCP 服务端的地址以及使用的大模型 deepseek 的 API key。
3. 编写 Controller 提供对外访问的统一接口
package com.example.springaimcpclient.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.mcp.SyncMcpToolCallbackProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "/chat")
public class MyChatController {
@Autowired
private ChatClient.Builder builder;
@Autowired
private SyncMcpToolCallbackProvider provider;
@PostMapping("/ask")
public String ask(@RequestParam("question") String question) {
ChatClient chatClient = builder.defaultSystem(
"你是 xxx 公司的一名行政 AI 助手,你的名字叫小静。你可以帮助用户解答关于 xxx 公司相关的知识").build();
return chatClient.prompt().user(question).toolCallbacks(provider.getToolCallbacks()).call().content();
}
}
四、效果演示
1. 启动服务端(8888 端口)
启动成功后,可以看到有五个工具,也就是我们 service 里面加了@Tool 注解的 5 个方法。
2. 启动客户端(8880 端口)
3. 访问客户端 controller 里面的 /chat/ask 接口,通过聊天方式调用你的 MCP 服务。
我这里使用 postman 作为演示工具,输入问题查看效果:公司有多少人?有哪些部门?每个部门有多少人?张三是哪个部门的?
可以看到,我们只有一个聊天的接口,并没有指定去调用服务端的某个方法,使用 MCP 架构之后,AI 能够自动的去识别和编排工具(方法)的调用顺序,服务端的日志如下:
此致,整个案例的落地分享结束。


