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
JavaScript
/**
* 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;
}