UNPKG

mcpdog

Version:

MCPDog - Universal MCP Server Manager with Web Interface

200 lines 8.26 kB
export class ToolRecommendationEngine { toolDatabase; constructor(toolDatabase) { this.toolDatabase = toolDatabase; } async getRecommendations(intent) { // 1. Get relevant tools from database const candidateTools = await this.toolDatabase.findToolsByCategory(intent.category); if (candidateTools.length === 0) { return []; } // 2. Calculate recommendation score for each tool const recommendations = []; for (const tool of candidateTools) { const score = this.calculateRecommendationScore(tool, intent); if (score > 0.3) { // Minimum recommendation threshold const recommendation = { tool, score, rating: this.calculateDisplayRating(tool, score), reasoning: this.generateReasoning(tool, intent, score), usageInstructions: this.generateUsageInstructions(tool, intent), configurationSteps: this.generateConfigurationSteps(tool) }; recommendations.push(recommendation); } } // 3. Sort by score and return top 3 return recommendations .sort((a, b) => b.score - a.score) .slice(0, 3); } calculateRecommendationScore(tool, intent) { let score = 0; // Basic category matching if (tool.category === intent.category) { score += 0.4; } // Keyword matching const toolKeywords = [ ...tool.name.toLowerCase().split(/\s+/), ...tool.description.toLowerCase().split(/\s+/), ...tool.keywords ]; let keywordMatches = 0; for (const keyword of intent.keywords) { if (toolKeywords.some(tk => tk.includes(keyword.toLowerCase()) || keyword.toLowerCase().includes(tk))) { keywordMatches++; } } score += (keywordMatches / intent.keywords.length) * 0.3; // Tool function matching const toolFunctions = tool.tools.map(t => t.name.toLowerCase()); for (const keyword of intent.keywords) { if (toolFunctions.some(tf => tf.includes(keyword))) { score += 0.2; } } // User data availability bonus if (this.hasRequiredData(tool, intent)) { score += 0.1; } // Tool popularity and rating bonus const popularityBonus = (tool.stats.users / 10000) * 0.05; // Normalized const ratingBonus = (tool.stats.rating / 5) * 0.1; score += Math.min(popularityBonus, 0.05) + ratingBonus; // Configuration difficulty penalty const difficultyPenalty = { 'easy': 0, 'medium': -0.05, 'hard': -0.1 }; score += difficultyPenalty[tool.complexity] || 0; return Math.max(0, Math.min(1, score)); } hasRequiredData(tool, intent) { // Check if user provided key data required by the tool const extracted = intent.extractedData; if (tool.category === 'email') { return !!(extracted.email || extracted.recipient); } if (tool.category === 'file') { return !!(extracted.filename || extracted.url); } if (tool.category === 'database') { return !!(extracted.database); } return true; // Other categories temporarily return true } calculateDisplayRating(tool, score) { // Combine tool's own rating and recommendation score const baseRating = tool.stats.rating; const scoreBonus = score * 0.5; // Recommendation score also affects display rating return Math.min(5, baseRating + scoreBonus); } generateReasoning(tool, intent, score) { const reasons = []; if (tool.category === intent.category) { reasons.push(`Specifically designed for ${intent.category} functionality`); } if (score > 0.8) { reasons.push("Highly matches your requirements"); } else if (score > 0.6) { reasons.push("Good match for your requirements"); } if (tool.stats.users > 5000) { reasons.push("Large user base, stable and reliable"); } if (tool.stats.rating > 4.5) { reasons.push("High user rating"); } if (tool.complexity === 'easy') { reasons.push("Simple configuration, easy to use"); } if (this.hasRequiredData(tool, intent)) { reasons.push("You have provided the required key information"); } return reasons.length > 0 ? reasons.join(", ") : "Feature match"; } generateUsageInstructions(tool, intent) { const instructions = []; // Basic usage instructions instructions.push(`1. Ensure ${tool.name} is properly configured`); // Specific tool call example if (tool.tools.length > 0) { const primaryTool = tool.tools[0]; const example = this.generateContextualExample(primaryTool, intent); instructions.push(`2. Call main function: ${example}`); } // Category-specific guidance if (tool.category === 'email') { instructions.push("3. Check email sending status and logs"); if (intent.extractedData.email) { instructions.push(`4. Confirm recipient email: ${intent.extractedData.email}`); } } else if (tool.category === 'database') { instructions.push("3. Test database connection"); instructions.push("4. Check query results"); } else if (tool.category === 'file') { instructions.push("3. Verify file path and permissions"); instructions.push("4. Check file processing results"); } return instructions; } generateContextualExample(toolDef, intent) { const params = { ...toolDef.exampleParams }; // Intelligently fill parameters based on user intent if (intent.extractedData.email && params.to) { params.to = intent.extractedData.email; } if (intent.extractedData.subject && params.subject) { params.subject = intent.extractedData.subject; } if (intent.extractedData.message && (params.body || params.message)) { if (params.body) params.body = intent.extractedData.message; if (params.message) params.message = intent.extractedData.message; } if (intent.extractedData.filename && params.filename) { params.filename = intent.extractedData.filename; } if (intent.extractedData.url && params.url) { params.url = intent.extractedData.url; } return `${toolDef.name}(${JSON.stringify(params, null, 2)})`; } generateConfigurationSteps(tool) { const steps = []; // General configuration steps steps.push(`1. Install ${tool.name}: npm install ${tool.id}`); if (tool.envVars && tool.envVars.length > 0) { steps.push(`2. Configure environment variables: ${tool.envVars.join(', ')}`); } // Category-specific configuration switch (tool.category) { case 'email': steps.push("3. Configure SMTP server or API keys"); steps.push("4. Test email sending functionality"); break; case 'database': steps.push("3. Configure database connection parameters"); steps.push("4. Test database connection"); break; case 'api': steps.push("3. Obtain and configure API keys"); steps.push("4. Test API calls"); break; default: steps.push("3. Complete specific configuration according to documentation"); steps.push("4. Test basic functionality"); } steps.push(`5. Add ${tool.name} to MCP client configuration`); return steps; } } //# sourceMappingURL=tool-recommender.js.map