UNPKG

@spaik/mcp-server-roi

Version:

MCP server for AI ROI prediction and tracking with Monte Carlo simulations

373 lines 17.1 kB
/** * Help Mode Service for Interactive LLM Assistance * * Provides context-aware help, tool recommendations, and troubleshooting * for optimal LLM interaction with the MCP Server ROI tools. */ import { getToolExamples, findBestExample, formatExampleForLLM } from '../utils/tool-examples.js'; import { createLogger } from '../utils/logger.js'; const logger = createLogger({ component: 'HelpModeService' }); export class HelpModeService { /** * Analyze a query and recommend the best tool */ async getToolRecommendation(query) { logger.info('Processing help query', { query: query.query }); const queryLower = query.query.toLowerCase(); const recommendation = this.analyzeQueryIntent(queryLower, query.context); // Get relevant examples const examples = this.getRelevantExamples(recommendation.tool, queryLower); // Generate usage guidance const usage = this.generateUsageGuidance(recommendation.tool, query.context); // Check if troubleshooting is needed const troubleshooting = query.context?.previousError ? this.generateTroubleshooting(query.context.previousError, recommendation.tool) : undefined; // Suggest alternatives const alternatives = this.suggestAlternatives(recommendation.tool, queryLower); // Generate next steps const nextSteps = this.generateNextSteps(recommendation.tool, query.context); return { recommendedTool: { name: recommendation.tool, confidence: recommendation.confidence, reasoning: recommendation.reasoning }, examples, usage, troubleshooting, alternativeApproaches: alternatives, nextSteps }; } /** * Analyze query intent to determine the best tool */ analyzeQueryIntent(query, context) { // Keywords for each tool const toolKeywords = { predict_roi: [ 'roi', 'return on investment', 'predict', 'forecast', 'projection', 'financial', 'npv', 'irr', 'payback', 'detailed', 'comprehensive', 'use case', 'implementation cost', 'timeline' ], compare_projects: [ 'compare', 'comparison', 'versus', 'vs', 'which', 'better', 'portfolio', 'multiple', 'projects', 'side by side', 'choose', 'decision', 'evaluate options', 'best option' ], quick_assessment: [ 'quick', 'fast', 'rapid', 'estimate', 'rough', 'ballpark', 'initial', 'preliminary', 'high level', 'assess', 'evaluate', 'natural language', 'conversational', 'simple' ] }; // Score each tool based on keyword matches const scores = { predict_roi: 0, compare_projects: 0, quick_assessment: 0 }; // Calculate scores for (const [tool, keywords] of Object.entries(toolKeywords)) { for (const keyword of keywords) { if (query.includes(keyword)) { scores[tool] += 1; } } } // Check for specific patterns if (query.includes('compar') && query.includes('project')) { scores.compare_projects += 3; } if (query.includes('quick') || query.includes('fast') || query.length < 100) { scores.quick_assessment += 2; } if (query.includes('detailed') || query.includes('comprehensive')) { scores.predict_roi += 2; } // Consider context if (context?.previousTool === 'quick_assessment' && query.includes('more detail')) { scores.predict_roi += 3; } // Find the best tool const bestTool = Object.entries(scores).reduce((a, b) => scores[a[0]] > scores[b[0]] ? a : b); const maxScore = Math.max(...Object.values(scores)); const confidence = maxScore === 0 ? 0.3 : Math.min(maxScore / 5, 1); // Generate reasoning const reasoning = this.generateReasoning(bestTool[0], query, scores); return { tool: bestTool[0], confidence, reasoning }; } /** * Generate reasoning for tool selection */ generateReasoning(tool, query, scores) { const reasons = { predict_roi: [ "You need detailed financial projections", "You want comprehensive ROI analysis", "You have specific use cases to evaluate", "You need NPV, IRR, and payback calculations" ], compare_projects: [ "You want to compare multiple options", "You need to make a decision between projects", "You want to see side-by-side analysis", "You need portfolio optimization insights" ], quick_assessment: [ "You want a rapid estimate", "You're in the early exploration phase", "You prefer natural language input", "You need a high-level assessment first" ] }; const toolReasons = reasons[tool] || []; const applicableReasons = toolReasons.filter((reason, index) => scores[tool] > index); return `Based on your query, ${tool} is recommended because: ${applicableReasons.join(', ')}.`; } /** * Get relevant examples for the recommended tool */ getRelevantExamples(tool, query) { const allExamples = getToolExamples(tool); // Find the best matching example const bestExample = findBestExample(query, tool); // Get one example from each category const categories = ['simple', 'complex', 'natural_language']; const diverseExamples = categories .map(cat => allExamples.find(ex => ex.category === cat)) .filter(Boolean); // Combine best match with diverse examples const examples = bestExample ? [bestExample, ...diverseExamples.filter(ex => ex !== bestExample)] : diverseExamples; return examples.slice(0, 3); // Return top 3 examples } /** * Generate usage guidance for a tool */ generateUsageGuidance(tool, context) { const guidance = { predict_roi: { quickStart: "Start by defining your project details, use cases with current/future states, and implementation costs.", detailedSteps: [ "1. Set organization_id to identify your organization", "2. Define project metadata (name, industry, type, start date)", "3. List use cases with current state metrics (volume, time, cost, error rate)", "4. Specify future state improvements (time/error reduction percentages)", "5. Add implementation costs (licenses, development, training, infrastructure)", "6. Set timeline in months (1-120) and confidence level (0-1)" ], commonMistakes: [ "Forgetting to include ongoing monthly costs", "Setting unrealistic time reduction percentages (>95%)", "Missing required fields in use case current/future states", "Using negative values for costs or percentages" ] }, compare_projects: { quickStart: "Provide 2-10 project IDs to compare, select metrics of interest, and optionally enable ML insights.", detailedSteps: [ "1. Collect project IDs from previous predict_roi results", "2. Add project IDs to the project_ids array (2-10 projects)", "3. Choose comparison metrics (default: ROI, payback period, NPV, risk)", "4. Set time horizon in months (default: 60)", "5. Enable ML insights for pattern detection (recommended)", "6. Optionally enable benchmarks and visualizations" ], commonMistakes: [ "Comparing only one project (minimum is 2)", "Including more than 10 projects (maximum limit)", "Using non-existent project IDs", "Forgetting to save project IDs from predict_roi calls" ] }, quick_assessment: { quickStart: "Provide company name, project type, and basic use case info for instant ROI estimate.", detailedSteps: [ "1. Enter client name for personalization", "2. Select project type or use 'custom'", "3. Add quick use cases with name, category, volume, and time saved %", "4. Specify company size (small/medium/large/enterprise)", "5. Set urgency level (low/medium/high)", "6. Optionally use natural_language_input for conversational interface" ], commonMistakes: [ "Providing too much detail (use predict_roi for comprehensive analysis)", "Not using natural language input when available", "Forgetting to specify company size for better estimates", "Using quick assessment for final investment decisions" ] } }; return guidance[tool] || { quickStart: "Select a tool based on your needs.", detailedSteps: ["Choose predict_roi, compare_projects, or quick_assessment"], commonMistakes: ["Using the wrong tool for your use case"] }; } /** * Generate troubleshooting guidance */ generateTroubleshooting(error, tool) { const errorLower = error.toLowerCase(); // Common error patterns if (errorLower.includes('validation') || errorLower.includes('invalid')) { return { issue: "Validation Error - Invalid input parameters", solution: "Check that all required fields are provided and values are within valid ranges. Use the examples as templates.", preventionTips: [ "Always include all required fields (check schema)", "Ensure numeric values are positive where required", "Verify enum values match exactly (case-sensitive)", "Use ISO date format (YYYY-MM-DD) for dates" ] }; } if (errorLower.includes('not found') || errorLower.includes('does not exist')) { return { issue: "Resource Not Found - Project or organization doesn't exist", solution: "Verify the IDs are correct. For compare_projects, ensure you're using IDs from previously created projects.", preventionTips: [ "Save project IDs from predict_roi responses", "Use the correct organization_id for your context", "Don't use example IDs from documentation", "Check ID format (should be UUID for projects)" ] }; } if (errorLower.includes('timeout') || errorLower.includes('slow')) { return { issue: "Performance Issue - Request taking too long", solution: "Disable optional features like benchmarks or reduce the number of use cases/projects.", preventionTips: [ "Set enable_benchmarks to false for faster response", "Limit to 5 projects in compare_projects", "Use quick_assessment for rapid estimates", "Break large analyses into smaller chunks" ] }; } return undefined; } /** * Suggest alternative approaches */ suggestAlternatives(recommendedTool, query) { const alternatives = { predict_roi: [ { tool: "quick_assessment", whenToUse: "When you need a rapid estimate or are in early exploration phase" }, { tool: "compare_projects", whenToUse: "When you have multiple implementation options to evaluate" } ], compare_projects: [ { tool: "predict_roi", whenToUse: "When you need detailed analysis of a single project first" }, { tool: "quick_assessment", whenToUse: "For initial screening before detailed comparison" } ], quick_assessment: [ { tool: "predict_roi", whenToUse: "When you're ready for comprehensive financial analysis" }, { tool: "compare_projects", whenToUse: "When you have multiple quick assessments to compare" } ] }; return alternatives[recommendedTool] || []; } /** * Generate next steps based on the tool and context */ generateNextSteps(tool, context) { const steps = { predict_roi: [ "Save the project_id from the response for future comparisons", "Review the Monte Carlo simulation results for risk assessment", "Use compare_projects if you have alternative approaches", "Consider adjusting confidence_level if results seem too optimistic", "Enable benchmarks for industry comparison" ], compare_projects: [ "Focus on the ML insights for strategic recommendations", "Check synergy opportunities between projects", "Use the risk scores to balance your portfolio", "Consider implementing the quick-win project first", "Export results for stakeholder presentation" ], quick_assessment: [ "Use predict_roi for detailed analysis if ROI looks promising", "Try natural language input for easier interaction", "Adjust use case volumes for sensitivity analysis", "Add more use cases to see cumulative impact", "Compare multiple scenarios using different assumptions" ] }; const baseSteps = steps[tool] || []; // Add context-specific steps if (context?.previousError) { baseSteps.unshift("Resolve the error using the troubleshooting guidance above"); } if (context?.previousTool) { baseSteps.unshift(`Build on your ${context.previousTool} results`); } return baseSteps.slice(0, 5); // Return top 5 next steps } /** * Format help response for LLM consumption */ formatHelpResponse(response) { let formatted = `## Tool Recommendation: ${response.recommendedTool.name}\n\n`; formatted += `**Confidence**: ${Math.round(response.recommendedTool.confidence * 100)}%\n`; formatted += `**Reasoning**: ${response.recommendedTool.reasoning}\n\n`; formatted += `### Quick Start\n${response.usage.quickStart}\n\n`; formatted += `### Detailed Steps\n`; response.usage.detailedSteps.forEach(step => { formatted += `${step}\n`; }); formatted += `\n### Examples\n`; response.examples.forEach(example => { formatted += formatExampleForLLM(example); }); if (response.troubleshooting) { formatted += `\n### Troubleshooting\n`; formatted += `**Issue**: ${response.troubleshooting.issue}\n`; formatted += `**Solution**: ${response.troubleshooting.solution}\n`; formatted += `**Prevention Tips**:\n`; response.troubleshooting.preventionTips.forEach(tip => { formatted += `- ${tip}\n`; }); } formatted += `\n### Next Steps\n`; response.nextSteps.forEach((step, index) => { formatted += `${index + 1}. ${step}\n`; }); if (response.alternativeApproaches && response.alternativeApproaches.length > 0) { formatted += `\n### Alternative Approaches\n`; response.alternativeApproaches.forEach(alt => { formatted += `- **${alt.tool}**: ${alt.whenToUse}\n`; }); } return formatted; } } // Export singleton instance export const helpModeService = new HelpModeService(); //# sourceMappingURL=help-mode.js.map