@aaswe/codebase-ai
Version:
AI-Assisted Software Engineering (AASWE) - Rich codebase context for IDE LLMs
436 lines • 17.9 kB
JavaScript
"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