| | |
| | | private final BuiltinMcpToolRegistry builtinMcpToolRegistry; |
| | | private final McpMountRuntimeFactory mcpMountRuntimeFactory; |
| | | private final ObjectMapper objectMapper; |
| | | private final AiRedisSupport aiRedisSupport; |
| | | |
| | | /** 查询某个租户下当前启用的 MCP 挂载列表。 */ |
| | | @Override |
| | |
| | | @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(), |
| | |
| | | } |
| | | updateHealthStatus(mount.getId(), AiDefaults.MCP_HEALTH_HEALTHY, |
| | | "工具解析成功,共 " + tools.size() + " 个工具", System.currentTimeMillis() - startedAt); |
| | | aiRedisSupport.cacheToolPreview(tenantId, mountId, tools); |
| | | return tools; |
| | | } catch (CoolException e) { |
| | | throw e; |
| | |
| | | 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) { |
| | |
| | | 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; |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | @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())) { |