Java 開發玩轉 MCP:從 Claude 自動化到 Spring AI Alibaba 生態整合

摘要

本文以原理與示例結合的形式講解?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           # 禁用bannerai:mcp:server:stdio: true            # 啟用stdio模式name: my-weather-server # 服務器名稱version: 0.0.1         # 服務器版本
實現?MCP?工具

使用?@Tool?注解標記方法,使其可以被?MCP?客戶端發現和調用,通過?@ToolParameter?注解工具的具體參數:

@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();// 解析響應并返回格式化的天氣信息// 這里簡化處理,實際應用中應該解析JSONreturn "當前位置(緯度:" + 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) {// 模擬數據,實際應用中應調用真實APIreturn "當前位置(緯度:" + latitude + ",經度:" + longitude + ")的空氣質量:\n" +"- PM2.5: 15 μg/m3 (優)\n" +"- PM10: 28 μg/m3 (良)\n" +"- 空氣質量指數(AQI): 42 (優)\n" +"- 主要污染物: 無";}
}

這里使用了?OpenMeteo,?OpenMeteo?是一個開源的天氣?API,為非商業用途提供免費訪問,無需?API?密鑰。

注冊?MCP?工具

在應用程序入口類中注冊工具:


@SpringBootApplication
public class McpServerApplication {public static void main(String[] args) {SpringApplication.run(McpServerApplication.class, args);}@Beanpublic 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
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) {// 模擬數據,實際應用中應調用真實APIreturn "當前位置(緯度:" + latitude + ",經度:" + longitude + ")的空氣質量:\n" +"- PM2.5: 15 μg/m3 (優)\n" +"- PM10: 28 μg/m3 (良)\n" +"- 空氣質量指數(AQI): 42 (優)\n" +"- 主要污染物: 無";}
}
注冊?MCP?工具

在應用程序入口類中注冊工具:

