Skip to main content
Glama

MoluAbi MCP Server

by oregpt
test-atxp-flow.js15.8 kB
#!/usr/bin/env node /** * ATXP Flow Comprehensive Test Suite * Tests the new ATXP server with OAuth2 authentication and crypto payments * Validates the complete payment flow and tool execution */ const https = require('https'); const http = require('http'); // Test configuration for ATXP server const ATXP_CONFIG = { serverUrl: 'http://localhost:5001', endpoints: { toolsList: '/', toolsCall: '/', oauth: '/auth/oauth', payment: '/payment' } }; // ANSI colors for output const colors = { green: '\x1b[32m', red: '\x1b[31m', yellow: '\x1b[33m', blue: '\x1b[34m', purple: '\x1b[35m', cyan: '\x1b[36m', reset: '\x1b[0m', bold: '\x1b[1m' }; class ATXPFlowTester { constructor() { this.results = { passed: 0, failed: 0, errors: [], warnings: [] }; this.authToken = null; this.walletAddress = null; } log(message, color = 'reset') { console.log(`${colors[color]}${message}${colors.reset}`); } success(test) { this.results.passed++; this.log(`✅ ${test}`, 'green'); } fail(test, error) { this.results.failed++; this.results.errors.push({ test, error }); this.log(`❌ ${test}: ${error}`, 'red'); } warning(test, message) { this.results.warnings.push({ test, message }); this.log(`⚠️ ${test}: ${message}`, 'yellow'); } info(message) { this.log(`ℹ️ ${message}`, 'blue'); } async makeATXPRequest(method, data = null, headers = {}) { return new Promise((resolve, reject) => { const url = new URL(ATXP_CONFIG.serverUrl); const defaultHeaders = { 'Content-Type': 'application/json', ...headers }; if (this.authToken) { defaultHeaders['Authorization'] = `Bearer ${this.authToken}`; } const options = { hostname: url.hostname, port: url.port, path: '/', method: 'POST', headers: defaultHeaders }; const req = http.request(options, (res) => { let body = ''; res.on('data', (chunk) => body += chunk); res.on('end', () => { try { const parsed = JSON.parse(body); resolve({ status: res.statusCode, data: parsed, headers: res.headers }); } catch (e) { resolve({ status: res.statusCode, data: body, headers: res.headers }); } }); }); req.on('error', reject); if (data) { req.write(JSON.stringify(data)); } req.end(); }); } async testServerAvailability() { this.log('\n🌐 Testing ATXP Server Availability', 'bold'); this.log('==================================', 'bold'); try { const response = await this.makeATXPRequest('POST'); if (response.status === 200 || response.status === 400) { this.success('ATXP server is running and reachable'); return true; } else { this.fail('Server availability', `HTTP ${response.status}`); return false; } } catch (error) { this.fail('Server availability', error.message); return false; } } async testToolsList() { this.log('\n🔧 Testing Tools List (No Auth Required)', 'bold'); this.log('========================================', 'bold'); try { const payload = { jsonrpc: "2.0", method: "tools/list", id: "test-tools-list" }; const response = await this.makeATXPRequest('POST', payload); if (response.status === 200 && response.data.result) { const tools = response.data.result.tools || []; this.success(`Tools list retrieved - Found ${tools.length} tools`); // Verify expected tools exist const expectedTools = ['create_agent', 'list_agents', 'get_pricing', 'prompt_agent']; const foundTools = tools.map(t => t.name); expectedTools.forEach(tool => { if (foundTools.includes(tool)) { this.log(` ✓ Found tool: ${tool}`, 'green'); } else { this.warning('Tools validation', `Missing expected tool: ${tool}`); } }); return true; } else { this.fail('Tools list', `Unexpected response: ${JSON.stringify(response.data)}`); return false; } } catch (error) { this.fail('Tools list', error.message); return false; } } async testOAuth2Flow() { this.log('\n🔐 Testing OAuth2 Authentication Flow', 'bold'); this.log('====================================', 'bold'); this.info('Note: OAuth2 requires interactive browser flow'); this.info('In production, users would:'); this.log(' 1. Visit OAuth2 authorization URL', 'cyan'); this.log(' 2. Connect their wallet (MetaMask/WalletConnect)', 'cyan'); this.log(' 3. Authorize the application', 'cyan'); this.log(' 4. Receive access token', 'cyan'); // Simulate getting a token (in real flow this comes from OAuth2) this.authToken = 'mock_atxp_token_' + Math.random().toString(36); this.warning('OAuth2 simulation', 'Using mock token for testing - real OAuth2 requires browser'); return true; } async testPaymentAuthentication() { this.log('\n💳 Testing Payment Authentication', 'bold'); this.log('=================================', 'bold'); // Test tool call that requires payment (should fail without proper ATXP auth) try { const payload = { jsonrpc: "2.0", method: "tools/call", params: { name: "list_agents", arguments: { apiKey: process.env.MOLUABI_API_KEY || 'mab_test_key' } }, id: "test-payment-auth" }; const response = await this.makeATXPRequest('POST', payload); if (response.status === 401 || response.status === 403) { this.success('Payment authentication enforced - Unauthorized access blocked'); } else if (response.status === 402) { this.success('Payment required response - ATXP payment system active'); } else if (response.data.error && response.data.error.code === -32001) { this.success('Payment required via MCP error - ATXP integration working'); } else { this.warning('Payment auth', `Unexpected response: HTTP ${response.status}`); } } catch (error) { this.fail('Payment authentication', error.message); } } async testCryptoPaymentFlow() { this.log('\n💰 Testing Crypto Payment Flow', 'bold'); this.log('==============================', 'bold'); this.info('Crypto payment flow simulation:'); this.log(' 1. User connects wallet (MetaMask/WalletConnect)', 'cyan'); this.log(' 2. Tool execution requires payment (e.g., $0.001 USDC)', 'cyan'); this.log(' 3. User approves transaction in wallet', 'cyan'); this.log(' 4. Payment confirmed on blockchain', 'cyan'); this.log(' 5. Tool executes successfully', 'cyan'); // Simulate wallet connection this.walletAddress = '0x' + Math.random().toString(16).substring(2, 42).padStart(40, '0'); this.log(` 💳 Simulated wallet: ${this.walletAddress}`, 'purple'); // Test payment pricing information try { const pricingPayload = { jsonrpc: "2.0", method: "tools/call", params: { name: "get_pricing", arguments: { apiKey: process.env.MOLUABI_API_KEY || 'mab_test_key' } }, id: "test-pricing" }; this.info('Testing pricing tool (should show payment required)...'); const response = await this.makeATXPRequest('POST', pricingPayload); if (response.status === 402 || (response.data.error && response.data.error.code === -32001)) { this.success('Pricing tool correctly requires payment'); } else { this.warning('Payment flow', 'Pricing tool should require payment'); } } catch (error) { this.fail('Crypto payment flow', error.message); } } async testATXPIntegration() { this.log('\n🔗 Testing ATXP Integration Features', 'bold'); this.log('===================================', 'bold'); // Test ATXP-specific headers and features const testCases = [ { name: 'ATXP version compatibility', check: () => { this.log(' 📦 @atxp/server version: Latest', 'cyan'); this.success('ATXP server package integrated'); } }, { name: 'Payment destination configured', check: () => { const destination = process.env.PAYMENT_DESTINATION; if (destination) { this.log(` 💳 Payment destination: ${destination.substring(0, 8)}...`, 'cyan'); this.success('Payment destination configured'); } else { this.warning('Configuration', 'PAYMENT_DESTINATION not set'); } } }, { name: 'ATXP client token', check: () => { const token = process.env.ATXP_AUTH_CLIENT_TOKEN; if (token) { this.log(' 🔑 ATXP client token: Configured', 'cyan'); this.success('ATXP authentication token configured'); } else { this.warning('Configuration', 'ATXP_AUTH_CLIENT_TOKEN not set'); } } } ]; testCases.forEach(test => test.check()); } async testToolExecution() { this.log('\n⚙️ Testing Tool Execution with Payment', 'bold'); this.log('======================================', 'bold'); const tools = [ { name: 'list_agents', args: { apiKey: process.env.MOLUABI_API_KEY || 'mab_test_key' }, expectedPrice: 0.001 }, { name: 'get_pricing', args: { apiKey: process.env.MOLUABI_API_KEY || 'mab_test_key' }, expectedPrice: 0.001 }, { name: 'create_agent', args: { apiKey: process.env.MOLUABI_API_KEY || 'mab_test_key', name: 'ATXP Test Agent', description: 'Test agent for ATXP flow validation' }, expectedPrice: 0.05 } ]; for (const tool of tools) { this.info(`Testing ${tool.name} (Expected: $${tool.expectedPrice} USDC)`); try { const payload = { jsonrpc: "2.0", method: "tools/call", params: { name: tool.name, arguments: tool.args }, id: `test-${tool.name}` }; const response = await this.makeATXPRequest('POST', payload); if (response.status === 402 || (response.data.error && response.data.error.code === -32001)) { this.success(`${tool.name} correctly requires payment ($${tool.expectedPrice})`); } else if (response.status === 200 && response.data.result) { this.warning(`${tool.name}`, 'Tool executed without payment - check ATXP configuration'); } else { this.warning(`${tool.name}`, `Unexpected response: ${response.status}`); } } catch (error) { this.fail(`${tool.name} execution`, error.message); } } } async testErrorHandling() { this.log('\n🚫 Testing Error Handling', 'bold'); this.log('=========================', 'bold'); const errorTests = [ { name: 'Invalid tool name', payload: { jsonrpc: "2.0", method: "tools/call", params: { name: "nonexistent_tool", arguments: {} }, id: "error-test-1" } }, { name: 'Malformed JSON-RPC', payload: { method: "tools/call", // Missing jsonrpc and id params: { name: "list_agents", arguments: {} } } }, { name: 'Missing arguments', payload: { jsonrpc: "2.0", method: "tools/call", params: { name: "create_agent", arguments: {} }, // Missing required fields id: "error-test-3" } } ]; for (const test of errorTests) { try { const response = await this.makeATXPRequest('POST', test.payload); if (response.data.error || response.status >= 400) { this.success(`${test.name} - Error properly handled`); } else { this.warning(test.name, 'Should have returned an error'); } } catch (error) { this.success(`${test.name} - Network error properly handled`); } } } printSummary() { this.log('\n📊 ATXP Flow Test Results', 'bold'); this.log('=========================', 'bold'); const total = this.results.passed + this.results.failed; this.log(`\nTotal Tests: ${total}`, 'cyan'); this.log(`Passed: ${this.results.passed}`, 'green'); this.log(`Failed: ${this.results.failed}`, this.results.failed > 0 ? 'red' : 'green'); this.log(`Warnings: ${this.results.warnings.length}`, 'yellow'); if (this.results.errors.length > 0) { this.log('\n❌ Failed Tests:', 'red'); this.results.errors.forEach(error => { this.log(` • ${error.test}: ${error.error}`, 'red'); }); } if (this.results.warnings.length > 0) { this.log('\n⚠️ Warnings:', 'yellow'); this.results.warnings.forEach(warning => { this.log(` • ${warning.test}: ${warning.message}`, 'yellow'); }); } this.log('\n🎯 ATXP Flow Status:', 'bold'); if (this.results.failed === 0) { this.log('✅ ATXP server is ready for production use!', 'green'); } else { this.log('⚠️ ATXP server needs attention before production.', 'yellow'); } this.log('\n💡 Next Steps for Agent Team:', 'bold'); this.log(' 1. Implement ATXP SDK integration in your client', 'cyan'); this.log(' 2. Set up OAuth2 flow with wallet connection', 'cyan'); this.log(' 3. Test payment flow with real crypto transactions', 'cyan'); this.log(' 4. Switch server URL to port 5001 for ATXP mode', 'cyan'); } async runAllTests() { this.log('🧪 ATXP Flow Comprehensive Test Suite', 'bold'); this.log('====================================', 'bold'); this.log('Testing OAuth2 authentication and crypto payment integration\n'); // Environment check const requiredEnvVars = ['MOLUABI_API_KEY', 'PAYMENT_DESTINATION', 'ATXP_AUTH_CLIENT_TOKEN']; requiredEnvVars.forEach(envVar => { if (process.env[envVar]) { this.log(`✅ ${envVar} configured`, 'green'); } else { this.log(`⚠️ ${envVar} not set`, 'yellow'); } }); // Run test suites const serverAvailable = await this.testServerAvailability(); if (!serverAvailable) { this.log('\n❌ ATXP server not available - stopping tests', 'red'); this.printSummary(); return; } await this.testToolsList(); await this.testOAuth2Flow(); await this.testPaymentAuthentication(); await this.testCryptoPaymentFlow(); await this.testATXPIntegration(); await this.testToolExecution(); await this.testErrorHandling(); this.printSummary(); } } // Usage instructions if (require.main === module) { console.log('💡 ATXP Flow Test Instructions:'); console.log(' 1. Make sure ATXP server is running: npm run start:atxp (port 5001)'); console.log(' 2. Set environment variables:'); console.log(' - MOLUABI_API_KEY=mab_your_key'); console.log(' - PAYMENT_DESTINATION=your_wallet_address'); console.log(' - ATXP_AUTH_CLIENT_TOKEN=your_client_token'); console.log(' 3. Run: node test-atxp-flow.js\n'); const tester = new ATXPFlowTester(); tester.runAllTests().catch(console.error); } module.exports = ATXPFlowTester;

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/oregpt/moluabi-mcp-server'

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