add 增加 ruoyi-common-mcp 模块 支持作为server提供mcp接口提供数据 与 接入多个client做数据采集

This commit is contained in:
疯狂的狮子Li
2026-05-18 17:24:59 +08:00
parent a2300b3a29
commit f237d0c391
15 changed files with 548 additions and 0 deletions
+5
View File
@@ -98,6 +98,11 @@
<artifactId>ruoyi-common-mqtt</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mcp</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,64 @@
package org.dromara.demo.controller;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.mcp.core.McpResourceReadResult;
import org.dromara.demo.mcp.McpDemoClientService;
import org.dromara.demo.mcp.McpDemoClientService.McpDemoHandleResult;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
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;
import java.util.Map;
/**
* MCP Client 演示案例。
* <p>
* 这些接口不是 MCP 协议接口,只是为了在后台系统中手动触发 MCP Client 调用。
* 真实 MCP Server 入口由 Spring AI 挂载到 `/mcp`。
* <p>
* 调用示例:
* <ul>
* <li>`GET /demo/mcp/tools`:查看已连接 MCP Server 的工具列表</li>
* <li>`GET /demo/mcp/receive?toolName=demo_get_data&amp;id=1`:调用外部工具并模拟业务处理</li>
* <li>`GET /demo/mcp/resource?uri=demo://summary`:读取外部 MCP 资源</li>
* </ul>
* 当 `spring.ai.mcp.client.enabled=false` 时,本 Controller 不会注册。
*
* @author Lion Li
*/
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/mcp")
@ConditionalOnBean(McpDemoClientService.class)
public class McpDemoController {
private final McpDemoClientService mcpDemoClientService;
/**
* 查询外部 MCP Server 工具列表。
*/
@GetMapping("/tools")
public R<Map<String, java.util.List<String>>> tools() {
return R.ok(mcpDemoClientService.listRemoteTools());
}
/**
* 调用外部 MCP 工具并模拟业务处理。
*/
@GetMapping("/receive")
public R<McpDemoHandleResult> receive(@RequestParam(defaultValue = "demo_get_data") String toolName,
@RequestParam(defaultValue = "1") String id) {
return R.ok(mcpDemoClientService.receiveAndHandle(toolName, Map.of("id", id)));
}
/**
* 读取外部 MCP 资源。
*/
@GetMapping("/resource")
public R<Map<String, McpResourceReadResult>> resource(@RequestParam(defaultValue = "demo://summary") String uri) {
return R.ok(mcpDemoClientService.readRemoteResource(uri));
}
}
@@ -0,0 +1,88 @@
package org.dromara.demo.mcp;
import org.dromara.common.mcp.core.McpClientTemplate;
import org.dromara.common.mcp.core.McpResourceReadResult;
import org.dromara.common.mcp.core.McpToolCallResult;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
/**
* MCP Client 演示服务,从外部 MCP Server 接收数据后交给业务层处理。
* <p>
* 本服务会注入 Spring AI 自动创建的多个 `McpSyncClient`。当
* `spring.ai.mcp.client.enabled=true` 且配置了多个 connection 时,
* 这里可以统一遍历这些 MCP Server。
* <p>
* 如果要用当前项目自己连自己测试,建议启动两个 `ruoyi-admin` 实例:
* 一个作为 server,一个作为 clientclient 指向 server 的地址。
*
* @author Lion Li
*/
@Service
@RequiredArgsConstructor
@ConditionalOnBean(McpClientTemplate.class)
public class McpDemoClientService {
private final McpClientTemplate mcpClientTemplate;
/**
* 查询已接入的 MCP Server 与工具列表。
*
* @return Server 名称与工具名称列表
*/
public Map<String, List<String>> listRemoteTools() {
return mcpClientTemplate.listTools();
}
/**
* 调用外部 MCP 工具接收数据。
*
* @param toolName 工具名称
* @param arguments 工具参数
* @return 工具返回内容
*/
public Map<String, McpToolCallResult> callRemoteTool(String toolName, Map<String, Object> arguments) {
return mcpClientTemplate.callTool(toolName, arguments);
}
/**
* 读取外部 MCP 资源。
*
* @param uri 资源地址
* @return 资源内容
*/
public Map<String, McpResourceReadResult> readRemoteResource(String uri) {
return mcpClientTemplate.readResource(uri);
}
/**
* 模拟业务处理入口。真实业务可在这里做校验、转换、去重、入库和审计。
* <p>
* MCP 返回数据不建议直接入库,应先转换成业务 BO/DTO,再进入业务 Service。
*
* @param toolName 工具名称
* @param arguments 工具参数
* @return 处理结果
*/
public McpDemoHandleResult receiveAndHandle(String toolName, Map<String, Object> arguments) {
return new McpDemoHandleResult("MCP", true, callRemoteTool(toolName, arguments));
}
/**
* MCP 数据处理结果。
*
* @param sourceType 数据来源类型
* @param handled 是否已处理
* @param data MCP 原始返回数据
*/
public record McpDemoHandleResult(
String sourceType,
boolean handled,
Map<String, McpToolCallResult> data
) {
}
}
@@ -0,0 +1,85 @@
package org.dromara.demo.mcp;
import org.springframework.ai.mcp.annotation.McpResource;
import org.springframework.ai.mcp.annotation.McpTool;
import org.springframework.ai.mcp.annotation.McpToolParam;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.List;
/**
* MCP Server 演示工具,对外提供业务数据。
* <p>
* 启动 `ruoyi-admin` 后,本类中的 `@McpTool` 与 `@McpResource` 会被 Spring AI
* MCP 注解扫描器注册到当前应用的 MCP Server,默认通过同端口 `/mcp` 暴露。
* <p>
* 可被外部 MCP Client 调用的示例能力:
* <ul>
* <li>`demo_get_data`:根据 id 查询一条演示数据</li>
* <li>`demo_list_data`:按 limit 查询演示数据列表</li>
* <li>`demo://summary`:读取演示模块摘要资源</li>
* </ul>
* 真实业务中不要在 MCP 工具里直接访问 Mapper,应继续调用业务 Service
* 并保留权限、租户、脱敏、审计和幂等规则。
*
* @author Lion Li
*/
@Component
public class McpDemoServerTool {
/**
* 查询一条演示数据。
*
* @param id 业务主键
* @return 演示数据
*/
@McpTool(name = "demo_get_data", description = "根据业务主键查询演示数据")
public McpDemoData getData(@McpToolParam(description = "业务主键") String id) {
return new McpDemoData(id, "演示数据-" + id, "ruoyi-demo", 100, LocalDateTime.now());
}
/**
* 查询演示数据列表。
*
* @param limit 返回条数
* @return 演示数据列表
*/
@McpTool(name = "demo_list_data", description = "查询演示数据列表")
public List<McpDemoData> listData(@McpToolParam(description = "返回条数") Integer limit) {
int size = limit == null || limit < 1 ? 3 : Math.min(limit, 20);
return java.util.stream.IntStream.rangeClosed(1, size)
.mapToObj(index -> new McpDemoData(String.valueOf(index), "演示数据-" + index, "ruoyi-demo", index * 10, LocalDateTime.now()))
.toList();
}
/**
* 读取演示资源。
*
* @return 演示资源内容
*/
@McpResource(
name = "demo_summary",
uri = "demo://summary",
description = "演示模块摘要资源",
mimeType = "text/plain"
)
public String summary() {
return "ruoyi-demo MCP resource summary";
}
/**
* MCP 演示数据。
*
* @author Lion Li
*/
public record McpDemoData(
String id,
String name,
String source,
Integer amount,
LocalDateTime syncTime
) {
}
}