UNPKG

ableton-mcp-server-rag

Version:
125 lines 6.06 kB
// src/mcp/tool-vector.ts import { MemoryVectorStore } from "langchain/vectorstores/memory"; import { OpenAIEmbeddings } from "@langchain/openai"; let toolVectorStore = null; let toolMetadataMap = new Map(); // Global registry to track tool metadata during decoration export const toolRegistry = new Map(); export function registerToolMetadata(name, description, paramsSchema) { const metadata = createEnhancedToolMetadata(name, description, paramsSchema); toolRegistry.set(name, metadata); // console.log(`📝 Registered tool metadata: ${name} (${metadata.category})`) // Silent for MCP } export async function initToolVectorStore() { console.log('🔧 Initializing tool vector store...'); // ✅ Use console instead if (toolRegistry.size === 0) { console.warn('⚠️ No tools registered in toolRegistry'); return; } // Skip re-initialization if already done if (toolVectorStore && toolMetadataMap.size > 0) { console.log(`✅ Tool vector store already initialized with ${toolRegistry.size} tools`); return; } console.log(`📋 Found ${toolRegistry.size} registered tools`); // Create tool metadata with enhanced descriptions const toolDocs = []; const toolMetadata = []; for (const [name, metadata] of toolRegistry) { toolMetadataMap.set(name, metadata); // Create searchable document for vector store const doc = `${metadata.name}: ${metadata.description}. Category: ${metadata.category}. Keywords: ${metadata.keywords.join(', ')}`; toolDocs.push(doc); toolMetadata.push(metadata); console.log(`🔨 Indexed tool: ${name} (${metadata.category})`); // ✅ Use console instead } // Create vector store for tool similarity search const apiKey = process.env.OPENAI_API_KEY || "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"; toolVectorStore = await MemoryVectorStore.fromTexts(toolDocs, toolMetadata.map((_, i) => ({ id: i })), new OpenAIEmbeddings({ apiKey })); console.log(`✅ Tool vector store initialized with ${toolRegistry.size} tools`); // ✅ Use console instead } function createEnhancedToolMetadata(name, description, paramsSchema) { // Categorize tools based on name patterns let category = 'general'; let keywords = []; if (name.includes('track')) { category = 'tracks'; keywords = ['track', 'channel', 'audio', 'midi', 'create', 'delete', 'modify']; } else if (name.includes('device') || name.includes('load')) { category = 'devices'; keywords = ['device', 'effect', 'instrument', 'plugin', 'reverb', 'delay', 'eq', 'compressor', 'load', 'add']; } else if (name.includes('clip')) { category = 'clips'; keywords = ['clip', 'audio', 'midi', 'notes', 'recording', 'create', 'modify']; } else if (name.includes('song')) { category = 'song'; keywords = ['song', 'tempo', 'time signature', 'arrangement', 'session']; } else if (name.includes('browser') || name.includes('resource')) { category = 'browser'; keywords = ['browser', 'preset', 'sample', 'instrument', 'effect', 'search', 'load']; } else if (name.includes('rag') || name.includes('query') || name.includes('smart')) { category = 'knowledge'; keywords = ['knowledge', 'help', 'information', 'guide', 'documentation']; } // Add specific keywords based on tool name and description const lowerName = name.toLowerCase(); const lowerDesc = description.toLowerCase(); if (lowerName.includes('reverb') || lowerDesc.includes('reverb')) keywords.push('reverb', 'spatial', 'room', 'hall'); if (lowerName.includes('delay') || lowerDesc.includes('delay')) keywords.push('delay', 'echo', 'repeat'); if (lowerName.includes('eq') || lowerDesc.includes('equalizer')) keywords.push('equalizer', 'frequency', 'bass', 'treble'); if (lowerName.includes('tempo') || lowerDesc.includes('tempo')) keywords.push('bpm', 'speed', 'timing'); if (lowerName.includes('create') || lowerDesc.includes('create')) keywords.push('create', 'new', 'add'); if (lowerName.includes('modify') || lowerDesc.includes('modify')) keywords.push('modify', 'change', 'edit', 'set'); if (lowerName.includes('get') || lowerDesc.includes('get')) keywords.push('get', 'retrieve', 'fetch', 'info'); return { name, description, category, keywords: [...new Set(keywords)], // Remove duplicates params: paramsSchema || {} }; } export async function findRelevantTools(query, maxTools = 4) { if (!toolVectorStore) { // console.warn('⚠️ Tool vector store not initialized, returning empty results') return []; } // console.log(`🔍 Finding relevant tools for: "${query}"`) try { // Search for similar tools const results = await toolVectorStore.similaritySearch(query, maxTools * 2); const relevantTools = []; const seenCategories = new Set(); for (const result of results) { const toolIndex = result.metadata.id; const toolName = result.pageContent.split(':')[0]; const metadata = toolMetadataMap.get(toolName); if (metadata && relevantTools.length < maxTools) { // Prefer diversity across categories if (!seenCategories.has(metadata.category) || relevantTools.length < 2) { relevantTools.push(metadata); seenCategories.add(metadata.category); // console.log(`✅ Selected tool: ${metadata.name} (${metadata.category})`) } } } return relevantTools; } catch (error) { // console.error('❌ Error finding relevant tools:', error) return []; } } //# sourceMappingURL=tool-vector.js.map