package com.claudecode.context; import com.claudecode.context.SkillLoader.Skill; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; /** * MCP Skill Builders 注册表 —— 对应 claude-code/src/skills/mcpSkillBuilders.ts。 *

* 允许 MCP 服务器注册技能构建器,将 MCP prompts 转换为 Skills。 * 使用注册表模式打破 MCP ↔ Skills 循环依赖。 *

* 用法: *

 * // 在 MCP 模块中注册
 * McpSkillBuilders.register("my-server", () -> List.of(
 *     new Skill("mcp-lint", "Lint code", ...)
 * ));
 *
 * // 在 SkillLoader 中获取
 * List<Skill> mcpSkills = McpSkillBuilders.getAllMcpSkills();
 * 
*/ public final class McpSkillBuilders { private static final Logger log = LoggerFactory.getLogger(McpSkillBuilders.class); /** Registry of MCP skill builders keyed by server name */ private static final Map>> builders = new ConcurrentHashMap<>(); /** Cache of built skills (invalidated when builders change) */ private static volatile List cachedSkills = null; private McpSkillBuilders() {} /** * Register an MCP skill builder for a given server. * Corresponds to TS registerMCPSkillBuilders(). * * @param serverName unique MCP server identifier * @param builder supplier that produces skills from MCP prompts */ public static void register(String serverName, Supplier> builder) { builders.put(serverName, builder); cachedSkills = null; // Invalidate cache log.debug("Registered MCP skill builder for server: {}", serverName); } /** * Unregister an MCP skill builder. */ public static void unregister(String serverName) { builders.remove(serverName); cachedSkills = null; log.debug("Unregistered MCP skill builder for server: {}", serverName); } /** * Get all MCP skills from all registered builders. * Corresponds to TS getMCPSkillBuilders() result aggregation. * * @return combined list of skills from all MCP servers */ public static List getAllMcpSkills() { List cached = cachedSkills; if (cached != null) return cached; List result = new ArrayList<>(); for (var entry : builders.entrySet()) { try { List skills = entry.getValue().get(); if (skills != null) { result.addAll(skills); } } catch (Exception e) { log.warn("Failed to build MCP skills from server '{}': {}", entry.getKey(), e.getMessage()); } } cachedSkills = Collections.unmodifiableList(result); return cachedSkills; } /** * Get registered server names. */ public static Set getRegisteredServers() { return Collections.unmodifiableSet(builders.keySet()); } /** * Clear all registered builders and cache. */ public static void clearAll() { builders.clear(); cachedSkills = null; } /** * Invalidate the cache (force rebuild on next access). */ public static void invalidateCache() { cachedSkills = null; } /** * Check if any builders are registered. */ public static boolean hasBuilders() { return !builders.isEmpty(); } }