摘要
本文以原理與示例結合的形式講解?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