Skip to main content
Glama
mcp_tool_tester.mjs9.55 kB
#!/usr/bin/env node import { spawn } from 'child_process'; import { writeFileSync, readFileSync } from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const testDir = 'mcp_test_results_20250827_155712'; // Load discovery results const discoveryResults = JSON.parse(readFileSync(path.join(testDir, 'discovery_results.json'), 'utf8')); const tools = discoveryResults.tools.result.tools; let testResults = { timestamp: new Date().toISOString(), totalTools: tools.length, testedTools: 0, passedTools: 0, failedTools: 0, skippedTools: 0, results: {}, errors: [] }; function log(message) { console.log(`[Tool-Tester] ${message}`); } function sendMessage(server, message) { return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error('Response timeout')); }, 15000); let buffer = ''; let responseReceived = false; const handler = (data) => { buffer += data.toString(); const lines = buffer.split('\n'); for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (line && line.startsWith('{') && !responseReceived) { try { const response = JSON.parse(line); if (response.jsonrpc === '2.0' && ('result' in response || 'error' in response)) { clearTimeout(timeout); server.stdout.off('data', handler); responseReceived = true; resolve(response); return; } } catch (error) { continue; } } } }; server.stdout.on('data', handler); server.stdin.write(JSON.stringify(message) + '\n'); }); } async function initializeServer() { const server = spawn('node', ['build/src/mcpServer.js'], { stdio: ['pipe', 'pipe', 'pipe'] }); // Initialize the server const initRequest = { jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: "2024-11-05", capabilities: { tools: {}, prompts: {}, resources: {} }, clientInfo: { name: "Tool-Tester", version: "1.0.0" } } }; await sendMessage(server, initRequest); // Send initialized notification const initializedNotification = { jsonrpc: "2.0", method: "notifications/initialized" }; server.stdin.write(JSON.stringify(initializedNotification) + '\n'); await new Promise(resolve => setTimeout(resolve, 500)); return server; } // Test cases for different tool categories const testCases = { // Basic network tools - no parameters required 'getSupportedNetworks': [], 'getAllNetworks': [], // Network query tools - optional provider 'getBlockNumber': [ {}, { provider: 'ethereum' }, { chainId: 1 } ], 'getGasPrice': [ {}, { provider: 'polygon' } ], 'getFeeData': [ {}, { provider: 'ethereum' } ], // Wallet generation (safe) 'generateWallet': [ {}, { saveToEnv: false } ], // Address queries (using known addresses) 'getWalletBalance': [ { address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' } // Vitalik's address ], 'getWalletTransactionCount': [ { address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' } ], // Block queries 'getBlockDetails': [ { blockTag: 'latest' }, { blockTag: 18000000 } ], // Utility functions 'formatEther': [ { wei: '1000000000000000000' }, { wei: '500000000000000000' } ], 'parseEther': [ { ether: '1.0' }, { ether: '0.5' } ], 'formatUnits': [ { value: '1000000', unit: 6 }, { value: '1000000000', unit: 'gwei' } ], // Contract queries (using known contracts) 'getContractCode': [ { address: '0xA0b86a33E6417c4b73f2Aa8e8e8b26bB47F8B628' } // USDC on Ethereum ], // ENS resolution 'resolveName': [ { name: 'vitalik.eth' }, { name: 'ethereum.eth' } ], 'lookupAddress': [ { address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' } ], // ERC20 queries (using USDC) 'getERC20TokenInfo': [ { contractAddress: '0xA0b86a33E6417c4b73f2Aa8e8e8b26bB47F8B628' } ], 'getERC20Balance': [ { tokenAddress: '0xA0b86a33E6417c4b73f2Aa8e8e8b26bB47F8B628', userAddress: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' } ], // Network tools 'getNetwork': [ { networkName: 'ethereum' }, { networkName: 'polygon' } ] }; async function testTool(server, tool, testCaseParams) { const toolName = tool.name; log(`Testing ${toolName} with params: ${JSON.stringify(testCaseParams)}`); const request = { jsonrpc: "2.0", id: Math.floor(Math.random() * 1000000), method: "tools/call", params: { name: toolName, arguments: testCaseParams } }; try { const response = await sendMessage(server, request); if (response.error) { return { success: false, error: response.error, response }; } if (response.result && response.result.isError) { return { success: false, toolError: response.result.content, response }; } return { success: true, result: response.result, response }; } catch (error) { return { success: false, exception: error.message, error }; } } async function testAllTools() { log('Starting comprehensive tool testing'); const server = await initializeServer(); for (let i = 0; i < tools.length; i++) { const tool = tools[i]; const toolName = tool.name; testResults.testedTools++; testResults.results[toolName] = { description: tool.description, inputSchema: tool.inputSchema, testCases: [], summary: { passed: 0, failed: 0, total: 0 } }; log(`[${i + 1}/${tools.length}] Testing tool: ${toolName}`); // Get test cases for this tool const cases = testCases[toolName] || [{}]; // Default to empty params for (let j = 0; j < cases.length; j++) { const testCase = cases[j]; testResults.results[toolName].summary.total++; const result = await testTool(server, tool, testCase); testResults.results[toolName].testCases.push({ params: testCase, ...result, timestamp: new Date().toISOString() }); if (result.success) { testResults.results[toolName].summary.passed++; log(` ✅ Test case ${j + 1}: PASSED`); } else { testResults.results[toolName].summary.failed++; log(` ❌ Test case ${j + 1}: FAILED - ${result.error?.message || result.exception || 'Tool error'}`); } // Short delay between test cases await new Promise(resolve => setTimeout(resolve, 100)); } // Update overall stats if (testResults.results[toolName].summary.passed > 0) { testResults.passedTools++; } else { testResults.failedTools++; } // Short delay between tools await new Promise(resolve => setTimeout(resolve, 200)); } server.kill(); // Write results writeFileSync( path.join(testDir, 'tool_test_results.json'), JSON.stringify(testResults, null, 2) ); // Generate summary report writeFileSync( path.join(testDir, 'tool_test_summary.md'), generateSummaryReport() ); log('Tool testing complete'); return testResults; } function generateSummaryReport() { const passRate = (testResults.passedTools / testResults.totalTools * 100).toFixed(2); return `# MCP Tool Testing Results ## Summary - **Total Tools**: ${testResults.totalTools} - **Tools Tested**: ${testResults.testedTools} - **Tools Passed**: ${testResults.passedTools} - **Tools Failed**: ${testResults.failedTools} - **Pass Rate**: ${passRate}% - **Test Date**: ${testResults.timestamp} ## Tool Results ${Object.entries(testResults.results).map(([toolName, result]) => { const status = result.summary.passed > 0 ? '✅' : '❌'; return `### ${status} ${toolName} - **Passed**: ${result.summary.passed}/${result.summary.total} test cases - **Description**: ${result.description || 'No description'} ${result.testCases.map((testCase, index) => { const caseStatus = testCase.success ? '✅' : '❌'; const error = testCase.error?.message || testCase.exception || (testCase.toolError ? 'Tool returned error' : ''); return ` ${caseStatus} Test ${index + 1}: ${JSON.stringify(testCase.params)} ${error ? `(${error})` : ''}`; }).join('\n')} `; }).join('\n')} ## Failed Tools Analysis ${Object.entries(testResults.results) .filter(([_, result]) => result.summary.passed === 0) .map(([toolName, result]) => `### ${toolName} ${result.testCases.map(testCase => `- Error: ${testCase.error?.message || testCase.exception || 'Tool error'}` ).join('\n')} `).join('\n')} ## Recommendations 1. **High Priority Fixes**: Address tools that fail basic functionality tests 2. **Network Connectivity**: Many failures may be due to network/RPC issues 3. **Authentication**: Some tools may require API keys or wallet setup 4. **Parameter Validation**: Review input schema validation for failed tools `; } // Run the tests testAllTools().then(() => { console.log('All tool testing completed'); process.exit(0); }).catch((error) => { console.error('Tool testing failed:', error); 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/crazyrabbitLTC/mcp-ethers-server'

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