├── mcp-client ├── src │ ├── main │ │ ├── resources │ │ │ ├── test.db │ │ │ ├── application.properties │ │ │ └── templates │ │ │ │ └── index.html │ │ └── java │ │ │ └── com │ │ │ └── ahucoding │ │ │ └── rocket │ │ │ └── mcpclient │ │ │ ├── McpClientApplication.java │ │ │ ├── view │ │ │ ├── IndexController.java │ │ │ └── ChatController.java │ │ │ └── cfg │ │ │ └── McpConfig.java │ └── test │ │ └── java │ │ └── com │ │ └── ahucoding │ │ └── rocket │ │ └── mcpclient │ │ └── McpClientApplicationTests.java └── pom.xml ├── mcp-server ├── src │ ├── main │ │ ├── resources │ │ │ └── application.yaml │ │ └── java │ │ │ └── com │ │ │ └── ahucoding │ │ │ └── rocket │ │ │ └── mcpserver │ │ │ ├── McpServerApplication.java │ │ │ ├── service │ │ │ └── BookService.java │ │ │ └── cfg │ │ │ └── McpServerConfig.java │ └── test │ │ └── java │ │ └── com │ │ └── ahucoding │ │ └── rocket │ │ └── mcpserver │ │ ├── McpServerApplicationTests.java │ │ └── SampleClient.java └── pom.xml ├── call-mcp-server ├── src │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── ahucoding │ │ │ └── rocket │ │ │ └── callmcpserver │ │ │ └── CallMcpServerApplicationTests.java │ └── main │ │ ├── resources │ │ ├── application.yaml │ │ ├── mcp-server.json │ │ ├── mcp-server-bak.json │ │ └── templates │ │ │ └── index.html │ │ └── java │ │ └── com │ │ └── ahucoding │ │ └── rocket │ │ └── callmcpserver │ │ ├── CallMcpServerApplication.java │ │ ├── view │ │ ├── IndexController.java │ │ └── ChatController.java │ │ └── cfg │ │ └── McpClientCfg.java └── pom.xml ├── .gitignore ├── README.md └── pom.xml /mcp-client/src/main/resources/test.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AHUCodingBeast/spring-ai-mcp-demo/HEAD/mcp-client/src/main/resources/test.db -------------------------------------------------------------------------------- /mcp-client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=mcp 2 | server.port=9090 3 | spring.thymeleaf.prefix=classpath:/templates/ 4 | spring.thymeleaf.suffix=.html 5 | 6 | spring.ai.dashscope.api-key={?????API-key} 7 | 8 | -------------------------------------------------------------------------------- /mcp-server/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: mcp-server 4 | ai: 5 | mcp: 6 | server: 7 | name: webmvc-mcp-server 8 | version: 1.0.0 9 | type: SYNC 10 | sse-message-endpoint: /mcp/messages 11 | -------------------------------------------------------------------------------- /mcp-client/src/test/java/com/ahucoding/rocket/mcpclient/McpClientApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.ahucoding.rocket.mcpclient; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class McpClientApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /call-mcp-server/src/test/java/com/ahucoding/rocket/callmcpserver/CallMcpServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.ahucoding.rocket.callmcpserver; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class CallMcpServerApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /call-mcp-server/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9999 3 | spring: 4 | ai: 5 | mcp: 6 | client: 7 | enabled: true 8 | name: call-mcp-server 9 | # stdio: 10 | # servers-configuration: classpath:mcp-server.json 11 | sse: 12 | connections: 13 | server1: 14 | url: http://127.0.0.1:8080 15 | dashscope: 16 | api-key: {阿里云千问apiKey} -------------------------------------------------------------------------------- /mcp-server/src/main/java/com/ahucoding/rocket/mcpserver/McpServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.ahucoding.rocket.mcpserver; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class McpServerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(McpServerApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /mcp-server/src/test/java/com/ahucoding/rocket/mcpserver/McpServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.ahucoding.rocket.mcpserver; 2 | 3 | 4 | import io.modelcontextprotocol.client.transport.HttpClientSseClientTransport; 5 | 6 | class McpServerApplicationTests { 7 | 8 | public static void main(String[] args) { 9 | var transport = new HttpClientSseClientTransport("http://localhost:8080"); 10 | new SampleClient(transport).run(); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /mcp-client/src/main/java/com/ahucoding/rocket/mcpclient/McpClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.ahucoding.rocket.mcpclient; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class McpClientApplication { 8 | 9 | public static void main(String[] args) { 10 | 11 | SpringApplication.run(McpClientApplication.class, args); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /call-mcp-server/src/main/java/com/ahucoding/rocket/callmcpserver/CallMcpServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.ahucoding.rocket.callmcpserver; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class CallMcpServerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(CallMcpServerApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /call-mcp-server/src/main/resources/mcp-server.json: -------------------------------------------------------------------------------- 1 | { 2 | "mcpServers": { 3 | "fileSystem": { 4 | "command": "D:\\software\\nodeJs\\npx.cmd", 5 | "args": [ 6 | "-y", 7 | "@modelcontextprotocol/server-filesystem", 8 | "D:\\software\\sqlite" 9 | ] 10 | }, 11 | "sqlLite": { 12 | "command": "D:\\Program Files\\python3.12.3\\Scripts\\uvx.exe", 13 | "args": [ 14 | "mcp-server-sqlite", 15 | "--db-path", 16 | "D:\\work-space-study\\spring-ai-mcp-demo\\mcp-client\\src\\main\\resources\\test.db" 17 | ] 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /mcp-client/src/main/java/com/ahucoding/rocket/mcpclient/view/IndexController.java: -------------------------------------------------------------------------------- 1 | package com.ahucoding.rocket.mcpclient.view; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.ui.Model; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | 7 | /** 8 | * @author jianzhang 9 | * 2025/03/11/上午10:51 10 | */ 11 | @Controller 12 | public class IndexController { 13 | 14 | @GetMapping("/") 15 | public String chat(Model model) { 16 | //model.addAttribute("name", "User"); 17 | // 返回视图名称,对应 templates/index.html 18 | return "index"; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /call-mcp-server/src/main/java/com/ahucoding/rocket/callmcpserver/view/IndexController.java: -------------------------------------------------------------------------------- 1 | package com.ahucoding.rocket.callmcpserver.view; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.ui.Model; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | 7 | /** 8 | * @author jianzhang 9 | * 2025/03/18/下午8:00 10 | */ 11 | @Controller 12 | public class IndexController { 13 | 14 | @GetMapping("/") 15 | public String chat(Model model) { 16 | //model.addAttribute("name", "User"); 17 | // 返回视图名称,对应 templates/index.html 18 | return "index"; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /call-mcp-server/src/main/java/com/ahucoding/rocket/callmcpserver/cfg/McpClientCfg.java: -------------------------------------------------------------------------------- 1 | package com.ahucoding.rocket.callmcpserver.cfg; 2 | 3 | import io.modelcontextprotocol.client.McpClient; 4 | import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | import java.time.Duration; 8 | 9 | /** 10 | * @author jianzhang 11 | * 2025/03/18/下午8:02 12 | */ 13 | @Configuration 14 | public class McpClientCfg implements McpSyncClientCustomizer { 15 | 16 | 17 | @Override 18 | public void customize(String name, McpClient.SyncSpec spec) { 19 | // do nothing 20 | spec.requestTimeout(Duration.ofSeconds(30)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /mcp-server/src/main/java/com/ahucoding/rocket/mcpserver/service/BookService.java: -------------------------------------------------------------------------------- 1 | package com.ahucoding.rocket.mcpserver.service; 2 | 3 | import org.springframework.ai.tool.annotation.Tool; 4 | import org.springframework.stereotype.Service; 5 | 6 | import java.util.List; 7 | 8 | @Service 9 | public class BookService { 10 | 11 | 12 | public record Book(List isbn, String title, List authorName) { 13 | } 14 | 15 | @Tool(description = "Get list of Books by title") 16 | public List getBooks(String title) { 17 | // 这里模拟查询DB操作 18 | return List.of(new Book(List.of("ISBN-88888888888"), "SpringAI教程", List.of("红专写的书"))); 19 | } 20 | 21 | @Tool(description = "Get book titles by author") 22 | public List getBookTitlesByAuthor(String authorName) { 23 | // 这里模拟查询DB操作 24 | return List.of(authorName+"SpringAI教程"); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 重要提示(必看): 4 | 5 | SpringAI和SpringAI-alibaba都发布了最新依赖稳定版本(之前基于快照版本需要设置Repository 如今已经不需要设置),如果遇到依赖下载不下来请按照最新的官方文档修改依赖版本,官网快照版本更新很快可能出现API冲突的情况 请以最新版本的API设计为准 6 | 推荐参考文档:https://java2ai.com/docs/1.0.0.2/practices/mcp/spring-ai-mcp-starter-server/?spm=4347728f.4dbc009c.0.0.179c6e97CtuJGQ 7 | 8 | 9 | # spring-ai-mcp-demo 10 | SpringAI MCP demo 结合通义千问大模型 11 | 12 | ## 环境要求 13 | - JDK 17+ 14 | - Maven 3.8.6+ 15 | - npm 10.9.2+ 16 | - python3.12.3+ 17 | - 需要去申请一个自己的千问大模型key 18 | - SpringAI 1.0.0-M5 + SpringAI 1.0.0-M6 19 | 20 | ## 模块功能 21 | - mcp-client模块:基于SpringAI 1.0.0-M5 版本,展示了如何使用FunctionCall的方式与MCP服务端对接 22 | - call-mcp-server模块:基于SpringAI 1.0.0-M6 版本,展示了如何使用ToolCall的方式与MCP服务端对接 23 | - mcp-server模块:简单的MCP服务端Demo(已经去除了数据库依赖,具体功能可以自己实现) 24 | 25 | ## call-mcp-server模块 26 | call-mcp-server模块可以充当cursor或者Claude的角色,直接调用各种开源MCP服务例如百度地图服务 27 | 修改call-mcp-server/src/main/resources/mcp-server.json中的内容即可 28 | 详情参考:[掘金技术社区 10分钟带你集成百度地图MCP服务](https://juejin.cn/post/7485758756913266707) 29 | 30 | ## 帮助文档 31 | - [掘金技术社区 SpringAI-MCP技术初探](https://juejin.cn/post/7483127098352877579) 32 | 33 | -------------------------------------------------------------------------------- /call-mcp-server/src/main/resources/mcp-server-bak.json: -------------------------------------------------------------------------------- 1 | { 2 | "mcpServers": { 3 | "fileSystem": { 4 | "command": "D:\\software\\nodeJs\\npx.cmd", 5 | "args": [ 6 | "-y", 7 | "@modelcontextprotocol/server-filesystem", 8 | "D:\\software\\sqlite" 9 | ] 10 | }, 11 | "sqlLite": { 12 | "command": "D:\\Program Files\\python3.12.3\\Scripts\\uvx.exe", 13 | "args": [ 14 | "mcp-server-sqlite", 15 | "--db-path", 16 | "D:\\work-space-study\\spring-ai-mcp-demo\\mcp-client\\src\\main\\resources\\test.db" 17 | ] 18 | }, 19 | "fetch": { 20 | "command": "D:\\Program Files\\python3.12.3\\Scripts\\uvx.exe", 21 | "args": [ 22 | "mcp-server-fetch" 23 | ] 24 | }, 25 | "baidu-map": { 26 | "command": "D:\\Program Files\\python3.12.3\\Scripts\\uvx.exe", 27 | "args": [ 28 | "run", 29 | "--with", 30 | "mcp[cli]", 31 | "mcp", 32 | "run", 33 | "D:\\work-space-python\\python-baidu-map\\baidu_map_mcp_server\\map.py" 34 | ], 35 | "env": { 36 | "BAIDU_MAPS_API_KEY": "{百度地图API-KEY}" 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.4.3 9 | 10 | 11 | com.ahucoding.rocket 12 | spring-ai-mcp-demo 13 | 0.0.1-SNAPSHOT 14 | spring-ai-mcp-demo 15 | spring-ai-mcp-demo 16 | pom 17 | 18 | 19 | 20 | 17 21 | 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-maven-plugin 28 | 29 | 30 | 31 | maven-resources-plugin 32 | 3.2.0 33 | 34 | 35 | copy-data 36 | validate 37 | 38 | copy-resources 39 | 40 | 41 | ${project.build.directory} 42 | 43 | 44 | ${project.basedir}/data 45 | false 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /mcp-client/src/main/java/com/ahucoding/rocket/mcpclient/view/ChatController.java: -------------------------------------------------------------------------------- 1 | package com.ahucoding.rocket.mcpclient.view; 2 | 3 | import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions; 4 | import jakarta.servlet.http.HttpServletResponse; 5 | import org.springframework.ai.chat.client.ChatClient; 6 | import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; 7 | import org.springframework.ai.chat.memory.ChatMemory; 8 | import org.springframework.ai.chat.memory.InMemoryChatMemory; 9 | import org.springframework.ai.chat.model.ChatResponse; 10 | import org.springframework.ai.mcp.spring.McpFunctionCallback; 11 | import org.springframework.web.bind.annotation.*; 12 | import reactor.core.publisher.Flux; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * @author jianzhang 18 | * 2025/03/12/下午2:05 19 | */ 20 | @RestController 21 | @RequestMapping("/dashscope/chat-client") 22 | public class ChatController { 23 | 24 | private final ChatClient chatClient; 25 | 26 | private final ChatMemory chatMemory = new InMemoryChatMemory(); 27 | 28 | public ChatController(ChatClient.Builder chatClientBuilder, List functionCallbacks) { 29 | this.chatClient = chatClientBuilder 30 | .defaultFunctions(functionCallbacks.toArray(new McpFunctionCallback[0])) 31 | .defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory())) 32 | .defaultOptions(DashScopeChatOptions.builder().withTopP(0.7).build()) 33 | .build(); 34 | } 35 | 36 | 37 | @RequestMapping(value = "/generate_stream", method = RequestMethod.GET) 38 | public Flux generateStream(HttpServletResponse response, @RequestParam("id") String id, @RequestParam("prompt") String prompt) { 39 | response.setCharacterEncoding("UTF-8"); 40 | var messageChatMemoryAdvisor = new MessageChatMemoryAdvisor(chatMemory, id, 10); 41 | return this.chatClient.prompt(prompt) 42 | .advisors(messageChatMemoryAdvisor).stream().chatResponse(); 43 | } 44 | 45 | 46 | @GetMapping("/advisor/chat/{id}/{prompt}") 47 | public Flux advisorChat( 48 | HttpServletResponse response, 49 | @PathVariable String id, 50 | @PathVariable String prompt) { 51 | 52 | response.setCharacterEncoding("UTF-8"); 53 | var messageChatMemoryAdvisor = new MessageChatMemoryAdvisor(chatMemory, id, 10); 54 | return this.chatClient.prompt(prompt) 55 | .advisors(messageChatMemoryAdvisor).stream().content(); 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /mcp-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.3.6 9 | 10 | 11 | mcp-server 12 | 0.0.1-SNAPSHOT 13 | mcp-server 14 | mcp-server 15 | 16 | 17 | 18 | 19 | 20 | 17 21 | 22 | 23 | 24 | 25 | 26 | 27 | org.springframework.ai 28 | spring-ai-bom 29 | 1.0.0-M6 30 | pom 31 | import 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter 42 | 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-test 47 | test 48 | 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-starter-web 53 | 54 | 55 | 56 | org.springframework.ai 57 | spring-ai-mcp-server-webmvc-spring-boot-starter 58 | 59 | 60 | 61 | org.springframework.ai 62 | spring-ai-mcp 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | org.springframework.boot 71 | spring-boot-maven-plugin 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /mcp-client/src/main/java/com/ahucoding/rocket/mcpclient/cfg/McpConfig.java: -------------------------------------------------------------------------------- 1 | package com.ahucoding.rocket.mcpclient.cfg; 2 | 3 | import org.springframework.ai.mcp.client.McpClient; 4 | import org.springframework.ai.mcp.client.McpSyncClient; 5 | import org.springframework.ai.mcp.client.transport.ServerParameters; 6 | import org.springframework.ai.mcp.client.transport.StdioClientTransport; 7 | import org.springframework.ai.mcp.spring.McpFunctionCallback; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | import java.time.Duration; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * @author jianzhang 17 | * 2025/03/12/下午2:20 18 | */ 19 | @Configuration 20 | public class McpConfig { 21 | 22 | 23 | @Bean 24 | public List functionCallbacks(List mcpSyncClients) { 25 | List list = new ArrayList<>(); 26 | 27 | for (McpSyncClient mcpSyncClient : mcpSyncClients) { 28 | list.addAll(mcpSyncClient.listTools(null) 29 | .tools() 30 | .stream() 31 | .map(tool -> new McpFunctionCallback(mcpSyncClient, tool)) 32 | .toList()); 33 | } 34 | return list; 35 | } 36 | 37 | @Bean(destroyMethod = "close") 38 | public McpSyncClient mcpFileSysClient() { 39 | // 把这里的路径记得改为自己的真实路径 40 | var stdioParams = ServerParameters.builder("D:\\software\\nodeJs\\npx.cmd") 41 | .args("-y", "@modelcontextprotocol/server-filesystem", "D:\\工作日志") 42 | .build(); 43 | var mcpClient = McpClient.using(new StdioClientTransport(stdioParams)) 44 | .requestTimeout(Duration.ofSeconds(10)).sync(); 45 | var init = mcpClient.initialize(); 46 | 47 | System.out.println("mcpFileSysClient loading init=" + init); 48 | return mcpClient; 49 | } 50 | 51 | // @Bean(destroyMethod = "close") 52 | // public McpSyncClient mcpDbClient() { 53 | // // 把这里的路径记得改为自己的真实路径 54 | // var stdioParams = ServerParameters.builder("D:\\Program Files\\python3.12.3\\Scripts\\uvx.exe") 55 | // .args("mcp-server-sqlite", "--db-path", "D:\\work-space-study\\spring-ai-mcp-demo\\mcp-client\\src\\main\\resources\\test.db") 56 | // .build(); 57 | // var mcpClient = McpClient.using(new StdioClientTransport(stdioParams)) 58 | // .requestTimeout(Duration.ofSeconds(10)).sync(); 59 | // var init = mcpClient.initialize(); 60 | // System.out.println("mcpDbClient loading init=" + init); 61 | // return mcpClient; 62 | // 63 | // } 64 | 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /call-mcp-server/src/main/java/com/ahucoding/rocket/callmcpserver/view/ChatController.java: -------------------------------------------------------------------------------- 1 | package com.ahucoding.rocket.callmcpserver.view; 2 | 3 | import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions; 4 | import io.modelcontextprotocol.client.McpSyncClient; 5 | import jakarta.servlet.http.HttpServletResponse; 6 | import org.springframework.ai.chat.client.ChatClient; 7 | import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; 8 | import org.springframework.ai.chat.memory.ChatMemory; 9 | import org.springframework.ai.chat.memory.InMemoryChatMemory; 10 | import org.springframework.ai.chat.model.ChatResponse; 11 | import org.springframework.ai.mcp.SyncMcpToolCallback; 12 | import org.springframework.ai.mcp.SyncMcpToolCallbackProvider; 13 | import org.springframework.ai.tool.ToolCallbackProvider; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.web.bind.annotation.*; 16 | import reactor.core.publisher.Flux; 17 | 18 | import java.util.List; 19 | 20 | /** 21 | * @author jianzhang 22 | * 2025/03/18/下午8:00 23 | */ 24 | @RestController 25 | @RequestMapping("/dashscope/chat-client") 26 | public class ChatController { 27 | 28 | private final ChatClient chatClient; 29 | 30 | private final ChatMemory chatMemory = new InMemoryChatMemory(); 31 | 32 | 33 | public ChatController(ChatClient.Builder chatClientBuilder, List mcpSyncClients, ToolCallbackProvider tools) { 34 | this.chatClient = chatClientBuilder 35 | .defaultTools(tools) 36 | .defaultOptions(DashScopeChatOptions.builder().withTopP(0.7).build()) 37 | .build(); 38 | } 39 | 40 | 41 | 42 | @RequestMapping(value = "/generate_stream", method = RequestMethod.GET) 43 | public Flux generateStream(HttpServletResponse response, @RequestParam("id") String id, @RequestParam("prompt") String prompt) { 44 | response.setCharacterEncoding("UTF-8"); 45 | var messageChatMemoryAdvisor = new MessageChatMemoryAdvisor(chatMemory, id, 10); 46 | return this.chatClient.prompt(prompt) 47 | .advisors(messageChatMemoryAdvisor) 48 | .stream() 49 | .chatResponse(); 50 | } 51 | 52 | 53 | @GetMapping("/advisor/chat/{id}/{prompt}") 54 | public Flux advisorChat( 55 | HttpServletResponse response, 56 | @PathVariable String id, 57 | @PathVariable String prompt) { 58 | 59 | response.setCharacterEncoding("UTF-8"); 60 | var messageChatMemoryAdvisor = new MessageChatMemoryAdvisor(chatMemory, id, 10); 61 | return this.chatClient.prompt(prompt) 62 | .advisors(messageChatMemoryAdvisor).stream().content(); 63 | } 64 | 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /mcp-server/src/test/java/com/ahucoding/rocket/mcpserver/SampleClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 - 2024 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ahucoding.rocket.mcpserver; 17 | 18 | import java.util.Map; 19 | 20 | import io.modelcontextprotocol.client.McpClient; 21 | import io.modelcontextprotocol.spec.ClientMcpTransport; 22 | import io.modelcontextprotocol.spec.McpSchema.CallToolRequest; 23 | import io.modelcontextprotocol.spec.McpSchema.CallToolResult; 24 | import io.modelcontextprotocol.spec.McpSchema.GetPromptRequest; 25 | import io.modelcontextprotocol.spec.McpSchema.ListPromptsResult; 26 | import io.modelcontextprotocol.spec.McpSchema.ListToolsResult; 27 | import io.modelcontextprotocol.spec.McpSchema.ReadResourceRequest; 28 | 29 | /** 30 | * @author Christian Tzolov 31 | */ 32 | 33 | public class SampleClient { 34 | 35 | private final ClientMcpTransport transport; 36 | 37 | public SampleClient(ClientMcpTransport transport) { 38 | this.transport = transport; 39 | } 40 | 41 | public void run() { 42 | 43 | var client = McpClient.sync(this.transport).build(); 44 | 45 | client.initialize(); 46 | 47 | client.ping(); 48 | 49 | // List and demonstrate tools 50 | ListToolsResult toolsList = client.listTools(); 51 | System.out.println("Available Tools = " + toolsList); 52 | 53 | 54 | CallToolResult books = client.callTool(new CallToolRequest("getBooks", Map.of("title", "Spring Framework"))); 55 | System.out.println("Books Response = " + books); 56 | 57 | // List and demonstrate resources 58 | var resourcesList = client.listResources(); 59 | System.out.println("\nAvailable Resources = " + resourcesList); 60 | 61 | // Read the system info resource 62 | var systemInfo = client.readResource(new ReadResourceRequest("system://info")); 63 | System.out.println("System Info = " + systemInfo); 64 | 65 | // List and demonstrate prompts 66 | ListPromptsResult promptsList = client.listPrompts(); 67 | System.out.println("\nAvailable Prompts = " + promptsList); 68 | 69 | // Try the greeting prompt 70 | var greetingResponse = client.getPrompt(new GetPromptRequest("greeting", Map.of("name", "Spring"))); 71 | System.out.println("Greeting Response = " + greetingResponse); 72 | 73 | client.closeGracefully(); 74 | 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /mcp-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.4.3 9 | 10 | 11 | 12 | mcp-client 13 | 0.0.1-SNAPSHOT 14 | mcp-client 15 | mcp-client 16 | 17 | 18 | 17 19 | 1.0.0-M5.1 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-thymeleaf 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-web 41 | 42 | 43 | 44 | 45 | com.alibaba.cloud.ai 46 | spring-ai-alibaba-starter 47 | ${spring.ai.alibaba} 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.experimental 54 | spring-ai-mcp 55 | 0.6.0 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | spring-milestones 66 | Spring Milestones 67 | https://repo.spring.io/milestone 68 | 69 | false 70 | 71 | 72 | 73 | spring-snapshots 74 | Spring Snapshots 75 | https://repo.spring.io/snapshot 76 | 77 | false 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /call-mcp-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.4.3 9 | 10 | 11 | com.ahucoding.rocket 12 | call-mcp-server 13 | 0.0.1-SNAPSHOT 14 | call-mcp-server 15 | call-mcp-server 16 | 17 | 18 | 19 | 17 20 | 1.0.0-M6.1 21 | 22 | 23 | 24 | 25 | 26 | 27 | org.springframework.ai 28 | spring-ai-bom 29 | 1.0.0-M6 30 | pom 31 | import 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-test 46 | test 47 | 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-starter-web 52 | 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-starter-thymeleaf 57 | 58 | 59 | 60 | 61 | org.springframework.ai 62 | spring-ai-mcp-client-spring-boot-starter 63 | 1.0.0-SNAPSHOT 64 | 65 | 66 | 67 | org.springframework.ai 68 | spring-ai-mcp 69 | 70 | 71 | 72 | com.alibaba.cloud.ai 73 | spring-ai-alibaba-starter 74 | ${spring.ai.alibaba} 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | org.springframework.boot 83 | spring-boot-maven-plugin 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /mcp-server/src/main/java/com/ahucoding/rocket/mcpserver/cfg/McpServerConfig.java: -------------------------------------------------------------------------------- 1 | package com.ahucoding.rocket.mcpserver.cfg; 2 | 3 | import com.ahucoding.rocket.mcpserver.service.BookService; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import io.modelcontextprotocol.server.McpServerFeatures; 6 | import io.modelcontextprotocol.spec.McpSchema; 7 | import org.springframework.ai.tool.ToolCallbackProvider; 8 | import org.springframework.ai.tool.method.MethodToolCallbackProvider; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 12 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 13 | 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.function.Consumer; 17 | 18 | /** 19 | * @author jianzhang 20 | * 2025/03/18/下午3:23 21 | */ 22 | @Configuration 23 | @EnableWebMvc 24 | public class McpServerConfig implements WebMvcConfigurer { 25 | 26 | @Bean 27 | public ToolCallbackProvider openLibraryTools(BookService bookService) { 28 | return MethodToolCallbackProvider.builder().toolObjects(bookService).build(); 29 | } 30 | 31 | @Bean 32 | public List resourceRegistrations() { 33 | 34 | // Create a resource registration for system information 35 | var systemInfoResource = new McpSchema.Resource( 36 | "system://info", 37 | "System Information", 38 | "Provides basic system information including Java version, OS, etc.", 39 | "application/json", null 40 | ); 41 | 42 | var resourceRegistration = new McpServerFeatures.SyncResourceRegistration(systemInfoResource, (request) -> { 43 | try { 44 | var systemInfo = Map.of( 45 | "javaVersion", System.getProperty("java.version"), 46 | "osName", System.getProperty("os.name"), 47 | "osVersion", System.getProperty("os.version"), 48 | "osArch", System.getProperty("os.arch"), 49 | "processors", Runtime.getRuntime().availableProcessors(), 50 | "timestamp", System.currentTimeMillis()); 51 | 52 | String jsonContent = new ObjectMapper().writeValueAsString(systemInfo); 53 | 54 | return new McpSchema.ReadResourceResult( 55 | List.of(new McpSchema.TextResourceContents(request.uri(), "application/json", jsonContent))); 56 | } 57 | catch (Exception e) { 58 | throw new RuntimeException("Failed to generate system info", e); 59 | } 60 | }); 61 | 62 | return List.of(resourceRegistration); 63 | } 64 | 65 | 66 | 67 | @Bean 68 | public List promptRegistrations() { 69 | 70 | var prompt = new McpSchema.Prompt("greeting", "A friendly greeting prompt", 71 | List.of(new McpSchema.PromptArgument("name", "The name to greet", true))); 72 | 73 | var promptRegistration = new McpServerFeatures.SyncPromptRegistration(prompt, getPromptRequest -> { 74 | 75 | String nameArgument = (String) getPromptRequest.arguments().get("name"); 76 | if (nameArgument == null) { 77 | nameArgument = "friend"; 78 | } 79 | 80 | var userMessage = new McpSchema.PromptMessage(McpSchema.Role.USER, 81 | new McpSchema.TextContent("Hello " + nameArgument + "! How can I assist you today?")); 82 | 83 | return new McpSchema.GetPromptResult("A personalized greeting message", List.of(userMessage)); 84 | }); 85 | 86 | return List.of(promptRegistration); 87 | } 88 | 89 | 90 | @Bean 91 | public Consumer> rootsChangeConsumer() { 92 | return roots -> { 93 | System.out.println("rootsChange"); 94 | }; 95 | } 96 | 97 | 98 | 99 | 100 | } 101 | -------------------------------------------------------------------------------- /mcp-client/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | AI 对话助手 7 | 8 | 9 | 10 |
11 | 12 |
13 |

AI 对话助手

14 |

基于 Spring AI 的流式对话系统 By AhuCodingBeast

15 |
16 | 17 | 18 |
19 | 20 |
21 |
22 | 您好!我是AI助手,有什么可以帮您? 23 |
24 |
25 |
26 | 27 | 28 |
29 | 32 | 40 |
41 |
42 | 43 | 146 | 147 | -------------------------------------------------------------------------------- /call-mcp-server/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | AI 对话助手 7 | 8 | 9 | 10 |
11 | 12 |
13 |

AI 对话助手

14 |

基于 Spring AI 的流式对话系统 By AhuCodingBeast

15 |
16 | 17 | 18 |
19 | 20 |
21 |
22 | 您好!我是AI助手,有什么可以帮您? 23 |
24 |
25 |
26 | 27 | 28 |
29 | 32 | 40 |
41 |
42 | 43 | 147 | 148 | --------------------------------------------------------------------------------