Files
apex-mcp-server/packages/builder/test/setup.ts
FilipBl4gojevic 0299e3176f refactor: move the MCP server into packages/builder
Pure file moves plus import repointing at the shared package. Removes
duplicated endpoint constants and formatting helpers that were copied
across three files. Verified: 23 tools with identical schemas.
2026-07-28 10:04:04 +02:00

66 lines
2.4 KiB
TypeScript

import { spawn, ChildProcess } from 'node:child_process';
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
const PROJECT_ROOT = resolve(import.meta.dirname!, '..');
export interface ServerContext {
client: Client;
process: ChildProcess;
port: number;
}
export function getMnemonic(): string {
const mnemonic = readFileSync(resolve(PROJECT_ROOT, 'mnemonic.txt'), 'utf-8').trim();
const wordCount = mnemonic.split(/\s+/).length;
const validLengths = [12, 15, 18, 21, 24];
if (!validLengths.includes(wordCount)) {
throw new Error(`mnemonic.txt has ${wordCount} words, expected one of: ${validLengths.join(', ')}`);
}
return mnemonic;
}
export async function startServer(): Promise<ServerContext> {
const port = 3100 + Math.floor(Math.random() * 900);
const child = spawn('node', ['build/index.js'], {
cwd: PROJECT_ROOT,
env: { ...process.env, PORT: String(port) },
stdio: ['ignore', 'ignore', 'pipe'],
});
await new Promise<void>((resolve, reject) => {
const timeout = setTimeout(() => reject(new Error('Server start timeout (60s)')), 60_000);
child.stderr!.on('data', (chunk: Buffer) => {
if (chunk.toString().includes('listening on port')) {
clearTimeout(timeout);
resolve();
}
});
child.on('error', (err) => { clearTimeout(timeout); reject(err); });
child.on('exit', (code) => { clearTimeout(timeout); reject(new Error(`Server exited with code ${code}`)); });
});
const transport = new SSEClientTransport(new URL(`http://localhost:${port}/sse`));
const client = new Client({ name: 'integration-test', version: '1.0.0' });
await client.connect(transport);
return { client, process: child, port };
}
export async function stopServer(ctx: ServerContext): Promise<void> {
try { await ctx.client.close(); } catch {}
ctx.process.kill('SIGTERM');
}
export async function callTool(client: Client, name: string, args: Record<string, unknown> = {}): Promise<string> {
const result = await client.callTool({ name, arguments: args });
const content = result.content as Array<{ type: string; text?: string }>;
return content?.[0]?.text ?? '';
}
export function wait(seconds: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, seconds * 1000));
}