Spring Boot+MCP实战:存量Java服务AI可调用工具指南

2026-06-12阅读 0热度 0
ai
好的,作为一名在该领域深耕多年的技术专家,我来把这篇文章从AI生成的“标准件”,变成一篇有温度、有节奏、读起来像老司机手把手分享的技术实战笔记。 聊个实际问题:在企业里头,那些跑了四五年的Spring Boot系统,个个都身经百战,承载着最核心的业务逻辑、数据和流程,早就是数字化的命根子了。但现在大模型和AI应用越来越火,一个普遍的尴尬就冒出来了——这些成熟的老系统,虽然有完整的接口和数据,但AI根本认不出来,更别说直接调用了。数据跟智能之间,硬生生隔了一堵墙。 传统的解决办法是什么?人工导出数据,复制粘贴到AI对话框里,效率低得让人抓狂,而且还提心吊胆的,生怕薪资这种敏感数据在传递过程中泄露。MCP(模型上下文协议)出来之后,搭配上Spring AI生态,这事儿就有了新思路。它能用一种轻量化、无侵入的方式,让咱们手头这些老旧的Spring Boot系统接上AI。 这篇文章,就拿一个企业人力资源管理系统来当例子,一步步教你怎么基于SSE传输模式把MCP服务端和客户端搭起来。最关键的是,你原有业务代码一行都不用改,就能让老系统无缝对接各种AI工具,实现用自然语言查业务、做统计、走流程。 ## 一、业务困境:存量Ja va系统与AI的对接鸿沟 这次实战选的载体,是个稳定跑了五年的员工绩效与薪酬管理平台。技术栈是Ja va 17搭配Spring Boot 3.x,持久层用MyBatis拉了数据,里面有员工管理、薪资统计、绩效考评三大块,接口文档齐全,业务逻辑也都经过考验了。 当公司想用AI来提升办公效率,比如用自然语言分析一下部门薪资结构,或者筛选出优秀晋升候选人,再或者批量生成绩效报告时,原有系统的短板就彻底暴露了。传统模式是:工作人员登录系统,手动查数据,导出Excel,再把文件内容粘到AI对话框里。整个流程全靠人工中转,不光耗时费力,还容易出错。薪资这种敏感数据在导出和传递过程中,安全风险也很大。更关键的是,AI根本调不动系统接口,那些业务接口对AI来说就是一堆无意义的字符,两者之间缺个标准化的桥梁。 想彻底解决这个问题,肯定不能去重构老系统,那成本太高了。最好的办法就是在现有系统外层搭个适配层,用MCP协议把业务方法封装成AI能认的工具。这样一来,AI调用Spring Boot里的业务逻辑,就像调用自己内置的能力一样,实现“AI提问、系统执行、结果反馈”的全自动链路。 ## 二、技术选型解析:MCP协议与SSE传输模式优势 MCP是专门用来打通大模型和外部应用的标准化协议。它定义了一套统一的工具描述、参数传递和结果返回规范,让不同技术栈的系统都能快速对接各种AI客户端。Spring AI 1.0.0及以上版本原生就提供了MCP相关的启动器,支持两种主流的传输模式:STDIO和SSE。考虑到企业多客户端、远程访问的场景,这次实战我们全程选用SSE(服务器推送事件)模式。 STDIO模式是把MCP服务当成AI客户端的子进程来跑的,依赖标准输入输出通信,只适合本地单场景调试。它有三个硬伤:第一,Spring Boot启动时的日志、Banner这些输出内容会破坏STDIO的JSON-RPC数据格式,得额外屏蔽所有控制台输出;第二,每个AI客户端都会独占一个独立的JVM进程,没法实现服务共享;第三,只支持本地访问,不能部署到服务器上让大家一起用。 而SSE模式就把MCP服务改造成了一个标准的Spring Boot Web应用,通过专属的HTTP端点提供服务,完美适配企业生产环境。它沿用普通的Web应用部署和运维逻辑,支持多客户端远程并发连接,不用改造日志输出规则,也兼容内网服务器、云主机等各种部署环境,是企业级MCP服务的首选。 整套技术架构分四层,逻辑清晰,耦合度很低: * **第一层**是原有的Spring Boot业务层,所有Service和数据访问逻辑都保留,零修改。 * **第二层**是MCP工具封装层,通过注解把业务方法转化成MCP标准工具。 * **第三层**是MCP服务传输层,依靠Spring AI Starter自动暴露SSE端点。 * **第四层**是消费端,包括Claude、Cursor这些AI客户端,以及集成了MCP客户端的自有业务系统,这两类都能通过SSE协议远程调用服务。 整体工作流程也很直接:开发者或运维人员提出自然语言请求后,AI客户端会自动解析意图,通过SSE连接调用对应的MCP工具,MCP服务再转发请求到原有业务Service,执行完成后把结果一层层传回来,最后由AI整合数据生成分析结论,全程不需要人工干预。 ## 三、实战部署一:搭建MCP服务端(Spring Boot MCP Server) 这次实战分MCP服务端和MCP客户端两大块。我们先来搭承载原有HRM业务的MCP服务端,所有业务代码都保持原样,只新增MCP工具类和配置,实现无侵入改造。 ### 3.1 项目整体结构 先把项目目录结构规范一下,区分开领域实体、数据访问层、业务服务层和MCP工具层。目录结构如下: ``` hrm-mcp-server/ ├── pom.xml ├── src/main/ │ ├── ja va/com/example/hrm/ │ │ ├── HrmMcpApplication.ja va # 项目启动类 │ │ ├── domain/ # 领域实体类 │ │ │ ├── Employee.ja va │ │ │ ├── SalaryRecord.ja va │ │ │ └── PerformanceReview.ja va │ │ ├── repository/ # 数据访问层 │ │ │ ├── EmployeeRepository.ja va │ │ │ ├── SalaryRepository.ja va │ │ │ └── PerformanceRepository.ja va │ │ ├── service/ # 原有业务服务层 │ │ │ ├── EmployeeService.ja va │ │ │ ├── SalaryService.ja va │ │ │ └── PerformanceService.ja va │ │ └── mcp/ # 新增MCP工具封装层 │ │ ├── EmployeeTools.ja va │ │ ├── SalaryTools.ja va │ │ └── PerformanceTools.ja va │ └── resources/ │ └── application.yml # 全局配置文件 ``` ### 3.2 引入MCP相关Ma ven依赖 修改根目录的`pom.xml`,指定Spring Boot和Spring AI版本,引入MCP服务端核心启动器、Web、数据访问等依赖。完整配置如下: ```xml 4.0.0 org.springframework.boot spring-boot-starter-parent 3.4.5 com.example hrm-mcp-server 1.0.0-SNAPSHOT HRM MCP Server 21 1.0.0 org.springframework.ai spring-ai-bom ${spring-ai.version} pom import org.springframework.ai spring-ai-starter-mcp-server-webmvc org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-data-jpa com.h2database h2 runtime org.projectlombok lombok true org.springframework.boot spring-boot-ma ven-plugin ``` ### 3.3 全局配置文件(application.yml) 配置服务端口、数据库、MCP SSE端点和日志级别。SSE端点是AI客户端连接的核心地址,配置如下: ```yaml server: port: 8081 # MCP服务端端口 spring: application: name: hrm-mcp-server # H2内存数据库配置 datasource: url: jdbc:h2:mem:hrmdb;DB_CLOSE_DELAY=-1 driver-class-name: org.h2.Driver username: sa password: jpa: hibernate: ddl-auto: create-drop show-sql: false h2: console: enabled: true path: /h2-console # MCP SSE端点配置 ai: mcp: server: name: hrm-mcp-server version: 1.0.0 sse-message-endpoint: /mcp/message logging: level: root: WARN com.example.hrm: INFO ``` ### 3.4 领域实体、数据访问与业务服务层 这三层就是原来的业务代码,不需要修改,只做基础实现。先看员工、薪资、绩效这三大实体类,以员工实体为例: ```ja va // domain/Employee.ja va package com.example.hrm.domain; import jakarta.persistence.*; import lombok.Data; import lombok.Builder; import lombok.NoArgsConstructor; import lombok.AllArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @Entity @Table(name = "employees") public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String department; private String role; private String email; private Integer yearsOfService; private String status; } ``` 薪资和绩效实体参照这个格式来写,然后编写JPA数据访问接口,不需要加额外逻辑: ```ja va // repository/EmployeeRepository.ja va package com.example.hrm.repository; import com.example.hrm.domain.Employee; import org.springframework.data.jpa.repository.JpaRepository; public interface EmployeeRepository extends JpaRepository { } ``` 业务服务层实现核心查询、统计、新增逻辑。以员工服务为例: ```ja va // service/EmployeeService.ja va package com.example.hrm.service; import com.example.hrm.domain.Employee; import com.example.hrm.repository.EmployeeRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import ja va.util.List; import ja va.util.Map; import ja va.util.stream.Collectors; @Service @RequiredArgsConstructor public class EmployeeService { private final EmployeeRepository employeeRepository; public List queryEmployees(String department, String role, String status) { List all = employeeRepository.findAll(); return all.stream() .filter(e -> department == null || e.getDepartment().contains(department)) .filter(e -> role == null || e.getRole().contains(role)) .filter(e -> status == null || e.getStatus().equalsIgnoreCase(status)) .collect(Collectors.toList()); } public Map getDepartmentHeadcount() { return employeeRepository.findAll().stream() .filter(e -> "ACTIVE".equals(e.getStatus())) .collect(Collectors.groupingBy(Employee::getDepartment, Collectors.counting())); } } ``` 薪资服务和绩效服务也按业务需求来,实现统计、新增、排名这些逻辑,保证原有业务能力完整。 ### 3.5 核心:MCP工具封装层 这是改造最关键的一步。我们用`@Tool`和`@ToolParam`注解,把业务方法封装成MCP标准工具。注解描述是AI识别调用规则的关键,得说清楚使用场景、参数是什么意思,以及返回什么内容。以员工工具类为例: ```ja va // mcp/EmployeeTools.ja va package com.example.hrm.mcp; import com.example.hrm.domain.Employee; import com.example.hrm.service.EmployeeService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.annotation.ToolParam; import org.springframework.stereotype.Component; import ja va.util.List; import ja va.util.Map; import ja va.util.stream.Collectors; @Slf4j @Component @RequiredArgsConstructor public class EmployeeTools { private final EmployeeService employeeService; @Tool(description = "查询员工列表,适用于询问部门人员、职级人员场景,返回员工基础信息,不含薪资") public List> queryEmployees( @ToolParam(description = "部门名称,选填", required = false) String department, @ToolParam(description = "职级名称,选填", required = false) String role, @ToolParam(description = "员工状态,ACTIVE在职/RESIGNED离职,选填", required = false) String status) { String effectiveStatus = (status == null) ? "ACTIVE" : status; return employeeService.queryEmployees(department, role, effectiveStatus).stream() .map(e -> { Map item = new ja va.util.LinkedHashMap<>(); item.put("id", e.getId()); item.put("name", e.getName()); item.put("department", e.getDepartment()); item.put("role", e.getRole()); item.put("yearsOfService", e.getYearsOfService()); item.put("status", e.getStatus()); return item; }) .collect(Collectors.toList()); } @Tool(description = "统计各在职部门人数,适用于查询组织人员分布场景") public Map getDepartmentHeadcount() { return employeeService.getDepartmentHeadcount(); } } ``` 薪资工具和绩效工具也用同样的方式封装。其中绩效提交属于写操作,需要在注解描述里提醒AI,调用前先向用户确认,避免误操作。 ### 3.6 启动类与测试数据初始化 在启动类里通过`CommandLineRunner`初始化一些演示数据,方便后面测试: ```ja va // HrmMcpApplication.ja va package com.example.hrm; import com.example.hrm.domain.Employee; import com.example.hrm.domain.SalaryRecord; import com.example.hrm.domain.PerformanceReview; import com.example.hrm.repository.EmployeeRepository; import com.example.hrm.repository.SalaryRepository; import com.example.hrm.repository.PerformanceRepository; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import ja va.math.BigDecimal; import ja va.time.LocalDate; import ja va.util.List; @SpringBootApplication public class HrmMcpApplication { public static void main(String[] args) { SpringApplication.run(HrmMcpApplication.class, args); } @Bean CommandLineRunner initData(EmployeeRepository empRepo, SalaryRepository salaryRepo, PerformanceRepository perfRepo) { return args -> { // 初始化员工数据 List employees = empRepo.sa veAll(List.of( Employee.builder().name("张伟").department("研发部").role("高级工程师").yearsOfService(4).status("ACTIVE").build(), Employee.builder().name("李娜").department("研发部").role("初级工程师").yearsOfService(1).status("ACTIVE").build() )); // 初始化薪资、绩效数据(代码省略,参照完整示例补充) }; } } ``` ### 3.7 服务端打包与启动 执行以下Ma ven命令打包并启动服务: ```bash # 打包项目,跳过测试 mvn clean package -DskipTests # 启动MCP服务端 ja va -jar target/hrm-mcp-server-1.0.0-SNAPSHOT.jar ``` 启动成功后,服务会监听8081端口,SSE访问地址是 `http://localhost:8081/sse`。 ## 四、实战部署二:AI客户端与业务系统接入MCP服务 MCP服务端部署完成后,接入场景分两类:一类是Claude、Cursor这类主流AI工具直接连接SSE端点;另一类是自有Spring Boot业务系统集成MCP客户端,在系统内部实现AI问答功能。 ### 4.1 主流AI工具配置(Claude、Cursor) 这两类工具的配置方式一样,只需要修改本地的配置文件,填入SSE远程地址就行。 **Claude配置** Windows系统的配置文件路径:`%APPDATA%\Claude\claude_desktop_config.json` macOS系统的配置文件路径:`~/Library/Application Support/Claude/claude_desktop_config.json` 写入以下配置: ```json { "mcpServers": { "hrm": { "url": "http://localhost:8081/sse" } } } ``` **Cursor配置** 在Cursor的MCP设置面板里,添加相同的JSON配置,重启工具后,它就能自动发现MCP服务暴露的所有工具了。这时候在对话框输入自然语言,比如“统计各部门在职人数”,AI会自动调用`getDepartmentHeadcount`工具去拿数据,并展示结果。 ### 4.2 自有业务系统集成MCP客户端 如果需要在企业内部系统里嵌入AI问答功能,那就得搭一个MCP客户端项目,来对接远程的MCP服务端。 #### 4.2.1 客户端项目结构 ``` hrm-ai-client/ ├── pom.xml ├── src/main/ │ ├── ja va/com/example/hrm/client/ │ │ ├── HrmAiClientApplication.ja va │ │ ├── config/McpClientConfig.ja va │ │ ├── controller/AiAdvisorController.ja va │ │ └── service/AiAdvisorService.ja va │ └── resources/application.yml ``` #### 4.2.2 客户端pom.xml依赖 引入MCP客户端、OpenAI模型、Web这些依赖: ```xml 4.0.0 org.springframework.boot spring-boot-starter-parent 3.4.5 com.example hrm-ai-client 1.0.0-SNAPSHOT 21 1.0.0 org.springframework.ai spring-ai-bom ${spring-ai.version} pom import org.springframework.boot spring-boot-starter-web org.springframework.ai spring-ai-starter-mcp-client org.springframework.ai spring-ai-starter-model-openai org.projectlombok lombok true ``` #### 4.2.3 客户端application.yml配置 配置客户端端口、大模型密钥和MCP服务端SSE地址: ```yaml server: port: 8082 spring: application: name: hrm-ai-client openai: api-key: sk-your-api-key base-url: https://api.openai.com chat: options: model: gpt-4o temperature: 0.3 # 连接远程MCP服务端 ai: mcp: client: sse: connections: hrm-server: url: http://localhost:8081/sse logging: level: root: WARN com.example.hrm.client: INFO org.springframework.ai.mcp: DEBUG ``` #### 4.2.4 核心配置、服务与接口代码 1. **MCP客户端配置类**,把MCP工具注册到对话客户端里: ```ja va // config/McpClientConfig.ja va package com.example.hrm.client.config; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.tool.ToolCallbackProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class McpClientConfig { @Bean ChatClient chatClient(ChatClient.Builder builder, ToolCallbackProvider toolCallbackProvider) { return builder .defaultSystem("你是HR智能顾问,可调用工具查询员工、薪资、绩效数据") .defaultToolCallbacks(toolCallbackProvider) .build(); } } ``` 2. **AI对话服务层**,处理用户的自然语言请求: ```ja va // service/AiAdvisorService.ja va package com.example.hrm.client.service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.chat.client.ChatClient; import org.springframework.stereotype.Service; @Slf4j @Service @RequiredArgsConstructor public class AiAdvisorService { private final ChatClient chatClient; public String ask(String userQuestion) { log.info("用户提问:{}", userQuestion); String response = chatClient.prompt() .user(userQuestion) .call() .content(); return response; } } ``` 3. **REST接口**,对外提供AI问答能力: ```ja va // controller/AiAdvisorController.ja va package com.example.hrm.client.controller; import com.example.hrm.client.service.AiAdvisorService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import ja va.util.Map; @RestController @RequestMapping("/api/ai") @RequiredArgsConstructor public class AiAdvisorController { private final AiAdvisorService aiAdvisorService; @PostMapping("/ask") public Map ask(@RequestBody Map request) { String answer = aiAdvisorService.ask(request.get("question")); return Map.of("question", request.get("question"), "answer", answer); } } ``` #### 4.2.5 客户端启动与接口测试 启动客户端项目后,用`curl`命令测试接口: ```bash curl -X POST http://localhost:8082/api/ai/ask \ -H "Content-Type: application/json" \ -d '{"question": "分析研发部2026-Q2薪资,找出薪资偏低的员工并给出调薪建议"}' ``` 请求发出去后,客户端会自动通过SSE调用MCP服务端的薪资、员工、绩效工具,然后把数据整合起来,由大模型生成分析报告,整个链路就跑通了。 ## 五、常见问题排查与企业级最佳实践 ### 5.1 高频问题与解决方案 * **注解版本不匹配**:Spring AI 1.0.x用的是`@Tool`和`@ToolParam`,早期版本是`@McpTool`,得统一依赖版本,免得注解报错。 * **返回类型序列化失败**:别直接返回实体类,优先用`Map`或者自定义的DTO,避免循环引用导致JSON解析异常。 * **写操作误触发**:在写类型工具的注解描述里,明确要求AI调用前得先问用户,同时加好接口日志和权限校验。 * **SSE连接失败**:检查服务端端口和防火墙规则。生产环境配反向袋里时,要保证SSE长连接不被中断。 * **工具数量过多**:单个MCP服务端的工具数量建议控制在20个以内,按业务域拆成多个MCP服务,能提升调用的稳定性。 ### 5.2 企业级优化策略 * **数据脱敏**:在MCP工具层对手机号、邮箱、明文密码这些敏感字段做脱敏处理,避免数据泄露。 * **分层权限**:结合权限框架,限制不同角色能调用的MCP工具。比如HR才能看薪资,普通员工只能看个人信息。 * **日志审计**:完整记录每一次MCP工具调用的用户、参数和结果,满足企业安全审计的要求。 * **分批部署**:先在非核心业务试点,验证稳定性之后再全量推广,能降低改造风险。 ## 六、总结 说到底,借助Spring AI和MCP协议,那些用了多年的Spring Boot系统完全不需要重构,只要新增一个适配层,就能快速接上AI生态。这对于老旧的Ja va系统来说,是一个成本很低的智能化改造方案。SSE传输模式完美适配企业远程、多客户端的生产场景,兼顾了部署的便捷性和扩展性。 这套方案的核心就是“业务系统不变,AI能力新增”,把传统接口转化成AI能调用的标准化工具,让自然语言交互落地到日常办公里。从AI工具直连,到自有业务系统集成MCP客户端,两种接入模式覆盖了绝大多数企业使用场景。在实际落地过程中,只要把注解描述规范、数据安全、权限控制这三个要点把握好,就能搭出一个稳定、高效的AI Ja va业务链路。这样一来,存量系统的业务价值就能得到充分释放,老旧的技术架构也能跟上智能化的发展趋势。
免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策