dynmcp 0.1.1 → 0.2.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/README.md +59 -0
- package/dist/index.cjs +238 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +241 -57
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/schema/mcp-config.json +10 -0
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import
|
|
4
|
+
import process6 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.
|
|
10
|
+
version: "0.2.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",
|
|
@@ -74,6 +74,7 @@ var package_default = {
|
|
|
74
74
|
boxen: "^8.0.1",
|
|
75
75
|
chalk: "^5.6.2",
|
|
76
76
|
commander: "^14.0.3",
|
|
77
|
+
dotenv: "^17.4.2",
|
|
77
78
|
enquirer: "^2.4.1",
|
|
78
79
|
fastmcp: "^4.0.1",
|
|
79
80
|
figlet: "^1.11.0",
|
|
@@ -99,13 +100,16 @@ import figlet from "figlet";
|
|
|
99
100
|
import chalk from "chalk";
|
|
100
101
|
|
|
101
102
|
// src/proxy/index.ts
|
|
102
|
-
import
|
|
103
|
+
import process5 from "process";
|
|
103
104
|
import { StdioClientTransport as StdioClientTransport2 } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
104
105
|
|
|
105
106
|
// src/config/schema.ts
|
|
106
107
|
import { z } from "zod";
|
|
107
108
|
var MCP_NAME_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
|
|
108
109
|
var mcpName = z.string().regex(MCP_NAME_PATTERN);
|
|
110
|
+
var envModeSchema = z.enum(["enable", "dotenv", "process", "disable"]).describe(
|
|
111
|
+
'Controls environment variable interpolation in config values. "enable" (default) merges .env and process.env (.env wins). "dotenv" loads .env only. "process" uses process.env only. "disable" turns interpolation off.'
|
|
112
|
+
);
|
|
109
113
|
var stdioTransport = z.object({
|
|
110
114
|
transport: z.literal("stdio"),
|
|
111
115
|
command: z.string(),
|
|
@@ -131,51 +135,227 @@ var transportConfig = z.discriminatedUnion("transport", [
|
|
|
131
135
|
sseTransport
|
|
132
136
|
]);
|
|
133
137
|
var mcpConfigSchema = z.object({
|
|
138
|
+
env: envModeSchema.optional(),
|
|
134
139
|
mcp: z.record(mcpName, transportConfig).refine((obj) => Object.keys(obj).length > 0, { message: "At least one MCP must be configured" })
|
|
135
140
|
});
|
|
136
141
|
|
|
137
142
|
// src/config/loader.ts
|
|
138
|
-
import { readFileSync } from "fs";
|
|
139
|
-
import {
|
|
140
|
-
import
|
|
143
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
144
|
+
import { resolve as resolve2 } from "path";
|
|
145
|
+
import process2 from "process";
|
|
141
146
|
import { parse as parseYaml } from "yaml";
|
|
147
|
+
|
|
148
|
+
// src/config/env-sources.ts
|
|
149
|
+
import { existsSync, readFileSync } from "fs";
|
|
150
|
+
import { resolve } from "path";
|
|
151
|
+
import process from "process";
|
|
152
|
+
import dotenv from "dotenv";
|
|
153
|
+
var DEFAULT_DOTENV_FILENAME = ".env";
|
|
154
|
+
function loadEnv(options) {
|
|
155
|
+
const { mode, envFilePath, cwd = process.cwd(), processEnv = process.env } = options;
|
|
156
|
+
if (envFilePath !== void 0 && (mode === "disable" || mode === "process")) {
|
|
157
|
+
throw new Error(
|
|
158
|
+
`--env flag is incompatible with env mode "${mode}". --env requires env mode "enable" or "dotenv".`
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
if (mode === "disable") {
|
|
162
|
+
return { variables: {}, interpolationEnabled: false };
|
|
163
|
+
}
|
|
164
|
+
const dotenvVars = mode === "process" ? {} : readDotenvFile(envFilePath, cwd);
|
|
165
|
+
const processVars = mode === "dotenv" ? {} : filterDefined(processEnv);
|
|
166
|
+
const variables = { ...processVars, ...dotenvVars };
|
|
167
|
+
return { variables, interpolationEnabled: true };
|
|
168
|
+
}
|
|
169
|
+
function readDotenvFile(envFilePath, cwd) {
|
|
170
|
+
const isExplicit = envFilePath !== void 0;
|
|
171
|
+
const resolvedPath = isExplicit ? resolve(envFilePath) : resolve(cwd, DEFAULT_DOTENV_FILENAME);
|
|
172
|
+
if (!existsSync(resolvedPath)) {
|
|
173
|
+
if (isExplicit) {
|
|
174
|
+
throw new Error(`.env file not found: ${resolvedPath}`);
|
|
175
|
+
}
|
|
176
|
+
return {};
|
|
177
|
+
}
|
|
178
|
+
let raw;
|
|
179
|
+
try {
|
|
180
|
+
raw = readFileSync(resolvedPath, "utf-8");
|
|
181
|
+
} catch (readError) {
|
|
182
|
+
const message = readError instanceof Error ? readError.message : String(readError);
|
|
183
|
+
throw new Error(`Failed to read .env file (${resolvedPath}): ${message}`);
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
return dotenv.parse(raw);
|
|
187
|
+
} catch (parseError) {
|
|
188
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
189
|
+
throw new Error(`Failed to parse .env file (${resolvedPath}): ${message}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function filterDefined(env) {
|
|
193
|
+
const result = {};
|
|
194
|
+
for (const [key, value] of Object.entries(env)) {
|
|
195
|
+
if (value !== void 0) {
|
|
196
|
+
result[key] = value;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// src/config/interpolate.ts
|
|
203
|
+
var TOP_LEVEL_PASSTHROUGH_KEYS = /* @__PURE__ */ new Set(["$schema", "env"]);
|
|
204
|
+
var MissingEnvVarsError = class extends Error {
|
|
205
|
+
constructor(missingVars) {
|
|
206
|
+
const list = missingVars.join(", ");
|
|
207
|
+
const plural = missingVars.length === 1 ? "" : "s";
|
|
208
|
+
super(`Missing required environment variable${plural}: ${list}`);
|
|
209
|
+
this.missingVars = missingVars;
|
|
210
|
+
this.name = "MissingEnvVarsError";
|
|
211
|
+
}
|
|
212
|
+
missingVars;
|
|
213
|
+
};
|
|
214
|
+
function interpolateConfig(config, env) {
|
|
215
|
+
if (config === null || typeof config !== "object" || Array.isArray(config)) {
|
|
216
|
+
return config;
|
|
217
|
+
}
|
|
218
|
+
const missing = [];
|
|
219
|
+
const result = {};
|
|
220
|
+
for (const [key, value] of Object.entries(config)) {
|
|
221
|
+
if (TOP_LEVEL_PASSTHROUGH_KEYS.has(key)) {
|
|
222
|
+
result[key] = value;
|
|
223
|
+
} else {
|
|
224
|
+
result[key] = walkNode(value, env, missing);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (missing.length > 0) {
|
|
228
|
+
const unique = Array.from(new Set(missing)).sort();
|
|
229
|
+
throw new MissingEnvVarsError(unique);
|
|
230
|
+
}
|
|
231
|
+
return result;
|
|
232
|
+
}
|
|
233
|
+
function walkNode(node, env, missing) {
|
|
234
|
+
if (typeof node === "string") {
|
|
235
|
+
return interpolateString(node, env, missing);
|
|
236
|
+
}
|
|
237
|
+
if (Array.isArray(node)) {
|
|
238
|
+
return node.map((item) => walkNode(item, env, missing));
|
|
239
|
+
}
|
|
240
|
+
if (node !== null && typeof node === "object") {
|
|
241
|
+
const result = {};
|
|
242
|
+
for (const [key, value] of Object.entries(node)) {
|
|
243
|
+
result[key] = walkNode(value, env, missing);
|
|
244
|
+
}
|
|
245
|
+
return result;
|
|
246
|
+
}
|
|
247
|
+
return node;
|
|
248
|
+
}
|
|
249
|
+
function interpolateString(value, env, missing) {
|
|
250
|
+
let result = "";
|
|
251
|
+
let i = 0;
|
|
252
|
+
const len = value.length;
|
|
253
|
+
while (i < len) {
|
|
254
|
+
const ch = value[i];
|
|
255
|
+
if (ch === "$" && value[i + 1] === "$" && value[i + 2] === "{") {
|
|
256
|
+
const close = value.indexOf("}", i + 3);
|
|
257
|
+
if (close === -1) {
|
|
258
|
+
result += ch;
|
|
259
|
+
i += 1;
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
result += value.substring(i + 1, close + 1);
|
|
263
|
+
i = close + 1;
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (ch === "$" && value[i + 1] === "{") {
|
|
267
|
+
const close = value.indexOf("}", i + 2);
|
|
268
|
+
if (close === -1) {
|
|
269
|
+
result += value.substring(i);
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
const expr = value.substring(i + 2, close);
|
|
273
|
+
const { name, defaultValue } = parseExpr(expr);
|
|
274
|
+
const resolved = env[name];
|
|
275
|
+
const hasValue = resolved !== void 0 && resolved !== "";
|
|
276
|
+
if (hasValue) {
|
|
277
|
+
result += resolved;
|
|
278
|
+
} else if (defaultValue !== void 0) {
|
|
279
|
+
result += defaultValue;
|
|
280
|
+
} else if (resolved !== void 0) {
|
|
281
|
+
result += "";
|
|
282
|
+
} else {
|
|
283
|
+
missing.push(name);
|
|
284
|
+
}
|
|
285
|
+
i = close + 1;
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
result += ch;
|
|
289
|
+
i += 1;
|
|
290
|
+
}
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
293
|
+
function parseExpr(expr) {
|
|
294
|
+
const sep = expr.indexOf(":-");
|
|
295
|
+
if (sep === -1) {
|
|
296
|
+
return { name: expr, defaultValue: void 0 };
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
name: expr.substring(0, sep),
|
|
300
|
+
defaultValue: expr.substring(sep + 2)
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// src/config/loader.ts
|
|
142
305
|
var AUTO_DISCOVER_NAMES = ["mcp.json", ".mcp.json"];
|
|
306
|
+
var DEFAULT_ENV_MODE = "enable";
|
|
307
|
+
var VALID_ENV_MODES = ["enable", "dotenv", "process", "disable"];
|
|
143
308
|
function resolveConfigPath(explicitPath) {
|
|
144
309
|
if (explicitPath) {
|
|
145
|
-
const resolved =
|
|
146
|
-
if (!
|
|
310
|
+
const resolved = resolve2(explicitPath);
|
|
311
|
+
if (!existsSync2(resolved)) {
|
|
147
312
|
throw new Error(`Config file not found: ${resolved}`);
|
|
148
313
|
}
|
|
149
314
|
return resolved;
|
|
150
315
|
}
|
|
151
|
-
const cwd =
|
|
316
|
+
const cwd = process2.cwd();
|
|
152
317
|
for (const name of AUTO_DISCOVER_NAMES) {
|
|
153
|
-
const candidate =
|
|
154
|
-
if (
|
|
318
|
+
const candidate = resolve2(cwd, name);
|
|
319
|
+
if (existsSync2(candidate)) {
|
|
155
320
|
return candidate;
|
|
156
321
|
}
|
|
157
322
|
}
|
|
158
|
-
const searched = AUTO_DISCOVER_NAMES.map((n) =>
|
|
323
|
+
const searched = AUTO_DISCOVER_NAMES.map((n) => resolve2(cwd, n)).join(", ");
|
|
159
324
|
throw new Error(`No config file found. Searched: ${searched}`);
|
|
160
325
|
}
|
|
161
|
-
function loadConfig(
|
|
162
|
-
const configPath =
|
|
163
|
-
const
|
|
326
|
+
function loadConfig(options = {}) {
|
|
327
|
+
const { configPath, envFilePath } = options;
|
|
328
|
+
const resolvedPath = resolveConfigPath(configPath);
|
|
329
|
+
const raw = readFileSync2(resolvedPath, "utf-8");
|
|
164
330
|
let content;
|
|
165
331
|
try {
|
|
166
|
-
content = isYamlFile(
|
|
332
|
+
content = isYamlFile(resolvedPath) ? parseYaml(raw) : JSON.parse(raw);
|
|
167
333
|
} catch (parseError) {
|
|
168
334
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
169
|
-
throw new Error(`Failed to parse config file (${
|
|
335
|
+
throw new Error(`Failed to parse config file (${resolvedPath}): ${message}`);
|
|
170
336
|
}
|
|
171
|
-
const
|
|
337
|
+
const envMode = readEnvMode(content);
|
|
338
|
+
const loadedEnv = loadEnv({ mode: envMode, envFilePath });
|
|
339
|
+
const interpolated = loadedEnv.interpolationEnabled ? interpolateConfig(content, loadedEnv.variables) : content;
|
|
340
|
+
const result = mcpConfigSchema.safeParse(interpolated);
|
|
172
341
|
if (!result.success) {
|
|
173
342
|
const formatted = result.error.issues.map((issue) => ` - ${issue.path.join(".")}: ${issue.message}`).join("\n");
|
|
174
|
-
throw new Error(`Invalid config file (${
|
|
343
|
+
throw new Error(`Invalid config file (${resolvedPath}):
|
|
175
344
|
${formatted}`);
|
|
176
345
|
}
|
|
177
346
|
return result.data;
|
|
178
347
|
}
|
|
348
|
+
function readEnvMode(content) {
|
|
349
|
+
if (content === null || typeof content !== "object" || Array.isArray(content)) {
|
|
350
|
+
return DEFAULT_ENV_MODE;
|
|
351
|
+
}
|
|
352
|
+
const value = content.env;
|
|
353
|
+
if (value === void 0) return DEFAULT_ENV_MODE;
|
|
354
|
+
if (typeof value === "string" && VALID_ENV_MODES.includes(value)) {
|
|
355
|
+
return value;
|
|
356
|
+
}
|
|
357
|
+
return DEFAULT_ENV_MODE;
|
|
358
|
+
}
|
|
179
359
|
function isYamlFile(filePath) {
|
|
180
360
|
return filePath.endsWith(".yml") || filePath.endsWith(".yaml");
|
|
181
361
|
}
|
|
@@ -316,7 +496,7 @@ function buildAnnotationLines(tool) {
|
|
|
316
496
|
}
|
|
317
497
|
|
|
318
498
|
// src/proxy/upstream-client.ts
|
|
319
|
-
import
|
|
499
|
+
import process3 from "process";
|
|
320
500
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
321
501
|
var UpstreamClient = class {
|
|
322
502
|
transport;
|
|
@@ -325,7 +505,7 @@ var UpstreamClient = class {
|
|
|
325
505
|
constructor({ name, transport, onTransportError }) {
|
|
326
506
|
this.transport = transport;
|
|
327
507
|
this.onTransportError = onTransportError ?? ((error) => {
|
|
328
|
-
|
|
508
|
+
process3.stderr.write(`[${name}] Upstream MCP transport error: ${error.message}
|
|
329
509
|
`);
|
|
330
510
|
});
|
|
331
511
|
}
|
|
@@ -437,7 +617,7 @@ var Orchestrator = class {
|
|
|
437
617
|
};
|
|
438
618
|
|
|
439
619
|
// src/proxy/server.ts
|
|
440
|
-
import
|
|
620
|
+
import process4 from "process";
|
|
441
621
|
import { FastMCP } from "fastmcp";
|
|
442
622
|
import { z as z3 } from "zod";
|
|
443
623
|
var ProxyServer = class {
|
|
@@ -475,7 +655,7 @@ var ProxyServer = class {
|
|
|
475
655
|
return result;
|
|
476
656
|
}
|
|
477
657
|
});
|
|
478
|
-
|
|
658
|
+
process4.stderr.write("Starting dynamic-discovery-mcp server over stdio\n");
|
|
479
659
|
await server.start({ transportType: "stdio" });
|
|
480
660
|
}
|
|
481
661
|
};
|
|
@@ -488,7 +668,7 @@ async function startProxy(command, args) {
|
|
|
488
668
|
name: command,
|
|
489
669
|
transport,
|
|
490
670
|
onTransportError: (error) => {
|
|
491
|
-
|
|
671
|
+
process5.stderr.write(`Upstream MCP transport error: ${error.message}
|
|
492
672
|
`);
|
|
493
673
|
shutdown(1);
|
|
494
674
|
}
|
|
@@ -497,36 +677,36 @@ async function startProxy(command, args) {
|
|
|
497
677
|
if (isShuttingDown) return;
|
|
498
678
|
isShuttingDown = true;
|
|
499
679
|
upstreamClient.disconnect().catch((error) => {
|
|
500
|
-
|
|
680
|
+
process5.stderr.write(
|
|
501
681
|
`dynmcp: error during disconnect: ${error instanceof Error ? error.message : String(error)}
|
|
502
682
|
`
|
|
503
683
|
);
|
|
504
|
-
}).finally(() =>
|
|
684
|
+
}).finally(() => process5.exit(exitCode));
|
|
505
685
|
};
|
|
506
686
|
try {
|
|
507
687
|
await upstreamClient.connect();
|
|
508
688
|
} catch (error) {
|
|
509
|
-
|
|
689
|
+
process5.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
510
690
|
`);
|
|
511
|
-
|
|
691
|
+
process5.exit(1);
|
|
512
692
|
}
|
|
513
693
|
let tools;
|
|
514
694
|
try {
|
|
515
695
|
tools = await upstreamClient.listTools();
|
|
516
696
|
} catch (error) {
|
|
517
|
-
|
|
697
|
+
process5.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
518
698
|
`);
|
|
519
|
-
|
|
699
|
+
process5.exit(1);
|
|
520
700
|
}
|
|
521
701
|
const catalog = ToolCatalog.fromFlat(tools);
|
|
522
702
|
const proxyServer = new ProxyServer({
|
|
523
703
|
catalog,
|
|
524
704
|
callTool: (name, input) => upstreamClient.callTool(name, input)
|
|
525
705
|
});
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
706
|
+
process5.on("SIGINT", () => shutdown(0));
|
|
707
|
+
process5.on("SIGTERM", () => shutdown(0));
|
|
708
|
+
process5.stdin.on("end", () => shutdown(0));
|
|
709
|
+
process5.stdin.on("close", () => shutdown(0));
|
|
530
710
|
try {
|
|
531
711
|
await proxyServer.start();
|
|
532
712
|
} catch (error) {
|
|
@@ -534,9 +714,9 @@ async function startProxy(command, args) {
|
|
|
534
714
|
throw error;
|
|
535
715
|
}
|
|
536
716
|
}
|
|
537
|
-
async function startProxyFromConfig(
|
|
717
|
+
async function startProxyFromConfig(options = {}) {
|
|
538
718
|
let isShuttingDown = false;
|
|
539
|
-
const config = loadConfig(
|
|
719
|
+
const config = loadConfig(options);
|
|
540
720
|
const mcps = /* @__PURE__ */ new Map();
|
|
541
721
|
for (const [name, entry] of Object.entries(config.mcp)) {
|
|
542
722
|
mcps.set(name, { transport: createTransport(entry) });
|
|
@@ -544,7 +724,7 @@ async function startProxyFromConfig(configPath) {
|
|
|
544
724
|
const orchestrator = new Orchestrator({
|
|
545
725
|
mcps,
|
|
546
726
|
onTransportError: (mcpName2, error) => {
|
|
547
|
-
|
|
727
|
+
process5.stderr.write(`Upstream MCP "${mcpName2}" transport error: ${error.message}
|
|
548
728
|
`);
|
|
549
729
|
shutdown(1);
|
|
550
730
|
}
|
|
@@ -553,27 +733,27 @@ async function startProxyFromConfig(configPath) {
|
|
|
553
733
|
if (isShuttingDown) return;
|
|
554
734
|
isShuttingDown = true;
|
|
555
735
|
orchestrator.disconnectAll().catch((error) => {
|
|
556
|
-
|
|
736
|
+
process5.stderr.write(
|
|
557
737
|
`dynmcp: error during disconnect: ${error instanceof Error ? error.message : String(error)}
|
|
558
738
|
`
|
|
559
739
|
);
|
|
560
|
-
}).finally(() =>
|
|
740
|
+
}).finally(() => process5.exit(exitCode));
|
|
561
741
|
};
|
|
562
742
|
try {
|
|
563
743
|
await orchestrator.connect();
|
|
564
744
|
} catch (error) {
|
|
565
|
-
|
|
745
|
+
process5.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
566
746
|
`);
|
|
567
|
-
|
|
747
|
+
process5.exit(1);
|
|
568
748
|
}
|
|
569
749
|
const proxyServer = new ProxyServer({
|
|
570
750
|
catalog: orchestrator.catalog,
|
|
571
751
|
callTool: (name, input) => orchestrator.callTool(name, input)
|
|
572
752
|
});
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
753
|
+
process5.on("SIGINT", () => shutdown(0));
|
|
754
|
+
process5.on("SIGTERM", () => shutdown(0));
|
|
755
|
+
process5.stdin.on("end", () => shutdown(0));
|
|
756
|
+
process5.stdin.on("close", () => shutdown(0));
|
|
577
757
|
try {
|
|
578
758
|
await proxyServer.start();
|
|
579
759
|
} catch (error) {
|
|
@@ -593,39 +773,43 @@ var cliBanner = chalk.bold.magentaBright(
|
|
|
593
773
|
var cli = new Command(package_default.name).description(package_default.description).version(package_default.version).addHelpText("beforeAll", cliBanner).addHelpText(
|
|
594
774
|
"after",
|
|
595
775
|
"\nExamples:\n dynmcp -- npx -y chrome-devtools-mcp@latest\n dynmcp --config ./mcp.json\n"
|
|
596
|
-
).option("-c, --config <path>", "Path to config file (JSON or YAML)").
|
|
597
|
-
|
|
776
|
+
).option("-c, --config <path>", "Path to config file (JSON or YAML)").option(
|
|
777
|
+
"-e, --env <path>",
|
|
778
|
+
"Path to a .env file for environment variable interpolation"
|
|
779
|
+
).allowExcessArguments(true).passThroughOptions(true).action(async (_options, cmd) => {
|
|
780
|
+
const separatorIndex = process6.argv.indexOf("--");
|
|
598
781
|
const configPath = cmd.opts().config;
|
|
782
|
+
const envFilePath = cmd.opts().env;
|
|
599
783
|
if (separatorIndex !== -1) {
|
|
600
|
-
const [command, ...args] =
|
|
784
|
+
const [command, ...args] = process6.argv.slice(separatorIndex + 1);
|
|
601
785
|
if (command === void 0) {
|
|
602
|
-
|
|
786
|
+
process6.stderr.write(
|
|
603
787
|
"dynmcp: no upstream command provided after --.\nUsage: dynmcp -- <command> [args...]\n"
|
|
604
788
|
);
|
|
605
|
-
|
|
789
|
+
process6.exit(1);
|
|
606
790
|
}
|
|
607
791
|
try {
|
|
608
792
|
await startProxy(command, args);
|
|
609
793
|
} catch (error) {
|
|
610
|
-
|
|
794
|
+
process6.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
611
795
|
`);
|
|
612
|
-
|
|
796
|
+
process6.exit(1);
|
|
613
797
|
}
|
|
614
798
|
return;
|
|
615
799
|
}
|
|
616
800
|
try {
|
|
617
|
-
await startProxyFromConfig(configPath);
|
|
801
|
+
await startProxyFromConfig({ configPath, envFilePath });
|
|
618
802
|
} catch (error) {
|
|
619
|
-
|
|
803
|
+
process6.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
620
804
|
`);
|
|
621
|
-
|
|
805
|
+
process6.exit(1);
|
|
622
806
|
}
|
|
623
807
|
});
|
|
624
808
|
|
|
625
809
|
// src/index.ts
|
|
626
|
-
import
|
|
810
|
+
import process7 from "process";
|
|
627
811
|
async function main() {
|
|
628
|
-
cli.parse(
|
|
812
|
+
cli.parse(process7.argv);
|
|
629
813
|
}
|
|
630
814
|
main();
|
|
631
815
|
//# sourceMappingURL=index.js.map
|