UNPKG

mcp-orchestrator

Version:

MCP Orchestrator - Discover and install MCPs with automatic OAuth support. Uses Claude CLI for OAuth MCPs (Canva, Asana, etc). 34 trusted MCPs from Claude Partners.

107 lines (106 loc) 4.46 kB
/** * Discovery Engine * Uses semantic search to recommend relevant MCP servers */ import { MCP_REGISTRY } from './mcp-registry.js'; import { SemanticSearchEngine } from './search/semantic-search.js'; import * as path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // Initialize semantic search engine const indexPath = path.join(__dirname, '../data/mcp-index.json'); const searchEngine = new SemanticSearchEngine(indexPath); /** * Analyze a task description to extract context */ export function analyzeTaskContext(taskDescription) { const text = taskDescription.toLowerCase(); const keywords = []; const categories = []; // Extract keywords (remove common stop words) const stopWords = new Set(['i', 'want', 'to', 'need', 'help', 'me', 'with', 'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'for', 'of', 'from']); const words = text.split(/\s+/).filter(w => w.length > 2 && !stopWords.has(w)); keywords.push(...words); // Detect categories based on keywords const categoryMap = { 'filesystem': ['file', 'files', 'directory', 'folder', 'read', 'write', 'save', 'load', 'path', 'disk'], 'version-control': ['git', 'commit', 'branch', 'merge', 'repository', 'repo', 'diff', 'log', 'version'], 'github': ['github', 'issue', 'pull request', 'pr', 'gist', 'repository'], 'database': ['database', 'sql', 'query', 'table', 'sqlite', 'postgres', 'mysql', 'data'], 'web': ['http', 'fetch', 'request', 'api', 'web', 'url', 'download', 'scrape'], 'search': ['search', 'find', 'lookup', 'query', 'google', 'brave'], 'browser': ['browser', 'screenshot', 'pdf', 'puppeteer', 'headless', 'automation'], 'communication': ['slack', 'message', 'channel', 'notification', 'email'], 'cloud': ['drive', 'google', 'dropbox', 'cloud', 'storage', 'sync'] }; for (const [category, terms] of Object.entries(categoryMap)) { if (terms.some(term => text.includes(term))) { categories.push(category); } } // Determine task type let taskType = 'unknown'; if (/read|get|show|list|view|display|see/.test(text)) { taskType = 'read'; } else if (/write|create|save|add|new|make/.test(text)) { taskType = 'create'; } else if (/edit|update|modify|change/.test(text)) { taskType = 'write'; } else if (/search|find|lookup|query/.test(text)) { taskType = 'search'; } else if (/analyze|check|inspect|review/.test(text)) { taskType = 'analyze'; } else if (/manage|organize|cleanup/.test(text)) { taskType = 'manage'; } return { keywords: [...new Set(keywords)], // dedupe categories: [...new Set(categories)], taskType }; } /** * Match and rank MCPs based on task context using semantic search */ export function discoverMCPs(taskDescription, limit = 5) { // Use semantic search to find relevant MCPs (synchronous) const searchResults = searchEngine.search(taskDescription, limit); // Convert search results to RankedMCP format const ranked = searchResults.map(result => { // Find the MCPServerConfig for this result const mcp = MCP_REGISTRY.find(m => m.id === result.mcp.id); if (!mcp) { // Fallback: create config from search result return { mcp: { id: result.mcp.id, name: result.mcp.name, description: result.mcp.description, command: result.mcp.command || result.mcp.packageName, packageName: result.mcp.packageName, runtime: result.mcp.metadata?.runtime || 'unknown', installTime: result.mcp.metadata?.installTime, useCases: result.mcp.useCases || [], pros: [], cons: [] }, score: result.score * 100, // Convert to percentage reasons: [result.reason], matchedKeywords: result.mcp.keywords || [] }; } return { mcp, score: result.score * 100, // Convert to percentage reasons: [result.reason], matchedKeywords: result.mcp.keywords || [] }; }); return ranked; }