dynmcp 0.0.1 → 0.1.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.js CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import process4 from "process";
4
+ import process5 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.0.1",
10
+ version: "0.1.1",
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",
@@ -52,9 +52,12 @@ var package_default = {
52
52
  }
53
53
  },
54
54
  files: [
55
- "dist"
55
+ "dist",
56
+ "schema"
56
57
  ],
57
58
  scripts: {
59
+ "generate:schema": "tsx scripts/generate-schema.ts",
60
+ prebuild: "tsx scripts/generate-schema.ts",
58
61
  build: "tsup",
59
62
  dev: "tsx src/index.ts",
60
63
  typecheck: "tsc --noEmit",
@@ -75,6 +78,7 @@ var package_default = {
75
78
  fastmcp: "^4.0.1",
76
79
  figlet: "^1.11.0",
77
80
  figures: "^6.1.0",
81
+ yaml: "^2.9.0",
78
82
  zod: "^4.4.3"
79
83
  },
80
84
  devDependencies: {
@@ -95,22 +99,147 @@ import figlet from "figlet";
95
99
  import chalk from "chalk";
96
100
 
97
101
  // src/proxy/index.ts
98
- import process3 from "process";
102
+ import process4 from "process";
103
+ import { StdioClientTransport as StdioClientTransport2 } from "@modelcontextprotocol/sdk/client/stdio.js";
104
+
105
+ // src/config/schema.ts
106
+ import { z } from "zod";
107
+ var MCP_NAME_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
108
+ var mcpName = z.string().regex(MCP_NAME_PATTERN);
109
+ var stdioTransport = z.object({
110
+ transport: z.literal("stdio"),
111
+ command: z.string(),
112
+ args: z.array(z.string()).optional(),
113
+ env: z.record(z.string(), z.string()).optional()
114
+ }).strict();
115
+ var httpUrl = z.string().url().refine((u) => u.startsWith("http://") || u.startsWith("https://"), {
116
+ message: "URL must use http:// or https:// scheme"
117
+ });
118
+ var streamableHttpTransport = z.object({
119
+ transport: z.literal("streamable-http"),
120
+ url: httpUrl,
121
+ headers: z.record(z.string(), z.string()).optional()
122
+ }).strict();
123
+ var sseTransport = z.object({
124
+ transport: z.literal("sse"),
125
+ url: httpUrl,
126
+ headers: z.record(z.string(), z.string()).optional()
127
+ }).strict();
128
+ var transportConfig = z.discriminatedUnion("transport", [
129
+ stdioTransport,
130
+ streamableHttpTransport,
131
+ sseTransport
132
+ ]);
133
+ var mcpConfigSchema = z.object({
134
+ mcp: z.record(mcpName, transportConfig).refine((obj) => Object.keys(obj).length > 0, { message: "At least one MCP must be configured" })
135
+ });
136
+
137
+ // src/config/loader.ts
138
+ import { readFileSync } from "fs";
139
+ import { existsSync } from "fs";
140
+ import { resolve } from "path";
141
+ import { parse as parseYaml } from "yaml";
142
+ var AUTO_DISCOVER_NAMES = ["mcp.json", ".mcp.json"];
143
+ function resolveConfigPath(explicitPath) {
144
+ if (explicitPath) {
145
+ const resolved = resolve(explicitPath);
146
+ if (!existsSync(resolved)) {
147
+ throw new Error(`Config file not found: ${resolved}`);
148
+ }
149
+ return resolved;
150
+ }
151
+ const cwd = process.cwd();
152
+ for (const name of AUTO_DISCOVER_NAMES) {
153
+ const candidate = resolve(cwd, name);
154
+ if (existsSync(candidate)) {
155
+ return candidate;
156
+ }
157
+ }
158
+ const searched = AUTO_DISCOVER_NAMES.map((n) => resolve(cwd, n)).join(", ");
159
+ throw new Error(`No config file found. Searched: ${searched}`);
160
+ }
161
+ function loadConfig(explicitPath) {
162
+ const configPath = resolveConfigPath(explicitPath);
163
+ const raw = readFileSync(configPath, "utf-8");
164
+ let content;
165
+ try {
166
+ content = isYamlFile(configPath) ? parseYaml(raw) : JSON.parse(raw);
167
+ } catch (parseError) {
168
+ const message = parseError instanceof Error ? parseError.message : String(parseError);
169
+ throw new Error(`Failed to parse config file (${configPath}): ${message}`);
170
+ }
171
+ const result = mcpConfigSchema.safeParse(content);
172
+ if (!result.success) {
173
+ const formatted = result.error.issues.map((issue) => ` - ${issue.path.join(".")}: ${issue.message}`).join("\n");
174
+ throw new Error(`Invalid config file (${configPath}):
175
+ ${formatted}`);
176
+ }
177
+ return result.data;
178
+ }
179
+ function isYamlFile(filePath) {
180
+ return filePath.endsWith(".yml") || filePath.endsWith(".yaml");
181
+ }
182
+
183
+ // src/config/json-schema.ts
184
+ import { z as z2 } from "zod";
185
+
186
+ // src/proxy/transport-factory.ts
187
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
188
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
189
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
190
+ function createTransport(config) {
191
+ switch (config.transport) {
192
+ case "stdio":
193
+ return new StdioClientTransport({
194
+ command: config.command,
195
+ args: config.args,
196
+ env: config.env
197
+ });
198
+ case "streamable-http":
199
+ return new StreamableHTTPClientTransport(
200
+ new URL(config.url),
201
+ config.headers ? { requestInit: { headers: config.headers } } : void 0
202
+ );
203
+ case "sse":
204
+ return new SSEClientTransport(
205
+ new URL(config.url),
206
+ config.headers ? { requestInit: { headers: config.headers } } : void 0
207
+ );
208
+ default: {
209
+ const _exhaustive = config;
210
+ return _exhaustive;
211
+ }
212
+ }
213
+ }
99
214
 
100
215
  // src/proxy/tool-catalog.ts
101
216
  var DISCOVER_TOOL_PREAMBLE = `Use this tool to look up the full schema of a tool before calling it with use_tool.
102
217
  Call discover_tool with a tool name from the list below to get its complete description,
103
218
  input parameters, and output schema. Always discover a tool before using it.`;
104
- var ToolCatalog = class {
219
+ var ToolCatalog = class _ToolCatalog {
105
220
  tools;
106
221
  discoverToolDescription;
107
- constructor(upstreamTools) {
222
+ constructor(tools, description) {
223
+ this.tools = tools;
224
+ this.discoverToolDescription = description;
225
+ }
226
+ static fromFlat(upstreamTools) {
108
227
  const toolMap = /* @__PURE__ */ new Map();
109
228
  for (const tool of upstreamTools) {
110
229
  toolMap.set(tool.name, tool);
111
230
  }
112
- this.tools = toolMap;
113
- this.discoverToolDescription = buildDiscoverToolDescription(upstreamTools);
231
+ const description = buildFlatDescription(upstreamTools);
232
+ return new _ToolCatalog(toolMap, description);
233
+ }
234
+ static fromGrouped(groups) {
235
+ const toolMap = /* @__PURE__ */ new Map();
236
+ for (const [mcpName2, tools] of groups) {
237
+ for (const tool of tools) {
238
+ toolMap.set(`${mcpName2}/${tool.name}`, tool);
239
+ }
240
+ }
241
+ const description = buildGroupedDescription(groups);
242
+ return new _ToolCatalog(toolMap, description);
114
243
  }
115
244
  getToolDetails(toolName) {
116
245
  const tool = this.tools.get(toolName);
@@ -118,10 +247,10 @@ var ToolCatalog = class {
118
247
  const sortedNames = [...this.tools.keys()].sort().join(", ");
119
248
  return `Unknown tool: "${toolName}". Available tools: ${sortedNames}`;
120
249
  }
121
- return buildToolDetailsString(tool);
250
+ return buildToolDetailsString(toolName, tool);
122
251
  }
123
252
  };
124
- function buildDiscoverToolDescription(tools) {
253
+ function buildFlatDescription(tools) {
125
254
  const sortedTools = [...tools].sort((a, b) => a.name.localeCompare(b.name));
126
255
  const toolLines = sortedTools.map((tool) => `- ${tool.name}: ${tool.description}`).join("\n");
127
256
  return `${DISCOVER_TOOL_PREAMBLE}
@@ -130,9 +259,24 @@ function buildDiscoverToolDescription(tools) {
130
259
  ${toolLines}
131
260
  </tools>`;
132
261
  }
133
- function buildToolDetailsString(tool) {
262
+ function buildGroupedDescription(groups) {
263
+ const sortedMcpNames = [...groups.keys()].sort();
264
+ const sections = sortedMcpNames.map((mcpName2) => {
265
+ const tools = groups.get(mcpName2);
266
+ const sortedTools = [...tools].sort((a, b) => a.name.localeCompare(b.name));
267
+ const toolLines = sortedTools.map((tool) => `- ${mcpName2}/${tool.name}: ${tool.description}`).join("\n");
268
+ return `${mcpName2}:
269
+ ${toolLines}`;
270
+ });
271
+ return `${DISCOVER_TOOL_PREAMBLE}
272
+
273
+ <tools>
274
+ ${sections.join("\n\n")}
275
+ </tools>`;
276
+ }
277
+ function buildToolDetailsString(displayName, tool) {
134
278
  const lines = [
135
- `Tool: ${tool.name}`,
279
+ `Tool: ${displayName}`,
136
280
  `Description: ${tool.description}`,
137
281
  "",
138
282
  "Input Schema:",
@@ -171,73 +315,21 @@ function buildAnnotationLines(tool) {
171
315
  return lines;
172
316
  }
173
317
 
174
- // src/proxy/server.ts
175
- import process from "process";
176
- import { FastMCP } from "fastmcp";
177
- import { z } from "zod";
178
- var ProxyServer = class {
179
- catalog;
180
- upstreamClient;
181
- constructor({ catalog, upstreamClient }) {
182
- this.catalog = catalog;
183
- this.upstreamClient = upstreamClient;
184
- }
185
- async start() {
186
- const server = new FastMCP({
187
- name: "dynamic-discovery-mcp",
188
- version: package_default.version
189
- });
190
- server.addTool({
191
- name: "discover_tool",
192
- description: this.catalog.discoverToolDescription,
193
- parameters: z.object({ tool_name: z.string() }),
194
- execute: async ({ tool_name }) => {
195
- return this.catalog.getToolDetails(tool_name);
196
- }
197
- });
198
- server.addTool({
199
- name: "use_tool",
200
- description: "Use a tool that was previously discovered with the discover_tool tool.",
201
- parameters: z.object({
202
- tool_name: z.string(),
203
- tool_input: z.record(z.string(), z.unknown()).default({})
204
- }),
205
- execute: async ({ tool_name, tool_input }) => {
206
- if (!this.catalog.tools.has(tool_name)) {
207
- return this.catalog.getToolDetails(tool_name);
208
- }
209
- const result = await this.upstreamClient.callTool(tool_name, tool_input);
210
- return result;
211
- }
212
- });
213
- process.stderr.write("Starting dynamic-discovery-mcp server over stdio\n");
214
- await server.start({ transportType: "stdio" });
215
- }
216
- };
217
-
218
318
  // src/proxy/upstream-client.ts
219
319
  import process2 from "process";
220
320
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
221
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
222
321
  var UpstreamClient = class {
223
- command;
224
- args;
322
+ transport;
225
323
  onTransportError;
226
324
  client = null;
227
- transport = null;
228
- constructor({ command, args, onTransportError }) {
229
- this.command = command;
230
- this.args = args;
325
+ constructor({ name, transport, onTransportError }) {
326
+ this.transport = transport;
231
327
  this.onTransportError = onTransportError ?? ((error) => {
232
- process2.stderr.write(`Upstream MCP transport error: ${error.message}
328
+ process2.stderr.write(`[${name}] Upstream MCP transport error: ${error.message}
233
329
  `);
234
330
  });
235
331
  }
236
332
  async connect() {
237
- this.transport = new StdioClientTransport({
238
- command: this.command,
239
- args: this.args
240
- });
241
333
  this.transport.onerror = this.onTransportError;
242
334
  this.client = new Client({ name: "dynamic-discovery-mcp", version: "1.0.0" });
243
335
  await this.client.connect(this.transport);
@@ -272,10 +364,8 @@ var UpstreamClient = class {
272
364
  if (this.client === null) {
273
365
  throw new Error("Client is not connected. Call connect() first.");
274
366
  }
275
- return this.client.callTool({
276
- name,
277
- arguments: input
278
- });
367
+ const result = await this.client.callTool({ name, arguments: input });
368
+ return result;
279
369
  }
280
370
  async disconnect() {
281
371
  if (this.client === null) {
@@ -283,54 +373,213 @@ var UpstreamClient = class {
283
373
  }
284
374
  await this.client.close();
285
375
  this.client = null;
286
- this.transport = null;
376
+ }
377
+ };
378
+
379
+ // src/proxy/orchestrator.ts
380
+ var Orchestrator = class {
381
+ config;
382
+ clients = /* @__PURE__ */ new Map();
383
+ toolCatalog = null;
384
+ constructor(config) {
385
+ this.config = config;
386
+ }
387
+ async connect() {
388
+ const groups = /* @__PURE__ */ new Map();
389
+ try {
390
+ for (const [mcpName2, { transport }] of this.config.mcps) {
391
+ const client = new UpstreamClient({
392
+ name: mcpName2,
393
+ transport,
394
+ onTransportError: (error) => {
395
+ this.config.onTransportError?.(mcpName2, error);
396
+ }
397
+ });
398
+ await client.connect();
399
+ const tools = await client.listTools();
400
+ this.clients.set(mcpName2, client);
401
+ groups.set(mcpName2, tools);
402
+ }
403
+ } catch (error) {
404
+ await this.disconnectAll();
405
+ throw error;
406
+ }
407
+ this.toolCatalog = ToolCatalog.fromGrouped(groups);
408
+ }
409
+ get catalog() {
410
+ if (this.toolCatalog === null) {
411
+ throw new Error("Orchestrator is not connected. Call connect() first.");
412
+ }
413
+ return this.toolCatalog;
414
+ }
415
+ async callTool(namespacedName, input) {
416
+ const separatorIndex = namespacedName.indexOf("/");
417
+ if (separatorIndex === -1) {
418
+ throw new Error(
419
+ `Invalid namespaced tool name: "${namespacedName}". Expected format: "mcpName/toolName".`
420
+ );
421
+ }
422
+ const mcpName2 = namespacedName.slice(0, separatorIndex);
423
+ const toolName = namespacedName.slice(separatorIndex + 1);
424
+ const client = this.clients.get(mcpName2);
425
+ if (client === void 0) {
426
+ const available = [...this.clients.keys()].sort().join(", ");
427
+ throw new Error(`Unknown MCP: "${mcpName2}". Available MCPs: ${available}`);
428
+ }
429
+ return client.callTool(toolName, input);
430
+ }
431
+ async disconnectAll() {
432
+ const disconnections = [...this.clients.values()].map((client) => client.disconnect());
433
+ await Promise.all(disconnections);
434
+ this.clients.clear();
435
+ this.toolCatalog = null;
436
+ }
437
+ };
438
+
439
+ // src/proxy/server.ts
440
+ import process3 from "process";
441
+ import { FastMCP } from "fastmcp";
442
+ import { z as z3 } from "zod";
443
+ var ProxyServer = class {
444
+ catalog;
445
+ callTool;
446
+ constructor({ catalog, callTool }) {
447
+ this.catalog = catalog;
448
+ this.callTool = callTool;
449
+ }
450
+ async start() {
451
+ const server = new FastMCP({
452
+ name: "dynamic-discovery-mcp",
453
+ version: package_default.version
454
+ });
455
+ server.addTool({
456
+ name: "discover_tool",
457
+ description: this.catalog.discoverToolDescription,
458
+ parameters: z3.object({ tool_name: z3.string() }),
459
+ execute: async ({ tool_name }) => {
460
+ return this.catalog.getToolDetails(tool_name);
461
+ }
462
+ });
463
+ server.addTool({
464
+ name: "use_tool",
465
+ description: "Use a tool that was previously discovered with the discover_tool tool.",
466
+ parameters: z3.object({
467
+ tool_name: z3.string(),
468
+ tool_input: z3.record(z3.string(), z3.unknown()).default({})
469
+ }),
470
+ execute: async ({ tool_name, tool_input }) => {
471
+ if (!this.catalog.tools.has(tool_name)) {
472
+ return this.catalog.getToolDetails(tool_name);
473
+ }
474
+ const result = await this.callTool(tool_name, tool_input);
475
+ return result;
476
+ }
477
+ });
478
+ process3.stderr.write("Starting dynamic-discovery-mcp server over stdio\n");
479
+ await server.start({ transportType: "stdio" });
287
480
  }
288
481
  };
289
482
 
290
483
  // src/proxy/index.ts
291
484
  async function startProxy(command, args) {
292
485
  let isShuttingDown = false;
486
+ const transport = new StdioClientTransport2({ command, args });
487
+ const upstreamClient = new UpstreamClient({
488
+ name: command,
489
+ transport,
490
+ onTransportError: (error) => {
491
+ process4.stderr.write(`Upstream MCP transport error: ${error.message}
492
+ `);
493
+ shutdown(1);
494
+ }
495
+ });
293
496
  const shutdown = (exitCode) => {
294
497
  if (isShuttingDown) return;
295
498
  isShuttingDown = true;
296
499
  upstreamClient.disconnect().catch((error) => {
297
- process3.stderr.write(
500
+ process4.stderr.write(
298
501
  `dynmcp: error during disconnect: ${error instanceof Error ? error.message : String(error)}
299
502
  `
300
503
  );
301
- }).finally(() => process3.exit(exitCode));
504
+ }).finally(() => process4.exit(exitCode));
302
505
  };
303
- const upstreamClient = new UpstreamClient({
304
- command,
305
- args,
306
- onTransportError: (error) => {
307
- process3.stderr.write(`Upstream MCP transport error: ${error.message}
308
- `);
309
- shutdown(1);
310
- }
311
- });
312
506
  try {
313
507
  await upstreamClient.connect();
314
508
  } catch (error) {
315
- process3.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
509
+ process4.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
316
510
  `);
317
- process3.exit(1);
511
+ process4.exit(1);
318
512
  }
319
513
  let tools;
320
514
  try {
321
515
  tools = await upstreamClient.listTools();
322
516
  } catch (error) {
323
- process3.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
517
+ process4.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
518
+ `);
519
+ process4.exit(1);
520
+ }
521
+ const catalog = ToolCatalog.fromFlat(tools);
522
+ const proxyServer = new ProxyServer({
523
+ catalog,
524
+ callTool: (name, input) => upstreamClient.callTool(name, input)
525
+ });
526
+ process4.on("SIGINT", () => shutdown(0));
527
+ process4.on("SIGTERM", () => shutdown(0));
528
+ process4.stdin.on("end", () => shutdown(0));
529
+ process4.stdin.on("close", () => shutdown(0));
530
+ try {
531
+ await proxyServer.start();
532
+ } catch (error) {
533
+ shutdown(1);
534
+ throw error;
535
+ }
536
+ }
537
+ async function startProxyFromConfig(configPath) {
538
+ let isShuttingDown = false;
539
+ const config = loadConfig(configPath);
540
+ const mcps = /* @__PURE__ */ new Map();
541
+ for (const [name, entry] of Object.entries(config.mcp)) {
542
+ mcps.set(name, { transport: createTransport(entry) });
543
+ }
544
+ const orchestrator = new Orchestrator({
545
+ mcps,
546
+ onTransportError: (mcpName2, error) => {
547
+ process4.stderr.write(`Upstream MCP "${mcpName2}" transport error: ${error.message}
548
+ `);
549
+ shutdown(1);
550
+ }
551
+ });
552
+ const shutdown = (exitCode) => {
553
+ if (isShuttingDown) return;
554
+ isShuttingDown = true;
555
+ orchestrator.disconnectAll().catch((error) => {
556
+ process4.stderr.write(
557
+ `dynmcp: error during disconnect: ${error instanceof Error ? error.message : String(error)}
558
+ `
559
+ );
560
+ }).finally(() => process4.exit(exitCode));
561
+ };
562
+ try {
563
+ await orchestrator.connect();
564
+ } catch (error) {
565
+ process4.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
324
566
  `);
325
- process3.exit(1);
326
- }
327
- const catalog = new ToolCatalog(tools);
328
- const proxyServer = new ProxyServer({ catalog, upstreamClient });
329
- process3.on("SIGINT", () => shutdown(0));
330
- process3.on("SIGTERM", () => shutdown(0));
331
- process3.stdin.on("end", () => shutdown(0));
332
- process3.stdin.on("close", () => shutdown(0));
333
- await proxyServer.start();
567
+ process4.exit(1);
568
+ }
569
+ const proxyServer = new ProxyServer({
570
+ catalog: orchestrator.catalog,
571
+ callTool: (name, input) => orchestrator.callTool(name, input)
572
+ });
573
+ process4.on("SIGINT", () => shutdown(0));
574
+ process4.on("SIGTERM", () => shutdown(0));
575
+ process4.stdin.on("end", () => shutdown(0));
576
+ process4.stdin.on("close", () => shutdown(0));
577
+ try {
578
+ await proxyServer.start();
579
+ } catch (error) {
580
+ shutdown(1);
581
+ throw error;
582
+ }
334
583
  }
335
584
 
336
585
  // src/cli.ts
@@ -341,34 +590,42 @@ var cliBanner = chalk.bold.magentaBright(
341
590
  verticalLayout: "fitted"
342
591
  })
343
592
  );
344
- var cli = new Command(package_default.name).description(package_default.description).version(package_default.version).addHelpText("beforeAll", cliBanner).addHelpText("after", "\nExample:\n dynmcp -- npx -y chrome-devtools-mcp@latest\n").allowExcessArguments(true).passThroughOptions(true).action(async () => {
345
- const separatorIndex = process4.argv.indexOf("--");
346
- if (separatorIndex === -1) {
347
- process4.stderr.write(
348
- "dynmcp: no upstream command provided.\nUsage: dynmcp -- <command> [args...]\nExample: dynmcp -- npx -y chrome-devtools-mcp@latest\n"
349
- );
350
- process4.exit(1);
351
- }
352
- const [command, ...args] = process4.argv.slice(separatorIndex + 1);
353
- if (command === void 0) {
354
- process4.stderr.write(
355
- "dynmcp: no upstream command provided.\nUsage: dynmcp -- <command> [args...]\nExample: dynmcp -- npx -y chrome-devtools-mcp@latest\n"
356
- );
357
- process4.exit(1);
593
+ var cli = new Command(package_default.name).description(package_default.description).version(package_default.version).addHelpText("beforeAll", cliBanner).addHelpText(
594
+ "after",
595
+ "\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)").allowExcessArguments(true).passThroughOptions(true).action(async (_options, cmd) => {
597
+ const separatorIndex = process5.argv.indexOf("--");
598
+ const configPath = cmd.opts().config;
599
+ if (separatorIndex !== -1) {
600
+ const [command, ...args] = process5.argv.slice(separatorIndex + 1);
601
+ if (command === void 0) {
602
+ process5.stderr.write(
603
+ "dynmcp: no upstream command provided after --.\nUsage: dynmcp -- <command> [args...]\n"
604
+ );
605
+ process5.exit(1);
606
+ }
607
+ try {
608
+ await startProxy(command, args);
609
+ } catch (error) {
610
+ process5.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
611
+ `);
612
+ process5.exit(1);
613
+ }
614
+ return;
358
615
  }
359
616
  try {
360
- await startProxy(command, args);
617
+ await startProxyFromConfig(configPath);
361
618
  } catch (error) {
362
- process4.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
619
+ process5.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
363
620
  `);
364
- process4.exit(1);
621
+ process5.exit(1);
365
622
  }
366
623
  });
367
624
 
368
625
  // src/index.ts
369
- import process5 from "process";
626
+ import process6 from "process";
370
627
  async function main() {
371
- cli.parse(process5.argv);
628
+ cli.parse(process6.argv);
372
629
  }
373
630
  main();
374
631
  //# sourceMappingURL=index.js.map