From b0728aba5c01842e24da3cff04e44be06c6bb655 Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期四, 19 三月 2026 13:38:38 +0800
Subject: [PATCH] #AI.去除多余mcp
---
rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiMcpMountServiceImpl.java | 223 +++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 188 insertions(+), 35 deletions(-)
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiMcpMountServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiMcpMountServiceImpl.java
index 822d55c..e358929 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiMcpMountServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiMcpMountServiceImpl.java
@@ -1,10 +1,12 @@
package com.vincent.rsf.server.ai.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.ai.config.AiDefaults;
+import com.vincent.rsf.server.ai.dto.AiMcpConnectivityTestDto;
import com.vincent.rsf.server.ai.dto.AiMcpToolPreviewDto;
import com.vincent.rsf.server.ai.dto.AiMcpToolTestDto;
import com.vincent.rsf.server.ai.dto.AiMcpToolTestRequest;
@@ -22,6 +24,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -34,45 +37,128 @@
private final ObjectMapper objectMapper;
@Override
- public List<AiMcpMount> listActiveMounts() {
+ public List<AiMcpMount> listActiveMounts(Long tenantId) {
+ ensureTenantId(tenantId);
return this.list(new LambdaQueryWrapper<AiMcpMount>()
+ .eq(AiMcpMount::getTenantId, tenantId)
.eq(AiMcpMount::getStatus, StatusType.ENABLE.val)
+ .eq(AiMcpMount::getDeleted, 0)
.orderByAsc(AiMcpMount::getSort)
.orderByAsc(AiMcpMount::getId));
}
@Override
- public void validateBeforeSave(AiMcpMount aiMcpMount) {
+ public void validateBeforeSave(AiMcpMount aiMcpMount, Long tenantId) {
+ ensureTenantId(tenantId);
+ aiMcpMount.setTenantId(tenantId);
fillDefaults(aiMcpMount);
- ensureRequiredFields(aiMcpMount);
+ ensureRequiredFields(aiMcpMount, tenantId);
}
@Override
- public void validateBeforeUpdate(AiMcpMount aiMcpMount) {
+ public void validateBeforeUpdate(AiMcpMount aiMcpMount, Long tenantId) {
+ ensureTenantId(tenantId);
fillDefaults(aiMcpMount);
if (aiMcpMount.getId() == null) {
throw new CoolException("MCP 鎸傝浇 ID 涓嶈兘涓虹┖");
}
- ensureRequiredFields(aiMcpMount);
+ AiMcpMount current = requireMount(aiMcpMount.getId(), tenantId);
+ aiMcpMount.setTenantId(current.getTenantId());
+ ensureRequiredFields(aiMcpMount, tenantId);
}
@Override
public List<AiMcpToolPreviewDto> previewTools(Long mountId, Long userId, Long tenantId) {
- AiMcpMount mount = requireMount(mountId);
+ AiMcpMount mount = requireMount(mountId, tenantId);
+ long startedAt = System.currentTimeMillis();
try (McpMountRuntimeFactory.McpMountRuntime runtime = mcpMountRuntimeFactory.create(List.of(mount), userId)) {
- List<AiMcpToolPreviewDto> tools = new ArrayList<>();
- for (ToolCallback callback : runtime.getToolCallbacks()) {
- if (callback == null || callback.getToolDefinition() == null) {
- continue;
- }
- tools.add(AiMcpToolPreviewDto.builder()
- .name(callback.getToolDefinition().name())
- .description(callback.getToolDefinition().description())
- .inputSchema(callback.getToolDefinition().inputSchema())
- .returnDirect(callback.getToolMetadata() == null ? null : callback.getToolMetadata().returnDirect())
- .build());
+ List<AiMcpToolPreviewDto> tools = buildToolPreviewDtos(runtime.getToolCallbacks(),
+ AiDefaults.MCP_TRANSPORT_BUILTIN.equals(mount.getTransportType())
+ ? builtinMcpToolRegistry.listBuiltinToolCatalog(mount.getBuiltinCode())
+ : List.of());
+ if (!runtime.getErrors().isEmpty()) {
+ String message = String.join("锛�", runtime.getErrors());
+ updateHealthStatus(mount.getId(), AiDefaults.MCP_HEALTH_UNHEALTHY, message, System.currentTimeMillis() - startedAt);
+ throw new CoolException(message);
}
+ updateHealthStatus(mount.getId(), AiDefaults.MCP_HEALTH_HEALTHY,
+ "宸ュ叿瑙f瀽鎴愬姛锛屽叡 " + tools.size() + " 涓伐鍏�", System.currentTimeMillis() - startedAt);
return tools;
+ } catch (CoolException e) {
+ throw e;
+ } catch (Exception e) {
+ updateHealthStatus(mount.getId(), AiDefaults.MCP_HEALTH_UNHEALTHY,
+ "宸ュ叿瑙f瀽澶辫触: " + e.getMessage(), System.currentTimeMillis() - startedAt);
+ throw new CoolException("鑾峰彇宸ュ叿鍒楄〃澶辫触: " + e.getMessage());
+ }
+ }
+
+ @Override
+ public AiMcpConnectivityTestDto testConnectivity(Long mountId, Long userId, Long tenantId) {
+ AiMcpMount mount = requireMount(mountId, tenantId);
+ long startedAt = System.currentTimeMillis();
+ try (McpMountRuntimeFactory.McpMountRuntime runtime = mcpMountRuntimeFactory.create(List.of(mount), userId)) {
+ long elapsedMs = System.currentTimeMillis() - startedAt;
+ if (!runtime.getErrors().isEmpty()) {
+ String message = String.join("锛�", runtime.getErrors());
+ updateHealthStatus(mount.getId(), AiDefaults.MCP_HEALTH_UNHEALTHY, message, elapsedMs);
+ AiMcpMount latest = requireMount(mount.getId(), tenantId);
+ return buildConnectivityDto(latest, message, elapsedMs, runtime.getToolCallbacks().length);
+ }
+ String message = "杩為�氭�ф祴璇曟垚鍔燂紝瑙f瀽鍑� " + runtime.getToolCallbacks().length + " 涓伐鍏�";
+ updateHealthStatus(mount.getId(), AiDefaults.MCP_HEALTH_HEALTHY, message, elapsedMs);
+ AiMcpMount latest = requireMount(mount.getId(), tenantId);
+ return buildConnectivityDto(latest, message, elapsedMs, runtime.getToolCallbacks().length);
+ } catch (CoolException e) {
+ throw e;
+ } catch (Exception e) {
+ long elapsedMs = System.currentTimeMillis() - startedAt;
+ String message = "杩為�氭�ф祴璇曞け璐�: " + e.getMessage();
+ updateHealthStatus(mount.getId(), AiDefaults.MCP_HEALTH_UNHEALTHY, message, elapsedMs);
+ AiMcpMount latest = requireMount(mount.getId(), tenantId);
+ return buildConnectivityDto(latest, message, elapsedMs, 0);
+ }
+ }
+
+ @Override
+ public AiMcpConnectivityTestDto testDraftConnectivity(AiMcpMount mount, Long userId, Long tenantId) {
+ ensureTenantId(tenantId);
+ if (userId == null) {
+ throw new CoolException("褰撳墠鐧诲綍鐢ㄦ埛涓嶅瓨鍦�");
+ }
+ if (mount == null) {
+ throw new CoolException("MCP 鎸傝浇鍙傛暟涓嶈兘涓虹┖");
+ }
+ mount.setTenantId(tenantId);
+ fillDefaults(mount);
+ ensureRequiredFields(mount, tenantId);
+ long startedAt = System.currentTimeMillis();
+ try (McpMountRuntimeFactory.McpMountRuntime runtime = mcpMountRuntimeFactory.create(List.of(mount), userId)) {
+ long elapsedMs = System.currentTimeMillis() - startedAt;
+ if (!runtime.getErrors().isEmpty()) {
+ return AiMcpConnectivityTestDto.builder()
+ .mountId(mount.getId())
+ .mountName(mount.getName())
+ .healthStatus(AiDefaults.MCP_HEALTH_UNHEALTHY)
+ .message(String.join("锛�", runtime.getErrors()))
+ .initElapsedMs(elapsedMs)
+ .toolCount(runtime.getToolCallbacks().length)
+ .testedAt(new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()))
+ .build();
+ }
+ return AiMcpConnectivityTestDto.builder()
+ .mountId(mount.getId())
+ .mountName(mount.getName())
+ .healthStatus(AiDefaults.MCP_HEALTH_HEALTHY)
+ .message("鑽夌杩為�氭�ф祴璇曟垚鍔燂紝瑙f瀽鍑� " + runtime.getToolCallbacks().length + " 涓伐鍏�")
+ .initElapsedMs(elapsedMs)
+ .toolCount(runtime.getToolCallbacks().length)
+ .testedAt(new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()))
+ .build();
+ } catch (CoolException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CoolException("鑽夌杩為�氭�ф祴璇曞け璐�: " + e.getMessage());
}
}
@@ -98,7 +184,8 @@
} catch (Exception e) {
throw new CoolException("宸ュ叿杈撳叆 JSON 鏍煎紡閿欒: " + e.getMessage());
}
- AiMcpMount mount = requireMount(mountId);
+ AiMcpMount mount = requireMount(mountId, tenantId);
+ long startedAt = System.currentTimeMillis();
try (McpMountRuntimeFactory.McpMountRuntime runtime = mcpMountRuntimeFactory.create(List.of(mount), userId)) {
ToolCallback callback = Arrays.stream(runtime.getToolCallbacks())
.filter(item -> item != null && item.getToolDefinition() != null)
@@ -109,11 +196,21 @@
request.getInputJson(),
new ToolContext(Map.of("userId", userId, "tenantId", tenantId, "mountId", mountId))
);
+ updateHealthStatus(mount.getId(), AiDefaults.MCP_HEALTH_HEALTHY,
+ "宸ュ叿娴嬭瘯鎴愬姛: " + request.getToolName(), System.currentTimeMillis() - startedAt);
return AiMcpToolTestDto.builder()
.toolName(request.getToolName())
.inputJson(request.getInputJson())
.output(output)
.build();
+ } catch (CoolException e) {
+ updateHealthStatus(mount.getId(), AiDefaults.MCP_HEALTH_UNHEALTHY,
+ "宸ュ叿娴嬭瘯澶辫触: " + e.getMessage(), System.currentTimeMillis() - startedAt);
+ throw e;
+ } catch (Exception e) {
+ updateHealthStatus(mount.getId(), AiDefaults.MCP_HEALTH_UNHEALTHY,
+ "宸ュ叿娴嬭瘯澶辫触: " + e.getMessage(), System.currentTimeMillis() - startedAt);
+ throw new CoolException("宸ュ叿娴嬭瘯澶辫触: " + e.getMessage());
}
}
@@ -130,15 +227,18 @@
if (aiMcpMount.getStatus() == null) {
aiMcpMount.setStatus(StatusType.ENABLE.val);
}
+ if (!StringUtils.hasText(aiMcpMount.getHealthStatus())) {
+ aiMcpMount.setHealthStatus(AiDefaults.MCP_HEALTH_NOT_TESTED);
+ }
}
- private void ensureRequiredFields(AiMcpMount aiMcpMount) {
+ private void ensureRequiredFields(AiMcpMount aiMcpMount, Long tenantId) {
if (!StringUtils.hasText(aiMcpMount.getName())) {
throw new CoolException("MCP 鎸傝浇鍚嶇О涓嶈兘涓虹┖");
}
if (AiDefaults.MCP_TRANSPORT_BUILTIN.equals(aiMcpMount.getTransportType())) {
builtinMcpToolRegistry.validateBuiltinCode(aiMcpMount.getBuiltinCode());
- ensureBuiltinConflictFree(aiMcpMount);
+ ensureBuiltinConflictFree(aiMcpMount, tenantId);
return;
}
if (AiDefaults.MCP_TRANSPORT_SSE_HTTP.equals(aiMcpMount.getTransportType())) {
@@ -156,18 +256,23 @@
throw new CoolException("涓嶆敮鎸佺殑 MCP 浼犺緭绫诲瀷: " + aiMcpMount.getTransportType());
}
- private AiMcpMount requireMount(Long mountId) {
+ private AiMcpMount requireMount(Long mountId, Long tenantId) {
+ ensureTenantId(tenantId);
if (mountId == null) {
throw new CoolException("MCP 鎸傝浇 ID 涓嶈兘涓虹┖");
}
- AiMcpMount mount = this.getById(mountId);
- if (mount == null || (mount.getDeleted() != null && mount.getDeleted() == 1)) {
+ AiMcpMount mount = this.getOne(new LambdaQueryWrapper<AiMcpMount>()
+ .eq(AiMcpMount::getId, mountId)
+ .eq(AiMcpMount::getTenantId, tenantId)
+ .eq(AiMcpMount::getDeleted, 0)
+ .last("limit 1"));
+ if (mount == null) {
throw new CoolException("MCP 鎸傝浇涓嶅瓨鍦�");
}
return mount;
}
- private void ensureBuiltinConflictFree(AiMcpMount aiMcpMount) {
+ private void ensureBuiltinConflictFree(AiMcpMount aiMcpMount, Long tenantId) {
if (aiMcpMount.getStatus() == null || aiMcpMount.getStatus() != StatusType.ENABLE.val) {
return;
}
@@ -176,8 +281,10 @@
return;
}
LambdaQueryWrapper<AiMcpMount> queryWrapper = new LambdaQueryWrapper<AiMcpMount>()
+ .eq(AiMcpMount::getTenantId, tenantId)
.eq(AiMcpMount::getTransportType, AiDefaults.MCP_TRANSPORT_BUILTIN)
.eq(AiMcpMount::getStatus, StatusType.ENABLE.val)
+ .eq(AiMcpMount::getDeleted, 0)
.in(AiMcpMount::getBuiltinCode, conflictCodes);
if (aiMcpMount.getId() != null) {
queryWrapper.ne(AiMcpMount::getId, aiMcpMount.getId());
@@ -191,18 +298,64 @@
}
private List<String> resolveConflictCodes(String builtinCode) {
- List<String> codes = new ArrayList<>();
if (AiDefaults.MCP_BUILTIN_RSF_WMS.equals(builtinCode)) {
- codes.add(AiDefaults.MCP_BUILTIN_RSF_WMS_STOCK);
- codes.add(AiDefaults.MCP_BUILTIN_RSF_WMS_TASK);
- codes.add(AiDefaults.MCP_BUILTIN_RSF_WMS_BASE);
- return codes;
+ return List.of();
}
- if (AiDefaults.MCP_BUILTIN_RSF_WMS_STOCK.equals(builtinCode)
- || AiDefaults.MCP_BUILTIN_RSF_WMS_TASK.equals(builtinCode)
- || AiDefaults.MCP_BUILTIN_RSF_WMS_BASE.equals(builtinCode)) {
- codes.add(AiDefaults.MCP_BUILTIN_RSF_WMS);
+ throw new CoolException("涓嶆敮鎸佺殑鍐呯疆 MCP 缂栫爜: " + builtinCode);
+ }
+
+ private void ensureTenantId(Long tenantId) {
+ if (tenantId == null) {
+ throw new CoolException("褰撳墠绉熸埛涓嶅瓨鍦�");
}
- return codes;
+ }
+
+ private List<AiMcpToolPreviewDto> buildToolPreviewDtos(ToolCallback[] callbacks, List<AiMcpToolPreviewDto> governedCatalog) {
+ List<AiMcpToolPreviewDto> tools = new ArrayList<>();
+ Map<String, AiMcpToolPreviewDto> catalogMap = new java.util.LinkedHashMap<>();
+ for (AiMcpToolPreviewDto item : governedCatalog) {
+ if (item == null || !StringUtils.hasText(item.getName())) {
+ continue;
+ }
+ catalogMap.put(item.getName(), item);
+ }
+ for (ToolCallback callback : callbacks) {
+ if (callback == null || callback.getToolDefinition() == null) {
+ continue;
+ }
+ AiMcpToolPreviewDto governedItem = catalogMap.get(callback.getToolDefinition().name());
+ tools.add(AiMcpToolPreviewDto.builder()
+ .name(callback.getToolDefinition().name())
+ .description(callback.getToolDefinition().description())
+ .inputSchema(callback.getToolDefinition().inputSchema())
+ .returnDirect(callback.getToolMetadata() == null ? null : callback.getToolMetadata().returnDirect())
+ .toolGroup(governedItem == null ? null : governedItem.getToolGroup())
+ .toolPurpose(governedItem == null ? null : governedItem.getToolPurpose())
+ .queryBoundary(governedItem == null ? null : governedItem.getQueryBoundary())
+ .exampleQuestions(governedItem == null ? List.of() : governedItem.getExampleQuestions())
+ .build());
+ }
+ return tools;
+ }
+
+ private void updateHealthStatus(Long mountId, String healthStatus, String message, Long initElapsedMs) {
+ this.update(new LambdaUpdateWrapper<AiMcpMount>()
+ .eq(AiMcpMount::getId, mountId)
+ .set(AiMcpMount::getHealthStatus, healthStatus)
+ .set(AiMcpMount::getLastTestTime, new Date())
+ .set(AiMcpMount::getLastTestMessage, message)
+ .set(AiMcpMount::getLastInitElapsedMs, initElapsedMs));
+ }
+
+ private AiMcpConnectivityTestDto buildConnectivityDto(AiMcpMount mount, String message, Long initElapsedMs, Integer toolCount) {
+ return AiMcpConnectivityTestDto.builder()
+ .mountId(mount.getId())
+ .mountName(mount.getName())
+ .healthStatus(mount.getHealthStatus())
+ .message(message)
+ .initElapsedMs(initElapsedMs)
+ .toolCount(toolCount)
+ .testedAt(mount.getLastTestTime$())
+ .build();
}
}
--
Gitblit v1.9.1