UNPKG

ultimate-mcp-server

Version:

The definitive all-in-one Model Context Protocol server for AI-assisted coding across 30+ platforms

253 lines 8.75 kB
/** * Smart Lazy Tool Registry * * Implements eager registration with lazy implementation loading * to maintain fast startup while showing all tools immediately */ export class LazyToolRegistry { tools = new Map(); loadingPromises = new Map(); loadedCount = 0; totalCount = 0; /** * Register a tool with lazy loading */ registerLazyTool(config) { // Check for duplicates if (this.tools.has(config.name)) { throw new Error(`Tool ${config.name} is already registered`); } const lazyTool = { name: config.name, description: config.description, inputSchema: config.inputSchema, tags: config.tags, loader: config.loader, loaded: false, handler: async (args) => { // Load implementation on first use await this.ensureLoaded(config.name); const tool = this.tools.get(config.name); return tool.implementation.handler(args); } }; this.tools.set(config.name, lazyTool); this.totalCount++; } /** * Check if a tool is registered (without loading) */ hasToolMetadata(name) { return this.tools.has(name); } /** * Get tool metadata without loading implementation */ getToolMetadata(name) { return this.tools.get(name) || null; } /** * Get all tool metadata without loading implementations */ getAllToolMetadata() { return Array.from(this.tools.values()); } /** * Get tool implementation (loads if needed) */ async getImplementation(name) { const tool = this.tools.get(name); if (!tool) { throw new Error(`Tool ${name} not found`); } await this.ensureLoaded(name); return tool.handler || tool.implementation?.handler; // Return the handler function } /** * Register all tools with their loaders */ registerAllTools() { // Debug tools this.registerLazyTool({ name: 'analyze_error', description: 'Analyze an error message and provide debugging suggestions', inputSchema: { type: 'object', properties: { error: { type: 'string', description: 'The error message or stack trace' }, code: { type: 'string', description: 'The code that caused the error' }, language: { type: 'string', enum: ['javascript', 'typescript', 'python', 'java', 'go', 'rust'] } }, required: ['error'] }, tags: ['debugging', 'error-analysis'], loader: () => import('../tools/debug-tools.js').then(m => m.analyzeError) }); // RAG tools this.registerLazyTool({ name: 'index_documents', description: 'Index documents for RAG system', inputSchema: { type: 'object', properties: { documents: { type: 'array', items: { type: 'object' } }, namespace: { type: 'string' } }, required: ['documents'] }, tags: ['rag', 'indexing'], loader: () => import('../tools/rag-tools.js').then(m => m.ragIngestDocument) }); // UI Understanding tools this.registerLazyTool({ name: 'analyze_ui_design', description: 'Analyze UI/UX design from URL or image', inputSchema: { type: 'object', properties: { source: { type: 'string' }, analysisType: { type: 'string', enum: ['comprehensive', 'layout', 'colors', 'typography', 'components'] } }, required: ['source'] }, tags: ['ui', 'design', 'analysis'], loader: () => import('../tools/ui-understanding-tools.js').then(m => m.analyze_ui_design) }); // Large Context tools this.registerLazyTool({ name: 'analyze_large_codebase', description: 'Analyze entire codebases beyond typical context limits', inputSchema: { type: 'object', properties: { rootDir: { type: 'string' }, pattern: { type: 'string' }, query: { type: 'string' } }, required: ['rootDir', 'query'] }, tags: ['codebase', 'analysis', 'large-context'], loader: () => import('../tools/large-context-tools.js').then(m => m.analyze_large_codebase) }); // Add more tools as needed... } /** * Ensure a tool is loaded */ async ensureLoaded(toolName) { const tool = this.tools.get(toolName); if (!tool || tool.loaded) return; // Check if already loading if (this.loadingPromises.has(toolName)) { await this.loadingPromises.get(toolName); return; } // Load implementation const loadingPromise = this.loadTool(tool); this.loadingPromises.set(toolName, loadingPromise); try { await loadingPromise; } finally { this.loadingPromises.delete(toolName); } } /** * Load a tool's implementation */ async loadTool(tool) { try { const loaded = await tool.loader(); // Convert MCP Tool to ToolDefinition if needed if (loaded && typeof loaded === 'object' && 'execute' in loaded && !('handler' in loaded)) { // It's an MCP Tool, wrap it const mcpTool = loaded; tool.implementation = { name: mcpTool.name || tool.name, description: mcpTool.description || tool.description, inputSchema: mcpTool.inputSchema || tool.inputSchema, handler: async (args) => { const result = await mcpTool.execute(args); return result; }, tags: tool.tags }; tool.handler = tool.implementation.handler; } else if (loaded && typeof loaded === 'object' && 'handler' in loaded) { // It's already a ToolDefinition tool.implementation = loaded; tool.handler = loaded.handler; } else { throw new Error(`Invalid tool implementation for ${tool.name}`); } tool.loaded = true; this.loadedCount++; } catch (error) { console.error(`Failed to load tool ${tool.name}:`, error); throw error; } } /** * Get all registered tools (immediate) */ getAllTools() { return Array.from(this.tools.values()).map(tool => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema, tags: tool.tags, handler: tool.handler || (async (args) => { // Load implementation on first use return this.getImplementation(tool.name).then(impl => impl(args)); }) })); } /** * Get a specific tool */ getTool(name) { const tool = this.tools.get(name); if (!tool) return undefined; return { name: tool.name, description: tool.description, inputSchema: tool.inputSchema, tags: tool.tags, handler: tool.handler || (async (args) => { // Load implementation on first use return this.getImplementation(tool.name).then(impl => impl(args)); }) }; } /** * Preload specific tools */ async preloadTools(toolNames) { await Promise.all(toolNames.map(name => this.ensureLoaded(name))); } /** * Preload tools by tag */ async preloadByTag(tag) { const toolsToLoad = Array.from(this.tools.values()) .filter(tool => tool.tags?.includes(tag)) .map(tool => tool.name); await this.preloadTools(toolsToLoad); } /** * Get loading statistics */ getStats() { return { total: this.totalCount, loaded: this.loadedCount, percentage: Math.round((this.loadedCount / this.totalCount) * 100) }; } } //# sourceMappingURL=lazy-tool-registry.js.map