=== NEW SERVERS ADDED (7) === - servers/closebot — 119 tools, 14 modules, 4,656 lines TS (Stage 7) - servers/google-console — Google Search Console MCP (Stage 7) - servers/meta-ads — Meta/Facebook Ads MCP (Stage 8) - servers/twilio — Twilio communications MCP (Stage 8) - servers/competitor-research — Competitive intel MCP (Stage 6) - servers/n8n-apps — n8n workflow MCP apps (Stage 6) - servers/reonomy — Commercial real estate MCP (Stage 1) === FACTORY INFRASTRUCTURE ADDED === - infra/factory-tools — mcp-jest, mcp-validator, mcp-add, MCP Inspector - 60 test configs, 702 auto-generated test cases - All 30 servers score 100/100 protocol compliance - infra/command-center — Pipeline state, operator playbook, dashboard config - infra/factory-reviews — Automated eval reports === DOCS ADDED === - docs/MCP-FACTORY.md — Factory overview - docs/reports/ — 5 pipeline evaluation reports - docs/research/ — Browser MCP research === RULES ESTABLISHED === - CONTRIBUTING.md — All MCP work MUST go in this repo - README.md — Full inventory of 37 servers + infra docs - .gitignore — Updated for Python venvs TOTAL: 37 MCP servers + full factory pipeline in one repo. This is now the single source of truth for all MCP work.
108 lines
3.5 KiB
JavaScript
108 lines
3.5 KiB
JavaScript
#!/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}`);
|