Spring AI Alibaba:玩转模型上下文协议(MCP)的Java实践

本文讲解Java开发者如何基于Spring AI Alibaba框架玩转MCP,包括MCP Server的发布与调用,以及在OpenManus中的集成应用,助力AI应用开发。

原文标题:从原理到示例:Java开发玩转MCP

原文作者:阿里云开发者

冷月清谈:

本文深入探讨了Java开发者如何利用Spring AI Alibaba框架驾驭模型上下文协议(MCP)。首先,文章简要介绍了MCP的基础概念和快速体验,随后详细阐述了如何将Spring应用发布为MCP Server,并通过Claude或Spring应用客户端进行验证,包括stdio和SSE两种模式的MCP Server发布。接着,文章讲解了如何使用Spring应用调用MCP Server,包括自建的和市面上的通用MCP Server,同样涵盖stdio和SSE模式的配置与调用。此外,还介绍了如何在Spring AI Alibaba OpenManus实现中使用MCP服务,通过集成百度地图的MCP服务,展示了如何在智能应用中调用地图API进行路线规划。最后,文章展望了MCP在AI开发领域的未来,强调其在简化工具集成、实现AI能力普惠化方面的价值。总而言之,本文旨在帮助Java开发者快速上手Spring AI Alibaba框架下的MCP应用开发,充分利用MCP协议提升AI应用的智能化水平。

怜星夜思:

1、文章提到了MCP协议可以连接各种数据源和服务,例如地图、代码仓库、数据库等。那么,对于特定行业(比如金融、医疗)来说,你认为MCP还能集成哪些有价值的数据源或服务,从而创造出更具行业针对性的AI应用?
2、文章中提到了使用Claude Desktop体验MCP,并集成了Github服务。如果让你设计一个基于MCP的智能应用,你觉得结合Github还能实现哪些有趣的功能?
3、文章介绍了基于stdio和SSE两种模式搭建MCP Server。在实际生产环境中,这两种模式分别适用于哪些场景?它们的优缺点是什么?

原文内容

摘要

本文以原理与示例结合的形式讲解 Java 开发者如何基于 Spring AI Alibaba 框架玩转 MCP,主要包含以下内容。

1. 一些 MCP 基础与快速体验(熟悉的读者可以跳过此部分)

2. 如何将自己开发的 Spring 应用发布为 MCP Server,验证使用 Claude 或 Spring 应用作为客户端接入自己发布的 Java MCP Server。


  • 发布 stdio 模式的 MCP Server

  • 发布 SSE 模式的 MCP Server

  • 开发另一个 Spring 应用作为 MCP Client 调用 MCP Server 服务

  • 使用 Claude 桌面应用接入我们的 Java MCP Server


3. 如何使用自己开发的 Spring 应用调用 MCP Server,包括调用自己发布的 Java MCP Server,也包括市面上其他通用 MCP Server。


  • 配置并调用 stdio 模式的 MCP Server

  • 配置并调用 SSE 模式的 MCP Server


4. 如何在 Spring AI Alibaba OpemManus 实现中使用 MCP 服务。


5. 关于存量应用如何一行代码不动就可以被当作 MCP 服务被智能体调用,请关注后续文章解决方案。


Spring AI Alibaba 开源项目地址:
https://github.com/alibaba/spring-ai-alibaba

本文外网博客地址:
https://java2ai.com

本示例源码地址:
https://github.com/springaialibaba/spring-ai-alibaba-examples/tree/main/spring-ai-alibaba-mcp-example


模型上下文协议

(Model Context Protocol)入门


2024 年 11 月,Anthropic 公司搞了个挺有意思的新玩意 - Model Context Protocol(模型上下文协议)简称为 MCP 协议。简单来说,它就是给 AI 和各类工具数据之间搭了个标准化的”桥梁”,让开发者不用再为对接问题头疼了。


大模型应用可以使用别人分享的 MCP 服务来完成各种各样的工作内容,你可以从这些地方获取 MCP 服务:


  • awesome-mcp-servers

  • mcp.so


MCP 协议在实际的应用场景上非常广泛,列举一些比较常见的应用场景:


  • 使用百度/高德地图分析旅线计算时间

  • 接 Puppeteer 自动操作网页

  • 使用 Github/Gitlab 让大模型接管代码仓库

  • 使用数据库组件完成对 Mysql、ES、Redis 等数据库的操作

  • 使用搜索组件扩展大模型的数据搜索能力

1.1 在 Claude Desktop 中体验 MCP

接下来我们使用 Claude 快速接入 Github 服务(提前申请 token),编辑一下 Claude Desktop 的配置文件:


macOS:

~/Library/Application Support/Claude/claude_desktop_config.json


Windows:

%APPDATA%\Claude\claude_desktop_config.json


添加如下内容,注意把<YOUR_TOKEN>替换成你自己申请的 token:

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-github"
      ],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "`"
      }
    }
  }

重启 Claude 之后,可以看到已经加载了 MCP 对应的工具:




点开之后可以看到具体的工具内容:




此时我们就可以享受 Github 服务提供的操作仓库的能力:



从图上可以看到,通过创建仓库 test-mcp 这样的提示词,Claude 的大模型自行判断需要使用 mcp 中提供的 create_repository 能力,从而完成了仓库的创建,接下来我们打开 Github 也确实发现了这个已经创建的仓库。



通过这种方式,大模型就可以利用 MCP 接入各式各样的能力,完成各种更为复杂的工作。

1.2 MCP 的架构

