二、使用Spring AI实现基于sse协议的MCP Server

二、使用Spring AI实现基于sse协议的MCP Server

==================================================================================

==================================================================================

参考资料:

==================================================================================

同第一篇《一、MCP和Spring AI MCP》参考资料

==================================================================================

SSE传输协议:SSE(Server-Sent Events)传输层是基于HTTP的单向通信机制,专门用于服务器向客户端推送数据。MCP Client远程调用MCP Server提供的SSE服务。实现客户端和服务端远程通信。

优点:

支持分布式部署;可跨网络访问;支持多客户端连接;轻量级,使用标准HTTP协议。

缺点:

需要额外的网络配置;相比stdio实现略微复杂;需要考虑网络安全性

STDIO传输协议:STDIO方式是基于进程间通信,MCP Client和MCP Server运行在同一主机,主要用于本地集成、命令行工具等场景。

优点:

简单可靠,无需网络配置;适合本地部署场景;进程隔离,安全性好。

缺点:

仅支持单机部署;不支持跨网络访问;每个客户端需要独立启动服务器进程。

1、创建SpringBoot工程

f9452494-6212-4a57-9e70-63bd0364e6bb
f7f18756-78f7-45da-bf56-b0d017a43a89

1.1、application.yml

server:
  port: 9090  # 服务器端口配置

spring:
  ai:
    mcp:
      server:
        name: springai_mcp_sse_server    # MCP服务器名称
        version: 1.0.0                # 服务器版本号
        type: ASYNC #异步
        sse-message-endpoint: /mcp/sse

1.2、pom.xml

MCP Server有三个常用依赖:

spring-ai-starter-mcp-server:支持STDIO(标准流)传输的核心服务器
spring-ai-starter-mcp-server-webmvc:基于Spring MVC的SSE传输实现
spring-ai-starter-mcp-server-webflux:基于Spring WebFlux的SSE传输实现

这里我们选择基于Spring WebFlux的SSE传输实现实现方式。

<?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.5.8</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.youzhuo</groupId>
    <artifactId>springai_mcp_sse_server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springai_mcp_sse_server</name>
    <description>springai_mcp_sse_server</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
        <spring-ai.version>1.1.0</spring-ai.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
<!--            <artifactId>spring-ai-starter-mcp-server</artifactId>-->
            <artifactId>spring-ai-starter-mcp-server-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>${spring-ai.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>

</project>

2、新建时间和天气预报工具服务类

创建一个TimeAndWeatherTools类,模拟天气预报服务,通过@Tool注解把方法标注为MCP服务接口。

@Service
public class TimeAndWeatherTools {
    private static final Logger log = LoggerFactory.getLogger(TimeAndWeatherTools.class);

    // 定义一个工具,和普通方法没有什么区别,仅多了一个 @Tool 注解
    // 注意,description 是工具的描述信息,要编写准确清晰,便于AI准确发现
    @Tool(description = "获取用户所在时区的当前日期和时间")
    public String getCurrentDateTime() {
        System.out.println("->> getCurrentDateTime() 获取用户所在时区的当前日期和时间");
        return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
    }

    @Tool(description = "根据 ISO-8601 格式设置用户在指定时间的闹钟")
    LocalDateTime setAlarm(String time) {
        System.out.println("->> setAlarm() 根据 ISO-8601 格式设置用户在指定时间的闹钟, time=" + time);
        LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println("->> 闹钟设置为 " + alarmTime);
        return alarmTime;
    }

    @Tool(description = "根据城市名称获取天气预报")
    public String getWeatherByCity(String city) {
        log.info("===============getWeatherByCity方法被调用:city=" + city);
        Map<String, String> mockData = Map.of(
                "西安", "天气炎热",
                "北京", "晴空万里",
                "上海", "阴雨绵绵"
        );
        return mockData.getOrDefault(city, "抱歉:未查询到对应城市!");
    }
}

3、注册为MCP工具

将 TimeAndWeatherTools封装为工具回调提供者(ToolCallbackProvider),便于被MCP Client端发现和调用。

@SpringBootApplication
public class SpringaiMcpSseServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringaiMcpSseServerApplication.class, args);
    }

    @Bean
    public ToolCallbackProvider forecastTools(TimeAndWeatherTools timeAndWeatherTools) {
        return MethodToolCallbackProvider.builder()
                .toolObjects(timeAndWeatherTools)
                .build();
    }
}

通过Spring AI创建的MCP Sse Server完成了,访问http://localhost:9090/sse,能看到信息,即表示该服务通过sse发布成功了。
d8e03c0e-3b3d-49ad-a970-80f7c9c41d56

posted @ 2025-11-27 15:17  老羅  阅读(126)  评论(0)    收藏  举报