optivise
Version:
Optivise - The Ultimate Optimizely Development Assistant with AI-powered features, zero-config setup, and comprehensive development support
688 lines • 31 kB
JavaScript
/**
* Optivise MCP Server
* Enhanced MCP server with AI-powered features and multiple specialized tools
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js';
import { ContextAnalysisEngine } from '../analyzers/context-analysis-engine.js';
import { createLogger } from '../utils/logger.js';
import { openAIClient } from '../integrations/openai-client.js';
import { chromaDBService } from '../integrations/chromadb-client.js';
import { documentationSyncService } from '../services/documentation-sync-service.js';
import { APIKeyDetector } from '../integrations/api-key-detector.js';
import { ImplementationGuideTool } from '../tools/implementation-guide-tool.js';
import { DebugHelperTool } from '../tools/debug-helper-tool.js';
import { CodeAnalyzerTool } from '../tools/code-analyzer-tool.js';
import { ProjectHelperTool } from '../tools/project-helper-tool.js';
import { auditTrail } from '../services/audit-trail.js';
import { monitoringService as createMonitoring } from '../services/monitoring-service.js';
import { formatZodError } from '../utils/validation.js';
import { generateCorrelationId, runWithCorrelationId } from '../utils/correlation.js';
export class OptiviseMCPServer {
server;
logger;
contextAnalyzer;
keyDetector;
implementationGuideTool;
debugHelperTool;
codeAnalyzerTool;
projectHelperTool;
isInitialized = false;
aiEnabled = false;
monitoring = createMonitoring(createLogger('error'));
constructor(options = {}) {
this.logger = createLogger(options.logging?.level || 'info');
// Initialize services
this.contextAnalyzer = new ContextAnalysisEngine(this.logger);
this.keyDetector = new APIKeyDetector();
this.implementationGuideTool = new ImplementationGuideTool(this.logger);
this.debugHelperTool = new DebugHelperTool(this.logger);
this.codeAnalyzerTool = new CodeAnalyzerTool(this.logger);
this.projectHelperTool = new ProjectHelperTool(this.logger);
// Create MCP server configuration with enhanced tools
const config = {
name: 'optivise-ultimate-assistant',
version: '5.2.2',
description: 'Ultimate Optimizely Development Assistant with AI-powered features',
capabilities: {
tools: true,
logging: true,
monitoring: true,
aiIntegration: true
},
tools: [
{
name: 'optidev_context_analyzer',
description: 'Enhanced context analysis with AI-powered relevance scoring and vector search',
parameters: {
type: 'object',
properties: {
prompt: {
type: 'string',
description: 'User prompt to analyze for Optimizely context'
},
projectPath: {
type: 'string',
description: 'Optional project path for IDE context'
},
ideRules: {
type: 'array',
items: { type: 'string' },
description: 'Optional IDE rules for context enhancement'
},
enableAI: {
type: 'boolean',
description: 'Enable AI-powered features (requires API keys)',
default: true
}
},
required: ['prompt']
}
},
{
name: 'optidev_implementation_guide',
description: 'Analyzes Jira tickets and provides complete implementation guidance',
parameters: {
type: 'object',
properties: {
ticketContent: {
type: 'string',
description: 'Jira ticket content or requirements text'
},
projectContext: {
type: 'string',
description: 'Optional project context or existing codebase information'
}
},
required: ['ticketContent']
}
},
{
name: 'optidev_debug_helper',
description: 'Provides intelligent debugging assistance for Optimizely-related issues',
parameters: {
type: 'object',
properties: {
bugDescription: {
type: 'string',
description: 'Description of the bug or issue encountered'
},
errorMessages: {
type: 'array',
items: { type: 'string' },
description: 'Optional error messages or stack traces'
},
codeContext: {
type: 'string',
description: 'Optional relevant code snippets'
}
},
required: ['bugDescription']
}
},
{
name: 'optidev_code_analyzer',
description: 'Real-time code analysis for performance, security, and best practices',
parameters: {
type: 'object',
properties: {
codeSnippet: {
type: 'string',
description: 'Code snippet to analyze'
},
language: {
type: 'string',
description: 'Programming language (typescript, csharp, html, etc.)',
default: 'typescript'
},
analysisType: {
type: 'string',
enum: ['performance', 'security', 'best-practices', 'all'],
description: 'Type of analysis to perform',
default: 'all'
}
},
required: ['codeSnippet']
}
},
{
name: 'optidev_project_helper',
description: 'Project setup, migration assistance, and development guidance',
parameters: {
type: 'object',
properties: {
requestType: {
type: 'string',
enum: ['setup', 'migration', 'configuration', 'best-practices'],
description: 'Type of project assistance needed'
},
projectDetails: {
type: 'string',
description: 'Project requirements or current setup details'
},
targetVersion: {
type: 'string',
description: 'Target Optimizely version (if applicable)'
}
},
required: ['requestType', 'projectDetails']
}
}
]
};
// Initialize MCP Server
this.server = new Server({
name: config.name,
version: config.version,
}, {
capabilities: {
tools: {}, // Always enable tools
},
});
this.setupHandlers();
if (process.env.OPTIDEV_DEBUG === 'true') {
this.logger.info('Optivise MCP Server initialized', { version: config.version });
}
}
setupHandlers() {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'optidev_context_analyzer',
description: 'Enhanced context analysis with AI-powered relevance scoring and vector search',
inputSchema: {
type: 'object',
properties: {
prompt: {
type: 'string',
description: 'User prompt to analyze for Optimizely context'
},
projectPath: {
type: 'string',
description: 'Optional project path for IDE context'
},
ideRules: {
type: 'array',
items: { type: 'string' },
description: 'Optional IDE rules for context enhancement'
},
enableAI: {
type: 'boolean',
description: 'Enable AI-powered features (requires API keys)'
}
},
required: ['prompt']
}
},
{
name: 'optidev_implementation_guide',
description: 'Analyzes Jira tickets and provides complete implementation guidance',
inputSchema: {
type: 'object',
properties: {
ticketContent: {
type: 'string',
description: 'Jira ticket content or requirements text'
},
projectContext: {
type: 'string',
description: 'Optional project context or existing codebase information'
}
},
required: ['ticketContent']
}
},
{
name: 'optidev_debug_helper',
description: 'Provides intelligent debugging assistance for Optimizely-related issues',
inputSchema: {
type: 'object',
properties: {
bugDescription: {
type: 'string',
description: 'Description of the bug or issue encountered'
},
errorMessages: {
type: 'array',
items: { type: 'string' },
description: 'Optional error messages or stack traces'
},
codeContext: {
type: 'string',
description: 'Optional relevant code snippets'
}
},
required: ['bugDescription']
}
},
{
name: 'optidev_code_analyzer',
description: 'Real-time code analysis for performance, security, and best practices',
inputSchema: {
type: 'object',
properties: {
codeSnippet: {
type: 'string',
description: 'Code snippet to analyze'
},
language: {
type: 'string',
description: 'Programming language (typescript, csharp, html, etc.)'
},
analysisType: {
type: 'string',
enum: ['performance', 'security', 'best-practices', 'all'],
description: 'Type of analysis to perform'
}
},
required: ['codeSnippet']
}
},
{
name: 'optidev_project_helper',
description: 'Project setup, migration assistance, and development guidance',
inputSchema: {
type: 'object',
properties: {
requestType: {
type: 'string',
enum: ['setup', 'migration', 'configuration', 'best-practices'],
description: 'Type of project assistance needed'
},
projectDetails: {
type: 'string',
description: 'Project requirements or current setup details'
},
targetVersion: {
type: 'string',
description: 'Target Optimizely version (if applicable)'
}
},
required: ['requestType', 'projectDetails']
}
}
]
};
});
// Handle tool calls
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
const corrId = generateCorrelationId('mcp');
const resultWrapped = await runWithCorrelationId(corrId, async () => {
let result;
switch (name) {
case 'optidev_context_analyzer':
result = await this.handleContextAnalysis(args);
break;
case 'optidev_implementation_guide':
result = await this.handleImplementationGuide(args);
break;
case 'optidev_debug_helper':
result = await this.handleDebugHelper(args);
break;
case 'optidev_code_analyzer':
result = await this.handleCodeAnalyzer(args);
break;
case 'optidev_project_helper':
result = await this.handleProjectHelper(args);
break;
default:
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
}
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2)
}
]
};
});
return resultWrapped;
}
catch (error) {
this.logger.error(`Tool execution failed for ${name}`, error);
// Structured invalid input handling
const maybeZod = error;
const isZod = !!maybeZod?.issues && Array.isArray(maybeZod.issues);
const payload = isZod
? { status: 'error', error: formatZodError(maybeZod) }
: {
status: 'error',
error: {
code: 'TOOL_EXECUTION_FAILED',
message: error instanceof Error ? error.message : 'Unknown error occurred',
details: { tool: name, timestamp: new Date() }
}
};
return {
content: [
{
type: 'text',
text: JSON.stringify(payload, null, 2)
}
]
};
}
});
}
async handleContextAnalysis(request) {
try {
const stop = this.monitoring.startTimer('tool:optidev_context_analyzer');
this.logger.debug('Processing context analysis request', {
promptLength: request.prompt.length,
hasProjectPath: !!request.projectPath,
hasIDERules: !!request.ideRules?.length
});
const startTime = Date.now();
const response = await this.contextAnalyzer.analyze(request);
const processingTime = Date.now() - startTime;
this.logger.info('Context analysis completed', {
relevance: response.relevance,
detectedProducts: response.detectedProducts,
processingTime
});
stop();
return {
status: 'success',
data: response
};
}
catch (error) {
try {
this.monitoring.recordPerformance({ operation: 'tool:optidev_context_analyzer', duration: 0, success: false });
}
catch (err) { /* noop */ }
this.logger.error('Context analysis failed', error, {
promptLength: request.prompt.length
});
return {
status: 'error',
error: {
code: 'ANALYSIS_FAILED',
message: error instanceof Error ? error.message : 'Unknown error occurred',
details: { timestamp: new Date() }
}
};
}
}
async handleImplementationGuide(request) {
try {
const stop = this.monitoring.startTimer('tool:optidev_implementation_guide');
this.logger.debug('Processing implementation guide request');
const response = await this.implementationGuideTool.analyzeTicket(request);
try {
auditTrail.record({ tool: 'optidev_implementation_guide', timestamp: new Date().toISOString(), promptLength: request?.userPrompt?.length, success: true });
}
catch { }
stop();
return {
status: 'success',
data: response
};
}
catch (error) {
try {
this.monitoring.recordPerformance({ operation: 'tool:optidev_implementation_guide', duration: 0, success: false });
}
catch (err) { /* noop */ }
this.logger.error('Implementation guide analysis failed', error);
try {
auditTrail.record({ tool: 'optidev_implementation_guide', timestamp: new Date().toISOString(), success: false });
}
catch { }
throw error;
}
}
async handleDebugHelper(request) {
try {
const stop = this.monitoring.startTimer('tool:optidev_debug_helper');
this.logger.debug('Processing debug helper request');
const response = await this.debugHelperTool.analyzeBug(request);
try {
auditTrail.record({ tool: 'optidev_debug_helper', timestamp: new Date().toISOString(), promptLength: request?.userPrompt?.length, success: true });
}
catch { }
stop();
return {
status: 'success',
data: response
};
}
catch (error) {
try {
this.monitoring.recordPerformance({ operation: 'tool:optidev_debug_helper', duration: 0, success: false });
}
catch (err) { /* noop */ }
this.logger.error('Debug helper analysis failed', error);
try {
auditTrail.record({ tool: 'optidev_debug_helper', timestamp: new Date().toISOString(), success: false });
}
catch { }
throw error;
}
}
async handleCodeAnalyzer(request) {
try {
const stop = this.monitoring.startTimer('tool:optidev_code_analyzer');
this.logger.debug('Processing code analyzer request');
const response = await this.codeAnalyzerTool.analyzeCode(request);
try {
auditTrail.record({ tool: 'optidev_code_analyzer', timestamp: new Date().toISOString(), promptLength: request?.userPrompt?.length, products: response.detectedProducts, success: true });
}
catch { }
stop();
return {
status: 'success',
data: response
};
}
catch (error) {
try {
this.monitoring.recordPerformance({ operation: 'tool:optidev_code_analyzer', duration: 0, success: false });
}
catch (err) { /* noop */ }
this.logger.error('Code analyzer analysis failed', error);
try {
auditTrail.record({ tool: 'optidev_code_analyzer', timestamp: new Date().toISOString(), success: false });
}
catch { }
throw error;
}
}
async handleProjectHelper(request) {
try {
const stop = this.monitoring.startTimer('tool:optidev_project_helper');
this.logger.debug('Processing project helper request');
const response = await this.projectHelperTool.provideAssistance(request);
try {
auditTrail.record({ tool: 'optidev_project_helper', timestamp: new Date().toISOString(), promptLength: request?.userPrompt?.length, success: true });
}
catch { }
stop();
return {
status: 'success',
data: response
};
}
catch (error) {
try {
this.monitoring.recordPerformance({ operation: 'tool:optidev_project_helper', duration: 0, success: false });
}
catch (err) { /* noop */ }
this.logger.error('Project helper analysis failed', error);
try {
auditTrail.record({ tool: 'optidev_project_helper', timestamp: new Date().toISOString(), success: false });
}
catch { }
throw error;
}
}
async initialize() {
if (this.isInitialized) {
return;
}
try {
this.logger.info('Initializing Optivise MCP Server...');
// 1. Initialize the context analyzer (now handles AI async)
// await this.contextAnalyzer.initialize();
// 2. Initialize all specialized tools
// await this.initializeTools();
// 3. Start documentation sync service
// documentationSyncService.startAutoSync();
this.isInitialized = true;
if (process.env.OPTIDEV_DEBUG === 'true') {
this.logger.info('Optivise MCP Server initialization completed', {
aiEnabled: this.aiEnabled,
features: {
contextAnalysis: true,
vectorSearch: this.aiEnabled,
documentationSync: true,
multipleTools: true
}
});
}
// 4. Initialize AI services asynchronously (non-blocking)
this.initializeAIServicesAsync();
}
catch (error) {
this.logger.error('Failed to initialize MCP Server', error);
throw error;
}
}
/**
* Initialize AI services asynchronously without blocking MCP startup
*/
initializeAIServicesAsync() {
this.initializeAIServices().catch((error) => {
this.logger.debug('AI services initialization completed with fallback to basic mode');
});
}
async initializeTools() {
try {
await Promise.all([
this.implementationGuideTool.initialize(),
this.debugHelperTool.initialize(),
this.codeAnalyzerTool.initialize(),
this.projectHelperTool.initialize()
]);
this.logger.info('All specialized tools initialized successfully');
}
catch (error) {
this.logger.error('Failed to initialize specialized tools', error);
throw error;
}
}
async initializeAIServices() {
try {
// Try to initialize OpenAI client with auto-detected keys
const openAIInitialized = await openAIClient.initialize();
if (openAIInitialized) {
if (process.env.OPTIDEV_DEBUG === 'true') {
this.logger.info('OpenAI client initialized successfully');
}
// Initialize ChromaDB if OpenAI is available
const chromaInitialized = await chromaDBService.initialize();
if (chromaInitialized) {
if (process.env.OPTIDEV_DEBUG === 'true') {
this.logger.info('ChromaDB service initialized successfully');
}
this.aiEnabled = true;
}
else {
if (process.env.OPTIDEV_DEBUG === 'true') {
this.logger.warn('ChromaDB initialization failed - vector search disabled');
}
}
}
else {
if (process.env.OPTIDEV_DEBUG === 'true') {
this.logger.warn('OpenAI client initialization failed - AI features disabled');
this.logger.info('Basic features will work without AI. To enable AI features:');
this.logger.info('1. Set OPENAI_API_KEY environment variable, or');
this.logger.info('2. Configure API key in your IDE (Cursor, VSCode)');
}
}
// Log API key detection results only in debug mode
if (process.env.OPTIDEV_DEBUG === 'true') {
const detection = await this.keyDetector.detectAPIKeys();
this.logger.info('API Key Detection Results', {
hasOpenAI: detection.hasOpenAI,
hasAnthropic: detection.hasAnthropic,
foundSources: detection.found.map(s => ({ source: s.source, type: s.type, valid: s.isValid }))
});
}
}
catch (error) {
this.logger.error('AI services initialization failed', error);
// Continue without AI features
}
}
async start() {
if (!this.isInitialized) {
this.logger.debug('Starting server initialization...');
await this.initialize();
this.logger.debug('Server initialization completed');
}
this.logger.debug('Creating stdio transport...');
const transport = new StdioServerTransport();
this.logger.debug('Connecting to transport...');
await this.server.connect(transport);
if (process.env.OPTIDEV_DEBUG === 'true') {
this.logger.info('Optivise MCP Server started and connected');
}
// The MCP SDK handles stdin, no need to resume it manually
}
async stop() {
try {
// Stop MCP server transport
await this.server.close();
// Stop background services and analyzers
await this.contextAnalyzer.shutdown?.();
// Stop documentation sync if running
documentationSyncService.stopAutoSync?.();
// Cleanup AI clients
openAIClient.cleanup?.();
await chromaDBService.cleanup?.();
this.logger.info('Optivise MCP Server stopped');
}
catch (error) {
this.logger.error('Error stopping MCP Server', error);
throw error;
}
}
getHealthStatus() {
return {
status: this.isInitialized ? 'healthy' : 'initializing',
version: '5.2.2',
uptime: process.uptime(),
features: {
contextAnalysis: true,
productDetection: true,
aiIntegration: this.aiEnabled,
aiEnhancedAnalysis: this.contextAnalyzer.isAIEnabled(),
vectorSearch: this.aiEnabled && chromaDBService.isAvailable(),
documentationSync: documentationSyncService.getSyncStatus().autoSyncEnabled,
multipleTools: true,
apiKeyDetection: true,
realTimeAnalysis: true
},
services: {
openAI: openAIClient.isAvailable(),
chromaDB: chromaDBService.isAvailable(),
documentationSync: !documentationSyncService.getSyncStatus().inProgress
},
stats: this.aiEnabled ? {
openAI: openAIClient.getUsageStats(),
chromaDB: chromaDBService.isAvailable() ? 'connected' : 'disconnected',
lastDocSync: documentationSyncService.getSyncStatus().lastSyncTime
} : undefined,
timestamp: new Date()
};
}
}
//# sourceMappingURL=mcp-server.js.map