dynmcp 0.5.0 → 0.6.1
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.cjs +307 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +307 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -23,13 +23,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
));
|
|
24
24
|
|
|
25
25
|
// src/cli.ts
|
|
26
|
-
var
|
|
26
|
+
var import_node_process14 = __toESM(require("process"), 1);
|
|
27
27
|
var import_commander = require("commander");
|
|
28
28
|
|
|
29
29
|
// package.json
|
|
30
30
|
var package_default = {
|
|
31
31
|
name: "dynmcp",
|
|
32
|
-
version: "0.
|
|
32
|
+
version: "0.6.1",
|
|
33
33
|
description: "Dynamic MCP context management tool for AI MCP-enabled agents and clients.",
|
|
34
34
|
author: "Brandon Burrus <brandon@burrus.io>",
|
|
35
35
|
license: "MIT",
|
|
@@ -487,14 +487,14 @@ var sseTransport = import_zod.z.object({
|
|
|
487
487
|
headers: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
|
|
488
488
|
auth: authConfig
|
|
489
489
|
}).strict();
|
|
490
|
-
var
|
|
490
|
+
var transportConfigSchema = import_zod.z.discriminatedUnion("transport", [
|
|
491
491
|
stdioTransport,
|
|
492
492
|
streamableHttpTransport,
|
|
493
493
|
sseTransport
|
|
494
494
|
]);
|
|
495
495
|
var mcpConfigSchema = import_zod.z.object({
|
|
496
496
|
env: envModeSchema.optional(),
|
|
497
|
-
mcp: import_zod.z.record(mcpName,
|
|
497
|
+
mcp: import_zod.z.record(mcpName, transportConfigSchema).refine((obj) => Object.keys(obj).length > 0, { message: "At least one MCP must be configured" })
|
|
498
498
|
});
|
|
499
499
|
|
|
500
500
|
// src/config/loader.ts
|
|
@@ -726,7 +726,7 @@ var import_node_child_process = require("child_process");
|
|
|
726
726
|
var import_node_process3 = __toESM(require("process"), 1);
|
|
727
727
|
async function openUrl(url) {
|
|
728
728
|
const { command, args } = openerForPlatform(url);
|
|
729
|
-
return new Promise((
|
|
729
|
+
return new Promise((resolve4, reject) => {
|
|
730
730
|
const child = (0, import_node_child_process.spawn)(command, args, {
|
|
731
731
|
stdio: "ignore",
|
|
732
732
|
detached: true
|
|
@@ -734,7 +734,7 @@ async function openUrl(url) {
|
|
|
734
734
|
child.once("error", reject);
|
|
735
735
|
child.once("spawn", () => {
|
|
736
736
|
child.unref();
|
|
737
|
-
|
|
737
|
+
resolve4();
|
|
738
738
|
});
|
|
739
739
|
});
|
|
740
740
|
}
|
|
@@ -809,14 +809,14 @@ var CallbackServer = class _CallbackServer {
|
|
|
809
809
|
throw new Error("CallbackServer is already started.");
|
|
810
810
|
}
|
|
811
811
|
const server = (0, import_node_http.createServer)((req, res) => this.handleRequest(req, res));
|
|
812
|
-
await new Promise((
|
|
812
|
+
await new Promise((resolve4, reject) => {
|
|
813
813
|
const onError = (err) => {
|
|
814
814
|
server.removeListener("listening", onListening);
|
|
815
815
|
reject(err);
|
|
816
816
|
};
|
|
817
817
|
const onListening = () => {
|
|
818
818
|
server.removeListener("error", onError);
|
|
819
|
-
|
|
819
|
+
resolve4();
|
|
820
820
|
};
|
|
821
821
|
server.once("error", onError);
|
|
822
822
|
server.once("listening", onListening);
|
|
@@ -854,12 +854,12 @@ var CallbackServer = class _CallbackServer {
|
|
|
854
854
|
if (this.pending !== null) {
|
|
855
855
|
return Promise.reject(new Error("awaitCallback already in progress."));
|
|
856
856
|
}
|
|
857
|
-
return new Promise((
|
|
857
|
+
return new Promise((resolve4, reject) => {
|
|
858
858
|
const timer = setTimeout(() => {
|
|
859
859
|
this.pending = null;
|
|
860
860
|
reject(new CallbackTimeoutError(timeoutMs));
|
|
861
861
|
}, timeoutMs);
|
|
862
|
-
this.pending = { resolve:
|
|
862
|
+
this.pending = { resolve: resolve4, reject, timer };
|
|
863
863
|
});
|
|
864
864
|
}
|
|
865
865
|
/** Closes the listening socket. Safe to call multiple times. */
|
|
@@ -869,8 +869,8 @@ var CallbackServer = class _CallbackServer {
|
|
|
869
869
|
this.pending = null;
|
|
870
870
|
}
|
|
871
871
|
if (this.server === null) return;
|
|
872
|
-
await new Promise((
|
|
873
|
-
this.server.close(() =>
|
|
872
|
+
await new Promise((resolve4) => {
|
|
873
|
+
this.server.close(() => resolve4());
|
|
874
874
|
});
|
|
875
875
|
this.server = null;
|
|
876
876
|
this.boundPort = null;
|
|
@@ -914,10 +914,10 @@ var CallbackServer = class _CallbackServer {
|
|
|
914
914
|
}
|
|
915
915
|
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
916
916
|
res.end(SUCCESS_HTML);
|
|
917
|
-
const { resolve:
|
|
917
|
+
const { resolve: resolve4, timer } = this.pending;
|
|
918
918
|
clearTimeout(timer);
|
|
919
919
|
this.pending = null;
|
|
920
|
-
|
|
920
|
+
resolve4({ code, state });
|
|
921
921
|
}
|
|
922
922
|
respondError(res, errorCode, description2) {
|
|
923
923
|
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
|
+
var import_node_fs3 = require("fs");
|
|
3314
|
+
var import_node_path4 = require("path");
|
|
3315
|
+
var import_node_process12 = __toESM(require("process"), 1);
|
|
3316
|
+
|
|
3317
|
+
// src/scaffold/format.ts
|
|
3318
|
+
var import_node_path3 = require("path");
|
|
3319
|
+
function detectFormat(filePath) {
|
|
3320
|
+
const ext = (0, import_node_path3.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 ?? import_node_process12.default.cwd();
|
|
3328
|
+
const stdout = options.write ?? ((chunk) => void import_node_process12.default.stdout.write(chunk));
|
|
3329
|
+
const fileWriter = options.fileWriter ?? ((p, c) => (0, import_node_fs3.writeFileSync)(p, c, "utf-8"));
|
|
3330
|
+
const fileExists = options.fileExists ?? ((p) => (0, import_node_fs3.existsSync)(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 (0, import_node_path4.resolve)(opts.cwd, opts.path);
|
|
3349
|
+
}
|
|
3350
|
+
return (0, import_node_path4.resolve)(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
|
+
var import_node_fs4 = require("fs");
|
|
3366
|
+
var import_node_process13 = __toESM(require("process"), 1);
|
|
3367
|
+
var import_yaml2 = require("yaml");
|
|
3368
|
+
function add(options) {
|
|
3369
|
+
validateName(options.name);
|
|
3370
|
+
const stdout = options.write ?? ((chunk) => void import_node_process13.default.stdout.write(chunk));
|
|
3371
|
+
const fileReader = options.fileReader ?? ((p) => (0, import_node_fs4.readFileSync)(p, "utf-8"));
|
|
3372
|
+
const fileWriter = options.fileWriter ?? ((p, c) => (0, import_node_fs4.writeFileSync)(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 = (0, import_yaml2.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 = import_chalk.default.bold.magentaBright(
|
|
3314
3523
|
import_figlet.default.textSync("DYNAMIC MCP", {
|
|
@@ -3319,36 +3528,100 @@ var cliBanner = import_chalk.default.bold.magentaBright(
|
|
|
3319
3528
|
);
|
|
3320
3529
|
var cli = new import_commander.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 =
|
|
3533
|
+
const separatorIndex = import_node_process14.default.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] =
|
|
3537
|
+
const [command, ...args] = import_node_process14.default.argv.slice(separatorIndex + 1);
|
|
3329
3538
|
if (command === void 0) {
|
|
3330
|
-
|
|
3539
|
+
import_node_process14.default.stderr.write(
|
|
3331
3540
|
"dynmcp: no upstream command provided after --.\nUsage: dynmcp -- <command> [args...]\n"
|
|
3332
3541
|
);
|
|
3333
|
-
|
|
3542
|
+
import_node_process14.default.exit(1);
|
|
3334
3543
|
}
|
|
3335
3544
|
try {
|
|
3336
3545
|
await startProxy(command, args);
|
|
3337
3546
|
} catch (error) {
|
|
3338
|
-
|
|
3547
|
+
import_node_process14.default.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
3339
3548
|
`);
|
|
3340
|
-
|
|
3549
|
+
import_node_process14.default.exit(1);
|
|
3341
3550
|
}
|
|
3342
3551
|
return;
|
|
3343
3552
|
}
|
|
3344
3553
|
try {
|
|
3345
3554
|
await startProxyFromConfig({ configPath, envFilePath });
|
|
3346
3555
|
} catch (error) {
|
|
3347
|
-
|
|
3556
|
+
import_node_process14.default.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
3348
3557
|
`);
|
|
3349
|
-
|
|
3558
|
+
import_node_process14.default.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
|
+
import_node_process14.default.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
3570
|
+
`);
|
|
3571
|
+
import_node_process14.default.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
|
+
import_node_process14.default.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
3620
|
+
`);
|
|
3621
|
+
import_node_process14.default.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
|
-
|
|
3633
|
+
import_node_process14.default.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
3361
3634
|
`);
|
|
3362
|
-
|
|
3635
|
+
import_node_process14.default.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
|
-
|
|
3646
|
+
import_node_process14.default.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
3374
3647
|
`);
|
|
3375
|
-
|
|
3648
|
+
import_node_process14.default.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
|
-
|
|
3659
|
+
import_node_process14.default.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
3387
3660
|
`);
|
|
3388
|
-
|
|
3661
|
+
import_node_process14.default.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)
|
|
3674
|
+
if (exitCode !== 0) import_node_process14.default.exit(exitCode);
|
|
3402
3675
|
} catch (error) {
|
|
3403
|
-
|
|
3676
|
+
import_node_process14.default.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
3404
3677
|
`);
|
|
3405
|
-
|
|
3678
|
+
import_node_process14.default.exit(1);
|
|
3406
3679
|
}
|
|
3407
3680
|
}
|
|
3408
3681
|
);
|
|
3409
3682
|
|
|
3410
3683
|
// src/index.ts
|
|
3411
|
-
var
|
|
3684
|
+
var import_node_process15 = __toESM(require("process"), 1);
|
|
3412
3685
|
async function main() {
|
|
3413
|
-
cli.parse(
|
|
3686
|
+
cli.parse(import_node_process15.default.argv);
|
|
3414
3687
|
}
|
|
3415
3688
|
main();
|
|
3416
3689
|
//# sourceMappingURL=index.cjs.map
|