当前位置: 首页 > news >正文

03.使用spring-ai玩转MCP

接着上篇:https://blog.csdn.net/sinat_15906013/article/details/147052013,我们介绍了,什么是MCP?使用cline插件/cherry-studio安装了Mcp Server,本篇我们要借助spring-ai实现MCP Client和Server。

使用spring-ai的话,需要spring-boot3和JDK17。

MCP Server

  1. 引入mcp-server依赖
<properties><java.version>17</java.version><spring-ai.version>1.0.0-M7</spring-ai.version>
</properties>
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>
<dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>${spring-ai.version}</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>
  1. 使用@Tool声明方法,使用@ToolParam声明参数
@Service
public class EchoService {/*** echo** @param msg* @return String*/@Tool(description = "echo")public String echo(@ToolParam(description = "消息") String msg) {return msg;}
}
  1. 将EchoService注入到ToolCallbackProvider
@Configuration
public class McpServerConfig {@Beanpublic ToolCallbackProvider allTools(EchoService echoService) {return MethodToolCallbackProvider.builder().toolObjects(echoService).build();}
}
  1. 单元测试
class ToolTest {private final static String url = "http://localhost:8899";private static McpSyncClient client;@BeforeAllpublic static void init() {var transport = new WebFluxSseClientTransport(WebClient.builder().baseUrl(url));client = McpClient.sync(transport).build();client.initialize();client.ping();}@Testpublic void test() {// List and demonstrate toolsListToolsResult toolsList = client.listTools();System.out.println("Available Tools = " + toolsList);CallToolResult echo = client.callTool(new CallToolRequest("echo",Map.of("msg", "hello world")));System.out.println("echo: " + echo);client.closeGracefully();}
}
  1. 扩展mcp-server不仅提供了tool,还有prompt和resource
@Configuration
public class PromptManagement {@Beanpublic List<McpServerFeatures.SyncPromptSpecification> myPrompts() {var prompt = new McpSchema.Prompt("greeting", "A friendly greeting prompt",List.of(new McpSchema.PromptArgument("name", "The name to greet", true)));var promptSpecification = new McpServerFeatures.SyncPromptSpecification(prompt, (exchange, getPromptRequest) -> {String nameArgument = (String) getPromptRequest.arguments().get("name");if (nameArgument == null) { nameArgument = "friend"; }var userMessage = new McpSchema.PromptMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello " + nameArgument + "! How can I assist you today?"));return new McpSchema.GetPromptResult("A personalized greeting message", List.of(userMessage));});return List.of(promptSpecification);}
}
@Configuration
public class ResourceManagement {@Beanpublic List<McpServerFeatures.SyncResourceSpecification> myResources() {var systemInfoResource = new McpSchema.Resource("file:///logs/app.log", "Application Logs", "Application Logs", "text/plain",new McpSchema.Annotations(List.of(McpSchema.Role.USER), 1.0));var resourceSpecification = new McpServerFeatures.SyncResourceSpecification(systemInfoResource, (exchange, request) -> {try {var systemInfo = Map.of();String jsonContent = new ObjectMapper().writeValueAsString(systemInfo);return new McpSchema.ReadResourceResult(List.of(new McpSchema.TextResourceContents(request.uri(), "application/json", jsonContent)));} catch (Exception e) {throw new RuntimeException("Failed to generate system info", e);}});return List.of(resourceSpecification);}
}

参考前面的单元测试:client.listTools(),下面两种应该也不在话下。
在这里插入图片描述

MCP Client

  1. 引入mcp-client依赖
<properties><java.version>17</java.version><spring-ai.version>1.0.0-M7</spring-ai.version>
</properties><!-- web&webflux start -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- web&webflux end --><!-- model start -->
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>
<!--		<dependency>-->
<!--			<groupId>org.springframework.ai</groupId>-->
<!--			<artifactId>spring-ai-starter-model-openai</artifactId>-->
<!--		</dependency>-->
<!-- model end --><!-- MCP start -->
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
</dependency>
<!-- MCP end --><dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>${spring-ai.version}</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>
  1. 在application.properties配置stdio方式的mcp-server
spring.ai.mcp.client.stdio.servers-configuration=classpath:/mcp-servers-config.json

发没发现,配合和之前的客户端一致,mcp-servers-config.json如下:

{"mcpServers": {"time": {"command": "cmd","args": ["/c","uvx","mcp-server-time","--local-timezone=Asia/Shanghai"]},"filesystem": {"command": "cmd","args": ["/c","npx","-y","@modelcontextprotocol/server-filesystem","D:\\SourceCode\\bsp-mcp"]}}
}
  1. 在application.yaml配置模型和sse方式的mcp-server
spring:ai:ollama:base-url: http://192.168.199.255:11434chat:options:model: qwen2.5:32bmcp:client:toolcallback:enabled: truesse:connections:amap:url: https://mcp.amap.com?key=xxxmy:url: http://localhost:8899
  1. 配置模型集成MCP
    ChatModel是对话模型,常见的还有Embedding是关于RAG的。
    在这里插入图片描述
    OllamaChatModel是支持function call的,我们就以它为例。
    在这里插入图片描述
    来自:https://docs.spring.io/spring-ai/reference/api/index.html#_ai_model_api
@Configuration
public class ChatClientConfig {@Beanpublic ChatClient client(OllamaChatModel ollamaChatModel,SyncMcpToolCallbackProvider syncMcpToolCallbackProvider) {return ChatClient.builder(ollamaChatModel).defaultTools(syncMcpToolCallbackProvider).build();}
}
  1. 对外提供API
@RequiredArgsConstructor
@RestController
public class MCPController {private final ChatClient client;private final List<McpSyncClient> mcpClientList;@GetMapping("/ai/mcp/generate")public Map<String, String> generate(@RequestParam(value = "message", defaultValue = "几点了?") String message) {return Map.of("generation", client.prompt(message).call().content());}@GetMapping("/ai/mcp/servers")public List<McpSyncClient> servers() {return mcpClientList;}@GetMapping("/ai/mcp/tools")public McpSchema.ListToolsResult tools(String name) {return mcpClientList.stream().filter(mcpSyncClient ->StringUtils.endsWithIgnoreCase(name, mcpSyncClient.getServerInfo().name())).findFirst().get().listTools();}@GetMapping("/ai/mcp/resources")public McpSchema.ListResourcesResult resources(String name) {return mcpClientList.stream().filter(mcpSyncClient ->StringUtils.endsWithIgnoreCase(name, mcpSyncClient.getServerInfo().name())).findFirst().get().listResources();}@GetMapping("/ai/mcp/prompts")public McpSchema.ListPromptsResult prompts(String name) {return mcpClientList.stream().filter(mcpSyncClient ->StringUtils.endsWithIgnoreCase(name, mcpSyncClient.getServerInfo().name())).findFirst().get().listPrompts();}
}

抓包分析交互流程

在这里插入图片描述
来自:https://docs.spring.io/spring-ai/reference/api/index.html#_tool_calling_api

http://www.xdnf.cn/news/171073.html

相关文章:

  • IdeaVim 配置与使用指南
  • 【Part 2安卓原生360°VR播放器开发实战】第二节|基于等距圆柱投影方式实现全景视频渲染
  • 位置差在坐标系间的相互转换
  • C++类和对象(上)
  • Spark SQL开发实战:从IDEA环境搭建到UDF/UDAF自定义函数实现
  • 《TVM模式匹配实战:从DFPatternNode到DFPattern的高级用法》
  • OceanBase数据库-学习笔记2-C#/C++程序如何访问
  • C++如何使用调试器(如GDB、LLDB)进行程序调试保姆级教程(2万字长文)
  • 使用 Autofac 实现依赖注入
  • 嵌入式软件--stm32 DAY 4 中断系统
  • Linux日志处理命令多管道实战应用
  • Python爬虫实战:获取网yi云音乐飙升榜的歌曲数据并作分析,为歌单推荐做参考
  • Spark SQL核心概念与编程实战:从DataFrame到DataSet的结构化数据处理
  • 《一键式江湖:Docker Compose中间件部署108式》开篇:告别“配置地狱”,从此笑傲云原生武林!》
  • python+adafruit_pca9685 测试舵机存储当前角度
  • 知识体系_数据量纲化处理方式
  • PWN基础-利用格式化字符串漏洞泄露canary结合栈溢出getshell
  • 神经网络笔记 - 神经网络
  • 东田数码科技前端面经
  • 运算符分为哪几类?哪些运算符常用作判断?简述运算符的优先级
  • 电池的寿命
  • 参数规模:衡量大语言模型体量的标尺
  • 【Java面试笔记:进阶】23.请介绍类加载过程,什么是双亲委派模型?
  • NEPCON China 2025 | 具身智能时代来临,灵途科技助力人形机器人“感知升级”
  • Spring MVC深度解析:从原理到实战
  • 进程与线程-----C语言经典题目(8)
  • Net版本Spire.doc 最新版去水印
  • OpenCV进阶操作:图像金字塔
  • Django(快速上手版)
  • IDEA中使用Git