Spring AI构建MCP服务与Cherry Studio配合使用案例

2025-06-13 · · 原创 · · 本文共 832个字,预计阅读需要 3分钟。

MCP相关概念

MCPModel Context Protocol,即模型上下文协议)是由 AnthropicClaude 的母公司)于 2024年11月 开源发布的一项 全新技术 1

MCP 是一个开放标准,旨在连接AI助手与数据所在的系统,包括内容存储库、业务工具和开发环境。其目标是帮助前沿模型产生更好、更相关的响应。

MCP为 AI 模型连接不同数据源和工具提供了标准化方法。

MCP 的核心组成部分

MCP 遵循客户端-服务器架构,其中主机应用可以连接到多个服务器。

服务器(Server):提供特定功能的工具,比如网页搜索、文件访问等

客户端(Client):在AI应用中与服务器保持连接

传输(Transport):客户端和服务器之间的通信方式

主机(Host):启动连接的应用程序,如Cherry Studio或Claude Desktop、Cline、Cursor、WindSurf

使用Spring AI构建MCP Server

根据Spring AI官方文档4, 可以使用多种输出构建:WebFlux、WebMvc等。

同时依赖的 JDK17/21、Spring Boot 3.4.x+、Spring AI 1.0.0-M6+版本

项目搭建步骤:

  1. 使用springboot搭建服务,依赖如下
  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>3.5.0</version>
  5. <relativePath/>
  6. </parent>
  7. <groupId>com.yuan.mcp</groupId>
  8. <artifactId>growx-mcp-server</artifactId>
  9. <version>0.0.1-SNAPSHOT</version>
  10. <name>growx-mcp-server</name>
  11. <properties>
  12. <java.version>17</java.version>
  13. <spring-ai.version>1.0.0</spring-ai.version>
  14. </properties>
  15. <dependencies>
  16. <dependency>
  17. <groupId>org.springframework.ai</groupId>
  18. <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId> <!--webflux -->
  19. </dependency>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-test</artifactId>
  23. <scope>test</scope>
  24. </dependency>
  25. </dependencies>
  26. <dependencyManagement>
  27. <dependencies>
  28. <dependency>
  29. <groupId>org.springframework.ai</groupId>
  30. <artifactId>spring-ai-bom</artifactId>
  31. <version>${spring-ai.version}</version>
  32. <type>pom</type>
  33. <scope>import</scope>
  34. </dependency>
  35. </dependencies>
  36. </dependencyManagement>
  37. <build>
  38. <plugins>
  39. <plugin>
  40. <groupId>org.springframework.boot</groupId>
  41. <artifactId>spring-boot-maven-plugin</artifactId>
  42. </plugin>
  43. </plugins>
  44. </build>
  1. 构建mcp服务(根据ip查询地址)
  1. @Service
  2. public class IPServiceImpl implements IPService {
  3. Logger log = LoggerFactory.getLogger(IPServiceImpl.class);
  4. @Value("${ip-info.token}")
  5. private String token;
  6. @Autowired
  7. private ObjectMapper objectMapper;
  8. @Tool(description = "根据id查询地理位置相关信息(机名hostname/城市city/地区region/国家country/位置loc/公司org/邮政编码postal/时区timezone)")
  9. @Override
  10. public Address queryAddressByIp(@ToolParam(description = "ip地址") String ip) {
  11. if (ip == null || ip.isEmpty()) {
  12. log.warn("IP地址为空");
  13. return null;
  14. }
  15. String requestUrl = String.format("https://ipinfo.io/%s?token=%s", ip, token);
  16. log.info("ip地址详情查询请求参数:{}", requestUrl);
  17. try {
  18. URL url = new URL(requestUrl);
  19. HttpURLConnection connection = (HttpURLConnection) url.openConnection();
  20. connection.setRequestMethod("GET");
  21. // connection.setRequestProperty("Authorization", "Bearer " + token);
  22. connection.setConnectTimeout(5000);
  23. connection.setReadTimeout(5000);
  24. int responseCode = connection.getResponseCode();
  25. if (responseCode != HttpURLConnection.HTTP_OK) {
  26. log.error("请求失败,响应码: {}", responseCode);
  27. return null;
  28. }
  29. BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
  30. StringBuilder response = new StringBuilder();
  31. String line;
  32. while ((line = reader.readLine()) != null) {
  33. response.append(line);
  34. }
  35. reader.close();
  36. log.info("返回的数据:{}", response);
  37. return objectMapper.readValue(response.toString(), Address.class);
  38. } catch (IOException e) {
  39. log.error("查询 IP 地址信息时发生异常: {}", e.getMessage(), e);
  40. return null;
  41. }
  42. }
  43. }
  1. 定义返回的对象
  1. public class Address {
  2. /**
  3. * ip地址
  4. */
  5. private String ip;
  6. /**
  7. * 主机名
  8. */
  9. private String hostname;
  10. /**
  11. * 城市
  12. */
  13. private String city;
  14. /**
  15. * 地区
  16. */
  17. private String region;
  18. /**
  19. * 国家
  20. */
  21. private String country;
  22. /**
  23. * 位置
  24. */
  25. private String loc;
  26. /**
  27. * 公司
  28. */
  29. private String org;
  30. /**
  31. * 邮政编码
  32. */
  33. private String postal;
  34. /**
  35. * 时区
  36. */
  37. private String timezone;
  38. private Boolean anycast;
  39. //get/set方法
  40. }
  1. 配置ToolCallbackProviderConfig
  1. @Configuration
  2. public class ToolCallbackProviderConfig {
  3. @Bean
  4. public ToolCallbackProvider recommendTools(IPService service) {
  5. return MethodToolCallbackProvider.builder().toolObjects(service).build();
  6. }
  7. }
  1. 编写测试类(WebFlux、WebMvc)
  1. // WebMvc
  2. var transport = HttpClientSseClientTransport.builder("http://localhost:8080").build();
  3. try (var client = McpClient.sync(transport).build()) {
  4. client.initialize();
  5. McpSchema.ListToolsResult toolsList = client.listTools();
  6. System.out.println("Available Tools = " + toolsList);
  7. McpSchema.CallToolResult currentTimResult = client.callTool(new McpSchema.CallToolRequest("queryAddressByIp", Map.of("ip", "8.8.8.8")));
  8. System.out.println("current time Response = " + currentTimResult);
  9. }
  10. }
  11. // WebFlux
  12. var transport = new WebFluxSseClientTransport(WebClient.builder().baseUrl("http://localhost:8080"));
  13. var client = McpClient.sync(transport).build();
  14. client.initialize();
  15. client.ping();
  16. // 列出并展示可用的工具
  17. McpSchema.ListToolsResult toolsList = client.listTools();
  18. System.out.println("可用工具 = " + toolsList);
  19. // 获取成都的天气
  20. McpSchema.CallToolResult result = client.callTool(new McpSchema.CallToolRequest("queryAddressByIp", Map.of("ip", "8.8.8.8")));
  21. System.out.println("返回结果: " + result.content());
  22. client.closeGracefully();