@SpringBootApplication
public class McpServerApplication {public static void main(String[] args) {SpringApplication.run(McpServerApplication.class, args);}@Beanpublic ToolCallbackProvider weatherTools(OpenMeteoService openMeteoService) {return MethodToolCallbackProvider.builder().toolObjects(openMeteoService).build();}@Beanpublic 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
public class Application {public static void main(String[] args) {// 啟動Spring Boot應用SpringApplication.run(Application.class, args);}@Beanpublic 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();};}
}

這段代碼展示了如何在?Spring?Boot?應用中使用?MCP?客戶端。它創建了一個命令行運行器,構建了?ChatClient?并注入了?MCP?工具,然后使用這個客戶端發送查詢并獲取響應。在?Spring?AI?Alibaba?中使用?Mcp?工具非常簡單,只需要把?ToolCallbackProvider?放到?chatClientBuilder的defaultTools?方法中,就可以自動的適配。通過命令啟動程序進行測試:Terminal?window```plaintext
mvn?spring-boot:run

啟動之后顯示結果為,從日志可以看到我們自己編寫的?mcp?server?被調用了,返回了數據:

>>> QUESTION: 北京的天氣如何?
2025-03-31T17:56:17.931+08:00 DEBUG 23455 --- [mcp] [pool-1-thread-1] io.modelcontextprotocol.spec.McpSchema   : Received JSON 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 DEBUG 23455 --- [mcp] [pool-1-thread-1] i.m.spec.McpClientSession                : Received Response: 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]

3.2?基于?SSE?的?MCP?客戶端實現

除了基于?stdio?的實現外,Spring?AI?Alibaba?還提供了基于?Server-Sent?Events?(SSE)的?MCP?客戶端實現。這種方式適用于遠程部署的?MCP?服務器,可以通過?HTTP?協議與?MCP?服務器進行通信。

添加依賴

首先,在您的項目中添加?Spring?AI?MCP?starter?依賴:

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

配置?MCP?服務器

在?application.yml?中配置?MCP?服務器,這里需要指定?SSE?啟動的服務地址,之前我們在?8080?端口上啟動了對應的服務:

spring:ai:dashscope:api-key: ${DASH_SCOPE_API_KEY}mcp:client:sse:connections:server1:url: http://localhost:8080  #服務地址

使用?MCP?客戶端

使用方式與基于?stdio?的實現相同,只需注入?ToolCallbackProvider?和?ChatClient.Builder:


@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}@Beanpublic CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder,ToolCallbackProvider tools,ConfigurableApplicationContext context) {return args -> {// 構建ChatClient并注入MCP工具var chatClient = chatClientBuilder.defaultTools(tools).build();// 使用ChatClient與LLM交互String userInput = "北京的天氣如何?";System.out.println("\n>>> QUESTION: " + userInput);System.out.println("\n>>> ASSISTANT: " + chatClient.prompt(userInput).call().content());context.close();};}
}

通過命令啟動程序進行測試:

Terminal?window

mvn?spring-boot:run

啟動之后會有報錯:

Caused by: java.lang.IllegalStateException: Multiple tools with the same name (spring-ai-mcp-client-getWeatherForecastByLocation, spring-ai-mcp-client-getAirQuality)at org.springframework.ai.mcp.SyncMcpToolCallbackProvider.validateToolCallbacks(SyncMcpToolCallbackProvider.java:126) ~[spring-ai-mcp-1.0.0-20250325.064812-147.jar:1.0.0-SNAPSHOT]at org.springframework.ai.mcp.SyncMcpToolCallbackProvider.getToolCallbacks(SyncMcpToolCallbackProvider.java:110) ~[spring-ai-mcp-1.0.0-20250325.064812-147.jar:1.0.0-SNAPSHOT]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]at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:171) ~[spring-beans-6.2.0.jar:6.2.0]... 23 common frames omitted

從日志上分析,是因為注冊了相同的服務名?spring-ai-mcp-client-getWeatherForecastByLocation?和?spring-ai-mcp-client-getAirQuality,但是從代碼上分析,這兩個服務我們都只注冊了一次,那為什么會報錯呢?

其實這是?Spring?AI?目前的一個?BUG,Spring?AI?提供了兩個自動配置類去生成客戶端工具處理?MCP?服務中?Tool?的獲取,分別是?SseHttpClientTransportAutoConfiguration?和?SseWebFluxTransportAutoConfiguration。這兩個自動配置類提供了同步和異步兩種方式,本身應該是互斥的,但是?Spring?AI?對于互斥的處理上出了問題,導致兩個自動配置類都會加載。

SseWebFluxTransportAutoConfiguration?的加載:

SseHttpClientTransportAutoConfiguration?的加載:

兩個自動配置類加載之后,就會向提供?SSE?服務的?MCP?服務申請?Tool,這樣就導致同樣的?Tool?被申請了兩次,自然就會重復了。解決方案也非常簡單,在啟動類上排除?SseHttpClientTransportAutoConfiguration?實現就可以了。

@SpringBootApplication(exclude = {org.springframework.ai.autoconfigure.mcp.client.SseHttpClientTransportAutoConfiguration.class
})
public class Application {
...

再次通過命令啟動程序進行測試:

Terminal?window

mvn?spring-boot:run

這一次就輸出了正確的結果:

在?Spring?AI?Alibaba?的?Open?Manus?中體驗?MCP

Spring?AI?Alibaba?中提供了?Open?Manus?的實現,整體架構如下:

在執行階段,會調用各種?Tool?來完成任務,如果我們能使用?MCP?增加?Tool?的能力,那勢必能?Open?Manus?如虎添翼,接下來我們就來看一下?Open?Manus?中是如何去使用?MCP?的。

源代碼如下:

++https://github.com/alibaba/spring-ai-alibaba/tree/main/community/openmanus++

添加依賴

首先,在項目中添加?Spring?AI?MCP?starter?依賴:

<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId><version>${spring-ai.version}</version>
</dependency>

配置?MCP?服務器

在?application.yml?中已經配置了?MCP?服務器,設置客戶端請求服務端的超時時間為?1?分鐘:

添加?mcp-servers-config.json,在?json?中配置了百度地圖。百度地圖核心?API?現已全面兼容?MCP?協議,是國內首家兼容?MCP?協議的地圖服務商。百度地圖已經完成了?8?個核心?API?接口和?MCP?協議的對接,?涵蓋逆地理編碼、地點檢索、路線規劃等。

使用百度地圖的?MCP,需要申請ak:

https://lbsyun.baidu.com/apiconsole/key。

{"mcpServers": {"baidu-map": {"command": "npx","args": ["-y","@baidumap/mcp-server-baidu-map"],"env": {"BAIDU_MAP_API_KEY": "your_baidu_AK"}}}
}

將其中BAIDU_MAP_API_KEY修改為申請的ak。

使用?MCP?工具

修改?LlmService?的構造方法源碼,在構造時直接通過?Spring?容器獲取?ToolCallbackProvider?并加入到?ChatClient.builder?中:

public LlmService(ChatModel chatModel, ToolCallbackProvider toolCallbackProvider) {this.chatModel = chatModel;this.planningChatClient = ChatClient.builder(chatModel).defaultSystem(PLANNING_SYSTEM_PROMPT).defaultAdvisors(new MessageChatMemoryAdvisor(planningMemory)).defaultAdvisors(new SimpleLoggerAdvisor()).defaultTools(ToolBuilder.getPlanningAgentToolCallbacks()).defaultTools(toolCallbackProvider).build();this.chatClient = ChatClient.builder(chatModel).defaultSystem(MANUS_SYSTEM_PROMPT).defaultAdvisors(new MessageChatMemoryAdvisor(memory)).defaultAdvisors(new SimpleLoggerAdvisor()).defaultTools(ToolBuilder.getManusAgentToolCalls()).defaultTools(toolCallbackProvider).defaultOptions(OpenAiChatOptions.builder().internalToolExecutionEnabled(false).build()).build();this.finalizeChatClient = ChatClient.builder(chatModel).defaultSystem(FINALIZE_SYSTEM_PROMPT).defaultAdvisors(new MessageChatMemoryAdvisor(finalizeMemory)).defaultAdvisors(new SimpleLoggerAdvisor()).build();
}

通過?defaultTools?將?mcp?服務提供的?tool?交給?ChatClient?處理。

測試效果

啟動?OpenManus,執行提示詞:規劃下從上海到北京的路線。但是如果這樣寫,可能會觸發?google?search,我們可以優化下提示詞主動選擇百度地圖。

使用百度地圖規劃從北京市到上海市的路線

執行程序之后可以看到規劃之后的計劃:

Steps:
0. [ ] [MANUS] 使用百度地圖的地理編碼服務獲取北京市和上海市的經緯度坐標
1. [ ] [MANUS] 使用百度地圖的路線規劃服務計算從北京市到上海市的駕車路線
2. [ ] [MANUS] 分析并提供最終的路線信息,包括距離、預計耗時等

很顯然,這一次?OpenManus?選擇了我們集成的百度地圖?mcp?server,我們來看一下結果。

獲取到了北京市和上海市的經緯度坐標:

Here is a summary of what we accomplished in this step:
- For Beijing, we received the coordinates: Longitude (lng): 116.4133836971231, Latitude (lat): 39.910924547299565.
- For Shanghai, we received the coordinates: Longitude (lng): 121.48053886017651, Latitude (lat): 31.235929042252014.

計算從北京市到上海市的駕車路線:

Distance: The total distance of the route is 1,223,200 meters (approximately 1,223 kilometers).
Duration: The estimated travel time is 50,592 seconds (approximately 14 hours and 3 minutes).

結果:

總距離:約?1223?公里

預計耗時:約?12?小時?45?分鐘

主要途徑:京滬高速公路(G2)

總結

作為?AI?開發領域的革命性突破,Model?Context?Protocol(MCP)重新定義了智能體與工具生態的交互范式。通過標準化協議打通地圖服務、代碼倉庫、數據庫等核心工具鏈,MCP?不僅解決了傳統?AI?開發中跨平臺對接的碎片化難題,更以”開箱即用”的輕量化集成模式,讓開發者能夠快速構建具備多模態能力的智能應用。

未來,隨著更多工具接入?MCP?生態,開發者只需專注于業務邏輯創新,而復雜的工具鏈整合將真正成為”看不見的底層能力”——這或許正是?AI?普惠化進程中,最具實際意義的技術躍遷。

Spring?AI?中的?MCP?支持可以讓?Java?開發者輕松的將自己的應用發布為?MCP?Server?或者是作為消費者去集成任意的?MCP?Server?實現。Spring?AI?Alibaba?社區?3?群:61290041831

Spring?AI?Alibaba?開源項目地址:

https://github.com/alibaba/spring-ai-alibaba

Spring?AI?Alibaba?官網地址:

https://java2ai.com/

本示例源碼地址:

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/79598.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/79598.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/79598.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【面試向】欠擬合和過擬合、正則化(Regularization)

訓練集、驗證集和測試集泛化誤差過擬合&#xff08;Overfitting&#xff09;和 欠擬合&#xff08;Underfitting&#xff09;如何區分過擬合和欠擬合&#xff1f;欠擬合 —— 在訓練集和驗證集上都表現很差過擬合 —— 在訓練集上表現很好&#xff0c;但在驗證集或測試集上表現…

ClawCloud的免費空間(github用戶登錄可以獲得$5元/月的免費額度)

免費的空間 Welcome to ClawCloud Lets create your workspace 官網&#xff1a;ClawCloud | Cloud Infrastructure And Platform for Developers 區域選擇新加坡 然后這個頁面會變成新加坡區域&#xff0c;再按一次確定&#xff0c;就創建好了工作臺。 初始界面&#xff0…

Spring Boot + Caffeine:打造高性能緩存解決方案

1. 引言 1.1 緩存的重要性 緩存是提升系統性能的關鍵技術之一,通過將頻繁訪問的數據存儲在內存中,減少對數據庫或其他外部系統的訪問次數,從而降低延遲并提高吞吐量。 緩存的基本概念:緩存是一種臨時存儲機制,用于快速訪問常用數據。緩存在提升系統性能中的作用:減少數…

每天學一個 Linux 命令(24):chattr

??可訪問網站查看,視覺品味拉滿: http://www.616vip.cn/24/index.html 每天學一個 Linux 命令(24):chattr 命令簡介 chattr(Change Attribute)用于修改文件或目錄的底層屬性(如防刪除、防修改),這些屬性比普通權限更嚴格。常用于保護重要文件或優化文件系統行為。…

【java 13天進階Day04】常用API、正則表達式,泛型、Collection集合API

Math類的使用。 Math用于做數學運算。Math類中的方法全部是靜態方法&#xff0c;直接用類名調用即可。方法&#xff1a; public static int abs(int a) 獲取參數a的絕對值public static double ceil(double a) 向上取整public static double floor(double a) 向下取整public s…

如何系統地入門學習stm32?

如何系統地入門學習stm32&#xff1f; 作為一個在嵌入式領域摸爬滾打十余年的工程師&#xff0c;看到這個問題&#xff0c;我不禁想起自己當年啃著厚重的數據手冊&#xff0c;對著一塊藍色的PCB板冥思苦想的日子。STM32的學習之路&#xff0c;說難不算特別難&#xff0c;說簡單…

考公:數字推理

文章目錄 1.真題12 312 530 756 ()-3 3 1 12 17 ()356 342 333 324 ()30 28 27 25 () 2215105 1494 1383 1272 ()2 3 8 21 46 ()4/25 1/4 4/9 1 ()39 416 630 848 ()5 8 11 17 () 10714 21 40 77 () 229 2.數字推理方法2.1 差值法2.2 比值法&#xff08;乘法關系&#xff09;2.…

自動化測試相關協議深度剖析及A2A、MCP協議自動化測試應用展望

一、不同協議底層邏輯關聯分析 1. OPENAPI協議 OPENAPI 協議核心在于定義 API 的規范結構&#xff0c;它使用 YAML 或 JSON 格式來描述 API 的端點、請求參數、響應格式等信息。其底層邏輯是構建一個清晰、標準化的 API 描述文檔&#xff0c;方便不同的客戶端和服務端進行對接…

2025.04.17【Dendrogram】生信數據可視化:Dendrogram圖表詳解

Dendrogram customization Go further with ggraph: edge style, general layout, node features, adding labels, and more. Customized circular dendrogram Learn how to build a circular dendrogram with proper labels. 文章目錄 Dendrogram customizationCustomized c…

SRS流媒體服務器

SRS流媒體服務器簡介 SRS(Simple RTMP Server)是一個開源的流媒體服務器&#xff0c;主要用于直播和WebRTC場景。以下是關于SRS的關鍵信息&#xff1a; 主要特性 支持多種協議&#xff1a;RTMP、HTTP-FLV、HLS、WebRTC、SRT等低延遲&#xff1a;特別優化了WebRTC和HTTP-FLV的…

R語言之環境清理

有時候 R 環境中殘留的變量可能會導致警告&#xff0c;可以嘗試清理工作空間并重新加載數據。 警告信息: In mget(objectNames, envir ns, inherits TRUE) : 重新評估被中斷的許諾 # 觀察前6行 head(iris)# 觀察數據結構 str(iris)# 探知數據的極值和分位數&#xff0c;以及…

RAG工程-基于LangChain 實現 Naive RAG

摘要 本篇文章以實現簡單的第一范式 RAG-Naive RAG為目標&#xff0c;并最終創建并實現一個基于RAG的論文分析器的項目。 LangChain 文檔加載 文檔加載是 RAG 流程的起點&#xff0c;它負責從各種數據源讀取原始文檔&#xff0c;將其轉化為程序可處理的格式。LangChain 支持多…

Rust網絡編程實戰:全面掌握reqwest庫的高級用法

一、開篇導引 1.1 對比Python Requests解釋為何reqwest是Rust生態的標桿HTTP客戶端 在Python生態中&#xff0c;Requests 庫以其簡潔易用的API成為了HTTP客戶端的首選。它使得開發者能夠輕松地發送各種HTTP請求&#xff0c;處理響應&#xff0c;而無需過多關注底層細節。然而…

k8s中sidecar死循環

序言 怎么發現我的同事們很上進呢&#xff0c;估計做了下賤的事兒吧。 傷不到我&#xff0c;不代表不疼&#xff01; sidecar產生的問題 1 背景 在k8s的環境中&#xff0c;pod的使用越來越多了&#xff0c;也就產生了sidecar容器&#xff0c;在現在的環境中&#xff0c;一個pod…

Day53 二叉樹的層序遍歷

給你二叉樹的根節點 root &#xff0c;返回其節點值的 層序遍歷 。 &#xff08;即逐層地&#xff0c;從左到右訪問所有節點&#xff09;。 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* T…

C盤清理技巧分享

一、系統級深度清理 1. 存儲感知自動化 路徑:設置 → 系統 → 存儲 → 開啟「存儲感知」配置策略: 臨時文件:每 1-2 周自動清理回收站:超過 30 天自動清空應用緩存:按需求設置清理頻率進階操作:在「高級存儲設置」中關閉「傳遞優化」(減少更新緩存占用)2. 磁盤清理工具…

面試題--隨機(一)

MySQL事務中的ACID特性&#xff1f; A 原子性 事務是一組SQL語句&#xff0c;不可分割 C 一致性 事務中的SQL語句要么同時執行&#xff0c;即全部執行成功&#xff0c;要么全部不執行&#xff0c;即執行失敗 I 隔離性 MySQL中的各個事務通過不同的事務隔離等級&#xff0c;產生…

Spring Boot資源耗盡問題排查與優化

Spring Boot服務運行一段時間后新請求無法處理的問題。服務沒有掛掉&#xff0c;也沒有異常日志。思考可能是一些資源耗盡或阻塞的問題。 思考分析 首先&#xff0c;資源耗盡可能涉及線程池、數據庫連接、內存、文件句柄或網絡連接等。常見的如線程池配置不當&#xff0c;導致…

Map和Set相關練習

目錄 1、只出現一次的數字 2、寶石與石頭 3、壞鍵盤打字 4、復制帶隨機指針的鏈表 5、大量數據去重 6、大量數據重復次數 7、前K個高頻單詞 1、只出現一次的數字 oj&#xff1a;136. 只出現一次的數字 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 1. 使用…

day45——非遞減數列(LeetCode-665)

題目描述 給你一個長度為 n 的整數數組 nums &#xff0c;請你判斷在 最多 改變 1 個元素的情況下&#xff0c;該數組能否變成一個非遞減數列。 我們是這樣定義一個非遞減數列的&#xff1a; 對于數組中任意的 i (0 < i < n-2)&#xff0c;總滿足 nums[i] < nums[i …