File size: 2,348 Bytes
cd8bd0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/usr/bin/env node

import { spawn } from "node:child_process";
import { existsSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const ROOT = join(__dirname, "..");

/**
 * @param {string} [rootDir] - project root directory (defaults to package root)
 * @param {(path: string) => boolean} [existsSyncFn] - injectable fs.existsSync
 *   for testing; defaults to the real existsSync
 * @returns {string|null} resolved absolute path to the MCP server entry, or null
 */
export function resolveMcpEntry(rootDir = ROOT, existsSyncFn = existsSync) {
  const candidates = [
    // Preferred distributable JS entry (npm publish artifact, built by prepublish.ts)
    join(rootDir, "dist", "open-sse", "mcp-server", "server.js"),
    // Local workspace TypeScript source fallback
    join(rootDir, "open-sse", "mcp-server", "server.ts"),
  ];

  for (const entry of candidates) {
    if (existsSyncFn(entry)) return entry;
  }
  return null;
}

function formatSpawnError(exitCode, signal) {
  if (signal) return `MCP server exited by signal ${signal}`;
  return `MCP server exited with code ${exitCode ?? 1}`;
}

export async function startMcpCli(rootDir = ROOT) {
  const mcpEntry = resolveMcpEntry(rootDir);
  if (!mcpEntry) {
    throw new Error(
      "MCP server entrypoint not found. Expected dist/open-sse/mcp-server/server.js or open-sse/mcp-server/server.ts."
    );
  }

  // `tsx` loader is only required for local `.ts` fallback; JS entry works without it.
  const loaderArgs = mcpEntry.endsWith(".ts") ? ["--import", "tsx"] : [];

  await new Promise((resolve, reject) => {
    const child = spawn(process.execPath, [...loaderArgs, mcpEntry], {
      cwd: rootDir,
      env: process.env,
      stdio: "inherit",
    });

    child.once("error", reject);
    child.once("exit", (code, signal) => {
      if ((code ?? 0) === 0 && !signal) {
        resolve(undefined);
        return;
      }
      reject(new Error(formatSpawnError(code, signal)));
    });
  });
}

if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
  startMcpCli().catch((err) => {
    console.error("\x1b[31m✖ Failed to start MCP server:\x1b[0m", err?.message || err);
    process.exit(1);
  });
}