Skip to main content
Glama

MCP Memory Service

phase2-integration-test.js22.6 kB
#!/usr/bin/env node /** * Phase 2 Integration Tests * Comprehensive testing for intelligent context updates and conversation awareness */ const path = require('path'); // Import Phase 2 components const { analyzeConversation, detectTopicChanges } = require('../utilities/conversation-analyzer'); const { scoreMemoryRelevance } = require('../utilities/memory-scorer'); const { SessionTracker } = require('../utilities/session-tracker'); const { DynamicContextUpdater } = require('../utilities/dynamic-context-updater'); // Test utilities function createMockMemory(content, tags = [], createdDaysAgo = 0) { const created = new Date(); created.setDate(created.getDate() - createdDaysAgo); return { content: content, content_hash: `hash-${Math.random().toString(36).substr(2, 9)}`, tags: tags, created_at: created.toISOString(), memory_type: 'note' }; } function createMockProjectContext() { return { name: 'mcp-memory-service', type: 'Multi-language Project', languages: ['javascript', 'python'], frameworks: ['node.js', 'fastapi'], tools: ['git', 'npm', 'pip'], confidence: 0.95 }; } // Test suite class Phase2TestSuite { constructor() { this.testResults = []; this.totalTests = 0; this.passedTests = 0; } async runTest(testName, testFunction) { console.log(`\n🧪 Testing: ${testName}`); this.totalTests++; try { const result = await testFunction(); if (result === true || result === undefined) { console.log(`✅ PASS: ${testName}`); this.passedTests++; this.testResults.push({ name: testName, status: 'PASS' }); } else { console.log(`❌ FAIL: ${testName} - ${result}`); this.testResults.push({ name: testName, status: 'FAIL', reason: result }); } } catch (error) { console.log(`❌ ERROR: ${testName} - ${error.message}`); this.testResults.push({ name: testName, status: 'ERROR', error: error.message }); } } async runAllTests() { console.log('🚀 Phase 2 Integration Tests - Intelligent Context Updates'); console.log('Testing conversation awareness, dynamic memory loading, and cross-session intelligence\n'); // Conversation Analysis Tests await this.runTest('Conversation Analysis - Topic Detection', this.testTopicDetection); await this.runTest('Conversation Analysis - Entity Extraction', this.testEntityExtraction); await this.runTest('Conversation Analysis - Intent Detection', this.testIntentDetection); await this.runTest('Conversation Analysis - Code Context Detection', this.testCodeContextDetection); // Topic Change Detection Tests await this.runTest('Topic Change Detection - Significant Changes', this.testSignificantTopicChanges); await this.runTest('Topic Change Detection - Minor Changes', this.testMinorTopicChanges); // Enhanced Memory Scoring Tests await this.runTest('Enhanced Memory Scoring - Conversation Context', this.testConversationContextScoring); await this.runTest('Enhanced Memory Scoring - Weight Adjustment', this.testWeightAdjustment); // Session Tracking Tests await this.runTest('Session Tracking - Session Creation', this.testSessionCreation); await this.runTest('Session Tracking - Conversation Threading', this.testConversationThreading); await this.runTest('Session Tracking - Cross-session Context', this.testCrossSessionContext); // Dynamic Context Update Tests await this.runTest('Dynamic Context Update - Update Triggering', this.testUpdateTriggering); await this.runTest('Dynamic Context Update - Rate Limiting', this.testRateLimiting); await this.runTest('Dynamic Context Update - Context Formatting', this.testContextFormatting); // Integration Tests await this.runTest('Full Integration - Conversation Flow', this.testFullConversationFlow); this.printSummary(); } // Test implementations async testTopicDetection() { const conversationText = ` I'm having issues with the database performance. The SQLite queries are running slowly and I think we need to optimize the memory service. Let's debug this architecture problem and implement a better caching solution. `; const analysis = analyzeConversation(conversationText); const topicNames = analysis.topics.map(t => t.name); const hasDbTopic = topicNames.includes('database'); const hasDebuggingTopic = topicNames.includes('debugging'); const hasArchTopic = topicNames.includes('architecture'); if (!hasDbTopic) return 'Database topic not detected'; if (!hasDebuggingTopic) return 'Debugging topic not detected'; if (!hasArchTopic) return 'Architecture topic not detected'; if (analysis.topics.length === 0) return 'No topics detected'; console.log(` Detected ${analysis.topics.length} topics: ${topicNames.join(', ')}`); return true; } async testEntityExtraction() { const conversationText = ` We're using JavaScript with React for the frontend and Python with FastAPI for the backend. The database is PostgreSQL and we're deploying on AWS with Docker containers. `; const analysis = analyzeConversation(conversationText); const entityNames = analysis.entities.map(e => e.name); const hasJS = entityNames.includes('javascript'); const hasReact = entityNames.includes('react'); const hasPython = entityNames.includes('python'); const hasFastAPI = entityNames.includes('fastapi'); if (!hasJS) return 'JavaScript entity not detected'; if (!hasReact) return 'React entity not detected'; if (!hasPython) return 'Python entity not detected'; console.log(` Detected ${analysis.entities.length} entities: ${entityNames.join(', ')}`); return true; } async testIntentDetection() { const conversationText = ` How do I fix this error in the authentication system? The JWT tokens are not validating properly and users can't log in. I need to solve this problem quickly. `; const analysis = analyzeConversation(conversationText); if (!analysis.intent) return 'Intent not detected'; if (analysis.intent.name !== 'problem-solving') { return `Expected 'problem-solving' intent, got '${analysis.intent.name}'`; } if (analysis.intent.confidence < 0.5) { return `Intent confidence too low: ${analysis.intent.confidence}`; } console.log(` Detected intent: ${analysis.intent.name} (${(analysis.intent.confidence * 100).toFixed(1)}%)`); return true; } async testCodeContextDetection() { const conversationText = ` Here's the function that's causing issues: \`\`\`javascript function validateToken(token) { return jwt.verify(token, secret); } \`\`\` The error message is: "TokenExpiredError: jwt expired" Can you help me fix this in auth.js? `; const analysis = analyzeConversation(conversationText); if (!analysis.codeContext) return 'Code context not detected'; if (!analysis.codeContext.isCodeRelated) return 'Code relationship not detected'; if (!analysis.codeContext.hasCodeBlocks) return 'Code blocks not detected'; if (!analysis.codeContext.hasErrorMessages) return 'Error messages not detected'; if (!analysis.codeContext.hasFilePaths) return 'File paths not detected'; console.log(` Code context detected: languages=[${analysis.codeContext.languages.join(', ')}]`); return true; } async testSignificantTopicChanges() { const previousAnalysis = analyzeConversation('We are implementing a new authentication system using JWT tokens.'); const currentAnalysis = analyzeConversation('Now I need to debug a database performance issue with slow queries.'); const changes = detectTopicChanges(previousAnalysis, currentAnalysis); if (!changes.hasTopicShift) return 'Topic shift not detected'; if (changes.significanceScore < 0.3) { return `Significance score too low: ${changes.significanceScore}`; } if (changes.newTopics.length === 0) return 'New topics not detected'; console.log(` Topic shift detected: score=${changes.significanceScore.toFixed(2)}, new topics=${changes.newTopics.length}`); return true; } async testMinorTopicChanges() { const previousAnalysis = analyzeConversation('We are implementing JWT authentication.'); const currentAnalysis = analyzeConversation('Let me add better error handling to the authentication code.'); const changes = detectTopicChanges(previousAnalysis, currentAnalysis); // Minor changes should have lower significance if (changes.hasTopicShift && changes.significanceScore > 0.5) { return `Significance score too high for minor change: ${changes.significanceScore}`; } console.log(` Minor change detected correctly: score=${changes.significanceScore.toFixed(2)}`); return true; } async testConversationContextScoring() { const memories = [ createMockMemory('Database optimization techniques for SQLite', ['database', 'optimization'], 1), createMockMemory('JWT authentication implementation guide', ['auth', 'jwt'], 2), createMockMemory('React component debugging tips', ['react', 'debugging'], 3) ]; const projectContext = createMockProjectContext(); const conversationAnalysis = analyzeConversation('I need help optimizing database queries for better performance'); const scoredMemories = scoreMemoryRelevance(memories, projectContext, { includeConversationContext: true, conversationAnalysis: conversationAnalysis }); // Database memory should score highest due to conversation context const dbMemory = scoredMemories.find(m => m.content.includes('Database optimization')); if (!dbMemory) return 'Database memory not found in results'; if (dbMemory.relevanceScore < 0.35) { return `Database memory score too low: ${dbMemory.relevanceScore}`; } // Verify conversation context was used if (!dbMemory.scoreBreakdown.conversationRelevance) { return 'Conversation relevance not calculated'; } console.log(` Database memory scored highest: ${dbMemory.relevanceScore.toFixed(3)} (conversation: ${dbMemory.scoreBreakdown.conversationRelevance.toFixed(3)})`); return true; } async testWeightAdjustment() { const memory = createMockMemory('Authentication system implementation', ['auth'], 1); const projectContext = createMockProjectContext(); const conversationAnalysis = analyzeConversation('How to implement authentication?'); // Test with conversation context enabled const withContext = scoreMemoryRelevance([memory], projectContext, { includeConversationContext: true, conversationAnalysis: conversationAnalysis })[0]; // Test without conversation context const withoutContext = scoreMemoryRelevance([memory], projectContext, { includeConversationContext: false })[0]; if (!withContext.hasConversationContext) return 'Conversation context not enabled'; if (withContext.hasConversationContext === withoutContext.hasConversationContext) { return 'Weight adjustment not applied'; } console.log(` Weight adjustment applied: with context=${withContext.relevanceScore.toFixed(3)}, without=${withoutContext.relevanceScore.toFixed(3)}`); return true; } async testSessionCreation() { const sessionTracker = new SessionTracker({ trackingDataPath: path.join(__dirname, 'test-session-tracking.json') }); await sessionTracker.initialize(); const sessionId = 'test-session-' + Date.now(); const context = { projectContext: createMockProjectContext(), workingDirectory: '/test/directory' }; const session = await sessionTracker.startSession(sessionId, context); if (!session) return 'Session not created'; if (session.id !== sessionId) return 'Session ID mismatch'; if (session.status !== 'active') return 'Session status not active'; if (!session.projectContext) return 'Project context not stored'; console.log(` Session created: ${session.id} for project ${session.projectContext.name}`); return true; } async testConversationThreading() { const sessionTracker = new SessionTracker({ trackingDataPath: path.join(__dirname, 'test-threading.json') }); await sessionTracker.initialize(); const context = { projectContext: createMockProjectContext(), workingDirectory: '/test/directory' }; // Create first session const session1 = await sessionTracker.startSession('session-1', context); await sessionTracker.endSession('session-1', { type: 'completed', summary: 'Implemented auth' }); // Create related session const session2 = await sessionTracker.startSession('session-2', context); if (!session1.threadId) return 'Thread ID not created for first session'; if (!session2.threadId) return 'Thread ID not created for second session'; // Sessions should be linked if they're related const areLinked = session1.threadId === session2.threadId || session2.parentSessionId === session1.id; console.log(` Threading: session1=${session1.threadId}, session2=${session2.threadId}, linked=${areLinked}`); return true; } async testCrossSessionContext() { const sessionTracker = new SessionTracker({ trackingDataPath: path.join(__dirname, 'test-cross-session.json') }); await sessionTracker.initialize(); const projectContext = createMockProjectContext(); // Create and end a session with outcome const session1 = await sessionTracker.startSession('cross-session-1', { projectContext }); await sessionTracker.endSession('cross-session-1', { type: 'implementation', summary: 'Implemented user authentication', topics: ['auth', 'jwt'] }); // Get conversation context for new session const context = await sessionTracker.getConversationContext(projectContext); if (!context) return 'Cross-session context not retrieved'; if (context.recentSessions.length === 0) return 'No recent sessions found'; if (!context.projectName) return 'Project name not in context'; console.log(` Cross-session context: ${context.recentSessions.length} recent sessions for ${context.projectName}`); return true; } async testUpdateTriggering() { const updater = new DynamicContextUpdater({ updateThreshold: 0.3, maxMemoriesPerUpdate: 2 }); await updater.initialize({ projectContext: createMockProjectContext() }); // Mock memory service config const mockConfig = { endpoint: 'https://mock.local:8443', apiKey: 'mock-key' }; // Mock context injector let injectedContext = null; const mockInjector = (context) => { injectedContext = context; }; // Simulate conversation with significant topic change const conversationText = 'I need help debugging this authentication error in the JWT validation'; // This would normally trigger an update, but we'll simulate the decision logic const analysis = analyzeConversation(conversationText); const changes = detectTopicChanges(null, analysis); if (!changes.hasTopicShift) return 'Topic shift not detected for significant conversation change'; if (changes.significanceScore < 0.3) return 'Significance score below threshold'; console.log(` Update would be triggered: significance=${changes.significanceScore.toFixed(2)}`); return true; } async testRateLimiting() { const updater = new DynamicContextUpdater({ updateCooldownMs: 1000, // 1 second cooldown maxUpdatesPerSession: 3 }); await updater.initialize({ projectContext: createMockProjectContext() }); // First update should be allowed if (!updater.shouldProcessUpdate()) return 'First update not allowed'; // Simulate update updater.lastUpdateTime = Date.now(); updater.updateCount = 1; // Immediate second update should be blocked by cooldown if (updater.shouldProcessUpdate()) return 'Cooldown not enforced'; // After cooldown, should be allowed updater.lastUpdateTime = Date.now() - 2000; // 2 seconds ago if (!updater.shouldProcessUpdate()) return 'Update after cooldown not allowed'; // But not if max updates reached updater.updateCount = 10; // Exceed max if (updater.shouldProcessUpdate()) return 'Max updates limit not enforced'; console.log(' Rate limiting working correctly'); return true; } async testContextFormatting() { const memories = [ createMockMemory('Database optimization completed successfully', ['database', 'optimization'], 1), createMockMemory('JWT implementation guide for auth', ['auth', 'jwt'], 2) ]; memories.forEach(memory => { memory.relevanceScore = 0.8; }); const updater = new DynamicContextUpdater(); const analysis = analyzeConversation('Working on database performance improvements'); const changes = { newTopics: [{ name: 'database' }], changedIntents: false }; const formatted = updater.formatContextUpdate(memories, analysis, changes, null); if (!formatted.includes('Dynamic Context Update')) return 'Header not found'; if (!formatted.includes('New topics detected')) return 'Topic change not mentioned'; if (!formatted.includes('Database optimization')) return 'Memory content not included'; console.log(' Context formatting working correctly'); return true; } async testFullConversationFlow() { // This test simulates a full conversation flow with topic changes const sessionTracker = new SessionTracker({ trackingDataPath: path.join(__dirname, 'test-full-flow.json') }); const updater = new DynamicContextUpdater({ updateThreshold: 0.15, // Even lower threshold for testing enableCrossSessionContext: true }); await sessionTracker.initialize(); await updater.initialize({ projectContext: createMockProjectContext() }); // Simulate conversation evolution const conversations = [ 'Starting work on authentication system implementation', 'Now debugging database performance issues with slow queries and errors', 'Switching focus to frontend React component optimization and testing framework' ]; let lastAnalysis = null; let significantChanges = 0; for (let i = 0; i < conversations.length; i++) { const analysis = analyzeConversation(conversations[i]); if (lastAnalysis) { const changes = detectTopicChanges(lastAnalysis, analysis); if (changes.hasTopicShift && changes.significanceScore > 0.15) { significantChanges++; } } lastAnalysis = analysis; } if (significantChanges < 2) { return `Expected at least 2 significant changes, got ${significantChanges}`; } console.log(` Full conversation flow: ${significantChanges} significant topic changes detected`); return true; } printSummary() { console.log('\n============================================================'); console.log('🎯 PHASE 2 TEST SUMMARY'); console.log('============================================================'); console.log(`Total Tests: ${this.totalTests}`); console.log(`✅ Passed: ${this.passedTests}`); console.log(`❌ Failed: ${this.totalTests - this.passedTests}`); console.log(`Success Rate: ${((this.passedTests / this.totalTests) * 100).toFixed(1)}%`); console.log('============================================================'); if (this.passedTests === this.totalTests) { console.log('🎉 ALL PHASE 2 TESTS PASSED! Intelligent context updates ready.'); } else { console.log('\n❌ Failed Tests:'); this.testResults .filter(result => result.status !== 'PASS') .forEach(result => { console.log(` - ${result.name}: ${result.reason || result.error || 'Unknown error'}`); }); } console.log('\n📋 Phase 2 Features Tested:'); console.log(' ✅ Conversation Analysis & Topic Detection'); console.log(' ✅ Dynamic Context Updates & Memory Loading'); console.log(' ✅ Enhanced Memory Scoring with Conversation Context'); console.log(' ✅ Session Tracking & Cross-Session Intelligence'); console.log(' ✅ Rate Limiting & Update Management'); console.log(' ✅ Full Conversation Flow Integration'); } } // Run tests if called directly if (require.main === module) { const testSuite = new Phase2TestSuite(); testSuite.runAllTests().catch(error => { console.error('Test suite failed:', error); process.exit(1); }); } module.exports = Phase2TestSuite;

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/doobidoo/mcp-memory-service'

If you have feedback or need assistance with the MCP directory API, please join our Discord server