zhou zhou
17 小时以前 4954d3978cf1967729a5a2d5b90f6baef18974da
rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiMcpMountServiceImpl.java
@@ -35,6 +35,7 @@
    private final BuiltinMcpToolRegistry builtinMcpToolRegistry;
    private final McpMountRuntimeFactory mcpMountRuntimeFactory;
    private final ObjectMapper objectMapper;
    private final AiRedisSupport aiRedisSupport;
    /** 查询某个租户下当前启用的 MCP 挂载列表。 */
    @Override
@@ -77,6 +78,11 @@
    @Override
    public List<AiMcpToolPreviewDto> previewTools(Long mountId, Long userId, Long tenantId) {
        AiMcpMount mount = requireMount(mountId, tenantId);
        // 工具目录预览初始化成本高,但变化频率低,适合做管理端短缓存。
        List<AiMcpToolPreviewDto> cached = aiRedisSupport.getToolPreview(tenantId, mountId);
        if (cached != null) {
            return cached;
        }
        long startedAt = System.currentTimeMillis();
        try (McpMountRuntimeFactory.McpMountRuntime runtime = mcpMountRuntimeFactory.create(List.of(mount), userId)) {
            List<AiMcpToolPreviewDto> tools = buildToolPreviewDtos(runtime.getToolCallbacks(),
@@ -90,6 +96,7 @@
            }
            updateHealthStatus(mount.getId(), AiDefaults.MCP_HEALTH_HEALTHY,
                    "工具解析成功,共 " + tools.size() + " 个工具", System.currentTimeMillis() - startedAt);
            aiRedisSupport.cacheToolPreview(tenantId, mountId, tools);
            return tools;
        } catch (CoolException e) {
            throw e;
@@ -111,12 +118,16 @@
                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);
                AiMcpConnectivityTestDto connectivity = buildConnectivityDto(latest, message, elapsedMs, runtime.getToolCallbacks().length);
                aiRedisSupport.cacheConnectivity(tenantId, mountId, connectivity);
                return connectivity;
            }
            String message = "连通性测试成功,解析出 " + 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);
            AiMcpConnectivityTestDto connectivity = buildConnectivityDto(latest, message, elapsedMs, runtime.getToolCallbacks().length);
            aiRedisSupport.cacheConnectivity(tenantId, mountId, connectivity);
            return connectivity;
        } catch (CoolException e) {
            throw e;
        } catch (Exception e) {
@@ -124,7 +135,9 @@
            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);
            AiMcpConnectivityTestDto connectivity = buildConnectivityDto(latest, message, elapsedMs, 0);
            aiRedisSupport.cacheConnectivity(tenantId, mountId, connectivity);
            return connectivity;
        }
    }
@@ -227,6 +240,40 @@
        }
    }
    @Override
    public boolean save(AiMcpMount entity) {
        boolean saved = super.save(entity);
        if (saved && entity != null && entity.getTenantId() != null) {
            aiRedisSupport.evictMcpMountCaches(entity.getTenantId(), entity.getId());
        }
        return saved;
    }
    @Override
    public boolean updateById(AiMcpMount entity) {
        boolean updated = super.updateById(entity);
        if (updated && entity != null && entity.getTenantId() != null) {
            aiRedisSupport.evictMcpMountCaches(entity.getTenantId(), entity.getId());
        }
        return updated;
    }
    @Override
    public boolean removeByIds(java.util.Collection<?> list) {
        java.util.List<java.io.Serializable> ids = list == null ? java.util.List.of() : list.stream()
                .filter(java.util.Objects::nonNull)
                .map(item -> (java.io.Serializable) item)
                .toList();
        java.util.List<AiMcpMount> records = this.listByIds(ids);
        boolean removed = super.removeByIds(list);
        if (removed) {
            records.stream()
                    .filter(java.util.Objects::nonNull)
                    .forEach(item -> aiRedisSupport.evictMcpMountCaches(item.getTenantId(), item.getId()));
        }
        return removed;
    }
    private void fillDefaults(AiMcpMount aiMcpMount) {
        /** 为挂载草稿补齐统一默认值,保证后续运行时代码不需要重复判断空值。 */
        if (!StringUtils.hasText(aiMcpMount.getTransportType())) {