@spaik/mcp-server-roi
Version:
MCP server for AI ROI prediction and tracking with Monte Carlo simulations
308 lines • 13.3 kB
JavaScript
import { z } from 'zod';
import { SonarBenchmarkService } from './sonar-benchmark-service.js';
import { createLogger } from '../utils/logger.js';
import { structuredLogger, PerformanceTracker } from '../utils/structured-logger.js';
// Validation result schema (same as original)
export const ValidationResultSchema = z.object({
isValid: z.boolean(),
adjustedInput: z.any(),
validationIssues: z.array(z.object({
field: z.string(),
originalValue: z.number(),
adjustedValue: z.number(),
reason: z.string(),
severity: z.enum(['warning', 'error', 'info']),
industryBenchmark: z.object({
average: z.number(),
p25: z.number(),
p75: z.number(),
source: z.string()
}).optional()
})),
marketInsights: z.array(z.object({
metric: z.string(),
dutchMarketValue: z.number(),
globalValue: z.number(),
trend: z.string(),
source: z.string()
})),
recommendations: z.array(z.string()),
citations: z.array(z.object({
url: z.string(),
title: z.string()
}))
});
// Validation thresholds
const VALIDATION_THRESHOLDS = {
MAX_SAVINGS_MULTIPLIER: 3.0,
ADJUSTED_SAVINGS_MULTIPLIER: 2.0,
MIN_IMPLEMENTATION_RATIO: 0.5,
MAX_ROI_PERCENTAGE: 300,
REALISTIC_ROI_RANGE: { min: 15, max: 150 },
MIN_PAYBACK_MONTHS: 6,
MAX_PAYBACK_MONTHS: 48,
};
/**
* Enhanced Dutch Benchmark Validator with parallel API calls
*/
export class DutchBenchmarkValidatorParallel extends SonarBenchmarkService {
dutchLogger = createLogger({ service: 'DutchBenchmarkValidator' });
constructor(apiKey) {
super({
apiKey,
model: 'sonar-pro'
});
}
/**
* Validate project inputs against Dutch market benchmarks with parallel API calls
*/
async validateProjectInputs(params, correlationId) {
const logger = structuredLogger.createApi('dutch-validator', 'validateProjectInputs', correlationId);
const tracker = new PerformanceTracker('dutch-validation.total', logger.correlationId);
logger.info('Starting Dutch market validation', {
industry: params.industry,
useCaseCount: params.useCases.length
});
try {
// Execute all API calls in parallel
tracker.checkpoint('parallel-api-calls-start');
const [benchmarks, marketInsights, industrySpecificData, regulatoryRequirements, competitorAnalysis] = await Promise.all([
// 1. Fetch general benchmarks
this.fetchDutchBenchmarks(params.industry, params.useCases)
.catch(err => {
logger.warn('Failed to fetch benchmarks, using defaults', { error: err.message });
return this.getDefaultBenchmarks(params.industry);
}),
// 2. Fetch market insights
this.fetchDutchMarketInsights(params.industry)
.catch(err => {
logger.warn('Failed to fetch market insights', { error: err.message });
return [];
}),
// 3. Fetch industry-specific data
this.fetchIndustrySpecificData(params.industry)
.catch(err => {
logger.warn('Failed to fetch industry data', { error: err.message });
return null;
}),
// 4. Fetch regulatory requirements (Dutch specific)
this.fetchDutchRegulatoryRequirements(params.industry)
.catch(err => {
logger.warn('Failed to fetch regulatory data', { error: err.message });
return null;
}),
// 5. Fetch competitor analysis
this.fetchCompetitorAnalysis(params.industry, params.useCases)
.catch(err => {
logger.warn('Failed to fetch competitor analysis', { error: err.message });
return null;
})
]);
tracker.checkpoint('parallel-api-calls-complete');
// Merge all data sources
const enrichedBenchmarks = {
...benchmarks,
industrySpecific: industrySpecificData,
regulatory: regulatoryRequirements,
competitors: competitorAnalysis
};
// Validate components in parallel where possible
tracker.checkpoint('parallel-validation-start');
const [useCaseValidations, timelineValidation, costValidation] = await Promise.all([
// Validate all use cases in parallel
Promise.all(params.useCases.map((useCase, index) => this.validateUseCaseSavings(useCase, enrichedBenchmarks, params.industry).then(validation => ({ index, validation })))),
// Validate timeline
this.validateTimeline(params.timelineMonths, params.industry, enrichedBenchmarks),
// Validate costs
this.validateImplementationCosts(params.implementationCosts, params.industry, enrichedBenchmarks)
]);
tracker.checkpoint('parallel-validation-complete');
// Process results
const validationIssues = [];
const adjustedInput = JSON.parse(JSON.stringify(params)); // Deep clone
// Process use case validations
for (const { index, validation } of useCaseValidations) {
if (validation.needsAdjustment) {
validationIssues.push({
field: `use_cases[${index}].monthly_cost_reduction`,
originalValue: validation.originalSavings,
adjustedValue: validation.adjustedSavings,
reason: validation.reason,
severity: validation.severity,
industryBenchmark: validation.benchmark
});
// Adjust the automation percentage
const useCase = params.useCases[index];
const currentCost = useCase.current_state.volume_per_month * useCase.current_state.cost_per_transaction;
const targetReduction = validation.adjustedSavings / currentCost;
adjustedInput.useCases[index].future_state.automation_percentage =
Math.min(targetReduction / useCase.future_state.time_reduction_percentage, 1);
}
}
// Process timeline validation
if (timelineValidation.needsAdjustment) {
validationIssues.push({
field: 'timelineMonths',
originalValue: params.timelineMonths,
adjustedValue: timelineValidation.adjustedTimeline,
reason: timelineValidation.reason,
severity: 'warning',
industryBenchmark: timelineValidation.benchmark
});
adjustedInput.timelineMonths = timelineValidation.adjustedTimeline;
}
// Process cost validation
if (costValidation.issues.length > 0) {
validationIssues.push(...costValidation.issues);
adjustedInput.implementationCosts = costValidation.adjustedCosts;
}
// Generate recommendations with all enriched data
const recommendations = this.generateEnhancedRecommendations(validationIssues, marketInsights, params.industry, enrichedBenchmarks);
tracker.end(true);
logger.info('Dutch validation completed', {
issueCount: validationIssues.length,
errorCount: validationIssues.filter(i => i.severity === 'error').length,
adjustmentsMade: validationIssues.filter(i => i.severity === 'warning').length
});
return {
isValid: validationIssues.filter(i => i.severity === 'error').length === 0,
adjustedInput,
validationIssues,
marketInsights,
recommendations,
citations: benchmarks.citations || []
};
}
catch (error) {
tracker.error(error);
logger.error('Dutch validation failed', error);
throw error;
}
}
/**
* Fetch Dutch regulatory requirements
*/
async fetchDutchRegulatoryRequirements(industry) {
const prompt = `
What are the key Dutch regulatory requirements and compliance considerations
for AI implementation in the ${industry} industry? Include:
- GDPR and Dutch privacy laws
- Industry-specific regulations
- Labor law considerations
- Tax implications
Provide as structured JSON.
`;
try {
const response = await this.askSonar(prompt);
return this.parseJsonResponse(response.content);
}
catch (error) {
this.dutchLogger.warn('Failed to fetch regulatory requirements', { error });
return null;
}
}
/**
* Fetch competitor analysis
*/
async fetchCompetitorAnalysis(industry, useCases) {
const useCaseNames = useCases.map(uc => uc.name).join(', ');
const prompt = `
Analyze Dutch companies in the ${industry} industry that have implemented
AI for use cases like: ${useCaseNames}. Include:
- Success rates and ROI achieved
- Implementation timelines
- Key challenges faced
- Technology stack used
Provide as structured JSON with specific examples.
`;
try {
const response = await this.askSonar(prompt);
return this.parseJsonResponse(response.content);
}
catch (error) {
this.dutchLogger.warn('Failed to fetch competitor analysis', { error });
return null;
}
}
/**
* Fetch industry-specific data
*/
async fetchIndustrySpecificData(industry) {
const prompt = `
Provide detailed Dutch market data for the ${industry} industry including:
- Market size and growth rate
- AI adoption rate
- Average IT budgets as % of revenue
- Key technology trends
- Major players and their AI initiatives
Format as structured JSON with sources.
`;
try {
const response = await this.askSonar(prompt);
return this.parseJsonResponse(response.content);
}
catch (error) {
this.dutchLogger.warn('Failed to fetch industry data', { error });
return null;
}
}
/**
* Generate enhanced recommendations with all data sources
*/
generateEnhancedRecommendations(validationIssues, marketInsights, industry, enrichedBenchmarks) {
const recommendations = [];
// Base recommendations from validation issues
const baseRecommendations = this.generateRecommendations(validationIssues, marketInsights, industry);
recommendations.push(...baseRecommendations);
// Add regulatory recommendations if available
if (enrichedBenchmarks.regulatory) {
if (enrichedBenchmarks.regulatory.gdprConsiderations) {
recommendations.push(`Ensure GDPR compliance: ${enrichedBenchmarks.regulatory.gdprConsiderations}`);
}
if (enrichedBenchmarks.regulatory.industrySpecific) {
recommendations.push(`Industry regulation: ${enrichedBenchmarks.regulatory.industrySpecific}`);
}
}
// Add competitor insights if available
if (enrichedBenchmarks.competitors?.successfulImplementations) {
recommendations.push(`Consider proven approaches: ${enrichedBenchmarks.competitors.successfulImplementations[0]?.approach || 'Study local success cases'}`);
}
// Add industry-specific recommendations
if (enrichedBenchmarks.industrySpecific?.trends) {
recommendations.push(`Align with industry trends: ${enrichedBenchmarks.industrySpecific.trends[0] || 'Monitor market evolution'}`);
}
return recommendations;
}
/**
* Default benchmarks for fallback
*/
getDefaultBenchmarks(industry) {
return {
savings: [{
category: 'general',
average: 25,
p25: 15,
p75: 35,
source: 'Industry defaults'
}],
timeline: {
average: 12,
min: 6,
max: 24,
source: 'Industry defaults'
},
costs: {
averagePercentOfRevenue: 2.5,
breakdown: {
software: 0.3,
development: 0.4,
training: 0.1,
infrastructure: 0.2
},
source: 'Industry defaults'
},
citations: []
};
}
}
//# sourceMappingURL=dutch-benchmark-validator-parallel.js.map