客户端配置地址参考McpServerProperties

  1. @ConfigurationProperties("spring.ai.mcp.server")
  2. public class McpServerProperties {
  3. public static final String CONFIG_PREFIX = "spring.ai.mcp.server";
  4. private boolean enabled = true;
  5. private boolean stdio = false;
  6. private String name = "mcp-server";
  7. private String version = "1.0.0";
  8. private String instructions = null;
  9. private boolean resourceChangeNotification = true;
  10. private boolean toolChangeNotification = true;
  11. private boolean promptChangeNotification = true;
  12. private String baseUrl = "";
  13. private String sseEndpoint = "/sse";
  14. private String sseMessageEndpoint = "/mcp/message";
  1. 配置文件application.yml配置参数
  1. spring:
  2. application:
  3. name: mcp-server
  4. ip-info:
  5. token: xx
  6. server:
  7. port: 8080

Cherry Studio中配置连接MCP Server

选择MCP服务,新建服务,给服务取名称、描述,类型选择:SSEURL配置为: http://localhost:8080/sse

再打开对话中,选中该MCP服务,然后就可以进行对话使用

参考:

  1. Java 实现 MCP Server 以及常用 MCP 服务分享:https://cloud.tencent.com/developer/article/2515900
  2. MCP:基于 Spring AI 实现 webmvc/webflux sse Mcp Server:https://juejin.cn/post/7484154732408274983
  3. spring ai mcp server代码示例:https://zhuanlan.zhihu.com/p/1901799795745620964
  4. SpringAI 参考:模型上下文协议 (MCP):https://docs.spring.io/spring-ai/reference/api/mcp/mcp-overview.html
  5. IP Geolocation API:https://ipinfo.io/products/ip-geolocation-api
  6. 如何为Spring AI MCP Server提供OAuth2认证:https://spring4all.com/forum-post/8595.html