Major refactor: Multi-user Chrome MCP extension with remote server architecture

This commit is contained in:
nasir@endelospay.com
2025-08-21 20:09:57 +05:00
parent d97cad1736
commit 5d869f6a7c
125 changed files with 16249 additions and 11906 deletions

243
test-direct-connection.js Normal file
View File

@@ -0,0 +1,243 @@
/**
* Test script to validate the new direct connection architecture
* This script tests:
* 1. Remote server startup
* 2. Chrome extension direct connection
* 3. Tool call routing without native server
*/
import fetch from 'node-fetch';
import WebSocket from 'ws';
const REMOTE_SERVER_URL = 'http://localhost:3001';
const CHROME_WS_URL = 'ws://localhost:3001/chrome';
const MCP_HTTP_URL = 'http://localhost:3001/mcp';
console.log('🧪 Testing Direct Connection Architecture');
console.log('==========================================');
// Test 1: Check if remote server is running
async function testRemoteServerHealth() {
console.log('\n1⃣ Testing Remote Server Health...');
try {
const response = await fetch(`${REMOTE_SERVER_URL}/health`);
if (response.ok) {
const data = await response.json();
console.log('✅ Remote server is running:', data);
return true;
} else {
console.log('❌ Remote server health check failed:', response.status);
return false;
}
} catch (error) {
console.log('❌ Remote server is not accessible:', error.message);
return false;
}
}
// Test 2: Test MCP tools list via Streamable HTTP
async function testMCPToolsList() {
console.log('\n2⃣ Testing MCP Tools List (Streamable HTTP)...');
try {
// Step 1: Initialize session
const initResponse = await fetch(MCP_HTTP_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json, text/event-stream'
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'initialize',
params: {
protocolVersion: '2024-11-05',
capabilities: {},
clientInfo: { name: 'test-client', version: '1.0.0' }
}
})
});
if (!initResponse.ok) {
throw new Error(`Init failed: ${initResponse.status}`);
}
const sessionId = initResponse.headers.get('mcp-session-id');
console.log('✅ MCP session initialized:', sessionId);
// Step 2: List tools
const toolsResponse = await fetch(MCP_HTTP_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json, text/event-stream',
'MCP-Session-ID': sessionId
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 2,
method: 'tools/list',
params: {}
})
});
if (!toolsResponse.ok) {
throw new Error(`Tools list failed: ${toolsResponse.status}`);
}
const toolsData = await toolsResponse.text();
console.log('✅ MCP tools list retrieved successfully');
console.log('📋 Available tools count:', (toolsData.match(/chrome_/g) || []).length);
return true;
} catch (error) {
console.log('❌ MCP tools list test failed:', error.message);
return false;
}
}
// Test 3: Test Chrome extension WebSocket connection
async function testChromeExtensionConnection() {
console.log('\n3⃣ Testing Chrome Extension WebSocket Connection...');
return new Promise((resolve) => {
try {
const ws = new WebSocket(CHROME_WS_URL);
let connected = false;
const timeout = setTimeout(() => {
if (!connected) {
console.log('❌ Chrome extension WebSocket connection timeout');
ws.close();
resolve(false);
}
}, 10000);
ws.on('open', () => {
connected = true;
clearTimeout(timeout);
console.log('✅ Chrome extension WebSocket connected successfully');
// Test sending a message
ws.send(JSON.stringify({
id: 'test-123',
action: 'ping',
params: {}
}));
setTimeout(() => {
ws.close();
resolve(true);
}, 1000);
});
ws.on('message', (data) => {
console.log('📨 Received message from Chrome extension:', data.toString());
});
ws.on('error', (error) => {
clearTimeout(timeout);
console.log('❌ Chrome extension WebSocket error:', error.message);
resolve(false);
});
ws.on('close', () => {
console.log('🔌 Chrome extension WebSocket connection closed');
});
} catch (error) {
console.log('❌ Chrome extension WebSocket test failed:', error.message);
resolve(false);
}
});
}
// Test 4: Test tool call via MCP (simulating Cherry Studio)
async function testToolCallViaMCP() {
console.log('\n4⃣ Testing Tool Call via MCP (Cherry Studio simulation)...');
try {
// Initialize session
const initResponse = await fetch(MCP_HTTP_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json, text/event-stream'
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'initialize',
params: {
protocolVersion: '2024-11-05',
capabilities: {},
clientInfo: { name: 'test-client', version: '1.0.0' }
}
})
});
const sessionId = initResponse.headers.get('mcp-session-id');
// Call a simple tool (get_windows_and_tabs)
const toolCallResponse = await fetch(MCP_HTTP_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json, text/event-stream',
'MCP-Session-ID': sessionId
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 3,
method: 'tools/call',
params: {
name: 'get_windows_and_tabs',
arguments: {}
}
})
});
if (toolCallResponse.ok) {
const result = await toolCallResponse.text();
console.log('✅ Tool call executed successfully');
console.log('📊 Tool call result preview:', result.substring(0, 200) + '...');
return true;
} else {
console.log('❌ Tool call failed:', toolCallResponse.status);
return false;
}
} catch (error) {
console.log('❌ Tool call test failed:', error.message);
return false;
}
}
// Run all tests
async function runAllTests() {
console.log('🚀 Starting Direct Connection Architecture Tests...\n');
const results = {
serverHealth: await testRemoteServerHealth(),
mcpToolsList: await testMCPToolsList(),
chromeConnection: await testChromeExtensionConnection(),
toolCall: await testToolCallViaMCP()
};
console.log('\n📊 Test Results Summary:');
console.log('========================');
console.log(`Remote Server Health: ${results.serverHealth ? '✅ PASS' : '❌ FAIL'}`);
console.log(`MCP Tools List: ${results.mcpToolsList ? '✅ PASS' : '❌ FAIL'}`);
console.log(`Chrome Extension Connection: ${results.chromeConnection ? '✅ PASS' : '❌ FAIL'}`);
console.log(`Tool Call Execution: ${results.toolCall ? '✅ PASS' : '❌ FAIL'}`);
const passCount = Object.values(results).filter(Boolean).length;
const totalCount = Object.keys(results).length;
console.log(`\n🎯 Overall: ${passCount}/${totalCount} tests passed`);
if (passCount === totalCount) {
console.log('🎉 All tests passed! Direct connection architecture is working correctly.');
} else {
console.log('⚠️ Some tests failed. Please check the remote server and Chrome extension setup.');
}
}
// Run the tests
runAllTests().catch(console.error);