Java 设计 MCP SSE 配置

@[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>

项目地址

项目地址

相关推荐
tuokuac43 分钟前
maven与maven-archetype-plugin版本匹配问题
java·maven
ankleless1 小时前
Spring Boot 实战:从项目搭建到部署优化
java·spring boot·后端
百锦再1 小时前
一文精通 Swagger 在 .NET 中的全方位配置与应用
后端·ui·.net·接口·配置·swagger·访问
用户4822137167752 小时前
C++——静态数组、动态数组
后端
野生技术架构师2 小时前
2025年中高级后端开发Java岗八股文最新开源
java·开发语言
用户4822137167752 小时前
C++—— String 类详解
后端
静若繁花_jingjing2 小时前
JVM常量池
java·开发语言·jvm
BothSavage2 小时前
Java获取被nginx代理的emqx客户端真实ip
后端
David爱编程2 小时前
为什么线程不是越多越好?一文讲透上下文切换成本
java·后端
诗人啊_程序员3 小时前
Flask 路由与视图函数绑定机制
后端·python·flask