dynmcp 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import process12 from "process";
4
+ import process14 from "process";
5
5
  import { Command } from "commander";
6
6
 
7
7
  // package.json
8
8
  var package_default = {
9
9
  name: "dynmcp",
10
- version: "0.5.0",
10
+ version: "0.6.0",
11
11
  description: "Dynamic MCP context management tool for AI MCP-enabled agents and clients.",
12
12
  author: "Brandon Burrus <brandon@burrus.io>",
13
13
  license: "MIT",
@@ -465,14 +465,14 @@ var sseTransport = z.object({
465
465
  headers: z.record(z.string(), z.string()).optional(),
466
466
  auth: authConfig
467
467
  }).strict();
468
- var transportConfig = z.discriminatedUnion("transport", [
468
+ var transportConfigSchema = z.discriminatedUnion("transport", [
469
469
  stdioTransport,
470
470
  streamableHttpTransport,
471
471
  sseTransport
472
472
  ]);
473
473
  var mcpConfigSchema = z.object({
474
474
  env: envModeSchema.optional(),
475
- mcp: z.record(mcpName, transportConfig).refine((obj) => Object.keys(obj).length > 0, { message: "At least one MCP must be configured" })
475
+ mcp: z.record(mcpName, transportConfigSchema).refine((obj) => Object.keys(obj).length > 0, { message: "At least one MCP must be configured" })
476
476
  });
477
477
 
478
478
  // src/config/loader.ts
@@ -704,7 +704,7 @@ import { spawn } from "child_process";
704
704
  import process3 from "process";
705
705
  async function openUrl(url) {
706
706
  const { command, args } = openerForPlatform(url);
707
- return new Promise((resolve3, reject) => {
707
+ return new Promise((resolve4, reject) => {
708
708
  const child = spawn(command, args, {
709
709
  stdio: "ignore",
710
710
  detached: true
@@ -712,7 +712,7 @@ async function openUrl(url) {
712
712
  child.once("error", reject);
713
713
  child.once("spawn", () => {
714
714
  child.unref();
715
- resolve3();
715
+ resolve4();
716
716
  });
717
717
  });
718
718
  }
@@ -787,14 +787,14 @@ var CallbackServer = class _CallbackServer {
787
787
  throw new Error("CallbackServer is already started.");
788
788
  }
789
789
  const server = createServer((req, res) => this.handleRequest(req, res));
790
- await new Promise((resolve3, reject) => {
790
+ await new Promise((resolve4, reject) => {
791
791
  const onError = (err) => {
792
792
  server.removeListener("listening", onListening);
793
793
  reject(err);
794
794
  };
795
795
  const onListening = () => {
796
796
  server.removeListener("error", onError);
797
- resolve3();
797
+ resolve4();
798
798
  };
799
799
  server.once("error", onError);
800
800
  server.once("listening", onListening);
@@ -832,12 +832,12 @@ var CallbackServer = class _CallbackServer {
832
832
  if (this.pending !== null) {
833
833
  return Promise.reject(new Error("awaitCallback already in progress."));
834
834
  }
835
- return new Promise((resolve3, reject) => {
835
+ return new Promise((resolve4, reject) => {
836
836
  const timer = setTimeout(() => {
837
837
  this.pending = null;
838
838
  reject(new CallbackTimeoutError(timeoutMs));
839
839
  }, timeoutMs);
840
- this.pending = { resolve: resolve3, reject, timer };
840
+ this.pending = { resolve: resolve4, reject, timer };
841
841
  });
842
842
  }
843
843
  /** Closes the listening socket. Safe to call multiple times. */
@@ -847,8 +847,8 @@ var CallbackServer = class _CallbackServer {
847
847
  this.pending = null;
848
848
  }
849
849
  if (this.server === null) return;
850
- await new Promise((resolve3) => {
851
- this.server.close(() => resolve3());
850
+ await new Promise((resolve4) => {
851
+ this.server.close(() => resolve4());
852
852
  });
853
853
  this.server = null;
854
854
  this.boundPort = null;
@@ -892,10 +892,10 @@ var CallbackServer = class _CallbackServer {
892
892
  }
893
893
  res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
894
894
  res.end(SUCCESS_HTML);
895
- const { resolve: resolve3, timer } = this.pending;
895
+ const { resolve: resolve4, timer } = this.pending;
896
896
  clearTimeout(timer);
897
897
  this.pending = null;
898
- resolve3({ code, state });
898
+ resolve4({ code, state });
899
899
  }
900
900
  respondError(res, errorCode, description2) {
901
901
  res.writeHead(400, { "content-type": "text/html; charset=utf-8" });
@@ -3309,6 +3309,215 @@ async function runProxy(orchestrator) {
3309
3309
  }
3310
3310
  }
3311
3311
 
3312
+ // src/scaffold/init.ts
3313
+ import { existsSync as existsSync3, writeFileSync } from "fs";
3314
+ import { resolve as resolve3 } from "path";
3315
+ import process12 from "process";
3316
+
3317
+ // src/scaffold/format.ts
3318
+ import { extname } from "path";
3319
+ function detectFormat(filePath) {
3320
+ const ext = extname(filePath).toLowerCase();
3321
+ return ext === ".yml" || ext === ".yaml" ? "yaml" : "json";
3322
+ }
3323
+ var SCHEMA_URL = "https://dynamicmcp.tools/config.json";
3324
+
3325
+ // src/scaffold/init.ts
3326
+ function init(options = {}) {
3327
+ const cwd = options.cwd ?? process12.cwd();
3328
+ const stdout = options.write ?? ((chunk) => void process12.stdout.write(chunk));
3329
+ const fileWriter = options.fileWriter ?? ((p, c) => writeFileSync(p, c, "utf-8"));
3330
+ const fileExists = options.fileExists ?? ((p) => existsSync3(p));
3331
+ const targetPath = resolveInitPath({ cwd, path: options.path, yaml: options.yaml === true });
3332
+ const format = detectFormat(targetPath);
3333
+ if (fileExists(targetPath) && options.force !== true) {
3334
+ throw new Error(`File already exists: ${targetPath}
3335
+ Use --force to overwrite.`);
3336
+ }
3337
+ const contents = format === "yaml" ? renderYamlSkeleton() : renderJsonSkeleton();
3338
+ fileWriter(targetPath, contents);
3339
+ stdout(`Wrote ${targetPath}
3340
+ `);
3341
+ stdout("\nThis config has no MCPs yet. Add one with:\n");
3342
+ stdout(" dynmcp add <name> --command <cmd> (stdio upstream)\n");
3343
+ stdout(" dynmcp add <name> --transport streamable-http --url <url> (remote HTTP upstream)\n");
3344
+ stdout("\nSee https://dynamicmcp.tools for full documentation.\n");
3345
+ }
3346
+ function resolveInitPath(opts) {
3347
+ if (opts.path !== void 0) {
3348
+ return resolve3(opts.cwd, opts.path);
3349
+ }
3350
+ return resolve3(opts.cwd, opts.yaml ? "mcp.yaml" : "mcp.json");
3351
+ }
3352
+ function renderJsonSkeleton() {
3353
+ const body = JSON.stringify({ $schema: SCHEMA_URL, mcp: {} }, null, 2);
3354
+ return `${body}
3355
+ `;
3356
+ }
3357
+ function renderYamlSkeleton() {
3358
+ return `# yaml-language-server: $schema=${SCHEMA_URL}
3359
+
3360
+ mcp: {}
3361
+ `;
3362
+ }
3363
+
3364
+ // src/scaffold/add.ts
3365
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
3366
+ import process13 from "process";
3367
+ import { parseDocument } from "yaml";
3368
+ function add(options) {
3369
+ validateName(options.name);
3370
+ const stdout = options.write ?? ((chunk) => void process13.stdout.write(chunk));
3371
+ const fileReader = options.fileReader ?? ((p) => readFileSync3(p, "utf-8"));
3372
+ const fileWriter = options.fileWriter ?? ((p, c) => writeFileSync2(p, c, "utf-8"));
3373
+ const resolvePath = options.resolvePath ?? resolveConfigPath;
3374
+ let targetPath;
3375
+ try {
3376
+ targetPath = resolvePath(options.configPath);
3377
+ } catch (error) {
3378
+ const message = error instanceof Error ? error.message : String(error);
3379
+ throw new Error(`${message}
3380
+ Hint: run 'dynmcp init' to create a starter config file.`);
3381
+ }
3382
+ const raw = fileReader(targetPath);
3383
+ const format = detectFormat(targetPath);
3384
+ const entry = buildEntry(options);
3385
+ const parsed = transportConfigSchema.safeParse(entry);
3386
+ if (!parsed.success) {
3387
+ const issues = parsed.error.issues.map((i) => ` - ${i.path.join(".") || "<root>"}: ${i.message}`).join("\n");
3388
+ throw new Error(`Invalid MCP entry:
3389
+ ${issues}`);
3390
+ }
3391
+ const next = format === "yaml" ? writeYaml(raw, options.name, parsed.data, options.force === true) : writeJson(raw, options.name, parsed.data, options.force === true);
3392
+ fileWriter(targetPath, next);
3393
+ stdout(`Added '${options.name}' (${options.transport}) to ${targetPath}
3394
+ `);
3395
+ }
3396
+ function validateName(name) {
3397
+ if (!MCP_NAME_PATTERN.test(name)) {
3398
+ throw new Error(
3399
+ `Invalid MCP name '${name}'. Names must match ${MCP_NAME_PATTERN.source} (lowercase letters, digits, and dashes; starting with a letter or digit).`
3400
+ );
3401
+ }
3402
+ }
3403
+ function buildEntry(options) {
3404
+ if (options.transport === "stdio") {
3405
+ if (options.command === void 0 || options.command.length === 0) {
3406
+ throw new Error("--command is required for stdio transport");
3407
+ }
3408
+ const entry2 = {
3409
+ transport: "stdio",
3410
+ command: options.command
3411
+ };
3412
+ if (options.description !== void 0) entry2.description = options.description;
3413
+ if (options.args !== void 0 && options.args.length > 0) {
3414
+ entry2.args = options.args;
3415
+ }
3416
+ if (options.envVars !== void 0 && options.envVars.length > 0) {
3417
+ entry2.env = parseKeyValuePairs(options.envVars, "--env");
3418
+ }
3419
+ return entry2;
3420
+ }
3421
+ if (options.url === void 0 || options.url.length === 0) {
3422
+ throw new Error(`--url is required for ${options.transport} transport`);
3423
+ }
3424
+ const entry = {
3425
+ transport: options.transport,
3426
+ url: options.url
3427
+ };
3428
+ if (options.description !== void 0) entry.description = options.description;
3429
+ if (options.headers !== void 0 && options.headers.length > 0) {
3430
+ entry.headers = parseHeaderPairs(options.headers);
3431
+ }
3432
+ const auth2 = buildAuthBlock(options);
3433
+ if (auth2 !== void 0) entry.auth = auth2;
3434
+ return entry;
3435
+ }
3436
+ function buildAuthBlock(options) {
3437
+ const hasAny = options.clientId !== void 0 || options.clientSecret !== void 0 || options.scope !== void 0;
3438
+ if (!hasAny) return void 0;
3439
+ if (options.clientId === void 0) {
3440
+ throw new Error("--client-id is required when --client-secret or --scope is provided");
3441
+ }
3442
+ const auth2 = { client_id: options.clientId };
3443
+ if (options.clientSecret !== void 0) auth2.client_secret = options.clientSecret;
3444
+ if (options.scope !== void 0) auth2.scope = options.scope;
3445
+ return auth2;
3446
+ }
3447
+ function parseKeyValuePairs(pairs, flag) {
3448
+ const out = {};
3449
+ for (const pair of pairs) {
3450
+ const eq = pair.indexOf("=");
3451
+ if (eq <= 0) {
3452
+ throw new Error(`${flag} expects KEY=VALUE (got: ${JSON.stringify(pair)})`);
3453
+ }
3454
+ const key = pair.slice(0, eq);
3455
+ out[key] = pair.slice(eq + 1);
3456
+ }
3457
+ return out;
3458
+ }
3459
+ function parseHeaderPairs(pairs) {
3460
+ const out = {};
3461
+ for (const pair of pairs) {
3462
+ const colon = pair.indexOf(":");
3463
+ if (colon <= 0) {
3464
+ throw new Error(`--header expects "Name: Value" (got: ${JSON.stringify(pair)})`);
3465
+ }
3466
+ const key = pair.slice(0, colon).trim();
3467
+ const value = pair.slice(colon + 1).trim();
3468
+ if (key.length === 0) {
3469
+ throw new Error(`--header name cannot be empty (got: ${JSON.stringify(pair)})`);
3470
+ }
3471
+ out[key] = value;
3472
+ }
3473
+ return out;
3474
+ }
3475
+ function writeJson(raw, name, entry, force) {
3476
+ let parsed;
3477
+ try {
3478
+ parsed = JSON.parse(raw);
3479
+ } catch (error) {
3480
+ const message = error instanceof Error ? error.message : String(error);
3481
+ throw new Error(`Failed to parse config as JSON: ${message}`);
3482
+ }
3483
+ if (!isPlainObject(parsed)) {
3484
+ throw new Error("Top-level config must be a JSON object.");
3485
+ }
3486
+ let mcp = parsed.mcp;
3487
+ if (mcp === void 0) {
3488
+ mcp = {};
3489
+ parsed.mcp = mcp;
3490
+ } else if (!isPlainObject(mcp)) {
3491
+ throw new Error("Config field 'mcp' must be an object.");
3492
+ }
3493
+ const mcpRecord = mcp;
3494
+ if (mcpRecord[name] !== void 0 && !force) {
3495
+ throw new Error(`Entry '${name}' already exists. Use --force to overwrite.`);
3496
+ }
3497
+ mcpRecord[name] = entry;
3498
+ return `${JSON.stringify(parsed, null, 2)}
3499
+ `;
3500
+ }
3501
+ function writeYaml(raw, name, entry, force) {
3502
+ const doc = parseDocument(raw);
3503
+ if (doc.errors.length > 0) {
3504
+ const first = doc.errors[0]?.message ?? "unknown error";
3505
+ throw new Error(`Failed to parse config as YAML: ${first}`);
3506
+ }
3507
+ if (!doc.has("mcp")) {
3508
+ doc.set("mcp", {});
3509
+ }
3510
+ const path = ["mcp", name];
3511
+ if (doc.hasIn(path) && !force) {
3512
+ throw new Error(`Entry '${name}' already exists. Use --force to overwrite.`);
3513
+ }
3514
+ doc.setIn(path, entry);
3515
+ return doc.toString();
3516
+ }
3517
+ function isPlainObject(value) {
3518
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3519
+ }
3520
+
3312
3521
  // src/cli.ts
3313
3522
  var cliBanner = chalk.bold.magentaBright(
3314
3523
  figlet.textSync("DYNAMIC MCP", {
@@ -3319,36 +3528,100 @@ var cliBanner = chalk.bold.magentaBright(
3319
3528
  );
3320
3529
  var cli = new Command(package_default.name).description(package_default.description).version(package_default.version).addHelpText("beforeAll", cliBanner).addHelpText(
3321
3530
  "after",
3322
- "\nExamples:\n dynmcp -- npx -y chrome-devtools-mcp@latest\n dynmcp --config ./mcp.json\n dynmcp ls\n dynmcp test github\n dynmcp login github\n dynmcp logout github\n"
3531
+ "\nExamples:\n dynmcp -- npx -y chrome-devtools-mcp@latest\n dynmcp --config ./mcp.json\n dynmcp init\n dynmcp add filesystem --command npx --arg -y --arg @modelcontextprotocol/server-filesystem --arg /tmp\n dynmcp add github --transport streamable-http --url https://api.githubcopilot.com/mcp\n dynmcp ls\n dynmcp test github\n dynmcp login github\n dynmcp logout github\n"
3323
3532
  ).option("-c, --config <path>", "Path to config file (JSON or YAML)").option("-e, --env <path>", "Path to a .env file for environment variable interpolation").allowExcessArguments(true).passThroughOptions(true).action(async (_options, cmd) => {
3324
- const separatorIndex = process12.argv.indexOf("--");
3533
+ const separatorIndex = process14.argv.indexOf("--");
3325
3534
  const configPath = cmd.opts().config;
3326
3535
  const envFilePath = cmd.opts().env;
3327
3536
  if (separatorIndex !== -1) {
3328
- const [command, ...args] = process12.argv.slice(separatorIndex + 1);
3537
+ const [command, ...args] = process14.argv.slice(separatorIndex + 1);
3329
3538
  if (command === void 0) {
3330
- process12.stderr.write(
3539
+ process14.stderr.write(
3331
3540
  "dynmcp: no upstream command provided after --.\nUsage: dynmcp -- <command> [args...]\n"
3332
3541
  );
3333
- process12.exit(1);
3542
+ process14.exit(1);
3334
3543
  }
3335
3544
  try {
3336
3545
  await startProxy(command, args);
3337
3546
  } catch (error) {
3338
- process12.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
3547
+ process14.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
3339
3548
  `);
3340
- process12.exit(1);
3549
+ process14.exit(1);
3341
3550
  }
3342
3551
  return;
3343
3552
  }
3344
3553
  try {
3345
3554
  await startProxyFromConfig({ configPath, envFilePath });
3346
3555
  } catch (error) {
3347
- process12.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
3556
+ process14.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
3348
3557
  `);
3349
- process12.exit(1);
3558
+ process14.exit(1);
3350
3559
  }
3351
3560
  });
3561
+ cli.command("init").description("Write a starter config file (mcp.json by default) in the current directory.").option("--path <path>", "Explicit target path (extension determines format).").option("--yaml", "Write mcp.yaml instead of mcp.json (ignored if --path is set).").option("--force", "Overwrite an existing file.").action((options) => {
3562
+ try {
3563
+ init({
3564
+ ...options.path !== void 0 ? { path: options.path } : {},
3565
+ ...options.yaml === true ? { yaml: true } : {},
3566
+ ...options.force === true ? { force: true } : {}
3567
+ });
3568
+ } catch (error) {
3569
+ process14.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
3570
+ `);
3571
+ process14.exit(1);
3572
+ }
3573
+ });
3574
+ var collectRepeatable = (value, previous) => [...previous, value];
3575
+ cli.command("add <name>").description("Insert a new MCP entry into the resolved config file.").option(
3576
+ "-t, --transport <transport>",
3577
+ "Transport: stdio | streamable-http | sse (default: stdio).",
3578
+ "stdio"
3579
+ ).option("-c, --config <path>", "Path to config file (otherwise auto-discovered).").option("--description <text>", "Per-entry description; presence makes the entry lazy.").option("--command <cmd>", "(stdio) Command to spawn for the upstream MCP.").option(
3580
+ "--arg <arg>",
3581
+ "(stdio) Repeatable positional argument passed after --command.",
3582
+ collectRepeatable,
3583
+ []
3584
+ ).option(
3585
+ "--env <KEY=VAL>",
3586
+ "(stdio) Repeatable env var for the spawned process.",
3587
+ collectRepeatable,
3588
+ []
3589
+ ).option("--url <url>", "(http/sse) Endpoint URL.").option(
3590
+ "--header <header>",
3591
+ '(http/sse) Repeatable "Name: Value" header.',
3592
+ collectRepeatable,
3593
+ []
3594
+ ).option("--client-id <id>", "(http/sse) Pre-registered OAuth client_id (skips DCR).").option("--client-secret <secret>", "(http/sse) Pre-registered OAuth client_secret.").option("--scope <scope>", "(http/sse) OAuth scope to request.").option("--force", "Overwrite an existing entry with the same name.").action(
3595
+ (name, options) => {
3596
+ try {
3597
+ const transport = options.transport;
3598
+ if (transport !== "stdio" && transport !== "streamable-http" && transport !== "sse") {
3599
+ throw new Error(
3600
+ `Invalid --transport '${options.transport}'. Must be one of: stdio, streamable-http, sse.`
3601
+ );
3602
+ }
3603
+ add({
3604
+ name,
3605
+ transport,
3606
+ ...options.config !== void 0 ? { configPath: options.config } : {},
3607
+ ...options.force === true ? { force: true } : {},
3608
+ ...options.description !== void 0 ? { description: options.description } : {},
3609
+ ...options.command !== void 0 ? { command: options.command } : {},
3610
+ ...options.arg.length > 0 ? { args: options.arg } : {},
3611
+ ...options.env.length > 0 ? { envVars: options.env } : {},
3612
+ ...options.url !== void 0 ? { url: options.url } : {},
3613
+ ...options.header.length > 0 ? { headers: options.header } : {},
3614
+ ...options.clientId !== void 0 ? { clientId: options.clientId } : {},
3615
+ ...options.clientSecret !== void 0 ? { clientSecret: options.clientSecret } : {},
3616
+ ...options.scope !== void 0 ? { scope: options.scope } : {}
3617
+ });
3618
+ } catch (error) {
3619
+ process14.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
3620
+ `);
3621
+ process14.exit(1);
3622
+ }
3623
+ }
3624
+ );
3352
3625
  cli.command("login <name>").description("Run the OAuth authorization-code flow for an upstream MCP and store tokens.").option("-c, --config <path>", "Path to config file (JSON or YAML)").option("-e, --env <path>", "Path to a .env file for environment variable interpolation").action(async (name, options) => {
3353
3626
  try {
3354
3627
  await login({
@@ -3357,9 +3630,9 @@ cli.command("login <name>").description("Run the OAuth authorization-code flow f
3357
3630
  ...options.env !== void 0 ? { envFilePath: options.env } : {}
3358
3631
  });
3359
3632
  } catch (error) {
3360
- process12.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
3633
+ process14.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
3361
3634
  `);
3362
- process12.exit(1);
3635
+ process14.exit(1);
3363
3636
  }
3364
3637
  });
3365
3638
  cli.command("logout <name>").description("Delete the OAuth keychain entry for an upstream MCP.").option("-c, --config <path>", "Path to config file (JSON or YAML)").option("-e, --env <path>", "Path to a .env file for environment variable interpolation").action(async (name, options) => {
@@ -3370,9 +3643,9 @@ cli.command("logout <name>").description("Delete the OAuth keychain entry for an
3370
3643
  ...options.env !== void 0 ? { envFilePath: options.env } : {}
3371
3644
  });
3372
3645
  } catch (error) {
3373
- process12.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
3646
+ process14.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
3374
3647
  `);
3375
- process12.exit(1);
3648
+ process14.exit(1);
3376
3649
  }
3377
3650
  });
3378
3651
  cli.command("ls").description("List configured upstream MCPs with transport, mode, endpoint, and auth status.").option("-c, --config <path>", "Path to config file (JSON or YAML)").option("-e, --env <path>", "Path to a .env file for environment variable interpolation").option("--json", "Emit JSON instead of the aligned text table").action(async (options) => {
@@ -3383,9 +3656,9 @@ cli.command("ls").description("List configured upstream MCPs with transport, mod
3383
3656
  ...options.json === true ? { json: true } : {}
3384
3657
  });
3385
3658
  } catch (error) {
3386
- process12.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
3659
+ process14.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
3387
3660
  `);
3388
- process12.exit(1);
3661
+ process14.exit(1);
3389
3662
  }
3390
3663
  });
3391
3664
  cli.command("test [name]").description("Probe one or all configured upstream MCPs and print their discovered catalogs.").option("-c, --config <path>", "Path to config file (JSON or YAML)").option("-e, --env <path>", "Path to a .env file for environment variable interpolation").option("--json", "Emit JSON instead of the formatted text output").option("--timeout <ms>", "Per-MCP timeout in milliseconds (default: 15000)", (v) => Number(v)).action(
@@ -3398,19 +3671,19 @@ cli.command("test [name]").description("Probe one or all configured upstream MCP
3398
3671
  ...options.json === true ? { json: true } : {},
3399
3672
  ...options.timeout !== void 0 && !Number.isNaN(options.timeout) ? { timeoutMs: options.timeout } : {}
3400
3673
  });
3401
- if (exitCode !== 0) process12.exit(exitCode);
3674
+ if (exitCode !== 0) process14.exit(exitCode);
3402
3675
  } catch (error) {
3403
- process12.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
3676
+ process14.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
3404
3677
  `);
3405
- process12.exit(1);
3678
+ process14.exit(1);
3406
3679
  }
3407
3680
  }
3408
3681
  );
3409
3682
 
3410
3683
  // src/index.ts
3411
- import process13 from "process";
3684
+ import process15 from "process";
3412
3685
  async function main() {
3413
- cli.parse(process13.argv);
3686
+ cli.parse(process15.argv);
3414
3687
  }
3415
3688
  main();
3416
3689
  //# sourceMappingURL=index.js.map