Java 开发玩转 MCP:从 Claude 自动化到 Spring AI Alibaba 生态整合

在 Spring AI 中使用 MCP Server

1.1 Spring AI MCP 的介绍

Spring AI MCP 为模型上下文协议提供 Java 和 Spring 框架集成。它使 Spring AI 应用程序能够通过标准化的接口与不同的数据源和工具进行交互,支持同步和异步通信模式。整体架构如下:

Spring AI MCP 采用模块化架构,包括以下组件:

Spring AI 应用程序:使用 Spring AI 框架构建想要通过 MCP 访问数据的生成式 AI 应用程序

Spring MCP 客户端:MCP 协议的 Spring AI 实现,与服务器保持 1:1 连接

通过 Spring AI MCP,可以快速搭建 MCP 客户端和服务端程序。

2.2 使用 Spring AI MCP 快速搭建 MCP Server

Spring AI 提供了两种机制快速搭建 MCP Server,通过这两种方式开发者可以快速向 AI 应用开放自身的能力,这两种机制如下:

基于 stdio 的进程间通信传输,以独立的进程运行在 AI 应用本地,适用于比较轻量级的工具。

基于 SSE(Server-Sent Events) 进行远程服务访问,需要将服务单独部署,客户端通过服务端的 URL 进行远程访问,适用于比较重量级的工具。

2.2.1 基于 stdio 的 MCP 服务端实现

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

添加依赖

首先,在项目中添加 Spring AI MCP Server Starter 依赖:

dart 复制代码
<dependency>
   <groupId>org.springframework.ai</groupId>
   <artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId>
</dependency>

配置 MCP 服务端

在 application.yml 中配置 MCP 服务端,这次要实现的是一个天气服务:

dart 复制代码
spring:
  main:
    web-application-type: none  # 必须禁用web应用类型
    banner-mode: off           # 禁用banner
  ai:
    mcp:
      server:
        stdio: true            # 启用stdio模式
        name: my-weather-server # 服务器名称
        version: 0.0.1         # 服务器版本

实现 MCP 工具

使用 @Tool 注解标记方法,使其可以被 MCP 客户端发现和调用,通过 @ToolParameter 注解工具的具体参数:

dart 复制代码
@Service
public class OpenMeteoService {

    private final WebClient webClient;

    public OpenMeteoService(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder
                .baseUrl("https://api.open-meteo.com/v1")
                .build();
    }

    @Tool(description = "根据经纬度获取天气预报")
    public String getWeatherForecastByLocation(
            @ToolParameter(description = "纬度,例如:39.9042") String latitude,
            @ToolParameter(description = "经度,例如:116.4074") String longitude) {

        try {
            String response = webClient.get()
                    .uri(uriBuilder -> uriBuilder
                            .path("/forecast")
                            .queryParam("latitude", latitude)
                            .queryParam("longitude", longitude)
                            .queryParam("current", "temperature_2m,wind_speed_10m")
                            .queryParam("timezone", "auto")
                            .build())
                    .retrieve()
                    .bodyToMono(String.class)
                    .block();

            // 解析响应并返回格式化的天气信息
            // 这里简化处理,实际应用中应该解析JSON
            return "当前位置(纬度:" + latitude + ",经度:" + longitude + ")的天气信息:\n" + response;
        } catch (Exception e) {
            return "获取天气信息失败:" + e.getMessage();
        }
    }

    @Tool(description = "根据经纬度获取空气质量信息")
    public String getAirQuality(
            @ToolParameter(description = "纬度,例如:39.9042") String latitude,
            @ToolParameter(description = "经度,例如:116.4074") String longitude) {

        // 模拟数据,实际应用中应调用真实API
        return "当前位置(纬度:" + latitude + ",经度:" + longitude + ")的空气质量:\n" +
                "- PM2.5: 15 μg/m³ (优)\n" +
                "- PM10: 28 μg/m³ (良)\n" +
                "- 空气质量指数(AQI): 42 (优)\n" +
                "- 主要污染物: 无";
    }
}

这里使用了 OpenMeteo, OpenMeteo 是一个开源的天气 API,为非商业用途提供免费访问,无需 API 密钥。

注册 MCP 工具

在应用程序入口类中注册工具:

dart 复制代码
@SpringBootApplication
public class McpServerApplication {

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

    @Bean
    public ToolCallbackProvider weatherTools(OpenMeteoService openMeteoService) {
        return MethodToolCallbackProvider.builder()
                .toolObjects(openMeteoService)
                .build();
    }
}

运行服务端

在控制台中执行如下命令,编译并打包应用:

Terminal window

dart 复制代码
mvn clean package -DskipTests

基于 SSE 的 MCP 服务端实现

基于 SSE 的 MCP 服务端通过 HTTP 协议与客户端通信,适用于作为独立服务部署的场景,可以被多个客户端远程调用,具体做法与 stdio 非常类似。

添加依赖

首先,在您的项目中添加依赖

dart 复制代码
<dependency>
   <groupId>org.springframework.ai</groupId>
   <artifactId>spring-ai-mcp-server-webflux-spring-boot-starter</artifactId>
</dependency>

配置 MCP 服务端

在application.yml中配置 MCP 服务端:

dart 复制代码
server:
  port: 8080  # 服务器端口配置

