/** * Complete Integration Test for Multi-User Chrome MCP System * * This test demonstrates the complete flow: * 1. Multiple Chrome extensions connect with unique user IDs * 2. Remote server automatically spawns LiveKit agents for each user * 3. Voice commands are routed to the correct Chrome extension * 4. Session isolation is maintained */ import WebSocket from 'ws'; import fetch from 'node-fetch'; const CHROME_WS_URL = 'ws://localhost:3001/chrome'; const MCP_HTTP_URL = 'http://localhost:3001/mcp'; class IntegratedUser { constructor(userNumber) { this.userNumber = userNumber; this.chromeUserId = `user_${Date.now()}_${userNumber}_${Math.random().toString(36).substring(2, 10)}`; this.ws = null; this.sessionInfo = null; this.receivedCommands = []; this.liveKitAgentExpected = false; } async connectChromeExtension() { return new Promise((resolve, reject) => { console.log(`\n๐Ÿ”Œ [User ${this.userNumber}] Connecting Chrome extension...`); console.log(` Generated User ID: ${this.chromeUserId}`); this.ws = new WebSocket(CHROME_WS_URL); this.ws.on('open', () => { console.log(`โœ… [User ${this.userNumber}] Chrome WebSocket connected`); // Send connection info with unique user ID const connectionInfo = { type: 'connection_info', userId: this.chromeUserId, userAgent: `IntegratedTestUser-${this.userNumber}`, timestamp: Date.now(), extensionId: `integrated-test-${this.userNumber}` }; this.ws.send(JSON.stringify(connectionInfo)); }); this.ws.on('message', (data) => { try { const message = JSON.parse(data.toString()); if (message.type === 'session_info') { this.sessionInfo = message.sessionInfo; console.log(`๐ŸŽฏ [User ${this.userNumber}] Session established:`); console.log(` Session ID: ${this.sessionInfo.sessionId}`); console.log(` User ID: ${this.sessionInfo.userId}`); console.log(` Expected LiveKit Room: mcp-chrome-user-${this.sessionInfo.userId}`); this.liveKitAgentExpected = true; resolve(); } // Handle voice commands from LiveKit agent if (message.action === 'callTool') { this.receivedCommands.push({ ...message, receivedAt: Date.now() }); console.log(`๐ŸŽค [User ${this.userNumber}] Received voice command: ${message.params.name}`); console.log(` Arguments:`, message.params.arguments); // Simulate Chrome extension executing the command const response = { id: message.id, success: true, result: { message: `Command ${message.params.name} executed successfully`, executedBy: `ChromeExtension-User${this.userNumber}`, userId: this.chromeUserId, timestamp: Date.now() } }; this.ws.send(JSON.stringify(response)); console.log(`๐Ÿ“ค [User ${this.userNumber}] Sent command response`); } } catch (error) { console.error(`โŒ [User ${this.userNumber}] Error parsing message:`, error); } }); this.ws.on('error', (error) => { console.error(`โŒ [User ${this.userNumber}] WebSocket error:`, error); reject(error); }); setTimeout(() => { if (!this.sessionInfo) { reject(new Error(`[User ${this.userNumber}] Timeout waiting for session info`)); } }, 10000); }); } async simulateVoiceCommand(toolName, args) { console.log(`๐ŸŽ™๏ธ [User ${this.userNumber}] Simulating voice command: ${toolName}`); const payload = { jsonrpc: '2.0', id: `voice_${this.userNumber}_${Date.now()}`, method: 'tools/call', params: { name: toolName, arguments: { ...args, userContext: this.chromeUserId } } }; const headers = { 'Content-Type': 'application/json', 'chrome-user-id': this.chromeUserId, // Route to this specific user 'user-agent': `LiveKitAgent-User${this.userNumber}` }; try { const response = await fetch(MCP_HTTP_URL, { method: 'POST', headers: headers, body: JSON.stringify(payload) }); const result = await response.json(); console.log(`๐Ÿ“จ [User ${this.userNumber}] Voice command response:`, result.result || result.error); return result; } catch (error) { console.error(`โŒ [User ${this.userNumber}] Error sending voice command:`, error); throw error; } } getStatus() { return { userNumber: this.userNumber, chromeUserId: this.chromeUserId, sessionId: this.sessionInfo?.sessionId, liveKitAgentExpected: this.liveKitAgentExpected, commandsReceived: this.receivedCommands.length, lastCommand: this.receivedCommands[this.receivedCommands.length - 1]?.params?.name }; } disconnect() { if (this.ws) { console.log(`๐Ÿ‘‹ [User ${this.userNumber}] Disconnecting Chrome extension`); this.ws.close(); } } } async function runCompleteIntegrationTest() { console.log('๐Ÿš€ COMPLETE INTEGRATION TEST FOR MULTI-USER CHROME MCP SYSTEM'); console.log('=' .repeat(80)); console.log('This test demonstrates:'); console.log('โœ“ Multiple Chrome extensions with unique user IDs'); console.log('โœ“ Automatic LiveKit agent spawning'); console.log('โœ“ Voice command routing with session isolation'); console.log('โœ“ End-to-end user experience'); console.log('=' .repeat(80)); const users = []; const NUM_USERS = 3; try { // Phase 1: Connect Chrome Extensions console.log('\n๐Ÿ“‹ PHASE 1: Chrome Extension Connections'); console.log('-' .repeat(50)); for (let i = 1; i <= NUM_USERS; i++) { const user = new IntegratedUser(i); users.push(user); await user.connectChromeExtension(); console.log(`โœ… User ${i} Chrome extension connected successfully`); // Wait between connections to see the flow clearly await new Promise(resolve => setTimeout(resolve, 2000)); } // Phase 2: Verify LiveKit Agent Spawning console.log('\n๐Ÿ“‹ PHASE 2: LiveKit Agent Verification'); console.log('-' .repeat(50)); console.log('โณ Waiting for LiveKit agents to start...'); await new Promise(resolve => setTimeout(resolve, 5000)); users.forEach(user => { const status = user.getStatus(); console.log(`๐Ÿค– User ${status.userNumber}: LiveKit agent expected for room mcp-chrome-user-${status.chromeUserId}`); }); // Phase 3: Test Voice Commands console.log('\n๐Ÿ“‹ PHASE 3: Voice Command Testing'); console.log('-' .repeat(50)); const voiceCommands = [ { tool: 'chrome_navigate', args: { url: 'https://www.google.com' } }, { tool: 'chrome_click_element', args: { selector: '#search-button' } }, { tool: 'chrome_get_web_content', args: { selector: 'body' } } ]; for (let i = 0; i < users.length; i++) { const user = users[i]; const command = voiceCommands[i % voiceCommands.length]; console.log(`\n๐ŸŽค Testing voice command for User ${user.userNumber}:`); console.log(` Command: ${command.tool}`); console.log(` Target: ${command.args.url || command.args.selector || 'page content'}`); await user.simulateVoiceCommand(command.tool, command.args); // Wait for command to be processed await new Promise(resolve => setTimeout(resolve, 3000)); } // Phase 4: Test Session Isolation console.log('\n๐Ÿ“‹ PHASE 4: Session Isolation Testing'); console.log('-' .repeat(50)); console.log('๐Ÿ”’ Testing that commands only go to the intended user...'); // Send a command from User 1 that should only affect User 1 await users[0].simulateVoiceCommand('chrome_navigate', { url: 'https://example.com/isolation-test', testId: 'isolation-test-user-1' }); await new Promise(resolve => setTimeout(resolve, 2000)); // Phase 5: Results Analysis console.log('\n๐Ÿ“‹ PHASE 5: Results Analysis'); console.log('-' .repeat(50)); let totalCommandsSent = NUM_USERS + 1; // 3 initial commands + 1 isolation test let totalCommandsReceived = 0; let isolationSuccess = true; console.log('\n๐Ÿ“Š USER STATUS REPORT:'); users.forEach(user => { const status = user.getStatus(); totalCommandsReceived += status.commandsReceived; console.log(`\n๐Ÿ‘ค User ${status.userNumber}:`); console.log(` Chrome User ID: ${status.chromeUserId}`); console.log(` Session ID: ${status.sessionId}`); console.log(` Commands Received: ${status.commandsReceived}`); console.log(` Last Command: ${status.lastCommand || 'None'}`); console.log(` LiveKit Agent Expected: ${status.liveKitAgentExpected ? 'โœ…' : 'โŒ'}`); }); // Check isolation: User 1 should have received 2 commands, others should have 1 each const user1Commands = users[0].getStatus().commandsReceived; const user2Commands = users[1].getStatus().commandsReceived; const user3Commands = users[2].getStatus().commandsReceived; if (user1Commands !== 2 || user2Commands !== 1 || user3Commands !== 1) { isolationSuccess = false; } // Final Results console.log('\n๐ŸŽฏ FINAL RESULTS:'); console.log('=' .repeat(50)); console.log(`๐Ÿ“ค Total Commands Sent: ${totalCommandsSent}`); console.log(`๐Ÿ“ฅ Total Commands Received: ${totalCommandsReceived}`); console.log(`๐ŸŽฏ Command Routing: ${totalCommandsReceived === totalCommandsSent ? 'โœ… SUCCESS' : 'โŒ FAILED'}`); console.log(`๐Ÿ”’ Session Isolation: ${isolationSuccess ? 'โœ… SUCCESS' : 'โŒ FAILED'}`); console.log(`๐Ÿค– LiveKit Agents: ${users.every(u => u.liveKitAgentExpected) ? 'โœ… ALL EXPECTED' : 'โŒ SOME MISSING'}`); if (totalCommandsReceived === totalCommandsSent && isolationSuccess) { console.log('\n๐ŸŽ‰ COMPLETE INTEGRATION TEST PASSED! ๐ŸŽ‰'); console.log('โœ… Multi-user Chrome MCP system is working correctly'); } else { console.log('\nโŒ COMPLETE INTEGRATION TEST FAILED!'); console.log('โŒ Issues detected in multi-user system'); } } catch (error) { console.error('\nโŒ Integration test failed:', error); } finally { // Cleanup console.log('\n๐Ÿงน Cleaning up test connections...'); users.forEach(user => user.disconnect()); setTimeout(() => { console.log('โœ… Integration test completed'); process.exit(0); }, 3000); } } // Run the complete integration test runCompleteIntegrationTest().catch(console.error);