#!/usr/bin/env node /** * MCP Factory — Batch Discovery * Runs mcp-jest discover on all 30 servers, generates test configs. * Uses dummy env vars so servers start without real API keys. */ import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs'; import { execSync } from 'child_process'; import { resolve, dirname } from 'path'; import { fileURLToPath } from 'url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const FACTORY_ROOT = resolve(__dirname, '..'); const registry = JSON.parse(readFileSync(resolve(FACTORY_ROOT, 'server-registry.json'), 'utf-8')); const SERVERS_ROOT = resolve(FACTORY_ROOT, registry.servers_root); // Output dirs const CONFIGS_DIR = resolve(FACTORY_ROOT, 'test-configs'); const REPORTS_DIR = resolve(FACTORY_ROOT, 'reports'); mkdirSync(CONFIGS_DIR, { recursive: true }); mkdirSync(REPORTS_DIR, { recursive: true }); const results = { passed: [], failed: [], total: 0 }; for (const [name, meta] of Object.entries(registry.servers)) { results.total++; const serverDir = resolve(SERVERS_ROOT, name); const distEntry = resolve(serverDir, 'dist/index.js'); if (!existsSync(distEntry)) { console.log(`⚠️ ${name}: No dist/index.js — needs build`); results.failed.push({ name, reason: 'no dist' }); continue; } // Build env object with dummy values const env = {}; for (const envVar of meta.env) { env[envVar] = 'factory_discovery_dummy'; } // Create test config const config = { server: { command: 'node', args: [distEntry], env } }; const configPath = resolve(CONFIGS_DIR, `${name}.json`); writeFileSync(configPath, JSON.stringify(config, null, 2)); try { console.log(`🔍 Discovering ${name}...`); const output = execSync(`mcp-jest discover --config "${configPath}"`, { timeout: 30000, encoding: 'utf-8', cwd: CONFIGS_DIR, stdio: ['pipe', 'pipe', 'pipe'] }); // Move generated config const generatedPath = resolve(CONFIGS_DIR, 'mcp-jest.generated.json'); if (existsSync(generatedPath)) { const generated = JSON.parse(readFileSync(generatedPath, 'utf-8')); // Merge env into generated config generated.server.env = env; writeFileSync(resolve(CONFIGS_DIR, `${name}-tests.json`), JSON.stringify(generated, null, 2)); execSync(`rm "${generatedPath}"`); const toolCount = Object.keys(generated.tests?.tools || {}).length; console.log(` ✅ ${name}: ${toolCount} test cases generated`); results.passed.push({ name, tools: toolCount }); } } catch (err) { const stderr = err.stderr?.toString() || err.message; console.log(` ❌ ${name}: ${stderr.split('\n')[0]}`); results.failed.push({ name, reason: stderr.split('\n')[0] }); } } // Summary console.log('\n' + '═'.repeat(60)); console.log(' MCP FACTORY — DISCOVERY REPORT'); console.log('═'.repeat(60)); console.log(`\nTotal: ${results.total}`); console.log(`Passed: ${results.passed.length}`); console.log(`Failed: ${results.failed.length}`); if (results.passed.length > 0) { const totalTools = results.passed.reduce((sum, r) => sum + r.tools, 0); console.log(`\nTotal test cases generated: ${totalTools}`); } if (results.failed.length > 0) { console.log('\nFailed servers:'); for (const f of results.failed) { console.log(` - ${f.name}: ${f.reason}`); } } // Write report const reportPath = resolve(REPORTS_DIR, `discovery-${new Date().toISOString().split('T')[0]}.json`); writeFileSync(reportPath, JSON.stringify(results, null, 2)); console.log(`\nReport saved: ${reportPath}`);