Skip to main content
Glama

mcp-server-airbnb

by openbnb-org
#!/usr/bin/env node /** * Simple test script for the Airbnb DXT extension * This script validates that the MCP server responds correctly to tool calls */ import { spawn } from 'child_process'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Test configuration const TEST_TIMEOUT = 30000; // 30 seconds const SERVER_PATH = join(__dirname, 'dist', 'index.js'); class MCPTester { constructor() { this.server = null; this.requestId = 1; } async startServer() { console.log('🚀 Starting MCP server...'); this.server = spawn('node', [SERVER_PATH, '--ignore-robots-txt'], { stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, IGNORE_ROBOTS_TXT: 'true' } }); this.server.stderr.on('data', (data) => { console.log('📋 Server log:', data.toString().trim()); }); // Wait for server to start await new Promise(resolve => setTimeout(resolve, 2000)); if (this.server.killed) { throw new Error('Server failed to start'); } console.log('✅ Server started successfully'); } async sendRequest(method, params = {}) { return new Promise((resolve, reject) => { const request = { jsonrpc: '2.0', id: this.requestId++, method, params }; const timeout = setTimeout(() => { reject(new Error(`Request timeout after ${TEST_TIMEOUT}ms`)); }, TEST_TIMEOUT); let responseData = ''; const onData = (data) => { responseData += data.toString(); // Check if we have a complete JSON response try { const lines = responseData.split('\n').filter(line => line.trim()); for (const line of lines) { const response = JSON.parse(line); if (response.id === request.id) { clearTimeout(timeout); this.server.stdout.off('data', onData); resolve(response); return; } } } catch (e) { // Not a complete JSON yet, continue waiting } }; this.server.stdout.on('data', onData); console.log(`📤 Sending request: ${method}`); this.server.stdin.write(JSON.stringify(request) + '\n'); }); } async testListTools() { console.log('\n🔧 Testing list_tools...'); try { const response = await this.sendRequest('tools/list'); if (response.error) { throw new Error(`Server error: ${response.error.message}`); } const tools = response.result?.tools || []; console.log(`✅ Found ${tools.length} tools:`); tools.forEach(tool => { console.log(` - ${tool.name}: ${tool.description}`); }); // Validate expected tools const expectedTools = ['airbnb_search', 'airbnb_listing_details']; const foundTools = tools.map(t => t.name); for (const expectedTool of expectedTools) { if (!foundTools.includes(expectedTool)) { throw new Error(`Missing expected tool: ${expectedTool}`); } } return true; } catch (error) { console.error('❌ list_tools test failed:', error.message); return false; } } async testSearchTool() { console.log('\n🔍 Testing airbnb_search tool...'); try { const response = await this.sendRequest('tools/call', { name: 'airbnb_search', arguments: { location: 'San Francisco, CA', adults: 2, ignoreRobotsText: true } }); if (response.error) { throw new Error(`Server error: ${response.error.message}`); } const result = response.result; if (!result || !result.content || !result.content[0]) { throw new Error('Invalid response format'); } const content = JSON.parse(result.content[0].text); if (content.error) { console.log('⚠️ Search returned error (expected for robots.txt):', content.error); return true; // This is expected behavior } if (content.searchResults) { console.log(`✅ Search successful, found ${content.searchResults.length} results`); if (content.searchResults.length > 0) { console.log(` First result: ${content.searchResults[0].id}`); } } return true; } catch (error) { console.error('❌ airbnb_search test failed:', error.message); return false; } } async testListingDetailsTool() { console.log('\n🏠 Testing airbnb_listing_details tool...'); try { const response = await this.sendRequest('tools/call', { name: 'airbnb_listing_details', arguments: { id: '670214003022775198', ignoreRobotsText: true } }); if (response.error) { throw new Error(`Server error: ${response.error.message}`); } const result = response.result; if (!result || !result.content || !result.content[0]) { throw new Error('Invalid response format'); } const content = JSON.parse(result.content[0].text); if (content.error) { console.log('⚠️ Listing details returned error (expected for dummy ID):', content.error); return true; // This is expected behavior } console.log('✅ Listing details tool responded correctly'); return true; } catch (error) { console.error('❌ airbnb_listing_details test failed:', error.message); return false; } } async stopServer() { if (this.server && !this.server.killed) { console.log('\n🛑 Stopping server...'); this.server.kill('SIGTERM'); // Wait for graceful shutdown await new Promise(resolve => { this.server.on('exit', resolve); setTimeout(() => { if (!this.server.killed) { this.server.kill('SIGKILL'); } resolve(); }, 5000); }); console.log('✅ Server stopped'); } } async runTests() { let allPassed = true; try { await this.startServer(); // Run all tests const tests = [ () => this.testListTools(), () => this.testSearchTool(), () => this.testListingDetailsTool() ]; for (const test of tests) { const passed = await test(); allPassed = allPassed && passed; } } catch (error) { console.error('❌ Test suite failed:', error.message); allPassed = false; } finally { await this.stopServer(); } console.log('\n' + '='.repeat(50)); if (allPassed) { console.log('🎉 All tests passed! Extension is ready for use.'); } else { console.log('❌ Some tests failed. Please check the issues above.'); process.exit(1); } } } // Run tests if this script is executed directly if (import.meta.url === `file://${process.argv[1]}`) { const tester = new MCPTester(); tester.runTests().catch(error => { console.error('💥 Test runner crashed:', error); process.exit(1); }); } export default MCPTester;

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/openbnb-org/mcp-server-airbnb'

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