Spring AI 实现 STDIO和SSE MCP Server
Java MCP 三层架构中,传输的方式有STDIO和SSE两种,如下图所示。
STDIO方式是基于进程间通信,MCP Client和MCP Server运行在同一主机,主要用于本地集成、命令行工具等场景。
SSE方式是基于HTTP协议,MCP Client远程调用MCP Server提供的SSE服务。实现客户端和服务端远程通信。
SSE Server
spring-ai-starter-mcp-server-webflux
基于WebFlux SSE 实现SSE Server。
jsx
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>
MCP 服务端功能支持基于 Spring WebFlux 的 SSE(服务器发送事件)服务器传输和可选的 STDIO 传输。
1.新建Spring Boot项目
使用start.spring.io/新建项目,引入以下依赖。
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.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.mcp.example</groupId>
<artifactId>mcp-webflux-server-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mcp-webflux-server-example</name>
<description>mcp-webflux-server-example</description>
<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-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<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>
<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>
</repositories>
</project>
2.application.yaml
配置
yaml
spring:
ai:
mcp:
server:
name: webflux-mcp-server
version: 1.0.0
type: ASYNC # Recommended for reactive applications
sse-message-endpoint: /mcp/messages
定义MCP名称和版本号以及同步或异步配置。
3.定义工具类
java
@Service
public class DateTimeService {
@Tool(description = "Get the current date and time in the user's timezone")
String getCurrentDateTime() {
return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
}
@Tool(description = "Set a user alarm for the given time, provided in ISO-8601 format")
String setAlarm(String time) {
LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
return "Alarm set for " + alarmTime;
}
}
定义二个工具:
1.获取当前日期和时间
2.设置提醒功能
4.暴露工具
java
@Configuration
public class McpWebFluxServiceExampleConfig {
@Bean
public ToolCallbackProvider dateTimeTools(DateTimeService dateTimeService) {
return MethodToolCallbackProvider.builder().toolObjects(dateTimeService).build();
}
}
5.启动MCP Server项目
启动项目发现注册的两个工具成功,可以端可以发现两个工具。到此MCP Server服务完成,SSE的端点路径:http://localhost:9090
,接下来是客户端连接使用服务端提供的工具。
6.MCP Client连接MCP Server
1.新建Spring Boot项目,然后引入starter
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
完整pom.xml
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.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.mcp.example</groupId>
<artifactId>mcp-client-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mcp-client-example</name>
<description>mcp-client-example</description>
<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-openai-spring-boot-starter</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<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.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<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>
<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>
</repositories>
</project>
2.配置
yaml
spring:
ai:
openai:
api-key: 你自己密钥
base-url: https://api.siliconflow.cn
chat:
options:
model: Qwen/Qwen2.5-72B-Instruct
mcp:
client:
sse:
connections:
server1:
url: http://localhost:9090
toolcallback:
enabled: true
server:
port: 9091
配置文件内容,大模型配置方便测试工具使用,mcp服务端设置就是mcp server提供的sse端点。
toolcalback.enable=true 自动注入Spring AI ToolCallbackProvider。
3.测试
java
package com.mcp.example.mcpclientexample;
import io.modelcontextprotocol.client.McpAsyncClient;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.mcp.SyncMcpToolCallbackProvider;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.Arrays;
import java.util.List;
@SpringBootApplication
public class McpClientExampleApplication implements CommandLineRunner {
@Resource
private ToolCallbackProvider tools;
@Resource
ChatClient.Builder chatClientBuilder;
public static void main(String[] args) {
SpringApplication.run(McpClientExampleApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
var chatClient = chatClientBuilder
.defaultTools(tools)
.build();
String content = chatClient.prompt("10分钟后,设置一个闹铃。").call().content();
System.out.println(content);
String content1 = chatClient.prompt("明天星期几?").call().content();
System.out.println(content1);
}
}
运行客户端项目:
结果表明定义的工具大模型根据用户的提问,选择了合适的工具进行回答。
STDIO Server
标准 MCP 服务器,通过 STDIO 服务器传输支持完整的 MCP 服务器功能。
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server</artifactId>
</dependency>
1.创建Server项目
新建Spring Boot项目引入以下依赖
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.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.mcp.example</groupId>
<artifactId>mcp-stdio-server-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mcp-stdio-server-example</name>
<description>mcp-stdio-server-example</description>
<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</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<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>
<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>
</repositories>
</project>
配置文件application.yaml
yaml
spring:
ai:
mcp:
server:
name: stdio-mcp-server
version: 1.0.0
stdio: true
main:
banner-mode: off
web-application-type: none
logging:
pattern:
console:
server:
port: 9090
main: banner-mode: off web-application-type: none 这个配置非常关键,否则client与server通信会提示json解析有问题。这个必须关掉。
2.新建工具
与sse server一样,新建DateTimeTool并注册。
3.打包项目
STDIO方式server和client之间是进程间通信,所以需要把server打包成jar,以便client命令启动执行,或者三方客户端命令启动执行。将server jar放到一个指定目录,如下所示:
target/mcp-stdio-server-example.jar
4.创建client项目
直接使用上面sse server使用的 Clinet,修改对应配置文件application.yaml
和新建mcp-server配置json。 mcp-servers-config.json
。
json
{
"mcpServers": {
"stdio-mcp-server": {
"command": "java",
"args": [
"-Dspring.ai.mcp.server.stdio=true",
"-Dspring.main.web-application-type=none",
"-jar",
"mcp server正确的路径 ../mcp-stdio-server-example-0.0.1-SNAPSHOT.jar"
],
"env": {}
}
}
}
application.yaml
yaml
spring:
ai:
openai:
api-key: sk-qwkegvacbfpsctyhfgakxlwfnklinwjunjyfmonnxddmcixr
base-url: https://api.siliconflow.cn
chat:
options:
model: Qwen/Qwen2.5-72B-Instruct
mcp:
client:
# sse:
# connections:
# server1:
# url: http://localhost:9090
stdio:
root-change-notification: false
servers-configuration: classpath:/mcp-servers-config.json
toolcallback:
enabled: true
server:
port: 9091