Skip to main content
Glama
test-mcp-manual.js10.5 kB
#!/usr/bin/env node /** * Manual Testing Script for MCP Debugger Server * * This script provides an interactive way to test the MCP debugger server * with colored output and clear pass/fail indicators. * * Usage: * node test-mcp-manual.js * * Requirements: * - Node.js 16+ * - Built MCP server (run `npx nx build @ai-capabilities-suite/mcp-server` first) */ const { spawn } = require("child_process"); const path = require("path"); const readline = require("readline"); // ANSI color codes const colors = { reset: "\x1b[0m", bright: "\x1b[1m", green: "\x1b[32m", red: "\x1b[31m", yellow: "\x1b[33m", blue: "\x1b[34m", cyan: "\x1b[36m", }; function log(message, color = "reset") { console.log(`${colors[color]}${message}${colors.reset}`); } function logSuccess(message) { log(`✓ ${message}`, "green"); } function logError(message) { log(`✗ ${message}`, "red"); } function logInfo(message) { log(`ℹ ${message}`, "cyan"); } function logWarning(message) { log(`⚠ ${message}`, "yellow"); } function logSection(message) { log(`\n${"=".repeat(60)}`, "blue"); log(message, "bright"); log("=".repeat(60), "blue"); } class MCPTester { constructor() { this.serverProcess = null; this.messageId = 0; this.pendingRequests = new Map(); } async start() { logSection("MCP Debugger Server - Manual Test Suite"); try { await this.startServer(); await this.runTests(); } catch (error) { logError(`Test suite failed: ${error.message}`); process.exit(1); } finally { this.stopServer(); } } async startServer() { logInfo("Starting MCP server..."); const serverPath = path.join(__dirname, "dist/src/index.js"); this.serverProcess = spawn("node", [serverPath], { stdio: ["pipe", "pipe", "pipe"], }); this.serverProcess.stderr.on("data", (data) => { logWarning(`Server stderr: ${data.toString()}`); }); this.serverProcess.stdout.on("data", (data) => { const lines = data.toString().split("\n"); for (const line of lines) { if (line.trim()) { try { const response = JSON.parse(line); if (response.id && this.pendingRequests.has(response.id)) { const { resolve, reject } = this.pendingRequests.get(response.id); this.pendingRequests.delete(response.id); if (response.error) { reject(new Error(response.error.message)); } else { resolve(response.result); } } } catch (e) { // Not JSON or not a response we're waiting for } } } }); // Wait for server to be ready await new Promise((resolve) => setTimeout(resolve, 500)); logSuccess("Server started"); } stopServer() { if (this.serverProcess && !this.serverProcess.killed) { this.serverProcess.kill(); logInfo("Server stopped"); } } async sendRequest(method, params = {}) { return new Promise((resolve, reject) => { const id = ++this.messageId; const request = { jsonrpc: "2.0", id, method, params, }; const timeout = setTimeout(() => { this.pendingRequests.delete(id); reject(new Error(`Request timeout for ${method}`)); }, 10000); this.pendingRequests.set(id, { resolve: (result) => { clearTimeout(timeout); resolve(result); }, reject: (error) => { clearTimeout(timeout); reject(error); }, }); this.serverProcess.stdin.write(JSON.stringify(request) + "\n"); }); } async runTests() { let passed = 0; let failed = 0; // Test 1: Initialize logSection("Test 1: Protocol Initialization"); try { const result = await this.sendRequest("initialize", { protocolVersion: "2024-11-05", capabilities: {}, clientInfo: { name: "manual-test", version: "1.0.0", }, }); if (result.serverInfo && result.serverInfo.name === "debugger-server") { logSuccess("Server initialized correctly"); logInfo( ` Server: ${result.serverInfo.name} v${result.serverInfo.version}` ); passed++; } else { logError("Server initialization returned unexpected response"); failed++; } } catch (error) { logError(`Initialization failed: ${error.message}`); failed++; } // Test 2: Tool Discovery logSection("Test 2: Tool Discovery"); try { const result = await this.sendRequest("tools/list"); if (result.tools && Array.isArray(result.tools)) { const toolNames = result.tools.map((t) => t.name); const expectedTools = [ "debugger_start", "debugger_set_breakpoint", "debugger_continue", "debugger_step_over", "debugger_inspect", "debugger_get_stack", "debugger_detect_hang", ]; const allPresent = expectedTools.every((name) => toolNames.includes(name) ); if (allPresent) { logSuccess(`All ${expectedTools.length} tools discovered`); expectedTools.forEach((name) => logInfo(` - ${name}`)); passed++; } else { logError("Some tools are missing"); failed++; } } else { logError("Tool list returned unexpected response"); failed++; } } catch (error) { logError(`Tool discovery failed: ${error.message}`); failed++; } // Test 3: Hang Detection logSection("Test 3: Hang Detection"); try { const testFile = path.join( __dirname, "../debugger-core/test-fixtures/infinite-loop.js" ); logInfo("Testing infinite loop detection..."); const result = await this.sendRequest("tools/call", { name: "debugger_detect_hang", arguments: { command: "node", args: [testFile], timeout: 2000, sampleInterval: 100, }, }); const response = JSON.parse(result.content[0].text); if (response.status === "success" && response.hung === true) { logSuccess("Hang detected correctly"); logInfo(` Location: ${response.location}`); passed++; } else { logError("Hang detection failed or returned unexpected result"); logInfo(` Response: ${JSON.stringify(response, null, 2)}`); failed++; } } catch (error) { logError(`Hang detection test failed: ${error.message}`); failed++; } // Test 4: Start Debug Session logSection("Test 4: Start Debug Session"); let sessionId = null; try { const testFile = path.join( __dirname, "../debugger-core/test-fixtures/simple-script.js" ); const result = await this.sendRequest("tools/call", { name: "debugger_start", arguments: { command: "node", args: [testFile], timeout: 10000, }, }); const response = JSON.parse(result.content[0].text); if (response.status === "success" && response.sessionId) { sessionId = response.sessionId; logSuccess("Debug session started"); logInfo(` Session ID: ${sessionId}`); logInfo(` State: ${response.state}`); passed++; } else { logError("Failed to start debug session"); logInfo(` Response: ${JSON.stringify(response, null, 2)}`); failed++; } } catch (error) { logError(`Debug session start failed: ${error.message}`); failed++; } // Test 5: Set Breakpoint if (sessionId) { logSection("Test 5: Set Breakpoint"); try { const testFile = path.join( __dirname, "../debugger-core/test-fixtures/simple-script.js" ); const result = await this.sendRequest("tools/call", { name: "debugger_set_breakpoint", arguments: { sessionId, file: testFile, line: 2, }, }); const response = JSON.parse(result.content[0].text); if (response.status === "success" && response.breakpointId) { logSuccess("Breakpoint set successfully"); logInfo(` Breakpoint ID: ${response.breakpointId}`); logInfo(` File: ${response.file}`); logInfo(` Line: ${response.line}`); passed++; } else { logError("Failed to set breakpoint"); logInfo(` Response: ${JSON.stringify(response, null, 2)}`); failed++; } } catch (error) { logError(`Set breakpoint failed: ${error.message}`); failed++; } } // Test 6: Error Handling logSection("Test 6: Error Handling"); try { const result = await this.sendRequest("tools/call", { name: "debugger_continue", arguments: { sessionId: "invalid-session-id", }, }); const response = JSON.parse(result.content[0].text); if ( response.status === "error" && response.code === "SESSION_NOT_FOUND" ) { logSuccess("Error handling works correctly"); logInfo(` Error code: ${response.code}`); logInfo(` Message: ${response.message}`); passed++; } else { logError("Error handling returned unexpected response"); failed++; } } catch (error) { logError(`Error handling test failed: ${error.message}`); failed++; } // Summary logSection("Test Summary"); const total = passed + failed; log(`Total tests: ${total}`, "bright"); logSuccess(`Passed: ${passed}`); if (failed > 0) { logError(`Failed: ${failed}`); } const percentage = total > 0 ? Math.round((passed / total) * 100) : 0; log( `\nSuccess rate: ${percentage}%`, percentage === 100 ? "green" : "yellow" ); if (failed === 0) { log("\n🎉 All tests passed!", "green"); } else { log( "\n⚠️ Some tests failed. Check the output above for details.", "yellow" ); } } } // Run the tests const tester = new MCPTester(); tester.start().catch((error) => { logError(`Fatal error: ${error.message}`); process.exit(1); });

Latest Blog Posts

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/Digital-Defiance/mcp-debugger-server'

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