
一条命令搞定!存量 Spring REST 服务秒变 MCP 服务
TL;DR
在 AI 技术浪潮中,MCP 为服务集成带来了创新性思路,LLM 与 MCP 的组合更是为存量 API 服务注入新活力。
本文先阐述基于 Spring AI MCP 开发 MCP 服务的详细步骤,随后引入 OpenRewrite 框架及其 spring-rest-to-mcp 工具,实现 Spring REST 服务到 MCP 服务的自动化转换。
最后,借助示例项目,全方位展示从环境搭建、代码转换到任务编排执行的完整流程,助力开发者快速打通存量 Spring REST 服务对接 MCP 协议的通道,大幅提升服务集成的灵活性与智能化水平 。
背景
在上一篇 超越 API:MCP 如何成为 AI 时代的 “万能适配器”? 文章发布后,我一直思考一件事。如果将以往的 API 集成看作系统的硬链接,那么 LLM + MCP 无疑是系统的软链接。MCP 的诞生,使我们能在运行时动态连接不同服务,摆脱设计阶段的束缚,实现更为灵活、智能的服务集成模式。
由此可见,LLM + MCP 的组合,对存量 API 服务而言是重大利好(当然也利好 LLM/GenAI 应用)。借助 MCP 的声明式服务描述,LLM 能自动获取并理解服务能力,实现服务的智能编排与调用。存量 API 服务只需实现 MCP 声明式服务描述,就能被 LLM 自动编排和调用。
那么,如何将存量 API 转换为 MCP 服务呢?有没有便捷的方法,比如一条命令就能完成?要是不行,两条命令也行。
接下来,先看看如何基于 3 月发布的 Spring AI 1.0.0-SNAPSHOT 开发 MCP 服务。熟悉 Spring AI MCP 的读者,可直接跳过此部分,前往 OpenRewrite 章节。
Spring AI MCP
MCP Java SDK 为 MCP 提供了 Java 语言实现,支持通过同步和异步通信模式,与 AI 模型和工具进行标准化交互。Spring AI MCP 则在 Spring Boot 框架下,对 MCP Java SDK 进行了扩展,提供了 客户端 和 服务器 启动器。
Client Starters:
spring-ai-starter-mcp-client
- 核心启动器提供 STDIO 和基于 HTTP 的 SSE 支持spring-ai-starter-mcp-client-webflux
基于 WebFlux 的 SSE 传输实现
Server Starters:
spring-ai-starter-mcp-server
- 具有 STDIO 传输支持的核心服务器spring-ai-starter-mcp-server-webmvc
- 基于 Spring MVC 的 SSE 传输实现spring-ai-starter-mcp-server-webflux
- 基于 WebFlux 的 SSE 传输实现
下面我们以 MVC-based SSE 类型的 MCP 服务为例,介绍如何开发一个简单的 MCP 服务。
代码实现
Spring AI 提供的注解极大简化了代码编写流程,下面具体介绍开发步骤。在 spring-ai-starter-mcp-server-webmvc
包中,提供了以下功能支持:
- 服务端 Tool 发生变更时,向客户端发送变更通知。
- 根据服务类型,自动为 Tool 切换同步或异步规范。
- 通过 Spring Beans 机制,为 Tool 自动生成规范。
1. 引入依赖
由于 Spring AI 当前处于 SNAPSHOT 阶段,需从特定快照仓库获取依赖。
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<name>Central Portal Snapshots</name>
<id>central-portal-snapshots</id>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
依赖可以通过 spring-ai-bom 引入依赖。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
</<dependencies>
也可以直接引用 1.0.0-SNAPSHOT 版本的 starter。
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</<dependencies>
2. 编写 Tool 类
写一个简单的服务类提供两个 Too:一个返回静态结果,另一个通过请求内容返回动态的结果。这里用到了两个注解 @Tool 和 @ToolParam
@Service
public class HelloService {
@Tool(description = "say hello")
public String hello() {
return "hello, devops";
}
@Tool(description = "say hello to someone")
public String helloTo(@ToolParam(description = "name of the guy you want to say hello to") String name) {
return "Hello, " + name;
}
}
3. 注册 Tool
通过定义 ToolCallbackProvider Bean 来注册上面编写的 Tool 类。
@Bean
ToolCallbackProvider toolCallbackProvider(HelloController helloController) {
return MethodToolCallbackProvider.builder()
.toolObjects( helloController)
.build();
}
4. 服务配置
在 application.yml 加入如下的配置,name、version 和 sse-message-endpoint 可以根据需要自定义;type 这里选择 SYNC(还支持异步服务 ASYNC)。
spring:
ai:
mcp:
server:
name: webmvc-mcp-server
version: 1.0.0
type: SYNC
sse-message-endpoint: /mcp/messages
5. 测试
使用 MCP 官方的调试工具 Inspector 进行测试。服务类型选择 SSE,地址使用 http://localhost:8080/sse 。通过 List Tools 查看服务的 Tool 列表,可选择其中任意一个进行测试。
6. 思考
通过几个简单的注解和配置,就能实现一个 MCP 服务。在实际开发中,复杂部分主要在于具体业务逻辑,如调用其他服务、访问数据库、缓存或文件系统等,这与编写普通 Spring Boot 服务并无二致。
回顾定义的 Tool 类,它本质上是通过 @Service
注解定义的普通 Bean,再使用 Spring AI MCP 的注解进行标注,其余工作由框架完成,包括 Tool 参数规范等。
@Tool
:定义 Tool,描述其功能。@ToolParam
:定义 Tool 参数,并对参数进行描述。
这种 Tool Bean 的定义方式,与定义 Controller 类颇为相似,主要区别在于方法和参数说明。
@RestController
public class HelloController {
/**
* say hello
*
* @return hardcoded hello world
*/
@GetMapping("/hi")
public String hello() {
return "Hello, world";
}
/**
* say hello to some guy
*
* @param name name of the guy you want to say hello
* @return hello message
*/
@GetMapping("/hi/{name}")
public String helloTo(@PathVariable("name") String name) {
return "Hello, " + name;
}
}
由此不禁思考,能否将现有 API 服务转换为 MCP 服务,且无需手动编写 Tool 类,通过简单命令就能完成?答案是肯定的,借助 OpenRewrite 就能实现这一目标。
OpenRewrite
OpenRewrite 是由 Moderne 公司开源的自动化重构框架。它的目标是通过一系列可组合的“配方”(官方术语 Recipes,可以理解为重构规则,为了更贴近官方文档的术语,将其翻译为配方。)在无需手动干预的情况下对代码进行有条理的结构重写。简言之,它不是简单的全局替换字符串工具,而是能基于 无损语义树(LST) 进行语义级别的代码修改。
LST 的特点是无损地保留了原始源代码的所有细节信息,这不仅包括代码的语法和语义,还包含了空格、换行、注释、格式化风格等。
此前,我发布过几篇关于 OpenRewrite 的学习笔记,因时间原因未能持续更新。今天这篇也算对之前学习的总结,后续我会继续分享近期的学习心得和笔记。
这里不展开介绍 OpenRewrite,感兴趣的读者可参考我之前的学习笔记:
- OpenRewrite 学习笔记(一):基本知识与原理解析
- OpenRewrite 学习笔记(二):无损语义树 LST
- OpenRewrite 学习笔记(三):重构配方 Recipe 与访问者 Visitor
- OpenRewrite 学习笔记(四):使用 JavaTemplate 创建复杂 LST
配方 spring-rest-to-mcp
接下来进入今天的重点部分,我们将使用 OpenRewrite 将现有的 Spring REST 服务自动转换成 MCP 服务。我们需要编写 Recipe 配方实现如下功能:
- 将 Spring Web 注释转换为 Spring AI MCP
@Tool
注解 - 添加必要的 MCP 配置和组件
- 更新 Maven 依赖项
这些配方自动从 Controller 的 javadoc 中提取方法描述和参数描述,并将其转换为 MCP 的 @Tool
和 @ToolParam
注解。
使用 OpenRewrite 开发的工具我已经发布到了 GitHub 仓库 spring-rest-to-mcp,欢迎大家下载体验。
目前工具的运行需要 Java 17 和 Maven 3.6+ 的环境,带转换的 API 需要 SpringBoot 3.x 版本并使用 Maven 作为构建工具。
该工具实现的效果
转换前的 Spring Web Controller:
@RestController
public class UserController {
/**
* Get all users
*
* @return list of users
*/
@GetMapping("/users")
public List<User> getUsers() {
//Implementation
}
/**
* Add a new user
*
* @param user user to add
* @return success message
*/
@PostMapping("/users")
public String addUser(User user) {
//Implementation
}
}
转换后的 MCP Tool(同时兼容 REST):
@RestController
public class UserController {
/**
* Get all users
*
* @return list of users
*/
@GetMapping("/users")
@Tool(description = "Get all users")
public List<User> getUsers() {
//Implementation
}
/**
* Add a new user
*
* @param user user to add
* @return success message
*/
@PostMapping("/users")
@Tool(description = "Add a new user")
public String addUser(@ToolParam(description = "user to add") User user) {
//Implementation
}
}
接下来,通过实际场景进行演示。
演示
环境准备
1. 编译 spring-rest-to-mcp 工具
git clone https://github.com/yourusername/web-to-mcp.git
cd web-to-mcp
#可以添加 -DskipTests 跳过测试
mvn clean install
2. 示例项目
克隆示例项目:
git clone https://github.com/addozhang/spring-boot-3-rest-api-sample.git
cd spring-boot-3-rest-api-sample
查看示例项目结构:
- 这是一个标准的 Spring Boot 3 应用程序,带有 REST Controller
- 包含 HTTP 方法(GET、POST)的典型 REST 端点
- 包含正确的 JavaDoc 注释,这些注释将被转换为 MCP 工具描述
3. 代码转换
首先,运行 Maven 命令更新 POM 文件,添加所需的依赖项和库:
mvn org.openrewrite.maven:rewrite-maven-plugin:6.4.0:run \
-Drewrite.activeRecipes=RewriteWebToMCP \
-Drewrite.recipeArtifactCoordinates=com.atbug.rewrite:web-to-mcp:1.0-SNAPSHOT \
-Drewrite.exportDatatables=true
然后,再次运行相同的命令以执行实际的代码转换:
mvn org.openrewrite.maven:rewrite-maven-plugin:6.4.0:run \
-Drewrite.activeRecipes=RewriteWebToMCP \
-Drewrite.recipeArtifactCoordinates=com.atbug.rewrite:web-to-mcp:1.0-SNAPSHOT \
-Drewrite.exportDatatables=true
验证更改(转换后的代码,我提交到了 另一个分支):
- 检查的控制器类中是否添加了
@Tool
和@ToolParam
注解 - 查找的主应用程序类中的新
ToolCallbackProvider
Bean
启动服务(服务端口为 8080):
mvn spring-boot:run
测试
前文已介绍 MCP Inspector 工具,本次测试将其配置到 LLM 应用中。我使用的是 VSCode + Cline + DeepSeek API。
1. 配置 MCP 服务
在 Cline 中配置 MCP 服务:
{
"mcpServers": {
"spring-ai-mcp-sample": {
"autoApprove": [],
"disabled": false,
"timeout": 60,
"url": "http://localhost:8080/sse",
"transportType": "sse"
}
}
}
配置后会自动获取服务的 Tool 列表:
2. 编排任务
编排一项涉及多阶段操作,并需要调用多个 Tool 的任务。
先帮我查看一下用户列表,检查是否包含名为 Carson 的用户。如果没有,就添加一个新用户:Carson carson@gmail.com;再查询下列表查看新用户是否添加成功。最后向 Carson 打个招呼。
3. 任务执行
通过上述配置和操作,任务成功执行。