Skip to main content
Glama

MCP Swagger Server

interactive.js8.79 kB
#!/usr/bin/env node /** * Interactive CLI tool to test MCP swagger server * Allows you to manually send MCP requests and see responses */ const { spawn } = require('child_process'); const readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); // Configuration const config = { args: [ 'dist/index.js', '--doc-url', 'https://petstore.swagger.io/v2/swagger.json', '--tool-prefix', 'petstore' ] }; console.log('🚀 Interactive MCP Swagger Server Test'); console.log('Command: node', config.args.join(' ')); console.log(''); let requestId = 1; let mcpServer; let tools = []; function startServer() { mcpServer = spawn('node', config.args, { stdio: ['pipe', 'pipe', 'pipe'] }); mcpServer.stdout.on('data', (data) => { const responses = data.toString().trim().split('\n'); responses.forEach(response => { if (response.trim()) { try { const parsed = JSON.parse(response); console.log('📥 Response:', JSON.stringify(parsed, null, 2)); // Store tools for easy reference if (parsed.result && parsed.result.tools) { tools = parsed.result.tools; console.log(`\n🔧 Found ${tools.length} tools. Type 'list' to see them.`); } } catch (e) { console.log('📥 Raw response:', response); } } }); showPrompt(); }); mcpServer.stderr.on('data', (data) => { console.log('❌', data.toString()); showPrompt(); }); mcpServer.on('close', (code) => { console.log(`🏁 Server process exited with code ${code}`); process.exit(code); }); // Auto-initialize setTimeout(() => { sendRequest('initialize', { protocolVersion: '2024-11-05', capabilities: { tools: {} }, clientInfo: { name: 'interactive-client', version: '1.0.0' } }); }, 500); } function sendRequest(method, params = {}) { const request = { jsonrpc: '2.0', id: requestId++, method: method, params: params }; console.log('📤 Sending:', JSON.stringify(request, null, 2)); mcpServer.stdin.write(JSON.stringify(request) + '\n'); } function parseCallCommand(input) { // Parse: toolName arg1 arg2 "quoted arg" {...json...} const parts = []; let current = ''; let inQuotes = false; let inJson = false; let braceCount = 0; for (let i = 0; i < input.length; i++) { const char = input[i]; if (char === '"' && !inJson) { inQuotes = !inQuotes; } else if (char === '{' && !inQuotes) { inJson = true; braceCount = 1; current += char; } else if (char === '}' && inJson && !inQuotes) { braceCount--; current += char; if (braceCount === 0) { inJson = false; } } else if (char === '{' && inJson && !inQuotes) { braceCount++; current += char; } else if (char === ' ' && !inQuotes && !inJson) { if (current.trim()) { parts.push(current.trim()); current = ''; } } else { current += char; } } if (current.trim()) { parts.push(current.trim()); } return { toolName: parts[0] || '', args: parts.slice(1) }; } function parseToolArguments(tool, userArgs) { const toolArgs = {}; if (!tool.inputSchema || !tool.inputSchema.properties) { return toolArgs; } const properties = tool.inputSchema.properties; const required = tool.inputSchema.required || []; const propertyNames = Object.keys(properties); // If only one argument and it looks like JSON, try to parse it if (userArgs.length === 1 && userArgs[0].startsWith('{')) { try { const jsonArgs = JSON.parse(userArgs[0]); console.log(`📝 Using JSON arguments:`, jsonArgs); return jsonArgs; } catch (e) { console.log(`⚠️ Invalid JSON, treating as string: ${e.message}`); } } // Map positional arguments to parameter names in order userArgs.forEach((arg, index) => { if (index < propertyNames.length) { const paramName = propertyNames[index]; const paramSchema = properties[paramName]; // Remove quotes if present let value = arg; if (value.startsWith('"') && value.endsWith('"')) { value = value.slice(1, -1); } // Type conversion if (paramSchema.type === 'number' || paramSchema.type === 'integer') { const num = Number(value); if (!isNaN(num)) { toolArgs[paramName] = num; } else { console.log(`⚠️ Warning: "${value}" is not a valid number for ${paramName}, using as string`); toolArgs[paramName] = value; } } else if (paramSchema.type === 'boolean') { toolArgs[paramName] = value.toLowerCase() === 'true'; } else if (paramSchema.type === 'array') { // Try to parse as JSON array, otherwise split by comma try { toolArgs[paramName] = JSON.parse(value); } catch { toolArgs[paramName] = value.split(',').map(s => s.trim()); } } else { toolArgs[paramName] = value; } } }); // Show what parameters were mapped if (Object.keys(toolArgs).length > 0) { console.log(`📝 Mapped arguments:`, toolArgs); } // Show missing required parameters const missingRequired = required.filter(param => !(param in toolArgs)); if (missingRequired.length > 0) { console.log(`⚠️ Missing required parameters: ${missingRequired.join(', ')}`); console.log(`💡 Available parameters: ${propertyNames.join(', ')}`); } return toolArgs; } function showPrompt() { rl.question('\n> ', handleInput); } function handleInput(input) { const trimmed = input.trim().toLowerCase(); if (trimmed === 'exit' || trimmed === 'quit') { mcpServer.kill(); rl.close(); return; } if (trimmed === 'help') { showHelp(); showPrompt(); return; } if (trimmed === 'list') { sendRequest('tools/list'); return; } if (trimmed.startsWith('call ')) { const callArgs = input.substring(5).trim(); // Use original input to preserve case and quotes const parts = parseCallCommand(callArgs); const toolNameQuery = parts.toolName; const userArgs = parts.args; const tool = tools.find(t => t.name.toLowerCase().includes(toolNameQuery.toLowerCase())); if (tool) { console.log(`\nCalling tool: ${tool.name}`); console.log(`Description: ${tool.description}`); // Parse and validate arguments const toolArgs = parseToolArguments(tool, userArgs); sendRequest('tools/call', { name: tool.name, arguments: toolArgs }); } else { console.log(`❌ Tool not found: ${toolNameQuery}`); console.log('Available tools:', tools.map(t => t.name).join(', ')); showPrompt(); } return; } if (trimmed.startsWith('raw ')) { try { const jsonStr = input.substring(4); const request = JSON.parse(jsonStr); request.jsonrpc = '2.0'; request.id = requestId++; console.log('📤 Sending raw request:', JSON.stringify(request, null, 2)); mcpServer.stdin.write(JSON.stringify(request) + '\n'); } catch (e) { console.log('❌ Invalid JSON:', e.message); showPrompt(); } return; } console.log('❌ Unknown command. Type "help" for available commands.'); showPrompt(); } function showHelp() { console.log(` 📖 Available Commands: ====================== help - Show this help message list - List all available tools call <tool> [args...] - Call a tool with optional arguments raw <json> - Send raw MCP request (without jsonrpc/id fields) exit/quit - Exit the interactive session Tool Call Examples: list call getPetById 779 call getUserByName "john_doe" call findPetsByStatus available call addPet {"name": "Fluffy", "category": {"name": "cat"}} call loginUser admin password123 Argument Types: - Strings: "quoted text" or unquoted_text - Numbers: 123 or 45.67 - Booleans: true or false - Arrays: ["item1", "item2"] or comma,separated,values - Objects: {"key": "value", "nested": {"data": true}} 💡 Arguments are mapped to parameters in the order they appear in the tool schema. 💡 Use 'list' to see all tools and their required parameters. Current tools: ${tools.length > 0 ? tools.map(t => t.name).join(', ') : 'None loaded yet'} `); } console.log('Starting server...'); startServer(); // Show initial help after server starts setTimeout(() => { console.log('\n💡 Type "help" for available commands, "list" to see tools'); showPrompt(); }, 2000);

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/HainanZhao/mcp-swagger'

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