作者簡介:你好,我是影子,Spring Ai Alibaba開源社區 Committer,持續分享Spring Ai Alibaba最新進展 + 業界各類AI工程相關的方案
- 最近有斷時間沒更了,熟悉我的朋友知道我剛結束完畢業旅行,最近也因為入職,參與公司為期一周的文化相關的培訓(培訓的東西真是太贊了,每一條都直擊高效生活的本質,受益非淺,主動積極、雙贏思維,個人成長->公眾成長等等),實在抽不出時間來寫文章了,這不趁著周末趕快寫點東西
本文是官網更詳細的上手例子:Spring AI Alibaba MCP Gateway 正式發布,零代碼實現存量應用轉換 MCP 工具!
Gateway 實現存量應用轉 MCP 工具
[!TIP]
Spring AI Alibaba MCP Gateway 基于 Nacos 提供的 MCP server registry 實現,為普通應用建立一個中間代理層 Java MCP 應用。一方面將 Nacos 中注冊的服務信息轉換成 MCP 協議的服務器信息,以便 MCP 客戶端可以無縫調用這些服務;另一方面可以實現協議轉化,將 MCP 協議轉換為對后端 HTTP、Dubbo 等服務的調用。基于 Spring AI Alibaba MCP Gateway,您無需對原有業務代碼進行改造,新增或者刪除 MCP 服務(在 Nacos 中)無需重啟代理應用實戰代碼可見:https://github.com/GTyingzi/spring-ai-tutorial 下的 other 目錄下的 nacos-restful 模塊、mcp 目錄下的 server 目錄下的 mcp-gateway 模塊
restful 服務
pom 文件
<properties><nacos.version>3.0.2</nacos.version>
</properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba.nacos</groupId><artifactId>nacos-client</artifactId><version>${nacos.version}</version><scope>compile</scope></dependency>
</dependencies>
application.yml
server:port: ${SERVERPORT:18081} # 默認端口為18081,可以通過命令行參數SERVERPORT覆蓋spring:application:name: nacos-restfultcloud:# nacos注冊中心配置nacos:discovery:username: nacospassword: nacosserver-addr: 127.0.0.1:8848namespace: 4ad3108b-4d44-43d0-9634-3c1ac4850c8c # nacos3.*版本
config
package com.spring.ai.tutorial.other.config;import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;/*** @author yingzi* @since 2025/7/7*/
@Configuration
public class NacosConfig {private static final Logger logger = LoggerFactory.getLogger(NacosConfig.class);@Value("${spring.application.name}")private String serviceName;@Value("${spring.cloud.nacos.discovery.server-addr}")private String serverAddr;@Value("${spring.cloud.nacos.discovery.namespace}")private String namespace;@Value("${spring.cloud.nacos.discovery.username}")private String username;@Value("${spring.cloud.nacos.discovery.password}")private String password;@Value("${server.port}")private int port;@Beanpublic NamingService namingService() throws NacosException, UnknownHostException {Properties properties = new Properties();properties.put(PropertyKeyConst.NAMESPACE, Objects.toString(this.namespace, ""));properties.put(PropertyKeyConst.SERVERADDR, Objects.toString(this.serverAddr, ""));properties.put(PropertyKeyConst.USERNAME, Objects.toString(this.username, ""));properties.put(PropertyKeyConst.PASSWORD, Objects.toString(this.password, ""));NamingService namingService = NamingFactory.createNamingService(properties);init(namingService);return namingService;}private void init(NamingService namingService) throws NacosException, UnknownHostException {Instance instance = new Instance();// 自動獲取本機IPinstance.setIp(InetAddress.getLocalHost().getHostAddress());instance.setPort(port);instance.setMetadata(Map.of("register.timestamp", String.valueOf(System.currentTimeMillis())));logger.info("注冊實例: {}:{}", instance.getIp(), port);namingService.registerInstance(serviceName, instance);}}
Controller
package com.spring.ai.tutorial.other.controller;import com.spring.ai.tutorial.other.utils.ZoneUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** @author yingzi* @date 2025/4/6:12:56*/
@RestController
@RequestMapping("/time")
public class TimeController {private static final Logger logger = LoggerFactory.getLogger(TimeController.class);/*** 獲取指定時區的時間*/@GetMapping("/city")public String getCiteTimeMethod(@RequestParam("timeZoneId") String timeZoneId) {logger.info("The current time zone is {}", timeZoneId);return String.format("The current time zone is %s and the current time is " + "%s", timeZoneId,ZoneUtils.getTimeByZoneId(timeZoneId));}
}
package com.spring.ai.tutorial.other.utils;import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;/*** @author yingzi* @date 2025/3/25:14:59*/
public class ZoneUtils {public static String getTimeByZoneId(String zoneId) {// Get the time zone using ZoneIdZoneId zid = ZoneId.of(zoneId);// Get the current time in this time zoneZonedDateTime zonedDateTime = ZonedDateTime.now(zid);// Defining a formatterDateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z");// Format ZonedDateTime as a stringString formattedDateTime = zonedDateTime.format(formatter);return formattedDateTime;}public static void main(String[] args) {System.out.println(getTimeByZoneId("Asia/Shanghai"));}}
效果:注冊至 Nacos 中
nacos 配置
Mcp server 連接 restful 配置
在 MCP 管理-MCP 列表處創建 MCP Server
- 填寫命名空間:4ad3108b-4d44-43d0-9634-3c1ac4850c8c
,不填寫默認為 Default
- MCP 服務名:mcp-nacos-restful
- 協議類型:這里選擇 sse
- HTTP 轉 MCP 服務:這里選擇 http
- 后端服務:選擇已有服務(因為我們的后端服務已經注冊在 Nacos 中了,故直接使用即可,也可以通過新建服務指定 ip+port 的形式)
- 描述:該項服務的說明
- 服務版本:指定版本
新增 Tool 配置
Tool 名稱:getCiteTimeMethod
Tool 描述:獲取指定時區的時間
啟用:True
Tool 入參描述:
- timeZoneId;string;time zone id, such as Asia/Shanghai
協議轉換配置(注意,這里輸出的轉換邏輯具體可看 com.alibaba.cloud.ai.mcp.nacos.gateway.jsontemplate 包下的 ResponseTemplateParser 類)
{
"requestTemplate":{"method":"GET","url":"/time/city","argsToUrlParam":true
},
"responseTemplate":{"body":"{{.}}"
}
}
發布后,可到配置管理處看到相關配置信息
gateway 轉接
pom 文件
<properties><!-- Spring AI Alibaba --><spring-ai-alibaba.version>1.0.0.3-SNAPSHOT</spring-ai-alibaba.version>
</properties><dependencies><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-nacos-mcp-gateway</artifactId><version>${spring-ai-alibaba.version}</version></dependency><!-- MCP Server WebFlux 支持(也可換成 WebMvc) --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-server-webflux</artifactId></dependency></dependencies>
application.yml
server:port: 19000spring:application:name: mcp-gateway-serverai:mcp:server:name: mcp-gateway-serverversion: 1.0.0alibaba:mcp:nacos:namespace: 4ad3108b-4d44-43d0-9634-3c1ac4850c8cserver-addr: 127.0.0.1:8848username: nacospassword: nacosgateway:enabled: trueservice-names: mcp-nacos-restful # 和nacos配置的mcp server保持一致# 調試日志
logging:level:io:modelcontextprotocol:client: DEBUGspec: DEBUGserver: DEBUG
驗證
啟動對應的兩個模塊
- nacos-restful 模塊
- mcp-gateway 模塊
在利用 MCP Inspector 進行測試
參考資料
Spring AI Alibaba MCP Gateway 正式發布,零代碼實現存量應用轉換 MCP 工具!
往期文章解讀
第一章內容
SpringAI(GA)的chat:快速上手+自動注入源碼解讀
SpringAI(GA):ChatClient調用鏈路解讀
第二章內容
SpringAI的Advisor:快速上手+源碼解讀
SpringAI(GA):Sqlite、Mysql、Redis消息存儲快速上手
第三章內容
SpringAI(GA):Tool工具整合—快速上手
SpringAI(GA):Tool源碼+工具觸發鏈路解讀
第四章內容
SpringAI(GA):結構化輸出的快速上手+源碼解讀
第五章內容
SpringAI(GA):內存、Redis、ES的向量數據庫存儲—快速上手
SpringAI(GA):向量數據庫理論源碼解讀+Redis、Es接入源碼
第六章內容
SpringAI(GA):RAG快速上手+模塊化解讀
SpringAI(GA):RAG下的ETL快速上手
SpringAI(GA):RAG下的ETL源碼解讀
第七章內容
SpringAI(GA):Nacos2下的分布式MCP
SpringAI(GA):Nacos3下的分布式MCP
SpringAI(GA):MCP源碼解讀
SpringAI(GA): SpringAI下的MCP源碼解讀
進階:MCP服務鑒權案例
第八章內容
SpringAI(GA): 多模型評估篇
第九章內容
SpringAI(GA):觀測篇快速上手+源碼解讀
第十章內容
Spring AI Alibaba Graph:快速入門
Spring AI Alibaba Graph:多節點并行—快速上手
Spring AI Alibaba Graph:節點流式透傳案例
Spring AI Alibaba Graph:分配MCP到指定節點
Spring AI Alibaba Graph:中斷!人類反饋介入,流程絲滑走完~