1. 初识Spring AI与MCP架构
如果你正在寻找一种高效的方式让AI模型与Java应用无缝集成,Spring AI的MCP(Model Context Protocol)架构绝对值得关注。MCP就像一座智能桥梁,让大语言模型能够调用外部工具和服务,而SSE(Server-Sent Events)则是实现实时通信的秘密武器。
记得我第一次尝试用传统REST API对接AI服务时,最头疼的就是处理长轮询和实时响应。直到发现Spring AI的SSE支持,才明白原来实时交互可以如此优雅。SSE采用单向事件流,服务端可以主动推送数据到客户端,特别适合需要持续获取AI生成内容的场景。
MCP的核心价值在于标准化交互协议。它定义了工具发现、调用和资源访问的统一方式,就像给AI模型装上了标准USB接口。通过Spring Boot Starter,我们只需几行配置就能让普通Java方法变身AI可调用的智能工具。
2. 搭建MCP Server工程
2.1 初始化项目骨架
打开start.spring.io,选择:
- Java 17
- Spring Boot 3.5.8
- 添加依赖:Spring Web、Spring AI MCP Server WebMVC
关键配置在pom.xml中:
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId> </dependency> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>1.1.2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>2.2 开发工具服务类
创建一个简单的数学工具类:
package com.example.tool; import org.springframework.ai.tool.annotation.Tool; public class MathTool { @Tool(description = "两个数字相加") public static int addNumbers(int a, int b) { return a + b; } @Tool(description = "两个数字相减") public static int subtractNumbers(int a, int b) { return a - b; } }2.3 配置工具注入
通过配置类将工具注册到Spring容器:
@Configuration public class McpConfig { @Bean public ToolCallbackProvider mathTool() { return MethodToolCallbackProvider.builder() .toolObjects(new MathTool()) .build(); } }2.4 关键配置参数
application.yaml需要特别注意SSE端点配置:
server: port: 8080 spring: ai: mcp: server: enabled: true sse-endpoint: /api/v1/sse sse-message-endpoint: /api/v1/mcp capabilities: tool: true启动应用后,控制台会显示类似日志:
Registered tools: 2, notification: true说明我们的数学工具已成功注册为AI可调用的服务。
3. 连接MCP Server的两种方式
3.1 通过Chatbox可视化调试
推荐使用Chatbox这类AI调试工具快速验证:
- 添加MCP服务器配置
- 填写SSE端点URL:
http://localhost:8080/api/v1/sse - 点击测试连接
成功后会显示可用的工具列表。试着提问:"请计算15加8等于多少",AI会自动调用addNumbers方法并返回结果。
3.2 开发自定义Client应用
3.2.1 初始化Client工程
创建新项目并添加关键依赖:
<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-zhipuai</artifactId> </dependency>3.2.2 配置连接参数
application.yaml配置:
spring: ai: mcp: client: sse: connections: server1: url: http://localhost:8080 sse-endpoint: /api/v1/sse3.2.3 实现调用Controller
创建对接端点:
@RestController @RequestMapping("/mcp") public class ConnectMcpServer { private final ChatClient chatClient; public ConnectMcpServer(ChatClient.Builder builder, ToolCallbackProvider toolCallbackProvider) { this.chatClient = builder .defaultToolCallbacks(toolCallbackProvider.getToolCallbacks()) .build(); } @GetMapping("/test") public String test(@RequestParam String query) { return chatClient.prompt() .system("你是有数学计算能力的AI助手") .user(query) .call().content(); } }启动后访问测试:
GET http://localhost:8081/mcp/test?query=25减13等于多少会返回正确计算结果:"25减13等于12"。
4. 生产环境注意事项
4.1 连接稳定性优化
SSE连接可能因网络波动中断,建议添加重试机制:
@Bean public WebClientCustomizer webClientCustomizer() { return webClientBuilder -> webClientBuilder .clientConnector(new ReactorClientHttpConnector( HttpClient.create() .doOnConnected(conn -> conn .addHandlerLast(new ReadTimeoutHandler(30)) .addHandlerLast(new WriteTimeoutHandler(10))) .retry(3) )); }4.2 性能监控配置
添加执行耗时监控:
@Aspect @Component public class ToolMonitorAspect { @Around("@annotation(org.springframework.ai.tool.annotation.Tool)") public Object logToolExecution(ProceedingJoinPoint pjp) throws Throwable { long start = System.currentTimeMillis(); try { return pjp.proceed(); } finally { long duration = System.currentTimeMillis() - start; Metrics.timer("mcp.tool.execution") .tag("tool", pjp.getSignature().getName()) .record(duration, TimeUnit.MILLISECONDS); } } }4.3 安全防护措施
建议添加JWT认证拦截器:
@Bean public SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) { return http .authorizeExchange(exchanges -> exchanges .pathMatchers("/api/v1/sse").authenticated() .anyExchange().permitAll() ) .oauth2ResourceServer(server -> server .jwt(Customizer.withDefaults()) ) .build(); }5. 调试技巧与问题排查
当SSE连接异常时,首先检查:
- 服务端是否启用CORS:
spring: mvc: cors: mappings: "/api/v1/**": allowed-origins: "*" allowed-methods: GET,POST- 客户端连接状态监控:
client.monitor() .doOnSubscribe(s -> log.info("连接建立")) .doOnError(e -> log.error("连接异常", e)) .doOnCancel(() -> log.warn("连接断开")) .subscribe();- 常见错误解决方案:
- 返回404:检查端点路径是否包含base-url前缀
- 连接立即断开:确认服务端keep-alive配置
- 工具未显示:检查@Tool注解的description是否为空
6. 扩展应用场景
6.1 结合知识库查询
开发文档检索工具:
@Tool(description = "根据关键词查询知识库") public List<String> searchKnowledge(@Param("关键词") String keyword) { return vectorStore.similaritySearch(keyword) .stream() .map(Document::getContent) .collect(Collectors.toList()); }6.2 业务流程自动化
订单状态查询示例:
@Tool(description = "查询订单状态") public OrderStatus getOrderStatus(@Param("订单号") String orderId) { return orderService.findById(orderId) .orElseThrow(() -> new RuntimeException("订单不存在")); }6.3 实时数据监控
股票价格推送工具:
@Tool(description = "订阅股票价格变动") public Flux<StockPrice> watchStock( @Param("股票代码") String symbol, McpAsyncServerExchange exchange) { return stockService.getPriceStream(symbol) .doOnNext(price -> exchange.createMessage( new TextContent("最新价格: " + price.getCurrent()))); }在实际项目中,我发现SSE的keep-alive机制需要特别注意。曾经遇到生产环境连接莫名断开的问题,后来发现是代理服务器超时设置过短。建议在Nginx配置中添加:
proxy_read_timeout 300s; proxy_send_timeout 300s;对于需要更高并发的场景,可以考虑使用WebFlux版本的starter:
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-server-webflux</artifactId> </dependency>