feat(lib): bundle MCP servers from .common/lib into factory/lib/
Copies source (no node_modules, dist, .tasks, .wiki, __pycache__) for: - projects-meta-mcp v2.25.0 (TypeScript/Node) - wiki-graph v0.3.1 (TypeScript/Node) - interns-mcp v0.3.3 (Python/FastMCP) .gitignore: exclude lib build artefacts (node_modules, dist, .venv, __pycache__, *.pyc) bootstrap.ps1: add MCP build step — npm install+build for TS servers, venv+pip for Python Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
82
lib/wiki-graph/scripts/smoke.mjs
Normal file
82
lib/wiki-graph/scripts/smoke.mjs
Normal file
@@ -0,0 +1,82 @@
|
||||
// Smoke test: drive the built MCP server over stdio against a live .wiki corpus.
|
||||
// Usage: node scripts/smoke.mjs <corpusDir> [from] [to] [hubNode]
|
||||
import { spawn } from 'node:child_process';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const serverPath = join(here, '..', 'dist', 'server.js');
|
||||
|
||||
const corpus = process.argv[2];
|
||||
const from = process.argv[3] ?? 'alm-pamelas-pro-workout';
|
||||
const to = process.argv[4] ?? 'euclidean-rhythms';
|
||||
const hub = process.argv[5] ?? 'euclidean-rhythms';
|
||||
if (!corpus) {
|
||||
console.error('usage: node scripts/smoke.mjs <corpusDir> [from] [to] [hubNode]');
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
const child = spawn('node', [serverPath], { stdio: ['pipe', 'pipe', 'inherit'] });
|
||||
let buf = '';
|
||||
const pending = new Map();
|
||||
child.stdout.on('data', (d) => {
|
||||
buf += d.toString();
|
||||
let nl;
|
||||
while ((nl = buf.indexOf('\n')) >= 0) {
|
||||
const line = buf.slice(0, nl).trim();
|
||||
buf = buf.slice(nl + 1);
|
||||
if (!line) continue;
|
||||
const msg = JSON.parse(line);
|
||||
if (msg.id && pending.has(msg.id)) {
|
||||
pending.get(msg.id)(msg);
|
||||
pending.delete(msg.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let nextId = 1;
|
||||
function rpc(method, params) {
|
||||
const id = nextId++;
|
||||
return new Promise((resolve) => {
|
||||
pending.set(id, resolve);
|
||||
child.stdin.write(JSON.stringify({ jsonrpc: '2.0', id, method, params }) + '\n');
|
||||
});
|
||||
}
|
||||
function notify(method, params) {
|
||||
child.stdin.write(JSON.stringify({ jsonrpc: '2.0', method, params }) + '\n');
|
||||
}
|
||||
async function call(name, args) {
|
||||
const t0 = performance.now();
|
||||
const res = await rpc('tools/call', { name, arguments: { corpus, ...args } });
|
||||
const ms = (performance.now() - t0).toFixed(1);
|
||||
return { text: res.result.content.map((c) => c.text).join('\n'), ms };
|
||||
}
|
||||
|
||||
const init = await rpc('initialize', {
|
||||
protocolVersion: '2024-11-05',
|
||||
capabilities: {},
|
||||
clientInfo: { name: 'wg-smoke', version: '0' },
|
||||
});
|
||||
notify('notifications/initialized', {});
|
||||
console.log(`server: ${init.result.serverInfo.name} ${init.result.serverInfo.version}`);
|
||||
console.log(`corpus: ${corpus}\n`);
|
||||
|
||||
const cold = await call('stats', {});
|
||||
console.log(`stats [cold ${cold.ms}ms] ${cold.text}`);
|
||||
const warm = await call('stats', {});
|
||||
console.log(`stats [warm ${warm.ms}ms] ${warm.text}`);
|
||||
|
||||
const p = await call('path', { from, to });
|
||||
console.log(`path [${p.ms}ms] ${from} → ${to}\n ${p.text}`);
|
||||
|
||||
const n = await call('neighbors', { node: hub, depth: 1 });
|
||||
console.log(`neighbrs[${n.ms}ms] ${n.text}`);
|
||||
|
||||
const b = await call('backlinks', { node: hub });
|
||||
console.log(`backlnks[${b.ms}ms] ${b.text}`);
|
||||
|
||||
const o = await call('orphans', {});
|
||||
console.log(`orphans [${o.ms}ms] ${o.text.split('\n')[0]} ...`);
|
||||
|
||||
child.stdin.end();
|
||||
child.kill();
|
||||
Reference in New Issue
Block a user