import { execFile } from 'node:child_process'; import fs from 'node:fs/promises'; import { createServer } from 'node:http'; import { createRequire } from 'node:module'; import os from 'node:os'; import path from 'node:path'; import { fileURLToPath, pathToFileURL } from 'node:url'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import express from 'express'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { z } from 'zod'; const CLI_ENTRY = fileURLToPath(new URL('../dist/cli.js', import.meta.url)); const testRequire = createRequire(import.meta.url); const MCP_SERVER_MODULE = pathToFileURL(testRequire.resolve('@modelcontextprotocol/sdk/server/mcp.js')).href; const STDIO_SERVER_MODULE = pathToFileURL(testRequire.resolve('@modelcontextprotocol/sdk/server/stdio.js')).href; const ZOD_MODULE = pathToFileURL(path.join(process.cwd(), 'node_modules', 'zod', 'index.js')).href; const PNPM_COMMAND = process.platform === 'win32' ? 'cmd.exe' : 'pnpm'; const PNPM_ARGS_PREFIX = process.platform === 'win32' ? ['/d', '/s', '/c', 'pnpm'] : []; function pnpmArgs(args: string[]): string[] { return [...PNPM_ARGS_PREFIX, ...args]; } async function ensureDistBuilt(): Promise { try { await fs.access(CLI_ENTRY); } catch { throw new Error('dist/cli.js is missing; run `pnpm build` before invoking this integration test directly.'); } } async function hasBun(): Promise { return await new Promise((resolve) => { execFile(process.env.BUN_BIN ?? 'bun', ['--version'], { cwd: process.cwd(), env: process.env }, (error) => { resolve(!error); }); }); } let bunCompileSupport: Promise | undefined; async function hasRunnableBunCompile(): Promise { bunCompileSupport ??= probeRunnableBunCompile(); return await bunCompileSupport; } async function probeRunnableBunCompile(): Promise { if (!(await hasBun())) { return false; } const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcporter-bun-compile-probe-')); const sourcePath = path.join(tempDir, 'probe.ts'); const binaryPath = path.join(tempDir, 'probe'); try { await fs.writeFile(sourcePath, 'console.log("mcporter-bun-compile-probe");\n', 'utf8'); const bun = process.env.BUN_BIN ?? 'bun'; const built = await new Promise((resolve) => { execFile( bun, ['build', sourcePath, '--compile', '--outfile', binaryPath], { cwd: tempDir, env: process.env }, (error) => resolve(!error) ); }); if (!built) { return false; } return await new Promise((resolve) => { execFile(binaryPath, [], { cwd: tempDir, env: process.env }, (error, stdout) => { resolve(!error && stdout.trim() === 'mcporter-bun-compile-probe'); }); }); } finally { await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {}); } } async function ensureBunSupport(reason: string): Promise { if (process.platform === 'win32') { console.warn(`bun not supported on Windows; skipping ${reason}.`); return false; } if (!(await hasBun())) { console.warn(`bun not available on this runner; skipping ${reason}.`); return false; } return true; } async function ensureRunnableBunCompile(reason: string): Promise { if (!(await ensureBunSupport(reason))) { return false; } if (!(await hasRunnableBunCompile())) { console.warn(`bun-compiled binaries cannot run on this runner; skipping ${reason}.`); return false; } return true; } async function runGeneratedCli( bundlePath: string, args: string[], env: NodeJS.ProcessEnv ): Promise<{ stdout: string; stderr: string }> { return await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => { execFile(process.execPath, [bundlePath, ...args], { env }, (error, stdout, stderr) => { if (error) { reject(new Error(`${error.message}\nSTDOUT:\n${stdout}\nSTDERR:\n${stderr}`)); return; } resolve({ stdout, stderr }); }); }); } function parseGeneratedDaemonJson(result: { stdout: string }): { instanceId: string; count: number } { const trimmed = result.stdout.trim(); const start = trimmed.indexOf('{'); const end = trimmed.lastIndexOf('}'); if (start === -1 || end === -1 || end < start) { throw new Error(`Unable to find JSON payload in generated CLI output:\n${result.stdout}`); } return JSON.parse(trimmed.slice(start, end + 1)) as { instanceId: string; count: number }; } describe('mcporter CLI integration', () => { let baseUrl: URL; let shutdown: (() => Promise) | undefined; beforeAll(async () => { await ensureDistBuilt(); const app = express(); app.use(express.json()); const server = new McpServer({ name: 'context7', title: 'Context7 integration harness', version: '1.0.0' }); server.registerTool( 'ping', { title: 'Ping', description: 'Simple health check', inputSchema: { echo: z.string().optional() }, outputSchema: { ok: z.boolean(), echo: z.string().optional() }, }, async ({ echo }) => ({ content: [{ type: 'text', text: JSON.stringify({ ok: true, echo: echo ?? 'hi' }) }], structuredContent: { ok: true, echo: echo ?? 'hi' }, }) ); server.registerTool( 'admin_reset', { title: 'Admin Reset', description: 'Dangerous admin action', inputSchema: { reason: z.string().optional() }, outputSchema: { ok: z.boolean() }, }, async () => ({ content: [{ type: 'text', text: JSON.stringify({ ok: true }) }], structuredContent: { ok: true }, }) ); server.registerTool( 'plain_text', { title: 'Plain Text', description: 'Returns non-JSON text', inputSchema: { value: z.string().optional() }, }, async ({ value }) => ({ content: [{ type: 'text', text: value ?? 'plain' }], }) ); app.post('/mcp', async (req, res) => { const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, enableJsonResponse: true }); res.on('close', () => { transport.close().catch(() => {}); }); await server.connect(transport); await transport.handleRequest(req, res, req.body); }); const httpServer = createServer(app); await new Promise((resolve) => httpServer.listen(0, '127.0.0.1', resolve)); const address = httpServer.address(); if (!address || typeof address === 'string') { throw new Error('Failed to start integration server'); } baseUrl = new URL(`http://127.0.0.1:${address.port}/mcp`); shutdown = async () => await new Promise((resolve, reject) => { httpServer.close((error) => { if (error) { reject(error); return; } resolve(); }); }); }, 60_000); afterAll(async () => { if (shutdown) { await shutdown(); } }); it('runs "node dist/cli.js generate-cli" from a dependency-less directory', async () => { const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcporter-cli-e2e-')); await fs.writeFile( path.join(tempDir, 'package.json'), JSON.stringify({ name: 'mcporter-e2e', version: '0.0.0' }, null, 2), 'utf8' ); const bundlePath = path.join(tempDir, 'context7.cli.js'); await new Promise((resolve, reject) => { execFile( process.execPath, [CLI_ENTRY, 'generate-cli', '--command', baseUrl.toString(), '--bundle', bundlePath, '--runtime', 'node'], { cwd: tempDir, env: { ...process.env, MCPORTER_NO_FORCE_EXIT: '1' }, }, (error) => { if (error) { reject(error); return; } resolve(); } ); }); const stats = await fs.stat(bundlePath); expect(stats.isFile()).toBe(true); const helpOutput = await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => { execFile(process.execPath, [bundlePath], { env: process.env }, (error, stdout, stderr) => { if (error) { reject(error); return; } resolve({ stdout, stderr }); }); }); expect(helpOutput.stdout).toMatch(/Usage: .+ \[options]/); expect(helpOutput.stdout).toContain('Context7 integration harness'); const plainOutput = await runGeneratedCli(bundlePath, ['plain-text', '--value', 'hello', '--output', 'json'], { ...process.env, MCPORTER_NO_FORCE_EXIT: '1', }); const plainJson = JSON.parse(plainOutput.stdout) as { content?: Array<{ text?: string }> }; expect(plainJson.content?.[0]?.text).toBe('hello'); await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {}); }); it('routes generated keep-alive stdio CLIs through the daemon', async () => { if (process.platform === 'win32') { console.warn('daemon sockets use Unix paths in this integration; skipping on Windows.'); return; } const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcporter-cli-daemon-')); const stateDir = await fs.mkdtemp('/tmp/mcporter-generated-daemon-'); const serverPath = path.join(tempDir, 'daemon-server.mjs'); const bundlePath = path.join(tempDir, 'daemon-cli.js'); const daemonDir = path.join(stateDir, 'daemon-state'); const generatedConfigDir = path.join(stateDir, 'generated-configs'); const cliEnv = { ...process.env, MCPORTER_NO_FORCE_EXIT: '1', MCPORTER_DAEMON_DIR: daemonDir, MCPORTER_GENERATED_CONFIG_DIR: generatedConfigDir, }; await fs.writeFile( serverPath, `import { randomUUID } from 'node:crypto'; import { McpServer } from '${MCP_SERVER_MODULE}'; import { StdioServerTransport } from '${STDIO_SERVER_MODULE}'; import { z } from '${ZOD_MODULE}'; const instanceId = randomUUID(); let counter = 0; const server = new McpServer({ name: 'generated-daemon', version: '1.0.0' }); server.registerTool('next_value', { title: 'Next value', description: 'Return process-local state', inputSchema: {}, outputSchema: { instanceId: z.string(), count: z.number() }, }, async () => { counter += 1; return { content: [{ type: 'text', text: JSON.stringify({ instanceId, count: counter }) }], structuredContent: { instanceId, count: counter }, }; }); const transport = new StdioServerTransport(); await server.connect(transport); await new Promise((resolve) => { transport.onclose = resolve; }); `, 'utf8' ); const inlineServer = JSON.stringify({ name: 'generated-daemon', description: 'Generated daemon test server', command: 'node', args: [serverPath], lifecycle: 'keep-alive', }); try { await new Promise((resolve, reject) => { execFile( process.execPath, [CLI_ENTRY, 'generate-cli', '--server', inlineServer, '--bundle', bundlePath, '--runtime', 'node'], { cwd: tempDir, env: cliEnv }, (error) => { if (error) { reject(error); return; } resolve(); } ); }); const first = parseGeneratedDaemonJson( await runGeneratedCli(bundlePath, ['next-value', '--output', 'json'], cliEnv) ); const second = parseGeneratedDaemonJson( await runGeneratedCli(bundlePath, ['next-value', '--output', 'json'], cliEnv) ); expect(first.count).toBe(1); expect(second.count).toBe(2); expect(second.instanceId).toBe(first.instanceId); } finally { const configFiles = await fs.readdir(generatedConfigDir).catch(() => []); await Promise.all( configFiles .filter((entry) => entry.endsWith('.json')) .map((entry) => runGeneratedCli( bundlePath, ['--config', path.join(generatedConfigDir, entry), 'daemon', 'stop'], cliEnv ).catch(() => '') ) ); await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {}); await fs.rm(stateDir, { recursive: true, force: true }).catch(() => {}); } }, 40_000); it('filters generated CLI tools via --include-tools/--exclude-tools', async () => { const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcporter-cli-filter-')); await fs.writeFile( path.join(tempDir, 'package.json'), JSON.stringify({ name: 'mcporter-cli-filter', version: '0.0.0' }, null, 2), 'utf8' ); const includePath = path.join(tempDir, 'context7-include.js'); await new Promise((resolve, reject) => { execFile( process.execPath, [ CLI_ENTRY, 'generate-cli', '--command', baseUrl.toString(), '--runtime', 'node', '--bundle', includePath, '--include-tools', 'ping', ], { cwd: tempDir, env: { ...process.env, MCPORTER_NO_FORCE_EXIT: '1' } }, (error) => { if (error) { reject(error); return; } resolve(); } ); }); const includeHelp = await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => { execFile(process.execPath, [includePath], { env: process.env }, (error, stdout, stderr) => { if (error) { reject(error); return; } resolve({ stdout, stderr }); }); }); expect(includeHelp.stdout).toContain('ping - Simple health check'); expect(includeHelp.stdout).not.toContain('admin-reset'); const excludePath = path.join(tempDir, 'context7-exclude.js'); await new Promise((resolve, reject) => { execFile( process.execPath, [ CLI_ENTRY, 'generate-cli', '--command', baseUrl.toString(), '--runtime', 'node', '--bundle', excludePath, '--exclude-tools', 'ping', ], { cwd: tempDir, env: { ...process.env, MCPORTER_NO_FORCE_EXIT: '1' } }, (error) => { if (error) { reject(error); return; } resolve(); } ); }); const excludeHelp = await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => { execFile(process.execPath, [excludePath], { env: process.env }, (error, stdout, stderr) => { if (error) { reject(error); return; } resolve({ stdout, stderr }); }); }); expect(excludeHelp.stdout).not.toContain('ping - Simple health check'); expect(excludeHelp.stdout).toContain('admin-reset'); await new Promise((resolve) => { execFile( process.execPath, [ CLI_ENTRY, 'generate-cli', '--command', baseUrl.toString(), '--runtime', 'node', '--bundle', path.join(tempDir, 'context7-missing.js'), '--include-tools', 'missing-tool', ], { cwd: tempDir, env: { ...process.env, MCPORTER_NO_FORCE_EXIT: '1' } }, (error, stdout, stderr) => { expect(error).toBeTruthy(); expect(`${stdout}\n${stderr}`).toMatch(/Requested tools not found|missing-tool/); resolve(); } ); }); await new Promise((resolve) => { execFile( process.execPath, [ CLI_ENTRY, 'generate-cli', '--command', baseUrl.toString(), '--runtime', 'node', '--bundle', path.join(tempDir, 'context7-empty.js'), '--include-tools', ',', ], { cwd: tempDir, env: { ...process.env, MCPORTER_NO_FORCE_EXIT: '1' } }, (error, stdout, stderr) => { expect(error).toBeTruthy(); expect(`${stdout}\n${stderr}`).toMatch(/--include-tools requires at least one/); resolve(); } ); }); await new Promise((resolve) => { execFile( process.execPath, [ CLI_ENTRY, 'generate-cli', '--command', baseUrl.toString(), '--runtime', 'node', '--bundle', path.join(tempDir, 'context7-both.js'), '--include-tools', 'ping', '--exclude-tools', 'ping', ], { cwd: tempDir, env: { ...process.env, MCPORTER_NO_FORCE_EXIT: '1' } }, (error, stdout, stderr) => { expect(error).toBeTruthy(); expect(`${stdout}\n${stderr}`).toMatch(/cannot be used together/); resolve(); } ); }); await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {}); }, 40_000); it('bundles with Bun automatically when runtime resolves to Bun', async () => { if (!(await ensureBunSupport('Bun bundler integration test'))) { return; } const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcporter-bun-bundle-')); await fs.writeFile( path.join(tempDir, 'package.json'), JSON.stringify({ name: 'mcporter-bun-bundle', version: '0.0.0' }, null, 2), 'utf8' ); const bundlePath = path.join(tempDir, 'context7-bun.js'); await new Promise((resolve, reject) => { execFile( process.execPath, [CLI_ENTRY, 'generate-cli', '--command', baseUrl.toString(), '--runtime', 'bun', '--bundle', bundlePath], { cwd: tempDir, env: { ...process.env, MCPORTER_NO_FORCE_EXIT: '1' }, }, (error) => { if (error) { reject(error); return; } resolve(); } ); }); const stats = await fs.stat(bundlePath); expect(stats.isFile()).toBe(true); const helpOutput = await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => { execFile(bundlePath, [], { env: process.env }, (error, stdout, stderr) => { if (error) { reject(error); return; } resolve({ stdout, stderr }); }); }); expect(helpOutput.stdout).toMatch(/Usage: .+ \[options]/); expect(helpOutput.stdout).toContain('Context7 integration harness'); expect(helpOutput.stdout).toContain('ping - Simple health check'); expect(helpOutput.stdout).toContain('--echo '); await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {}); }, 20000); it('generates a Bun CLI that can call a tool', async () => { if (!(await ensureBunSupport('Bun CLI execution test'))) { return; } const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcporter-bun-cli-')); await fs.writeFile( path.join(tempDir, 'package.json'), JSON.stringify({ name: 'mcporter-bun-cli', version: '0.0.0' }, null, 2), 'utf8' ); const bundlePath = path.join(tempDir, 'context7-bun-cli.js'); await new Promise((resolve, reject) => { execFile( process.execPath, [CLI_ENTRY, 'generate-cli', '--command', baseUrl.toString(), '--runtime', 'bun', '--bundle', bundlePath], { cwd: tempDir, env: { ...process.env, MCPORTER_NO_FORCE_EXIT: '1' }, }, (error) => { if (error) { reject(error); return; } resolve(); } ); }); const result = await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => { execFile( bundlePath, ['ping', '--echo', 'ban', '--output', 'json'], { env: process.env }, (error, stdout, stderr) => { if (error) { reject(error); return; } resolve({ stdout, stderr }); } ); }); const parsed = JSON.parse(result.stdout.trim()) as { ok: boolean; echo?: string }; expect(parsed.ok).toBe(true); expect(parsed.echo).toBe('ban'); await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {}); }, 20000); it('runs "node dist/cli.js generate-cli --compile" when bun is available', async () => { if (!(await ensureRunnableBunCompile('compile integration test'))) { return; } const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcporter-cli-compile-')); await fs.writeFile( path.join(tempDir, 'package.json'), JSON.stringify({ name: 'mcporter-compile-e2e', version: '0.0.0' }, null, 2), 'utf8' ); const binaryPath = path.join(tempDir, 'context7-cli'); await new Promise((resolve, reject) => { execFile( process.execPath, [CLI_ENTRY, 'generate-cli', '--command', baseUrl.toString(), '--compile', binaryPath, '--runtime', 'bun'], { cwd: tempDir, env: { ...process.env, MCPORTER_NO_FORCE_EXIT: '1' }, }, (error) => { if (error) { reject(error); return; } resolve(); } ); }); const stats = await fs.stat(binaryPath); expect(stats.isFile()).toBe(true); const helpOutput = await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => { execFile(binaryPath, [], { env: process.env }, (error, stdout, stderr) => { if (error) { reject(error); return; } resolve({ stdout, stderr }); }); }); expect(helpOutput.stdout).toMatch(/Usage: .+ \[options]/); expect(helpOutput.stdout).toContain('Context7 integration harness'); expect(helpOutput.stdout).toContain('ping - Simple health check'); expect(helpOutput.stdout).toContain('--echo '); await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {}); }, 20000); it('end-to-end: compiles a "bun" CLI and calls ping', async () => { if (!(await ensureRunnableBunCompile('Bun CLI end-to-end test'))) { return; } const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcporter-cli-bun-')); await fs.writeFile( path.join(tempDir, 'package.json'), JSON.stringify({ name: 'mcporter-bun-e2e', version: '0.0.0' }, null, 2), 'utf8' ); const binaryPath = path.join(tempDir, 'bun'); await new Promise((resolve, reject) => { execFile( process.execPath, [ CLI_ENTRY, 'generate-cli', '--command', baseUrl.toString(), '--runtime', 'bun', '--compile', binaryPath, '--name', 'bun', '--include-tools', 'ping', ], { cwd: tempDir, env: { ...process.env, MCPORTER_NO_FORCE_EXIT: '1' } }, (error) => { if (error) { reject(error); return; } resolve(); } ); }); const helpOutput = await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => { execFile(binaryPath, [], { env: process.env }, (error, stdout, stderr) => { if (error) { reject(error); return; } resolve({ stdout, stderr }); }); }); expect(helpOutput.stdout).toMatch(/Usage: bun \[options]/); expect(helpOutput.stdout).toContain('ping - Simple health check'); expect(helpOutput.stdout).not.toContain('admin-reset'); const pingOutput = await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => { execFile( binaryPath, ['ping', '--echo', 'works', '--output', 'json'], { env: process.env }, (error, stdout, stderr) => { if (error) { reject(error); return; } resolve({ stdout, stderr }); } ); }); const parsed = JSON.parse(pingOutput.stdout.trim()) as { ok: boolean; echo?: string }; expect(parsed.ok).toBe(true); expect(parsed.echo).toBe('works'); await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {}); }, 30000); it('runs "node dist/cli.js generate-cli --compile" using the Bun bundler by default', async () => { if (!(await ensureRunnableBunCompile('Bun bundler compile integration test'))) { return; } const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcporter-cli-compile-bun-')); await fs.writeFile( path.join(tempDir, 'package.json'), JSON.stringify({ name: 'mcporter-compile-bun', version: '0.0.0' }, null, 2), 'utf8' ); const binaryPath = path.join(tempDir, 'context7-cli-bun'); await new Promise((resolve, reject) => { execFile( process.execPath, [CLI_ENTRY, 'generate-cli', '--command', baseUrl.toString(), '--compile', binaryPath, '--runtime', 'bun'], { cwd: tempDir, env: { ...process.env, MCPORTER_NO_FORCE_EXIT: '1' }, }, (error) => { if (error) { reject(error); return; } resolve(); } ); }); const stats = await fs.stat(binaryPath); expect(stats.isFile()).toBe(true); const helpOutput = await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => { execFile(binaryPath, [], { env: process.env }, (error, stdout, stderr) => { if (error) { reject(error); return; } resolve({ stdout, stderr }); }); }); expect(helpOutput.stdout).toMatch(/Usage: .+ \[options]/); expect(helpOutput.stdout).toContain('ping - Simple health check'); expect(helpOutput.stdout).toContain('--echo '); await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {}); }, 20000); it('accepts inline stdio commands (e.g., "npx -y chrome-devtools-mcp@latest") when compiling', async () => { if (!(await ensureRunnableBunCompile('inline stdio compile integration test'))) { return; } const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcporter-inline-stdio-')); await fs.writeFile( path.join(tempDir, 'package.json'), JSON.stringify({ name: 'mcporter-inline-stdio', version: '0.0.0' }, null, 2), 'utf8' ); const scriptPath = path.join(tempDir, 'mock-stdio.mjs'); const scriptSource = `import { McpServer } from '${MCP_SERVER_MODULE}'; import { StdioServerTransport } from '${STDIO_SERVER_MODULE}'; import { z } from '${ZOD_MODULE}'; const server = new McpServer({ name: 'inline-cli', version: '1.0.0' }); server.registerTool('echo', { title: 'Echo', description: 'Return the provided text', // Use Zod schemas to keep SDK 1.22.x happy when converting to JSON Schema. inputSchema: z.object({ text: z.string() }), outputSchema: z.object({ text: z.string() }), }, async ({ text }) => ({ content: [{ type: 'text', text }], structuredContent: { text }, })); const transport = new StdioServerTransport(); await server.connect(transport); await new Promise((resolve) => { transport.onclose = resolve; }); `; await fs.writeFile(scriptPath, scriptSource, 'utf8'); const binaryPath = path.join(tempDir, 'inline-cli'); await new Promise((resolve, reject) => { execFile( process.execPath, [CLI_ENTRY, 'generate-cli', `node ${scriptPath}`, '--compile', binaryPath, '--runtime', 'bun'], { cwd: tempDir, env: { ...process.env, MCPORTER_NO_FORCE_EXIT: '1' }, }, (error) => { if (error) { reject(error); return; } resolve(); } ); }); const stats = await fs.stat(binaryPath); expect(stats.isFile()).toBe(true); const { stdout } = await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => { execFile(binaryPath, [], { env: process.env }, (error, childStdout, childStderr) => { if (error) { reject(error); return; } resolve({ stdout: childStdout, stderr: childStderr }); }); }); expect(stdout).toContain('echo - Return the provided text'); expect(stdout).toContain('[--raw ]'); await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {}); }, 40_000); it('resolves relative stdio args from the bundle directory when invoked from any cwd (#56)', async () => { const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcporter-cli-reloc-')); const distDir = path.join(tempDir, 'dist'); await fs.mkdir(distDir, { recursive: true }); await fs.writeFile( path.join(tempDir, 'package.json'), JSON.stringify({ name: 'mcporter-reloc-e2e', version: '0.0.0' }, null, 2), 'utf8' ); const serverPath = path.join(distDir, 'server.mjs'); const serverSource = `import { McpServer } from '${MCP_SERVER_MODULE}'; import { StdioServerTransport } from '${STDIO_SERVER_MODULE}'; import { z } from '${ZOD_MODULE}'; const server = new McpServer({ name: 'reloc', version: '1.0.0' }); server.registerTool('echo', { title: 'Echo', description: 'Return the provided text', inputSchema: z.object({ text: z.string() }), outputSchema: z.object({ text: z.string() }), }, async ({ text }) => ({ content: [{ type: 'text', text }], structuredContent: { text }, })); const transport = new StdioServerTransport(); await server.connect(transport); await new Promise((resolve) => { transport.onclose = resolve; }); `; await fs.writeFile(serverPath, serverSource, 'utf8'); const bundlePath = path.join(distDir, 'reloc-cli.cjs'); await new Promise((resolve, reject) => { execFile( process.execPath, [CLI_ENTRY, 'generate-cli', '--command', 'node dist/server.mjs', '--bundle', bundlePath, '--runtime', 'node'], { cwd: tempDir, env: { ...process.env, MCPORTER_NO_FORCE_EXIT: '1' } }, (error) => { if (error) { reject(error); return; } resolve(); } ); }); const callerCwd = await fs.mkdtemp(path.join(os.tmpdir(), 'mcporter-cli-reloc-caller-')); const result = await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => { execFile( process.execPath, [bundlePath, 'echo', '--text', 'relocated'], { cwd: callerCwd, env: process.env }, (error, stdout, stderr) => { if (error) { reject(error); return; } resolve({ stdout, stderr }); } ); }); expect(result.stdout).toContain('relocated'); await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {}); await fs.rm(callerCwd, { recursive: true, force: true }).catch(() => {}); }, 30_000); it('compiles a generated CLI from the standalone Bun release binary in an empty directory', async () => { if (process.env.MCPORTER_STANDALONE_BINARY_TEST !== '1') { console.warn('set MCPORTER_STANDALONE_BINARY_TEST=1 to run standalone Bun release binary smoke'); return; } if (!(await ensureRunnableBunCompile('standalone Bun release binary smoke'))) { return; } await new Promise((resolve, reject) => { execFile(PNPM_COMMAND, pnpmArgs(['build:bun']), { cwd: process.cwd(), env: process.env }, (error) => { if (error) { reject(error); return; } resolve(); }); }); const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcporter-standalone-bun-')); const binaryPath = path.join(tempDir, 'context7-cli'); const mcporterBinary = path.join(process.cwd(), 'dist-bun', 'mcporter'); const packedTarball = await new Promise((resolve, reject) => { execFile( 'npm', ['pack', '--ignore-scripts', '--pack-destination', tempDir], { cwd: process.cwd(), env: process.env }, (error, stdout, stderr) => { if (error) { reject(new Error(`${error.message}\nSTDOUT:\n${stdout}\nSTDERR:\n${stderr}`)); return; } resolve(path.join(tempDir, stdout.trim().split('\n').at(-1) ?? '')); } ); }); await new Promise((resolve, reject) => { execFile( mcporterBinary, ['generate-cli', '--command', baseUrl.toString(), '--compile', binaryPath], { cwd: tempDir, env: { ...process.env, MCPORTER_BUNDLER_DEP_PACKAGE: packedTarball, MCPORTER_NO_FORCE_EXIT: '1', }, }, (error, stdout, stderr) => { if (error) { reject(new Error(`${error.message}\nSTDOUT:\n${stdout}\nSTDERR:\n${stderr}`)); return; } resolve(); } ); }); const helpOutput = await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => { execFile(binaryPath, [], { env: process.env }, (error, stdout, stderr) => { if (error) { reject(error); return; } resolve({ stdout, stderr }); }); }); expect(helpOutput.stdout).toMatch(/Usage: .+ \[options]/); expect(helpOutput.stdout).toContain('ping - Simple health check'); await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {}); }, 90_000); });