MCP 主要分为 MCP 服务和 MCP 客户端:

  • 客户端:一般指的是大模型应用,比如 Claude、通过 Spring AI Alibaba、Langchain 等框架开发的 AI 应用

  • 服务端:连接各种数据源的服务和工具

整体架构如下:




整体的工作流程是这样的:AI 应用中集成 MCP 客户端,通过 MCP 协议向 MCP 服务端发起请求,MCP 服务端可以连接本地/远程的数据源,或者通过 API 访问其他服务,从而完成数据的获取,返回给 AI 应用去使用。

在 Spring AI 中使用 Mcp Server

2.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 进行远程访问,适用于比较重量级的工具。

接下来逐一介绍一下这两种方式的实现,示例代码可以通过如下链接获取:

https://github.com/springaialibaba/spring-ai-alibaba-examples/tree/main/spring-ai-alibaba-mcp-example/starter-example/server


2.2.1 基于 stdio 的 MCP 服务端实现

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


添加依赖

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

<dependency>
   <groupId>org.springframework.ai</groupId>
   <artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId>
</dependency>


配置 MCP 服务端

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

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 注解工具的具体参数:


@Service

publicclassOpenMeteoService {
    privatefinal WebClient webClient;
    publicOpenMeteoService(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 工具

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


@SpringBootApplication
publicclassMcpServerApplication {
    publicstaticvoidmain(String[] args){
        SpringApplication.run(McpServerApplication.class, args);
    }

    @Bean

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

运行服务端

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


Terminal window

mvn clean package -DskipTests
2.2.2 基于 SSE 的 MCP 服务端实现

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


添加依赖

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

<dependency>
   <groupId>org.springframework.ai</groupId>
   <artifactId>spring-ai-mcp-server-webflux-spring-boot-starter</artifactId>
</dependency>
配置 MCP 服务端

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

server:
  port: 8080  # 服务器端口配置
spring:
  ai:
    mcp:
      server:
        name: my-weather-server    # MCP服务器名称
        version: 0.0.1            # 服务器版本号
实现 MCP 工具

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

@Service

publicclassOpenMeteoService {
    privatefinal WebClient webClient;
    publicOpenMeteoService(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 工具

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

@SpringBootApplication

publicclassMcpServerApplication {
    publicstaticvoidmain(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

mvn spring-boot:run

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

2.3 在 Claude 中测试 mcp 服务

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


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

{
    "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 服务。


在 Spring AI Alibaba 

中集成 Mcp Client


对于客户端,Spring AI 同样提供了 stdio 和 SSE 两种机制快速集成 MCP Server,分别对应到 MCP Server 的 stdio 和 SSE 两种模式,参考代码如下:

https://github.com/springaialibaba/spring-ai-alibaba-examples/tree/main/spring-ai-alibaba-mcp-example/starter-example/client

3.1 基于 stdio 的 MCP 客户端实现

基于 stdio 的实现是最常见的 MCP 客户端实现方式,它通过标准输入输出流与 MCP 服务器进行通信。这种方式适用于使用了 stdio 方式本地部署的 MCP 服务器,可以直接在同一台机器上启动 MCP 服务器进程。


添加依赖

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

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
</dependency>
<!-- 添加Spring AI MCP starter依赖 -->
<dependency>
   <groupId>org.springframework.ai</groupId>
   <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
</dependency>


配置 MCP 服务器

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

spring:
  ai:
    dashscope:
      # 配置通义千问API密钥
      api-key: ${DASH_SCOPE_API_KEY}
    mcp:
      client:
        stdio:
          # 指定MCP服务器配置文件路径(推荐)
          servers-configuration: classpath:/mcp-servers-config.json
          # 直接配置示例,和上边的配制二选一
          # connections:
          #   server1:
          #     command: java
          #     args:
          #       - -jar

          #       - /path/to/your/mcp-server.jar


这个配置文件设置了 MCP 客户端的基本配置,包括 API 密钥和服务器配置文件的位置。你也可以选择直接在配置文件中定义服务器配置,但是还是建议使用 json 文件管理 mcp 配置。在 resources 目录下创建 mcp-servers-config.json 配置文件:

{
    "mcpServers": {
        // 定义名为"weather"的MCP服务器
        "weather": {
            // 指定启动命令为java
            "command": "java",
            // 定义启动参数
            "args": [
                "-Dspring.ai.mcp.server.stdio=true",
                "-Dspring.main.web-application-type=none",
                "-jar",
                "<修改为stdio编译之后的jar包全路径>"
            ],
            // 环境变量配置(可选)
            "env": {}
        }
    }
}

这个 JSON 配置文件定义了 MCP 服务器的详细配置,包括如何启动服务器进程、需要传递的参数以及环境变量设置,还是要注意引用的 jar 包必须是全路径的。


编写一个启动类进行测试:

```java

@SpringBootApplication
publicclassApplication {
    publicstaticvoidmain(String args){
        // 启动Spring Boot应用
        SpringApplication.run(Application.class, args);
    }
    @Bean
    public CommandLineRunner predefinedQuestions(
            ChatClient.Builder chatClientBuilder,
            ToolCallbackProvider tools,
            ConfigurableApplicationContext context) {
        return args -> {
            // 构建ChatClient并注入MCP工具
            var chatClient = chatClientBuilder
                    .defaultTools(tools)
                    .build();
            // 定义用户输入
            String userInput = “北京的天气如何?”;
            // 打印问题
            System.out.println(“\n>>> QUESTION: " + userInput);
            // 调用LLM并打印响应
            System.out.println(”\n>>> ASSISTANT: " +
                chatClient.prompt(userInput).call().content());
            // 关闭应用上下文
            context.close();
        };
    }
}

</code></pre>
   </div>
  </div>
 </div>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>这段代码展示了如何在 Spring Boot 应用中使用 MCP 客户端。它创建了一个命令行运行器,构建了 ChatClient 并注入了 MCP 工具,然后使用这个客户端发送查询并获取响应。在 Spring AI Alibaba 中使用 Mcp 工具非常简单,只需要把&nbsp;</span></span></span><code><span><span data-wct-cr-23><span data-wct-cr-12>ToolCallbackProvider&nbsp;</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>放到&nbsp;</span></span></span><code><span><span data-wct-cr-23><span data-wct-cr-12>chatClientBuilder&nbsp;</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>的&nbsp;</span></span></span><code><span><span data-wct-cr-23><span data-wct-cr-12>defaultTools&nbsp;</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>方法中,就可以自动的适配。</span></span></span></p>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>通过命令启动程序进行测试:</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>Termin</span></span><span data-wct-cr-23><span data-wct-cr-12>al window</span></span></span></p>
 <div data-wct-cr-27>
  <div data-wct-cr-39>
   <div>
    <pre><code>mvn&nbsp;spring-boot:run
</code></pre>
   </div>
  </div>
 </div>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>启动之后显示结果为,从日志可以看到我们自己编写的 mcp server 被调用了,返回了数据:</span></span></span></p>
 <div data-wct-cr-27>
  <div data-wct-cr-39>
   <div>
    <pre><code>&gt;&gt;&gt;&nbsp;QUESTION: 北京的天气如何?
2025-03-31T17:56:17.931+08:00&nbsp;DEBUG&nbsp;23455&nbsp;---&nbsp;[mcp] [pool-1-thread-1] io.modelcontextprotocol.spec.McpSchema&nbsp; &nbsp;:&nbsp;Received&nbsp;JSON&nbsp;message: {"jsonrpc":"2.0","id":"60209de5-3","result":{"content":[{"type":"text","text":"\"当前天气:\\n温度: 18.6°C (体感温度: 15.1°C)\\n天气: 多云\\n风向: 南风 (4.7 km/h)\\n湿度: 18%\\n降水量: 0.0 毫米\\n\\n未来天气预报:\\n2025-03-31 (周一):\\n温度: 2.4°C ~ 19.5°C\\n天气: 多云\\n风向: 南风 (8.4 km/h)\\n降水量: 0.0 毫米\\n\\n2025-04-01 (周二):\\n温度: 7.6°C ~ 20.6°C\\n天气: 多云\\n风向: 西北风 (19.1 km/h)\\n降水量: 0.0 毫米\\n\\n2025-04-02 (周三):\\n温度: 6.9°C ~ 18.4°C\\n天气: 晴朗\\n风向: 西北风 (12.8 km/h)\\n降水量: 0.0 毫米\\n\\n2025-04-03 (周四):\\n温度: 7.0°C ~ 19.8°C\\n天气: 多云\\n风向: 南风 (16.3 km/h)\\n降水量: 0.0 毫米\\n\\n2025-04-04 (周五):\\n温度: 7.5°C ~ 21.6°C\\n天气: 多云\\n风向: 西北风 (19.6 km/h)\\n降水量: 0.0 毫米\\n\\n2025-04-05 (周六):\\n温度: 5.6°C ~ 20.7°C\\n天气: 多云\\n风向: 西风 (16.5 km/h)\\n降水量: 0.0 毫米\\n\\n2025-04-06 (周日):\\n温度: 8.4°C ~ 22.3°C\\n天气: 晴朗\\n风向: 南风 (9.4 km/h)\\n降水量: 0.0 毫米\\n\\n\""}],"isError":false}}
2025-03-31T17:56:17.932+08:00&nbsp;DEBUG&nbsp;23455&nbsp;---&nbsp;[mcp] [pool-1-thread-1] i.m.spec.McpClientSession&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; :&nbsp;Received&nbsp;Response:&nbsp;JSONRPCResponse[jsonrpc=2.0, id=60209de5-3, result={content=[{type=text, text="当前天气:\n温度: 18.6°C (体感温度: 15.1°C)\n天气: 多云\n风向: 南风 (4.7 km/h)\n湿度: 18%\n降水量: 0.0 毫米\n\n未来天气预报:\n2025-03-31 (周一):\n温度: 2.4°C ~ 19.5°C\n天气: 多云\n风向: 南风 (8.4 km/h)\n降水量: 0.0 毫米\n\n2025-04-01 (周二):\n温度: 7.6°C ~ 20.6°C\n天气: 多云\n风向: 西北风 (19.1 km/h)\n降水量: 0.0 毫米\n\n2025-04-02 (周三):\n温度: 6.9°C ~ 18.4°C\n天气: 晴朗\n风向: 西北风 (12.8 km/h)\n降水量: 0.0 毫米\n\n2025-04-03 (周四):\n温度: 7.0°C ~ 19.8°C\n天气: 多云\n风向: 南风 (16.3 km/h)\n降水量: 0.0 毫米\n\n2025-04-04 (周五):\n温度: 7.5°C ~ 21.6°C\n天气: 多云\n风向: 西北风 (19.6 km/h)\n降水量: 0.0 毫米\n\n2025-04-05 (周六):\n温度: 5.6°C ~ 20.7°C\n天气: 多云\n风向: 西风 (16.5 km/h)\n降水量: 0.0 毫米\n\n2025-04-06 (周日):\n温度: 8.4°C ~ 22.3°C\n天气: 晴朗\n风向: 南风 (9.4 km/h)\n降水量: 0.0 毫米\n\n"}], isError=false}, error=null]
</code></pre>
   </div>
  </div>
 </div>
 <div data-wct-cr-27>
  <div data-wct-cr-31>
   <div data-wct-cr-32>
    <div data-wct-cr-33>
     <div data-wct-cr-34>
     </div>
    </div>
   </div>
   <div data-wct-cr-35>
    <div data-wct-cr-36>
     <p data-wct-cr-52><span data-wct-cr-38><strong><span>3.2 基于 SSE 的 MCP 客户端实现</span></strong></span></p>
    </div>
   </div>
  </div>
 </div>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>除了基于 stdio 的实现外,Spring AI Alibaba 还提供了基于 Server-Sent Events (SSE)的 MCP 客户端实现。这种方式适用于远程部署的 MCP 服务器,可以通过 HTTP 协议与 MCP 服务器进行通信。</span></span></span></p>
 <h5><span data-wct-cr-21><span data-wct-cr-55><br></span></span></h5>
 <h5><span data-wct-cr-21><span data-wct-cr-22><span data-wct-cr-57>添加依赖</span></span></span></h5>
 <h5><span data-wct-cr-21><span data-wct-cr-22><br></span></span></h5>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>首先,在您的项目中添加 Spring AI MCP starter 依赖:</span></span></span></p>
 <div data-wct-cr-27>
  <div data-wct-cr-39>
   <div>
    <pre><code>&lt;dependency&gt;
&nbsp; &nbsp;&lt;groupId&gt;org.springframework.ai&lt;/groupId&gt;
&nbsp; &nbsp;&lt;artifactId&gt;spring-ai-mcp-client-webflux-spring-boot-starter&lt;/artifactId&gt;
&lt;/dependency&gt;
</code></pre>
   </div>
  </div>
 </div>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <h5><span data-wct-cr-21><span data-wct-cr-22><span data-wct-cr-57>配置 MCP 服务器</span></span></span></h5>
 <h5><span data-wct-cr-21><span data-wct-cr-22><br></span></span></h5>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>在&nbsp;</span></span></span><code><span><span data-wct-cr-23><span data-wct-cr-12>application.yml&nbsp;</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>中配置 MCP 服务器,这里需要指定 SSE 启动的服务地址,之前我们在 8080 端口上启动了对应的服务:</span></span></span></p>
 <div data-wct-cr-27>
  <div data-wct-cr-39>
   <div>
    <pre><code>spring:
&nbsp; ai:
&nbsp; &nbsp; dashscope:
&nbsp; &nbsp; &nbsp; api-key:&nbsp;${DASH_SCOPE_API_KEY}
&nbsp; &nbsp; mcp:
&nbsp; &nbsp; &nbsp; client:
&nbsp; &nbsp; &nbsp; &nbsp; sse:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;connections:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; server1:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; url: http://localhost:8080 &nbsp;#服务地址
</code></pre>
   </div>
  </div>
 </div>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <h5><span data-wct-cr-21><span data-wct-cr-22><span data-wct-cr-57>使用 MCP 客户端</span></span></span></h5>
 <h5><span data-wct-cr-21><span data-wct-cr-22><br></span></span></h5>
 <p data-wct-cr-64><span><span data-wct-cr-65><span data-wct-cr-12>使用方式与基于 stdio 的实现相同,只需注入&nbsp;</span></span></span><code><span><span data-wct-cr-65><span data-wct-cr-12>ToolCallbackProvider&nbsp;</span></span></span></code><span><span data-wct-cr-65><span data-wct-cr-12>和&nbsp;</span></span></span><code><span><span data-wct-cr-65><span data-wct-cr-12>ChatClient.Builder</span></span></span></code><span><span data-wct-cr-65><span data-wct-cr-12>:</span></span></span></p>
 <div data-wct-cr-27>
  <div data-wct-cr-39>
   <div>
    <pre><code>@SpringBootApplication

publicclassApplication {
&nbsp; &nbsp;&nbsp;publicstaticvoidmain(String[] args){
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;SpringApplication.run(Application.class, args);
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;@Bean
&nbsp; &nbsp;&nbsp;public&nbsp;CommandLineRunner&nbsp;predefinedQuestions(ChatClient.Builder chatClientBuilder,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ToolCallbackProvider tools,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ConfigurableApplicationContext context) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;args -&gt; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 构建ChatClient并注入MCP工具
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;var&nbsp;chatClient = chatClientBuilder
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .defaultTools(tools)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .build();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 使用ChatClient与LLM交互
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;String&nbsp;userInput =&nbsp;"北京的天气如何?";
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;System.out.println("\n&gt;&gt;&gt; QUESTION: "&nbsp;+ userInput);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;System.out.println("\n&gt;&gt;&gt; ASSISTANT: "&nbsp;+ chatClient.prompt(userInput).call().content());
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; context.close();
&nbsp; &nbsp; &nbsp; &nbsp; };
&nbsp; &nbsp; }

}
</code></pre>
   </div>
  </div>
 </div>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>通过命令启动程序进行测试:</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>Terminal window</span></span></span></p>
 <div data-wct-cr-27>
  <div data-wct-cr-39>
   <div>
    <pre><code>mvn&nbsp;spring-boot:run
</code></pre>
   </div>
  </div>
 </div>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>启动之后会有报错:</span></span></span></p>
 <div data-wct-cr-27>
  <div data-wct-cr-39>
   <div>
    <pre><code>Caused by: java.lang.IllegalStateException: Multiple tools with the same&nbsp;name(spring-ai-mcp-client-getWeatherForecastByLocation, spring-ai-mcp-client-getAirQuality)
&nbsp; &nbsp; &nbsp; &nbsp; at org.springframework.ai.mcp.SyncMcpToolCallbackProvider.validateToolCallbacks(SyncMcpToolCallbackProvider.java:126) ~[spring-ai-mcp-1.0.0-20250325.064812-147.jar:1.0.0-SNAPSHOT]
&nbsp; &nbsp; &nbsp; &nbsp; at org.springframework.ai.mcp.SyncMcpToolCallbackProvider.getToolCallbacks(SyncMcpToolCallbackProvider.java:110) ~[spring-ai-mcp-1.0.0-20250325.064812-147.jar:1.0.0-SNAPSHOT]
&nbsp; &nbsp; &nbsp; &nbsp; at org.springframework.ai.autoconfigure.mcp.client.McpClientAutoConfiguration.toolCallbacksDeprecated(McpClientAutoConfiguration.java:196) ~[spring-ai-mcp-client-spring-boot-autoconfigure-1.0.0-M6.jar:1.0.0-M6]
&nbsp; &nbsp; &nbsp; &nbsp; at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
&nbsp; &nbsp; &nbsp; &nbsp; at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
&nbsp; &nbsp; &nbsp; &nbsp; at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:171) ~[spring-beans-6.2.0.jar:6.2.0]
&nbsp; &nbsp; &nbsp; &nbsp; ...&nbsp;23&nbsp;common frames omitted
</code></pre>
   </div>
  </div>
 </div>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>从日志上分析,是因为注册了相同的服务名&nbsp;</span></span></span><code><span><span data-wct-cr-23><span data-wct-cr-12>spring-ai-mcp-client-getWeatherForecastByLocation&nbsp;</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>和&nbsp;</span></span></span><code><span><span data-wct-cr-23><span data-wct-cr-12>spring-ai-mcp-client-getAirQuality</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>,但是从代码上分析,这两个服务我们都只注册了一次,那为什么会报错呢?</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><br></span></span></p>
 <p data-wct-cr-64><span data-wct-cr-65><span data-wct-cr-65><span data-wct-cr-12>其实这是 Spring AI 目前的一个 BUG,Spring AI 提供了两个自动配置类去生成客户端工具处理 MCP 服务中 Tool 的获取,分别是&nbsp;</span></span></span><code><span><span data-wct-cr-65><span data-wct-cr-12>SseHttpClientTransportAutoConfiguration&nbsp;</span></span></span></code><span><span data-wct-cr-65><span data-wct-cr-12>和&nbsp;</span></span></span><code><span><span data-wct-cr-65><span data-wct-cr-12>SseWebFluxTransportAutoConfiguration</span></span></span></code><span><span data-wct-cr-65><span data-wct-cr-12>。这两个自动配置类提供了同步和异步两种方式,本身应该是互斥的,但是 Spring AI 对于互斥的处理上出了问题,导致两个自动配置类都会加载。</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><br></span></span></p>
 <p data-wct-cr-24><code><span><span data-wct-cr-23><span data-wct-cr-12>SseWebFluxTransportAutoConfiguration&nbsp;</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>的加载:</span></span></span></p>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span><span data-wct-cr-21><span data-wct-cr-21><span data-wct-cr-22><img alt="图片" src="https://raw.xinfinite.net/wct-cr-img/c3e76b8dc170a2af34429283d1374d9f.webp" data-wct-cr-66></span></span><span data-wct-cr-67></span><span data-wct-cr-42></span></span><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <p data-wct-cr-20><code><span data-wct-cr-21><span data-wct-cr-22><br></span></span></code></p>
 <p data-wct-cr-24><code><span><span data-wct-cr-23><span data-wct-cr-12>SseHttpClientTransportAutoConfiguration&nbsp;</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>的加载:</span></span></span></p>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span><span data-wct-cr-21><span data-wct-cr-21><span data-wct-cr-22><img alt="图片" src="https://raw.xinfinite.net/wct-cr-img/d1788179388bac05ff2b244ff4ef3e4b.webp" data-wct-cr-68></span></span><span data-wct-cr-69></span><span data-wct-cr-42></span></span><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>两个自动配置类加载之后,就会向提供 SSE 服务的 MCP 服务申请 Tool,这样就导致同样的 Tool 被申请了两次,自然就会重复了。解决方案也非常简单,在启动类上排除&nbsp;</span></span></span><code><span><span data-wct-cr-23><span data-wct-cr-12>SseHttpClientTransportAutoConfiguration&nbsp;</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>实现就可以了。</span></span></span></p>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <div data-wct-cr-27>
  <div data-wct-cr-39>
   <div>
    <pre><code>@SpringBootApplication(exclude = {
&nbsp; &nbsp; &nbsp; &nbsp; org.springframework.ai.autoconfigure.mcp.client.SseHttpClientTransportAutoConfiguration.class
})
publicclassApplication {
...
</code></pre>
   </div>
  </div>
 </div>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>再次通过命令启动程序进行测试:</span></span></span></p>
 <p data-wct-cr-70><span><span data-wct-cr-71><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>Terminal window</span></span></span></p>
 <div data-wct-cr-27>
  <div data-wct-cr-39>
   <div>
    <pre><code>mvn&nbsp;spring-boot:run
</code></pre>
   </div>
  </div>
 </div>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>这一次就输出了正确的结果:</span></span></span></p>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span><span data-wct-cr-21><span data-wct-cr-21><span data-wct-cr-22><img alt="图片" src="https://raw.xinfinite.net/wct-cr-img/163bbdf615a681de4731fcc8d73114e7.webp" data-wct-cr-72></span></span><span data-wct-cr-73></span><span data-wct-cr-42></span></span><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <h5><span data-wct-cr-55><br></span></h5>
 <div data-wct-cr-74>
  <div data-wct-cr-75>
   <div data-wct-cr-76>
    <div data-wct-cr-77>
     <div data-wct-cr-78>
      <div data-wct-cr-27>
       <div data-wct-cr-28>
        <div data-wct-cr-29>
         <p data-wct-cr-30><span>在 Spring AI Alibaba 的</span></p>
         <p data-wct-cr-30><span>&nbsp;Open Manus 中体验 MCP</span><span data-wct-cr-21><br></span></p>
        </div>
       </div>
      </div>
     </div>
    </div>
   </div>
  </div>
 </div>
 <h5><span data-wct-cr-55><br></span></h5>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>Spring AI Alibaba 中提供了 Open Manus 的实现,整体架构如下:</span></span></span></p>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span><span data-wct-cr-21><span data-wct-cr-21><span data-wct-cr-22><img alt="图片" src="https://raw.xinfinite.net/wct-cr-img/908fe280c6dd148c2cfbec2750514b3b.webp" data-wct-cr-79></span></span><span data-wct-cr-80></span><span data-wct-cr-42></span></span><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>在执行阶段,会调用各种 Tool 来完成任务,如果我们能使用 MCP 增加 Tool 的能力,那势必能 Open Manus 如虎添翼,接下来我们就来看一下 Open Manus 中是如何去使用 MCP 的。</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><br></span></span></p>
 <p data-wct-cr-64><span data-wct-cr-65><span data-wct-cr-65><span data-wct-cr-12>源代码如下:</span></span></span><span><span data-wct-cr-65><span data-wct-cr-12>https://github.com/alibaba/spring-ai-alibaba/tree/main/community/openmanus</span></span></span><span><span data-wct-cr-65><br></span></span></p>
 <h5><span><span data-wct-cr-23><br></span></span></h5>
 <h5><span><span data-wct-cr-23><span data-wct-cr-13>添加依赖</span></span></span></h5>
 <h5><span><span data-wct-cr-23><br></span></span></h5>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>首先,在项目中添加 Spring AI MCP starter 依赖:</span></span></span></p>
 <div data-wct-cr-27>
  <div data-wct-cr-39>
   <div>
    <pre><code>&lt;dependency&gt;
&nbsp; &nbsp;&nbsp;&lt;groupId&gt;org.springframework.ai&lt;/groupId&gt;
&nbsp; &nbsp;&nbsp;&lt;artifactId&gt;spring-ai-mcp-client-spring-boot-starter&lt;/artifactId&gt;
&nbsp; &nbsp;&nbsp;&lt;version&gt;${spring-ai.version}&lt;/version&gt;
&lt;/dependency&gt;
</code></pre>
   </div>
  </div>
 </div>
 <h5><span data-wct-cr-21><span data-wct-cr-22><span data-wct-cr-57>配置 MCP 服务器</span></span></span></h5>
 <h5><span data-wct-cr-21><span data-wct-cr-22><br></span></span></h5>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>在&nbsp;</span></span></span><code><span><span data-wct-cr-23><span data-wct-cr-12>application.yml&nbsp;</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>中已经配置了 MCP 服务器,设置客户端请求服务端的超时时间为 1 分钟:</span></span></span></p>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span><span data-wct-cr-21><span data-wct-cr-21><span data-wct-cr-22><img alt="图片" src="https://raw.xinfinite.net/wct-cr-img/81198c3d2a3a95a0c6fa4e3006bd3ba4.webp" data-wct-cr-81></span></span><span data-wct-cr-82></span><span data-wct-cr-42></span></span><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>添加&nbsp;</span></span></span><code><span><span data-wct-cr-23><span data-wct-cr-12>mcp-servers-config.json</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>,在 json 中配置了百度地图。百度地图核心 API 现已全面兼容 MCP 协议,是国内首家兼容 MCP 协议的地图服务商。百度地图已经完成了 8 个核心 API 接口和 MCP 协议的对接, 涵盖逆地理编码、地点检索、路线规划等。</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><br></span></span></p>
 <p data-wct-cr-83><span data-wct-cr-23><span data-wct-cr-23><span data-wct-cr-12>使用百度地图的 MCP,需要申请 ak:</span></span></span><span data-wct-cr-23><span data-wct-cr-23><span data-wct-cr-12>https://lbsyun.baidu.com/apiconsole/key。</span></span></span><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <p data-wct-cr-83><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <div data-wct-cr-27>
  <div data-wct-cr-39>
   <div>
    <pre><code>{
&nbsp; &nbsp;&nbsp;"mcpServers": {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"baidu-map": {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"command":&nbsp;"npx",
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"args": [
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"-y",
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"@baidumap/mcp-server-baidu-map"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ],
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"env": {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"BAIDU_MAP_API_KEY":&nbsp;"your_baidu_AK"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
}
</code></pre>
   </div>
  </div>
 </div>
 <p data-wct-cr-20><span data-wct-cr-23><span data-wct-cr-23><span data-wct-cr-12>将其中</span></span></span><span data-wct-cr-23><span data-wct-cr-23><span data-wct-cr-12>&nbsp;</span></span></span><code><span><span data-wct-cr-23><span data-wct-cr-12>BAIDU_MAP_API_KEY&nbsp;</span></span></span></code><span data-wct-cr-23><span data-wct-cr-23><span data-wct-cr-12>修改为申请的 ak。</span></span></span></p>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <h5><span data-wct-cr-21><span data-wct-cr-22><span data-wct-cr-57>使用 MCP 工具</span></span></span></h5>
 <h5><span data-wct-cr-21><span data-wct-cr-22><br></span></span></h5>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>修改&nbsp;</span></span></span><code><span><span data-wct-cr-23><span data-wct-cr-12>LlmService&nbsp;</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>的构造方法源码,在构造时直接通过 Spring 容器获取&nbsp;</span></span></span><code><span><span data-wct-cr-23><span data-wct-cr-12>ToolCallbackProvider&nbsp;</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>并加入到&nbsp;</span></span></span><code><span><span data-wct-cr-23><span data-wct-cr-12>ChatClient.builder&nbsp;</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>中:</span></span></span></p>
 <div>
  <pre><code>public&nbsp;LlmService(ChatModel chatModel, ToolCallbackProvider toolCallbackProvider)&nbsp;{
&nbsp; &nbsp;&nbsp;this.chatModel = chatModel;

&nbsp; &nbsp;&nbsp;this.planningChatClient = ChatClient.builder(chatModel)
&nbsp; &nbsp; &nbsp; &nbsp;.defaultSystem(PLANNING_SYSTEM_PROMPT)
&nbsp; &nbsp; &nbsp; &nbsp;.defaultAdvisors(new&nbsp;MessageChatMemoryAdvisor(planningMemory))
&nbsp; &nbsp; &nbsp; &nbsp;.defaultAdvisors(new&nbsp;SimpleLoggerAdvisor())
&nbsp; &nbsp; &nbsp; &nbsp;.defaultTools(ToolBuilder.getPlanningAgentToolCallbacks())
&nbsp; &nbsp; &nbsp; &nbsp;.defaultTools(toolCallbackProvider)
&nbsp; &nbsp; &nbsp; &nbsp;.build();

&nbsp; &nbsp;&nbsp;this.chatClient = ChatClient.builder(chatModel)
&nbsp; &nbsp; &nbsp; &nbsp;.defaultSystem(MANUS_SYSTEM_PROMPT)
&nbsp; &nbsp; &nbsp; &nbsp;.defaultAdvisors(new&nbsp;MessageChatMemoryAdvisor(memory))
&nbsp; &nbsp; &nbsp; &nbsp;.defaultAdvisors(new&nbsp;SimpleLoggerAdvisor())
&nbsp; &nbsp; &nbsp; &nbsp;.defaultTools(ToolBuilder.getManusAgentToolCalls())
&nbsp; &nbsp; &nbsp; &nbsp;.defaultTools(toolCallbackProvider)
&nbsp; &nbsp; &nbsp; &nbsp;.defaultOptions(OpenAiChatOptions.builder().internalToolExecutionEnabled(false).build())
&nbsp; &nbsp; &nbsp; &nbsp;.build();

&nbsp; &nbsp;&nbsp;this.finalizeChatClient = ChatClient.builder(chatModel)
&nbsp; &nbsp; &nbsp; &nbsp;.defaultSystem(FINALIZE_SYSTEM_PROMPT)
&nbsp; &nbsp; &nbsp; &nbsp;.defaultAdvisors(new&nbsp;MessageChatMemoryAdvisor(finalizeMemory))
&nbsp; &nbsp; &nbsp; &nbsp;.defaultAdvisors(new&nbsp;SimpleLoggerAdvisor())
&nbsp; &nbsp; &nbsp; &nbsp;.build();
}
</code></pre>
 </div>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>通过&nbsp;</span></span></span><code><span><span data-wct-cr-23><span data-wct-cr-12>defaultTools&nbsp;</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>将 mcp 服务提供的 tool 交给&nbsp;</span></span></span><code><span><span data-wct-cr-23><span data-wct-cr-12>ChatClient&nbsp;</span></span></span></code><span><span data-wct-cr-23><span data-wct-cr-12>处理。</span></span></span></p>
 <h5><span data-wct-cr-21><span data-wct-cr-55><br></span></span></h5>
 <h5><span data-wct-cr-21><span data-wct-cr-22><span data-wct-cr-57>测试效果</span></span></span></h5>
 <h5><span data-wct-cr-21><span data-wct-cr-22><br></span></span></h5>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>启动 OpenManus,执行提示词:规划下从上海到北京的路线。但是如果这样写,可能会触发 google search,我们可以优化下提示词主动选择百度地图。</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>使用百度地图规划从北京市到上海市的路线</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>执行程序之后可以看到规划之后的计划:</span></span></span></p>
 <div data-wct-cr-27>
  <div data-wct-cr-39>
   <div>
    <pre><code>Steps:
0.&nbsp;[ ] [MANUS] 使用百度地图的地理编码服务获取北京市和上海市的经纬度坐标
1.&nbsp;[ ] [MANUS] 使用百度地图的路线规划服务计算从北京市到上海市的驾车路线
2.&nbsp;[ ] [MANUS] 分析并提供最终的路线信息,包括距离、预计耗时等
</code></pre>
   </div>
  </div>
 </div>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>很显然,这一次 OpenManus 选择了我们集成的百度地图 mcp server,我们来看一下结果。</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>获取到了北京市和上海市的经纬度坐标:</span></span></span></p>
 <div data-wct-cr-27>
  <div data-wct-cr-39>
   <div>
    <pre><code>Here&nbsp;is&nbsp;a summary of what we accomplished&nbsp;in&nbsp;this&nbsp;step:
- For Beijing, we received the coordinates: Longitude (lng):&nbsp;116.4133836971231, Latitude (lat):&nbsp;39.910924547299565.
- For Shanghai, we received the coordinates: Longitude (lng):&nbsp;121.48053886017651, Latitude (lat):&nbsp;31.235929042252014.
</code></pre>
   </div>
  </div>
 </div>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>计算从北京市到上海市的驾车路线:</span></span></span></p>
 <div data-wct-cr-27>
  <div data-wct-cr-39>
   <div>
    <pre><code>Distance: The total distance of the route is&nbsp;1,223,200&nbsp;meters (approximately&nbsp;1,223&nbsp;kilometers).
Duration: The estimated travel time is&nbsp;50,592&nbsp;seconds (approximately&nbsp;14&nbsp;hours and3 minutes).
</code></pre>
   </div>
  </div>
 </div>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>结果:&nbsp;</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>总距离:约 1223 公里&nbsp;</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>预计耗时:约 12 小时 45 分钟&nbsp;</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>主要途径:京沪高速公路(G2)</span></span></span></p>
 <p data-wct-cr-20><span data-wct-cr-21><span data-wct-cr-22><br></span></span></p>
 <div data-wct-cr-27>
  <div data-wct-cr-28>
   <div data-wct-cr-29>
    <p data-wct-cr-30><span>总结</span></p>
   </div>
  </div>
 </div>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>作为 AI 开发领域的革命性突破,Model Context Protocol(MCP)重新定义了智能体与工具生态的交互范式。通过标准化协议打通地图服务、代码仓库、数据库等核心工具链,MCP 不仅解决了传统 AI 开发中跨平台对接的碎片化难题,更以”开箱即用”的轻量化集成模式,让开发者能够快速构建具备多模态能力的智能应用。</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>未来,随着更多工具接入 MCP 生态,开发者只需专注于业务逻辑创新,而复杂的工具链整合将真正成为”看不见的底层能力”——这或许正是 AI 普惠化进程中,最具实际意义的技术跃迁。</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>Spring AI 中的 MCP 支持可以让 Java 开发者轻松的将自己的应用发布为 MCP Server 或者是作为消费者去集成任意的 MCP Server 实现。</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><br></span></span></p>
 <p data-wct-cr-24><span data-wct-cr-23><span data-wct-cr-12>添加钉钉群获取更多Spring AI Alibaba一手更新。</span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><br></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><span data-wct-cr-12>Spring AI Alibaba 社区 3 群(钉钉群),群号:61290041831</span></span></span></p>
 <p data-wct-cr-24><span><span data-wct-cr-23><br></span></span></p>
 <div data-wct-cr-24>
  <span data-wct-cr-23><span data-wct-cr-12>Spring AI Alibaba 开源项目地址:</span></span>
 </div>
 <div data-wct-cr-24>
  <span data-wct-cr-23><span data-wct-cr-12>https://github.com/alibaba/spring-ai-alibaba</span></span><span><span data-wct-cr-23><br></span></span>
 </div>
 <div data-wct-cr-24>
  <span><span data-wct-cr-23><br></span></span>
 </div>
 <div data-wct-cr-24>
  <span data-wct-cr-23><span data-wct-cr-12>Spring AI Alibaba 官网地址:</span></span>
 </div>
 <div data-wct-cr-24>
  <span data-wct-cr-23><span data-wct-cr-12>https://java2ai.com/</span></span><span><span data-wct-cr-23><br></span></span>
 </div>
 <div data-wct-cr-24>
  <span><span data-wct-cr-23><br></span></span>
 </div>
 <div data-wct-cr-24>
  <span data-wct-cr-23><span data-wct-cr-12>本示例源码地址:</span></span>
 </div>
 <div data-wct-cr-24>
  <span data-wct-cr-23><span data-wct-cr-12>https://github.com/springaialibaba/spring-ai-alibaba-examples/tree/main/spring-ai-alibaba-mcp-example</span></span>
 </div>
 <div>
  <span><br></span>
 </div>
 <div>
  <span><br></span>
 </div>
 <p></p>
 <p data-wct-cr-84></p>
 <p data-wct-cr-85></p>
</div>
    </div>
</div>

从架构上看,stdio更像是进程内的插件,SSE是独立的微服务。选择哪种模式,要看你的工具的复杂度和性能要求。

stdio模式适合轻量级的、与AI应用紧密耦合的工具,比如一些简单的脚本或者本地数据处理程序。优点是部署简单,缺点是性能受限,容易受到AI应用进程的影响。
SSE模式适合重量级的、独立部署的服务,比如数据库连接池、复杂的API接口等。优点是性能好,可扩展性强,缺点是部署复杂,需要考虑网络通信的开销。

我觉得金融行业可以集成股票、基金等投资数据API,还有征信数据,这样能做风险评估和智能投顾。医疗行业可以集成医学影像数据、电子病历,辅助医生诊断和治疗方案制定。

可以做一个AI驱动的开源项目推荐系统,根据用户的编程技能和兴趣,推荐合适的开源项目参与贡献。

我觉得还可以考虑安全性。如果工具涉及到敏感数据,SSE模式可能更安全,因为可以做独立的权限控制。

我想到的是智能issue管理,AI能自动给issue打标签、分配负责人,还能根据issue内容生成解决方案的草稿

可以做一个智能代码审查工具,AI自动分析pull request,找出潜在的bug和代码风格问题,提高代码质量

从技术角度看,我觉得关键是数据源要有标准化的API接口,方便MCP协议对接。另外,数据安全和隐私合规也很重要,特别是医疗和金融数据。

金融行业还可以对接宏观经济数据,比如GDP、CPI这些,帮助分析市场走势;医疗行业可以对接药品信息数据库,提供用药指导。