spring:
  ai:
    mcp:
      server:
        name: my-weather-server    # MCP服务器名称
        version: 0.0.1            # 服务器版本号

实现 MCP 工具

与基于 stdio 的实现完全相同:

dart 复制代码
@Service
public class OpenMeteoService {

    private final WebClient webClient;

    public OpenMeteoService(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder
                .baseUrl("https://api.open-meteo.com/v1")
                .build();
    }

    @Tool(description = "根据经纬度获取天气预报")
    public String getWeatherForecastByLocation(
            @ToolParameter(description = "纬度,例如:39.9042") String latitude,
            @ToolParameter(description = "经度,例如:116.4074") String longitude) {

        try {
            String response = webClient.get()
                    .uri(uriBuilder -> uriBuilder
                            .path("/forecast")
                            .queryParam("latitude", latitude)
                            .queryParam("longitude", longitude)
                            .queryParam("current", "temperature_2m,wind_speed_10m")
                            .queryParam("timezone", "auto")
                            .build())
                    .retrieve()
                    .bodyToMono(String.class)
                    .block();

            // 解析响应并返回格式化的天气信息
            return "当前位置(纬度:" + latitude + ",经度:" + longitude + ")的天气信息:\n" + response;
        } catch (Exception e) {
            return "获取天气信息失败:" + e.getMessage();
        }
    }

    @Tool(description = "根据经纬度获取空气质量信息")
    public String getAirQuality(
            @ToolParameter(description = "纬度,例如:39.9042") String latitude,
            @ToolParameter(description = "经度,例如:116.4074") String longitude) {

        // 模拟数据,实际应用中应调用真实API
        return "当前位置(纬度:" + latitude + ",经度:" + longitude + ")的空气质量:\n" +
                "- PM2.5: 15 μg/m³ (优)\n" +
                "- PM10: 28 μg/m³ (良)\n" +
                "- 空气质量指数(AQI): 42 (优)\n" +
                "- 主要污染物: 无";
    }
}

注册 MCP 工具

在应用程序入口类中注册工具:

dart 复制代码
@SpringBootApplication
public class McpServerApplication {

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

    @Bean
    public ToolCallbackProvider weatherTools(OpenMeteoService openMeteoService) {
        return MethodToolCallbackProvider.builder()
                .toolObjects(openMeteoService)
                .build();
    }

    @Bean
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
}

运行服务端

在控制台中输入命令,运行服务端:

Terminal window

dart 复制代码
mvn spring-boot:run

服务端将在 http://localhost:8080 启动。

2.3 在 Claude 中测试 mcp 服务

在上一小节中我们编写完了 MCP 服务,这些服务到底是否能正常运行呢?在 Claude Desktop 中可以测试一下。

修改配置文件,添加 weather 的配置,一定要注意 jar 包的路径必须是全路径:

dart 复制代码
{
    "mcpServers": {
        "github": {
            "command": "npx",
            "args": [
                "-y",
                "@modelcontextprotocol/server-github"
            ],
            "env": {
                "GITHUB_PERSONAL_ACCESS_TOKEN": your token
            }
        },
        "weather": {
            "command": "java",
            "args": [
                "-Dspring.ai.mcp.server.stdio=true",
                "-Dspring.main.web-application-type=none",
                "-Dlogging.pattern.console=",
                "-jar",
                "<修改为stdio编译之后的jar包全路径>"
            ],
            "env": {}
        }
    }
}

重启 Claude 之后看到,我们编写的两个 Tool 已经被加载进来了:

输入提示词,查询今天北京的空气质量:

Claude 触发了我们自己编写的天气服务,展示了完整的数据:

上面使用了 stdio 的方式在 Claude Desktop 中使用我们自己编写的 MCP 服务,但是很可惜 Claude Desktop 不支持直接通过 SSE 模式访问,必须使用 mcp-proxy 作为中介,所以这里我们不再演示 Claude Desktop 接入 SSE 模式的 MCP 服务。

资料推荐

💡大模型中转API推荐

中转使用教程

相关推荐
lybugproducer1 小时前
创建型设计模式之:简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式
java·设计模式·建造者模式·简单工厂模式·工厂方法模式·抽象工厂模式·面向对象
南客先生2 小时前
马架构的Netty、MQTT、CoAP面试之旅
java·mqtt·面试·netty·coap
Minyy112 小时前
SpringBoot程序的创建以及特点,配置文件,LogBack记录日志,配置过滤器、拦截器、全局异常
xml·java·spring boot·后端·spring·mybatis·logback
百锦再2 小时前
Java与Kotlin在Android开发中的全面对比分析
android·java·google·kotlin·app·效率·趋势
武昌库里写JAVA3 小时前
39.剖析无处不在的数据结构
java·vue.js·spring boot·课程设计·宠物管理
Nelson_hehe5 小时前
Java基础第四章、面向对象
java·语法基础·面向对象程序设计
Thomas_YXQ5 小时前
Unity3D Lua集成技术指南
java·开发语言·驱动开发·junit·全文检索·lua·unity3d
ShiinaMashirol6 小时前
代码随想录打卡|Day27(合并区间、单调递增的数字、监控二叉树)
java·算法
东阳马生架构8 小时前
Nacos简介—3.Nacos的配置简介
java
北极的企鹅888 小时前
XML内容解析成实体类
xml·java·开发语言