@[toc]
简述
在开发一个结合了 Server-Sent Events (SSE) 和 Model Context Protocol (MCP) 的Java应用时,目标是构建一个能够实时与AI模型交互并接收更新的系统。这样的系统可以用于多种场景,比如实时数据分析、智能监控或个性化推荐等。下面是一个基于Spring Boot框架的示例,展示了如何使用Java来实现这种类型的集成。
当前 mcp 情况
默认方式 | spring支持 |
---|---|
stdio | webflux sse |
sse | webmvc sse4.2 |
studio |
使用 Cherry studio 作为 ai 引擎
配置 mcp 链接 选择 类型为 sse, 地址为spring boot 项目启动地址

问答情况
mcp 服务配置类
配置 McpServerConfig
java
package com.mcp;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpSyncServer;
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
import io.modelcontextprotocol.server.transport.WebFluxSseServerTransportProvider;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpServerTransportProvider;
import org.springframework.ai.mcp.McpToolUtils;
import org.springframework.ai.support.ToolCallbacks;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
@Configuration
public class McpServerConfig {
@Bean
@ConditionalOnProperty(prefix = "transport", name = "mode", havingValue = "stdio")
public StdioServerTransportProvider stdioServerTransportProvider() {
return new StdioServerTransportProvider();
}
@Bean
@ConditionalOnProperty(prefix = "transport", name = "mode", havingValue = "sse")
public WebFluxSseServerTransportProvider sseServerTransportProvider() {
return new WebFluxSseServerTransportProvider(new ObjectMapper(), "/mcp/message");
}
@Bean
@ConditionalOnProperty(prefix = "transport", name = "mode", havingValue = "sse")
public RouterFunction<?> mcpRouterFunction(WebFluxSseServerTransportProvider transportProvider) {
return transportProvider.getRouterFunction();
}
@Bean
public McpToolClient mcpToolClient() {
return new McpToolClient();
}
@Bean
public McpSyncServer mcpServer(McpServerTransportProvider transportProvider, McpToolClient mcpToolClient) {
var capabilities = McpSchema.ServerCapabilities.builder()
.tools(true)
.logging()
.build();
McpSyncServer server = McpServer.sync(transportProvider)
.serverInfo("MCP Demo Weather Server", "1.0.0")
.capabilities(capabilities)
.tools(McpToolUtils.toSyncToolSpecifications(ToolCallbacks.from(mcpToolClient)))
.build();
return server;
}
}
@ConditionalOnProperty
元素 | 说明 |
---|---|
@Bean |
告诉 Spring 容器:这是一个需要注册为 Bean 的方法。返回的对象会被加入 Spring 应用上下文中。 |
@ConditionalOnProperty(...) |
只有在满足指定的配置属性时才创建这个 Bean。 |
prefix = "transport" |
属性前缀,表示我们要检查的是以 transport. 开头的配置项。 |
name = "mode" |
要检查的属性名是 mode ,即完整的属性路径是 transport.mode 。 |
havingValue = "stdio" |
只有当 transport.mode=stdio 时才会加载这个 Bean。 |
方法体 | 如果条件成立,则返回一个新的 StdioServerTransportProvider 实例。 |
STDIO 传输配置
作用:创建一个基于标准输入输出(stdin/stdout)的传输层。 条件加载:仅当 application.properties 中配置了 transport.mode=stdio 时才会加载。
java
@Bean
@ConditionalOnProperty(prefix = "transport", name = "mode", havingValue = "stdio")
public StdioServerTransportProvider stdioServerTransportProvider() {
return new StdioServerTransportProvider();
}
SSE 传输配置
作用:创建基于 HTTP + SSE 的传输层。 路径:/mcp/message 是客户端连接的端点。 依赖:需要 spring-boot-starter-webflux 支持。
java
@Bean
@ConditionalOnProperty(prefix = "transport", name = "mode", havingValue = "sse")
public WebFluxSseServerTransportProvider sseServerTransportProvider() {
return new WebFluxSseServerTransportProvider(new ObjectMapper(), "/mcp/message");
}
路由器
作用:将 MCP 服务绑定到 WebFlux 路由中,启动 HTTP 服务器。
java
@Bean
@ConditionalOnProperty(prefix = "transport", name = "mode", havingValue = "sse")
public RouterFunction<?> mcpRouterFunction(WebFluxSseServerTransportProvider transportProvider) {
return transportProvider.getRouterFunction();
}
工具客户端 Bean
作用:注册一个 MCP 工具客户端,用于处理 MCP 客户端发起的工具调用请求。
java
@Bean
public McpToolClient mcpToolClient() {
return new McpToolClient();
}
创建 MCP 同步服务器
参数说明:
- transportProvider:根据配置选择的传输方式(stdio 或 sse)
- weatherApiClient:提供工具调用逻辑的客户端
服务器功能说明:
- 设置服务器能力:
- 支持工具调用 .tools(true)
- 支持日志功能 .logging()
- 添加工具:
- 使用 ToolCallbacks.from(...) 提取 @Tool 注解的方法
- 使用 McpToolUtils.toSyncToolSpecifications(...) 转换为 MCP 工具规范
- 构建并返回同步的 MCP 服务器实例
java
@Bean
public McpSyncServer mcpServer(McpServerTransportProvider transportProvider, McpToolClient mcpToolClient) {
var capabilities = McpSchema.ServerCapabilities.builder()
.tools(true)
.logging()
.build();
McpSyncServer server = McpServer.sync(transportProvider)
.serverInfo("MCP Demo Weather Server", "1.0.0")
.capabilities(capabilities)
.tools(McpToolUtils.toSyncToolSpecifications(ToolCallbacks.from(mcpToolClient)))
.build();
return server;
}
Client 类
@Tool(description = "Testing method, used to test whether the tool is called") 表示这是一个工具方法。 描述信息将被用于生成工具文档或提供给模型理解用途。
java
package com.mcp;
import org.springframework.ai.tool.annotation.Tool;
import java.text.SimpleDateFormat;
import java.util.Date;
public class McpToolClient {
@Tool(description = "Testing method, used to test whether the tool is called")
public String helloworld(){
return "hello, world";
}
@Tool(description = "获取当前时间")
public String nowTime(){
// 定义日期格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 获取当前时间
Date now = new Date();
// 转换为字符串
String nowStr = sdf.format(now);
return "当前时间: " + nowStr;
}
}
yaml 文件配置
yaml
server:
port: 8080
spring:
main:
banner-mode: OFF
transport:
mode: sse
logging:
file:
name: mcp.weather.log
项目maven 信息导入配置
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.5</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.mcp</groupId>
<artifactId>mcp-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mcp-test</name>
<description>Demo project for Spring Boot</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
<mcp.version>0.10.0</mcp.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-model</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp</artifactId>
</dependency>
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-spring-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.1.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-bom</artifactId>
<version>${mcp.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>central-portal-snapshots</id>
<name>Central Portal Snapshots</name>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>