三、使用Spring AI实现基于stdio协议的MCP Server

三、使用Spring AI实现基于stdio协议的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运行在同一主机,主要用于本地集成、命令行工具等场景。

优点:

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

缺点:

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

基于stdio的MCP服务端通过标准输入输出流与客户端通信,适用于作为子进程被客户端启动和管理的场景,非常适合嵌入式应用。

1、创建SpringBoot工程

484e8b78-149e-415c-96dd-c211d16abca1

4bdd7566-8a17-47b2-896a-c000e9b83669

1.1、application.yml

spring:
  ai:
    mcp:
      server:
        name: springai_mcp_stdio_server  # MCP服务器名称
        version: 1.0.0  # 服务器版本号

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_stdio_server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springai_mcp_stdio_server</name>
    <description>springai_mcp_stdio_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、配置log日志

在resources目录下,新建一个log日志配置文件logback-spring.xml,目的是记录MCP Server端的接口是否被调用。

<configuration>
    <!-- 定义日志文件存储的路径,可以使用Spring的属性占位符 -->
    <property name="LOGS_PATH" value="${user.dir}/logs"/>
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOGS_PATH}/springai_mcp_stdio_server.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${LOGS_PATH}/springai_mcp_stdio_server.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>10MB</maxFileSize>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="FILE" />
    </root>
</configuration>

3、新建计算器工具服务类

创建一个MathTools类,模拟计算器服务,通过@Tool注解把方法标注为MCP服务接口。

@Service
public class MathTools {
    private static final Logger log = LoggerFactory.getLogger(MathTools.class);
    @Tool(description = "将两个数相加")
    public double add(double x, double y) {
        log.info("CalculatorTools的add被调用了: x={}, y={}", x, y);
        return x + y;
    }

    @Tool(description = "将两个数相减")
    public double subtract(double x, double y) {
        log.info("CalculatorTools的subtract被调用了: x={}, y={}", x, y);
        return x - y;
    }

    @Tool(description = "将两个数相乘")
    public double multiply(double x, double y) {
        log.info("CalculatorTools的multiply被调用了: x={}, y={}", x, y);
        return x * y;
    }

    @Tool(description = "将两个数相除")
    public double divide(double x, double y) {
        if (y == 0) {
            throw new IllegalArgumentException("除数不能为零");
        }
        log.info("CalculatorTools的divide被调用了: x={}, y={}", x, y);
        return x / y;
    }

    @Tool(description = "计算平方根")
    public double sqrt(double x) {
        if (x < 0) {
            throw new IllegalArgumentException("不能对负数开平方根");
        }
        log.info("CalculatorTools的sqrt被调用了: x={}", x);
        return Math.sqrt(x);
    }
}

4、注册为MCP工具

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

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

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

        log.info("=============================================");
        log.info("SpringaiMcpStdioServerApplication服务启动成功");
        log.info("=============================================");
    }

    @Bean
    public ToolCallbackProvider calculatorTools(MathTools mathTools) {
        return MethodToolCallbackProvider.builder()
                .toolObjects(mathTools).build();
    }
}

通过Spring AI创建的MCP Stdio Server完成了。

stdio方式是server和client通过进程通信,所以需要把server打包成jar,以便client命令启动执行。

通过maven工具打包即可,打包后路径为:{项目工程目录}\target\springai_mcp_stdio_server-0.0.1-SNAPSHOT.jar。

5、测试Mcp Stdio服务是否发布成功

启动项目,测试服务是否启动成功

启动项目,验证服务是否启动成功。
e8f013a4-6fd2-4211-bcf6-aa9cb390894f
在日志文件中可以看出工具注册成功,服务也启动成功
d1546d40-24f8-4ccd-a99f-dee82baa0733

6、使用bat启动jar,方便MCP Client调用

在{项目工程目录}下新建run_mcp_stdio_server.bat

java -Dspring.ai.mcp.server.stdio=true -Dspring.main.web-application-type=none -Dspring.main.banner-mode=off -Dfile.encoding=UTF-8 -jar target/springai_mcp_stdio_server-0.0.1-SNAPSHOT.jar
pause

启动bat文件,验证服务是否启动成功。

至此,我们通过spring ai框架开发完成了2个MCP Server服务,一个通过sse协议发布,另一个通过stdio协议发布,接下来,开发一个MCP Client端,调用这两个MCP Server服务。

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