Skip to main content
Glama

Apex MCP for X Management

by xonack
extract-api-docs.ts6.12 kB
#!/usr/bin/env tsx /** * Apex API Documentation Extractor * * This script uses Puppeteer to extract the Swagger specification * from the dynamically rendered Apex API documentation page. * * Usage: tsx utils/extract-api-docs.ts * Output: docs/apex-api-spec.json */ import puppeteer from 'puppeteer'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); interface APIInfo { title?: string; version?: string; description?: string; } interface APISpec { swagger?: string; openapi?: string; info?: APIInfo; paths?: Record<string, any>; [key: string]: any; } const API_URL = 'https://api.apexagents.ai/api#/'; const OUTPUT_PATH = path.join(__dirname, '..', 'docs', 'apex-api-spec.json'); async function extractApiDocs(): Promise<APISpec | null> { console.log('🚀 Starting Apex API documentation extraction...'); console.log(`📄 Target URL: ${API_URL}`); const browser = await puppeteer.launch({ headless: 'new', args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage(); let apiSpec: APISpec | null = null; // Set up network interception to catch API spec requests page.on('response', async response => { const url = response.url(); const contentType = response.headers()['content-type'] || ''; // Look for JSON responses that might contain the API spec if (contentType.includes('application/json')) { try { const json = await response.json() as any; // Check if this looks like a Swagger specification if (json && (json.swagger || json.openapi || (json.info && json.paths))) { console.log(`✅ Found API specification at: ${url}`); apiSpec = json as APISpec; } } catch (error) { // Not JSON or parsing failed, ignore } } }); try { console.log('📱 Loading Swagger UI page...'); await page.goto(API_URL, { waitUntil: 'networkidle0', timeout: 30000 }); // Wait for the page to fully load console.log('⏳ Waiting for Swagger UI to initialize...'); await new Promise(resolve => setTimeout(resolve, 3000)); // If we didn't catch the spec via network interception, try extracting from the page if (!apiSpec) { console.log('🔍 Attempting to extract spec from page JavaScript...'); apiSpec = await page.evaluate((): APISpec | null => { // Try common Swagger UI global variables if ((window as any).ui && (window as any).ui.specSelectors) { try { const spec = (window as any).ui.specSelectors.specJsonWithResolvedSubtrees(); return spec ? spec.toJSON() : null; } catch (e) { console.log('Failed to get spec from UI selectors:', e); } } // Try other common locations if ((window as any).swaggerSpec) return (window as any).swaggerSpec; if ((window as any).apiSpec) return (window as any).apiSpec; if ((window as any).spec) return (window as any).spec; // Look for script tags that might contain the spec const scripts = document.querySelectorAll('script'); for (let script of scripts) { const content = script.textContent || script.innerHTML; if (content.includes('"openapi"') || content.includes('"swagger"')) { try { // Try to extract JSON from the script content const jsonMatch = content.match(/\{[^}]*"openapi"[^{]*\{.*\}/s) || content.match(/\{[^}]*"swagger"[^{]*\{.*\}/s); if (jsonMatch) { return JSON.parse(jsonMatch[0]); } } catch (e) { // Failed to parse, continue } } } return null; }); } if (apiSpec) { // Ensure the docs directory exists const docsDir = path.dirname(OUTPUT_PATH); if (!fs.existsSync(docsDir)) { fs.mkdirSync(docsDir, { recursive: true }); } // Save the extracted specification fs.writeFileSync(OUTPUT_PATH, JSON.stringify(apiSpec, null, 2)); console.log('✅ API specification extracted successfully!'); console.log(`📁 Saved to: ${OUTPUT_PATH}`); console.log(`📊 Found ${Object.keys(apiSpec.paths || {}).length} endpoints`); // Log some basic info about the API if (apiSpec.info) { console.log(`📋 API Title: ${apiSpec.info.title || 'Unknown'}`); console.log(`📌 API Version: ${apiSpec.info.version || 'Unknown'}`); if (apiSpec.info.description) { console.log(`📝 Description: ${apiSpec.info.description.substring(0, 100)}...`); } } } else { console.log('❌ Failed to extract API specification'); console.log('💡 The page might use a different structure or require authentication'); // Save the page HTML for debugging const html = await page.content(); const debugPath = path.join(__dirname, '..', 'docs', 'debug-page.html'); fs.writeFileSync(debugPath, html); console.log(`🐛 Page HTML saved to ${debugPath} for debugging`); } } catch (error) { console.error('❌ Error during extraction:', error instanceof Error ? error.message : String(error)); throw error; } finally { await browser.close(); } return apiSpec; } // Run the extraction if this script is executed directly if (import.meta.url === `file://${process.argv[1]}`) { extractApiDocs() .then(spec => { if (spec) { console.log('🎉 Extraction completed successfully!'); process.exit(0); } else { console.log('⚠️ No API specification found'); process.exit(1); } }) .catch(error => { console.error('💥 Extraction failed:', error); process.exit(1); }); } export { extractApiDocs };

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/xonack/apex-mcp'

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