UNPKG

@aaswe/codebase-ai

Version:

AI-Assisted Software Engineering (AASWE) - Rich codebase context for IDE LLMs

436 lines 17.9 kB
"use strict"; /** * Enhanced MCP Server Integration * * Integrates the TTLContextLoader with the existing MCP server to provide * automatic context loading from TTL files generated by the analysis system. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.EnhancedMCPServer = void 0; const events_1 = require("events"); const logger_1 = __importDefault(require("../../utils/logger")); const MCPServer_1 = require("./MCPServer"); const TTLContextLoader_1 = require("./TTLContextLoader"); const Neo4jContextProvider_1 = require("./Neo4jContextProvider"); /** * Enhanced MCP Server with automatic TTL context loading */ class EnhancedMCPServer extends events_1.EventEmitter { mcpServer; ttlContextLoader; neo4jContextProvider = null; _knowledgeGraphPopulator; _rdfGenerator; _informationExtractor; config; metrics; isRunning = false; constructor(config, layer3Service, hybridStorage, knowledgeGraphPopulator, rdfGenerator, informationExtractor, neo4jService) { super(); this.config = config; this._knowledgeGraphPopulator = knowledgeGraphPopulator; this._rdfGenerator = rdfGenerator; this._informationExtractor = informationExtractor; // Initialize base MCP server this.mcpServer = new MCPServer_1.MCPServer(config.mcpServer, layer3Service, hybridStorage); // Initialize TTL context loader this.ttlContextLoader = new TTLContextLoader_1.TTLContextLoader(config.ttlContextLoader, this._knowledgeGraphPopulator, this._rdfGenerator, this._informationExtractor); // Initialize Neo4j context provider if Neo4j service is available if (neo4jService && neo4jService.isConnected()) { this.neo4jContextProvider = new Neo4jContextProvider_1.Neo4jContextProvider(neo4jService, { maxResults: 10, includeSourceCode: true, relevanceThreshold: 0.3, queryTimeout: 30000 }); logger_1.default.info('Neo4j context provider initialized'); } this.metrics = this.initializeMetrics(); this.setupEventHandlers(); logger_1.default.info('EnhancedMCPServer initialized', { mcpServerPort: config.mcpServer.server.port, ttlWatchEnabled: config.ttlContextLoader.watchEnabled, neo4jEnabled: !!this.neo4jContextProvider }); } /** * Initialize metrics */ initializeMetrics() { return { server: { uptime: 0, totalRequests: 0, enhancedContextRequests: 0, ttlContextRequests: 0, averageResponseTime: 0, errorRate: 0 }, ttlIntegration: { ttlFilesLoaded: 0, contextCacheHits: 0, contextCacheMisses: 0, averageRelevanceScore: 0, knowledgeGraphQueries: 0 }, performance: { memoryUsage: 0, contextLoadingTime: 0, ttlProcessingTime: 0, lastOptimization: new Date() } }; } /** * Setup event handlers for integration */ setupEventHandlers() { // Handle TTL file changes this.ttlContextLoader.on('ttl_file_changed', (event) => { this.handleTTLFileChange(event); }); // Handle TTL file refresh this.ttlContextLoader.on('ttl_file_refreshed', (event) => { this.handleTTLFileRefresh(event); }); // Handle MCP server events this.mcpServer.on('ttl_file_changed', (event) => { this.emit('ttl_integration_update', event); }); } /** * Start the enhanced MCP server */ async start() { try { logger_1.default.info('Starting Enhanced MCP Server...'); // Start TTL context loader first await this.ttlContextLoader.start(); // Override MCP server context generation with enhanced version this.enhanceMCPServerContextGeneration(); // Start base MCP server await this.mcpServer.start(); this.isRunning = true; logger_1.default.info('Enhanced MCP Server started successfully', { ttlFiles: this.ttlContextLoader.getTTLFiles().size, mcpServerRunning: true }); } catch (error) { logger_1.default.error('Failed to start Enhanced MCP Server', { error }); throw error; } } /** * Stop the enhanced MCP server */ async stop() { try { logger_1.default.info('Stopping Enhanced MCP Server...'); this.isRunning = false; // Stop MCP server await this.mcpServer.stop(); // Stop TTL context loader await this.ttlContextLoader.stop(); logger_1.default.info('Enhanced MCP Server stopped'); } catch (error) { logger_1.default.error('Failed to stop Enhanced MCP Server', { error }); throw error; } } /** * Get enhanced context using both TTL loader and Neo4j source code */ async getEnhancedContext(request) { const startTime = Date.now(); this.metrics.server.enhancedContextRequests++; try { // Get TTL context const ttlResponse = await this.ttlContextLoader.loadContext(request); // Get Neo4j source code context if available let neo4jSources = []; if (this.neo4jContextProvider) { try { const neo4jResult = await this.neo4jContextProvider.getSourceCodeContext(request); neo4jSources = neo4jResult.sources; logger_1.default.debug('Neo4j context retrieved', { sources: neo4jSources.length, languages: neo4jResult.metadata.languages }); } catch (neo4jError) { logger_1.default.warn('Neo4j context retrieval failed, using TTL only', { error: neo4jError }); } } // Combine TTL and Neo4j sources const combinedSources = [...ttlResponse.sources, ...neo4jSources]; // Generate enhanced context with both TTL metadata and source code const enhancedContext = this.buildTripleContext(ttlResponse.context, neo4jSources, request); // Calculate combined metrics const totalTokens = this.estimateTokens(enhancedContext); const avgRelevance = combinedSources.length > 0 ? combinedSources.reduce((sum, s) => sum + s.relevanceScore, 0) / combinedSources.length : 0; const response = { context: enhancedContext, sources: combinedSources, metadata: { totalTokens, processingTime: Date.now() - startTime, relevanceScore: avgRelevance, cached: false }, suggestions: { relatedFiles: ttlResponse.suggestions?.relatedFiles || [], followUpQueries: [ ...ttlResponse.suggestions?.followUpQueries || [], ...(neo4jSources.length > 0 ? ['What are the implementation details of this code?'] : []) ], improvements: [ ...ttlResponse.suggestions?.improvements || [], ...(neo4jSources.length > 0 ? ['Source code analysis shows concrete implementation patterns'] : []) ] } }; // Update metrics this.updateMetrics(response.metadata.processingTime, response); return response; } catch (error) { logger_1.default.error('Failed to get enhanced context', { request, error }); this.metrics.server.errorRate++; throw error; } } /** * Refresh TTL files and update context */ async refreshTTLContext() { try { logger_1.default.info('Refreshing TTL context...'); const ttlFiles = this.ttlContextLoader.getTTLFiles(); const refreshPromises = Array.from(ttlFiles.keys()).map(path => this.ttlContextLoader.refreshTTLFile(path)); await Promise.allSettled(refreshPromises); logger_1.default.info(`Refreshed ${ttlFiles.size} TTL files`); } catch (error) { logger_1.default.error('Failed to refresh TTL context', { error }); throw error; } } /** * Get server status including TTL integration */ getStatus() { const baseStatus = this.mcpServer.getStatus(); const ttlMetrics = this.ttlContextLoader.getMetrics(); return { ...baseStatus, enhanced: { isRunning: this.isRunning, ttlIntegration: { ttlFilesLoaded: ttlMetrics.ttlFiles.loaded, ttlFilesWatching: ttlMetrics.ttlFiles.watching, contextCacheSize: ttlMetrics.performance.cacheSize, lastCleanup: ttlMetrics.performance.lastCleanup }, metrics: this.metrics } }; } /** * Get enhanced metrics */ getMetrics() { const ttlMetrics = this.ttlContextLoader.getMetrics(); // Update performance metrics this.metrics.performance.memoryUsage = process.memoryUsage().heapUsed; this.metrics.ttlIntegration.ttlFilesLoaded = ttlMetrics.ttlFiles.loaded; this.metrics.ttlIntegration.contextCacheHits = ttlMetrics.context.cacheHits; this.metrics.ttlIntegration.contextCacheMisses = ttlMetrics.context.cacheMisses; this.metrics.ttlIntegration.averageRelevanceScore = ttlMetrics.context.averageRelevanceScore; return { ...this.metrics }; } /** * Get TTL files information */ getTTLFiles() { return this.ttlContextLoader.getTTLFiles(); } /** * Enhance MCP server context generation */ enhanceMCPServerContextGeneration() { // Override the generateContext method in MCPServer to use our enhanced loader const originalGenerateContext = this.mcpServer.generateContext; this.mcpServer.generateContext = async (request) => { try { // Try enhanced context first const enhancedResponse = await this.getEnhancedContext(request); this.metrics.server.ttlContextRequests++; return enhancedResponse; } catch (error) { logger_1.default.warn('Enhanced context failed, falling back to original', { error }); // Fallback to original implementation return await originalGenerateContext.call(this.mcpServer, request); } }; logger_1.default.info('MCP Server context generation enhanced with TTL integration'); } /** * Handle TTL file change events */ handleTTLFileChange(event) { logger_1.default.debug('TTL file changed', { type: event.type, path: event.path }); // Emit integration event this.emit('ttl_integration_update', { type: 'file_changed', data: event, timestamp: Date.now() }); // Update metrics if (event.type === 'created') { this.metrics.ttlIntegration.ttlFilesLoaded++; } } /** * Handle TTL file refresh events */ handleTTLFileRefresh(event) { logger_1.default.debug('TTL file refreshed', { path: event.path }); // Emit integration event this.emit('ttl_integration_update', { type: 'file_refreshed', data: event, timestamp: Date.now() }); } /** * Update metrics */ updateMetrics(processingTime, response) { const total = this.metrics.server.enhancedContextRequests; // Update average response time this.metrics.server.averageResponseTime = (this.metrics.server.averageResponseTime * (total - 1) + processingTime) / total; // Update context loading time this.metrics.performance.contextLoadingTime = (this.metrics.performance.contextLoadingTime * (total - 1) + processingTime) / total; // Update cache metrics if (response.metadata.cached) { this.metrics.ttlIntegration.contextCacheHits++; } else { this.metrics.ttlIntegration.contextCacheMisses++; } } /** * Optimize performance */ async optimizePerformance() { try { logger_1.default.info('Optimizing Enhanced MCP Server performance...'); // Clear old cache entries const ttlMetrics = this.ttlContextLoader.getMetrics(); if (ttlMetrics.performance.cacheSize > this.config.ttlContextLoader.maxCacheSize * 0.8) { // Trigger cache cleanup logger_1.default.info('Triggering cache cleanup for performance optimization'); } // Update optimization timestamp this.metrics.performance.lastOptimization = new Date(); logger_1.default.info('Performance optimization completed'); } catch (error) { logger_1.default.error('Failed to optimize performance', { error }); } } /** * Health check for the enhanced server */ async healthCheck() { try { const baseStatus = this.mcpServer.getStatus(); const ttlMetrics = this.ttlContextLoader.getMetrics(); let status = 'healthy'; const details = { mcpServer: baseStatus.status, ttlLoader: { filesLoaded: ttlMetrics.ttlFiles.loaded, filesFailed: ttlMetrics.ttlFiles.failed, cacheSize: ttlMetrics.performance.cacheSize }, performance: { memoryUsage: process.memoryUsage().heapUsed, uptime: baseStatus.uptime } }; // Check for degraded performance if (ttlMetrics.ttlFiles.failed > ttlMetrics.ttlFiles.loaded * 0.1) { status = 'degraded'; details.warning = 'High TTL file loading failure rate'; } // Check for unhealthy state if (baseStatus.status !== 'running' || !this.isRunning) { status = 'unhealthy'; details.error = 'Server not running'; } return { status, details }; } catch (error) { logger_1.default.error('Health check failed', { error }); return { status: 'unhealthy', details: { error: error instanceof Error ? error.message : String(error) } }; } } /** * Build triple context combining TTL metadata and Neo4j source code */ buildTripleContext(ttlContext, neo4jSources, request) { const lines = [ '# AASWE Triple Context System', `# Current File: ${request.filePath}`, `# Cursor Position: Line ${request.cursorPosition.line}, Column ${request.cursorPosition.column}`, '' ]; if (request.query) { lines.push(`# Query: ${request.query}`, ''); } if (request.intent) { lines.push(`# Intent: ${request.intent}`, ''); } // Add TTL metadata context lines.push('## 📋 Structured Knowledge (TTL Metadata)', 'This section provides architectural insights, business context, and module relationships:', '', ttlContext, ''); // Add Neo4j source code context if (neo4jSources.length > 0) { lines.push('## 💻 Source Code Analysis (Neo4j Graph)', 'This section provides actual implementation details and code structure:', ''); for (const source of neo4jSources.slice(0, 5)) { // Limit to top 5 most relevant lines.push(`### ${source.metadata.module} (${source.metadata.language?.toUpperCase()})`, `Relevance: ${(source.relevanceScore * 100).toFixed(1)}% | ` + `Classes: ${source.metadata.classes || 0} | ` + `Methods: ${source.metadata.methods || 0} | ` + `Complexity: ${source.metadata.complexity || 0}/10`, '', source.content, ''); } } // Add integration insights lines.push('## 🔗 Integration Insights', 'The above context combines:', '- **TTL Metadata**: Business logic, architectural patterns, and module relationships', '- **Source Code**: Actual implementation, classes, methods, and code structure', '- **Graph Relationships**: Dependencies, imports, and code connections', '', 'This triple context provides both high-level understanding and implementation details.'); return lines.join('\n'); } /** * Estimate tokens in text */ estimateTokens(text) { // Simple token estimation (roughly 4 characters per token) return Math.ceil(text.length / 4); } } exports.EnhancedMCPServer = EnhancedMCPServer; //# sourceMappingURL=EnhancedMCPServer.js.map