multicorn-shield 0.6.2 → 0.8.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.cjs CHANGED
@@ -2106,7 +2106,7 @@ var MulticornShield = class {
2106
2106
  *
2107
2107
  * @example
2108
2108
  * ```ts
2109
- * const shield = new MulticornShield({ apiKey: 'mcs_your_key_here' });
2109
+ * const shield = new MulticornShield({ apiKey: 'mcs_live_abc123...' });
2110
2110
  * ```
2111
2111
  */
2112
2112
  constructor(config) {
@@ -2463,16 +2463,20 @@ function validateBaseUrl(baseUrl) {
2463
2463
  );
2464
2464
  }
2465
2465
  }
2466
+ var PLACEHOLDER_KEYS = /* @__PURE__ */ new Set(["mcs_your_key_here"]);
2467
+ var INVALID_KEY_MESSAGE = "Invalid Multicorn Shield API key. Get your key at https://app.multicorn.ai/settings";
2466
2468
  function validateApiKey(apiKey) {
2469
+ if (typeof apiKey !== "string" || apiKey.length === 0) {
2470
+ throw new Error(INVALID_KEY_MESSAGE);
2471
+ }
2467
2472
  if (!apiKey.startsWith(API_KEY_PREFIX)) {
2468
- throw new Error(
2469
- `[MulticornShield] Invalid API key format. Keys must start with "${API_KEY_PREFIX}". Find your API key in the Multicorn dashboard under Settings \u2192 API Keys.`
2470
- );
2473
+ throw new Error(INVALID_KEY_MESSAGE);
2471
2474
  }
2472
2475
  if (apiKey.length < MIN_API_KEY_LENGTH) {
2473
- throw new Error(
2474
- `[MulticornShield] API key is too short (${String(apiKey.length)} characters). Minimum length is ${String(MIN_API_KEY_LENGTH)} characters. Find your API key in the Multicorn dashboard under Settings \u2192 API Keys.`
2475
- );
2476
+ throw new Error(INVALID_KEY_MESSAGE);
2477
+ }
2478
+ if (PLACEHOLDER_KEYS.has(apiKey)) {
2479
+ throw new Error(INVALID_KEY_MESSAGE);
2476
2480
  }
2477
2481
  }
2478
2482
 
package/dist/index.d.cts CHANGED
@@ -1902,7 +1902,7 @@ declare function createMcpAdapter(config: McpAdapterConfig): McpAdapter;
1902
1902
  * @example
1903
1903
  * ```ts
1904
1904
  * const shield = new MulticornShield({
1905
- * apiKey: 'mcs_your_key_here',
1905
+ * apiKey: 'mcs_live_abc123...',
1906
1906
  * baseUrl: 'https://api.multicorn.ai',
1907
1907
  * timeout: 5000,
1908
1908
  * });
@@ -1938,7 +1938,7 @@ interface MulticornShieldConfig {
1938
1938
  * @example
1939
1939
  * ```ts
1940
1940
  * const shield = new MulticornShield({
1941
- * apiKey: 'mcs_your_key_here',
1941
+ * apiKey: 'mcs_live_abc123...',
1942
1942
  * onError: (err) => myLogger.warn(err.message),
1943
1943
  * });
1944
1944
  * ```
@@ -2052,7 +2052,7 @@ declare class MulticornShield {
2052
2052
  *
2053
2053
  * @example
2054
2054
  * ```ts
2055
- * const shield = new MulticornShield({ apiKey: 'mcs_your_key_here' });
2055
+ * const shield = new MulticornShield({ apiKey: 'mcs_live_abc123...' });
2056
2056
  * ```
2057
2057
  */
2058
2058
  constructor(config: MulticornShieldConfig);
package/dist/index.d.ts CHANGED
@@ -1902,7 +1902,7 @@ declare function createMcpAdapter(config: McpAdapterConfig): McpAdapter;
1902
1902
  * @example
1903
1903
  * ```ts
1904
1904
  * const shield = new MulticornShield({
1905
- * apiKey: 'mcs_your_key_here',
1905
+ * apiKey: 'mcs_live_abc123...',
1906
1906
  * baseUrl: 'https://api.multicorn.ai',
1907
1907
  * timeout: 5000,
1908
1908
  * });
@@ -1938,7 +1938,7 @@ interface MulticornShieldConfig {
1938
1938
  * @example
1939
1939
  * ```ts
1940
1940
  * const shield = new MulticornShield({
1941
- * apiKey: 'mcs_your_key_here',
1941
+ * apiKey: 'mcs_live_abc123...',
1942
1942
  * onError: (err) => myLogger.warn(err.message),
1943
1943
  * });
1944
1944
  * ```
@@ -2052,7 +2052,7 @@ declare class MulticornShield {
2052
2052
  *
2053
2053
  * @example
2054
2054
  * ```ts
2055
- * const shield = new MulticornShield({ apiKey: 'mcs_your_key_here' });
2055
+ * const shield = new MulticornShield({ apiKey: 'mcs_live_abc123...' });
2056
2056
  * ```
2057
2057
  */
2058
2058
  constructor(config: MulticornShieldConfig);
package/dist/index.js CHANGED
@@ -2104,7 +2104,7 @@ var MulticornShield = class {
2104
2104
  *
2105
2105
  * @example
2106
2106
  * ```ts
2107
- * const shield = new MulticornShield({ apiKey: 'mcs_your_key_here' });
2107
+ * const shield = new MulticornShield({ apiKey: 'mcs_live_abc123...' });
2108
2108
  * ```
2109
2109
  */
2110
2110
  constructor(config) {
@@ -2461,16 +2461,20 @@ function validateBaseUrl(baseUrl) {
2461
2461
  );
2462
2462
  }
2463
2463
  }
2464
+ var PLACEHOLDER_KEYS = /* @__PURE__ */ new Set(["mcs_your_key_here"]);
2465
+ var INVALID_KEY_MESSAGE = "Invalid Multicorn Shield API key. Get your key at https://app.multicorn.ai/settings";
2464
2466
  function validateApiKey(apiKey) {
2467
+ if (typeof apiKey !== "string" || apiKey.length === 0) {
2468
+ throw new Error(INVALID_KEY_MESSAGE);
2469
+ }
2465
2470
  if (!apiKey.startsWith(API_KEY_PREFIX)) {
2466
- throw new Error(
2467
- `[MulticornShield] Invalid API key format. Keys must start with "${API_KEY_PREFIX}". Find your API key in the Multicorn dashboard under Settings \u2192 API Keys.`
2468
- );
2471
+ throw new Error(INVALID_KEY_MESSAGE);
2469
2472
  }
2470
2473
  if (apiKey.length < MIN_API_KEY_LENGTH) {
2471
- throw new Error(
2472
- `[MulticornShield] API key is too short (${String(apiKey.length)} characters). Minimum length is ${String(MIN_API_KEY_LENGTH)} characters. Find your API key in the Multicorn dashboard under Settings \u2192 API Keys.`
2473
- );
2474
+ throw new Error(INVALID_KEY_MESSAGE);
2475
+ }
2476
+ if (PLACEHOLDER_KEYS.has(apiKey)) {
2477
+ throw new Error(INVALID_KEY_MESSAGE);
2474
2478
  }
2475
2479
  }
2476
2480
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { existsSync } from 'fs';
3
- import { readFile, writeFile, mkdir, unlink } from 'fs/promises';
3
+ import { mkdir, writeFile, readFile, unlink } from 'fs/promises';
4
4
  import { join } from 'path';
5
5
  import { homedir } from 'os';
6
6
  import { createInterface } from 'readline';
@@ -366,16 +366,39 @@ async function isCursorConnected() {
366
366
  return false;
367
367
  }
368
368
  }
369
- var PLATFORM_LABELS = ["OpenClaw", "Claude Code", "Cursor"];
369
+ function getWindsurfConfigPath() {
370
+ return join(homedir(), ".codeium", "windsurf", "mcp_config.json");
371
+ }
372
+ async function isWindsurfConnected() {
373
+ try {
374
+ const raw = await readFile(getWindsurfConfigPath(), "utf8");
375
+ const obj = JSON.parse(raw);
376
+ const mcpServers = obj["mcpServers"];
377
+ if (mcpServers === void 0 || typeof mcpServers !== "object") return false;
378
+ for (const entry of Object.values(mcpServers)) {
379
+ if (typeof entry !== "object" || entry === null) continue;
380
+ const rec = entry;
381
+ const url = rec["serverUrl"];
382
+ if (typeof url === "string" && url.includes("multicorn")) return true;
383
+ }
384
+ return false;
385
+ } catch {
386
+ return false;
387
+ }
388
+ }
389
+ var PLATFORM_LABELS = ["OpenClaw", "Claude Code", "Cursor", "Windsurf", "Local MCP / Other"];
370
390
  var PLATFORM_BY_SELECTION = {
371
391
  1: "openclaw",
372
392
  2: "claude-code",
373
- 3: "cursor"
393
+ 3: "cursor",
394
+ 4: "windsurf",
395
+ 5: "other-mcp"
374
396
  };
375
397
  var DEFAULT_AGENT_NAMES = {
376
398
  openclaw: "my-openclaw-agent",
377
399
  "claude-code": "my-claude-code-agent",
378
- cursor: "my-cursor-agent"
400
+ cursor: "my-cursor-agent",
401
+ windsurf: "my-windsurf-agent"
379
402
  };
380
403
  async function promptPlatformSelection(ask) {
381
404
  process.stderr.write(
@@ -384,20 +407,24 @@ async function promptPlatformSelection(ask) {
384
407
  const connectedFlags = [
385
408
  await isOpenClawConnected(),
386
409
  isClaudeCodeConnected(),
387
- await isCursorConnected()
410
+ await isCursorConnected(),
411
+ await isWindsurfConnected()
388
412
  ];
389
413
  for (let i = 0; i < PLATFORM_LABELS.length; i++) {
390
- const marker = connectedFlags[i] ? " " + style.green("\u2713") + style.dim(" connected") : "";
414
+ const marker = i < connectedFlags.length && connectedFlags[i] ? " " + style.dim("\u25CF detected locally") : "";
391
415
  process.stderr.write(
392
416
  ` ${style.violet(String(i + 1))}. ${PLATFORM_LABELS[i] ?? ""}${marker}
393
417
  `
394
418
  );
395
419
  }
420
+ process.stderr.write(
421
+ style.dim(" Pick 5 if you want to wrap a local MCP server with multicorn-proxy --wrap.") + "\n"
422
+ );
396
423
  let selection = 0;
397
424
  while (selection === 0) {
398
- const input = await ask("Select (1-3): ");
425
+ const input = await ask("Select (1-5): ");
399
426
  const num = parseInt(input.trim(), 10);
400
- if (num >= 1 && num <= 3) {
427
+ if (num >= 1 && num <= 5) {
401
428
  selection = num;
402
429
  }
403
430
  }
@@ -501,12 +528,14 @@ async function createProxyConfig(baseUrl, apiKey, agentName, targetUrl, serverNa
501
528
  return typeof data?.["proxy_url"] === "string" ? data["proxy_url"] : "";
502
529
  }
503
530
  function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
504
- const authHeader = platform === "cursor" ? `Bearer ${apiKey}` : "Bearer YOUR_SHIELD_API_KEY";
531
+ const usesInlineKey = platform === "cursor" || platform === "windsurf";
532
+ const authHeader = usesInlineKey ? `Bearer ${apiKey}` : "Bearer YOUR_SHIELD_API_KEY";
533
+ const urlKey = platform === "windsurf" ? "serverUrl" : "url";
505
534
  const mcpSnippet = JSON.stringify(
506
535
  {
507
536
  mcpServers: {
508
537
  [shortName]: {
509
- url: routingToken,
538
+ [urlKey]: routingToken,
510
539
  headers: {
511
540
  Authorization: authHeader
512
541
  }
@@ -520,14 +549,18 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
520
549
  process.stderr.write("\n" + style.dim("Add this to your OpenClaw agent config:") + "\n\n");
521
550
  } else if (platform === "claude-code") {
522
551
  process.stderr.write("\n" + style.dim("Add this to your Claude Code MCP config:") + "\n\n");
552
+ } else if (platform === "windsurf") {
553
+ process.stderr.write(
554
+ "\n" + style.dim("Add this to ~/.codeium/windsurf/mcp_config.json:") + "\n\n"
555
+ );
523
556
  } else {
524
557
  process.stderr.write("\n" + style.dim("Add this to ~/.cursor/mcp.json:") + "\n\n");
525
558
  }
526
559
  process.stderr.write(style.cyan(mcpSnippet) + "\n\n");
527
- if (platform !== "cursor") {
560
+ if (!usesInlineKey) {
528
561
  process.stderr.write(
529
562
  style.dim(
530
- "Replace YOUR_SHIELD_API_KEY with your API key. Find it in Settings > API keys at https://app.multicorn.ai/settings/api-keys"
563
+ "Replace YOUR_SHIELD_API_KEY with your API key. Find it in Settings > API keys at https://app.multicorn.ai/settings#api-keys"
531
564
  ) + "\n"
532
565
  );
533
566
  }
@@ -543,6 +576,14 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
543
576
  ) + "\n"
544
577
  );
545
578
  }
579
+ if (platform === "windsurf") {
580
+ process.stderr.write(style.dim("Then restart Windsurf (Cmd/Ctrl+Q, then reopen).") + "\n");
581
+ process.stderr.write(
582
+ style.dim(
583
+ "Open the Cascade panel and verify the server appears with a green status indicator."
584
+ ) + "\n"
585
+ );
586
+ }
546
587
  }
547
588
  var DEFAULT_SHIELD_API_BASE_URL = "https://api.multicorn.ai";
548
589
  async function runInit(explicitBaseUrl) {
@@ -560,7 +601,7 @@ async function runInit(explicitBaseUrl) {
560
601
  process.stderr.write(style.dim("Agent governance for the AI era") + "\n\n");
561
602
  process.stderr.write(style.bold(style.violet("Multicorn Shield proxy setup")) + "\n\n");
562
603
  process.stderr.write(
563
- style.dim("Get your API key at https://app.multicorn.ai/settings/api-keys") + "\n\n"
604
+ style.dim("Get your API key at https://app.multicorn.ai/settings#api-keys") + "\n\n"
564
605
  );
565
606
  const existing = await loadConfig().catch(() => null);
566
607
  let resolvedBaseUrl;
@@ -632,6 +673,40 @@ async function runInit(explicitBaseUrl) {
632
673
  const selection = await promptPlatformSelection(ask);
633
674
  const selectedPlatform = PLATFORM_BY_SELECTION[selection] ?? "cursor";
634
675
  const selectedLabel = PLATFORM_LABELS[selection - 1] ?? "Cursor";
676
+ if (selection === 5) {
677
+ const raw = existing !== null ? { ...existing } : {};
678
+ raw["apiKey"] = apiKey;
679
+ raw["baseUrl"] = resolvedBaseUrl;
680
+ delete raw["agentName"];
681
+ delete raw["platform"];
682
+ lastConfig = raw;
683
+ try {
684
+ await saveConfig(lastConfig);
685
+ process.stderr.write(
686
+ style.green("\u2713") + ` Config saved to ${style.cyan(CONFIG_PATH)}
687
+ `
688
+ );
689
+ process.stderr.write(
690
+ "\n" + style.bold("Try it:") + " " + style.cyan(
691
+ "npx multicorn-proxy --wrap npx @modelcontextprotocol/server-filesystem /tmp"
692
+ ) + "\n"
693
+ );
694
+ } catch (error) {
695
+ const detail = error instanceof Error ? error.message : String(error);
696
+ process.stderr.write(style.red(`Failed to save config: ${detail}`) + "\n");
697
+ }
698
+ configuredAgents.push({
699
+ selection,
700
+ platform: selectedPlatform,
701
+ platformLabel: selectedLabel,
702
+ agentName: ""
703
+ });
704
+ const another2 = await ask("\nConnect another agent? (Y/n) ");
705
+ if (another2.trim().toLowerCase() === "n") {
706
+ configuring = false;
707
+ }
708
+ continue;
709
+ }
635
710
  const existingForPlatform = currentAgents.find((a) => a.platform === selectedPlatform);
636
711
  if (existingForPlatform !== void 0) {
637
712
  process.stderr.write(
@@ -820,14 +895,15 @@ An agent for ${selectedLabel} already exists: ${style.cyan(existingForPlatform.n
820
895
  if (configuredAgents.length > 0) {
821
896
  process.stderr.write("\n" + style.bold(style.violet("Setup complete")) + "\n\n");
822
897
  for (const agent of configuredAgents) {
898
+ const namePart = agent.agentName.length > 0 ? ` - ${style.cyan(agent.agentName)}` : "";
899
+ const urlPart = agent.proxyUrl != null ? ` ${style.dim(`(${agent.proxyUrl})`)}` : "";
823
900
  process.stderr.write(
824
- ` ${style.green("\u2713")} ${agent.platformLabel} - ${style.cyan(agent.agentName)}${agent.proxyUrl != null ? ` ${style.dim(`(${agent.proxyUrl})`)}` : ""}
901
+ ` ${style.green("\u2713")} ${agent.platformLabel}${namePart}${urlPart}
825
902
  `
826
903
  );
827
904
  }
828
905
  process.stderr.write("\n");
829
906
  const configuredPlatforms = new Set(configuredAgents.map((a) => a.platform));
830
- process.stderr.write("\n" + style.bold(style.violet("Next steps")) + "\n");
831
907
  const blocks = [];
832
908
  if (configuredPlatforms.has("openclaw")) {
833
909
  blocks.push(
@@ -846,15 +922,23 @@ An agent for ${selectedLabel} already exists: ${style.cyan(existingForPlatform.n
846
922
  }
847
923
  if (configuredPlatforms.has("cursor")) {
848
924
  blocks.push(
849
- "\n" + style.bold("To complete your Cursor setup:") + "\n \u2192 Restart Cursor to pick up MCP config changes\n"
925
+ "\n" + style.bold("To complete your Cursor setup:") + "\n 1. If you don't have Cursor yet, download it from " + style.cyan("https://cursor.com/downloads") + "\n 2. Open " + style.cyan("~/.cursor/mcp.json") + " and paste the config snippet shown above\n 3. Restart Cursor (or launch it for the first time) to load the new MCP server\n"
850
926
  );
851
927
  }
852
- if (configuredPlatforms.has("other-mcp")) {
928
+ if (configuredPlatforms.has("windsurf")) {
853
929
  blocks.push(
854
- "\n" + style.bold("To complete your Other MCP Agent setup:") + "\n \u2192 Start your agent with: " + style.cyan("npx multicorn-proxy --wrap <your-server> --agent-name <name>") + "\n"
930
+ "\n" + style.bold("To complete your Windsurf setup:") + "\n 1. If you don't have Windsurf yet, download it from " + style.cyan("https://windsurf.com/download") + "\n 2. Open " + style.cyan("~/.codeium/windsurf/mcp_config.json") + " and paste the config snippet shown above\n 3. Restart Windsurf (or launch it for the first time) to load the new MCP server\n"
855
931
  );
856
932
  }
857
- process.stderr.write(blocks.join("") + "\n");
933
+ if (configuredPlatforms.has("windsurf")) {
934
+ blocks.push(
935
+ "\n" + style.bold("To complete your Windsurf setup:") + "\n Config file: " + style.cyan("~/.codeium/windsurf/mcp_config.json") + "\n Restart Windsurf to load the new MCP server.\n"
936
+ );
937
+ }
938
+ if (blocks.length > 0) {
939
+ process.stderr.write("\n" + style.bold(style.violet("Next steps")) + "\n");
940
+ process.stderr.write(blocks.join("") + "\n");
941
+ }
858
942
  }
859
943
  return lastConfig;
860
944
  }
@@ -1851,6 +1935,15 @@ function createProxyServer(config) {
1851
1935
  agentId = agentRecord.id;
1852
1936
  grantedScopes = agentRecord.scopes;
1853
1937
  authInvalid = agentRecord.authInvalid === true;
1938
+ if (authInvalid) {
1939
+ config.logger.error("API key rejected by the Multicorn service.", {
1940
+ agent: config.agentName
1941
+ });
1942
+ process.stderr.write(
1943
+ "\nError: API key was rejected by the Multicorn service.\nCheck your key at https://app.multicorn.ai/settings#api-keys or run `npx multicorn-proxy init` to reconfigure.\n\n"
1944
+ );
1945
+ throw new Error("API key was rejected by the Multicorn service.");
1946
+ }
1854
1947
  config.logger.info("Agent resolved.", {
1855
1948
  agent: config.agentName,
1856
1949
  id: agentId,
@@ -1968,6 +2061,7 @@ function parseArgs(argv) {
1968
2061
  let dashboardUrl = "";
1969
2062
  let agentName = "";
1970
2063
  let deleteAgentName = "";
2064
+ let apiKey = void 0;
1971
2065
  for (let i = 0; i < args.length; i++) {
1972
2066
  const arg = args[i];
1973
2067
  if (arg === "init") {
@@ -1986,46 +2080,56 @@ function parseArgs(argv) {
1986
2080
  i++;
1987
2081
  } else if (arg === "--wrap") {
1988
2082
  subcommand = "wrap";
1989
- const next = args[i + 1];
1990
- if (next === void 0 || next.startsWith("-")) {
1991
- process.stderr.write("Error: --wrap requires a command to run.\n");
1992
- process.stderr.write("Example: npx multicorn-proxy --wrap my-mcp-server\n");
1993
- process.exit(1);
1994
- }
1995
- wrapCommand = next;
1996
- wrapArgs = args.slice(i + 2);
1997
- const cleaned = [];
1998
- for (let j = 0; j < wrapArgs.length; j++) {
1999
- const token = wrapArgs[j];
2083
+ const tail = args.slice(i + 1);
2084
+ const remaining = [];
2085
+ for (let j = 0; j < tail.length; j++) {
2086
+ const token = tail[j];
2087
+ if (token === void 0) continue;
2088
+ if (remaining.length > 0) {
2089
+ remaining.push(token);
2090
+ continue;
2091
+ }
2000
2092
  if (token === "--agent-name") {
2001
- const value = wrapArgs[j + 1];
2093
+ const value = tail[j + 1];
2002
2094
  if (value !== void 0) {
2003
2095
  agentName = value;
2004
2096
  j++;
2005
2097
  }
2006
2098
  } else if (token === "--log-level") {
2007
- const value = wrapArgs[j + 1];
2099
+ const value = tail[j + 1];
2008
2100
  if (value !== void 0 && isValidLogLevel(value)) {
2009
2101
  logLevel = value;
2010
2102
  j++;
2011
2103
  }
2012
2104
  } else if (token === "--base-url") {
2013
- const value = wrapArgs[j + 1];
2105
+ const value = tail[j + 1];
2014
2106
  if (value !== void 0) {
2015
2107
  baseUrl = value;
2016
2108
  j++;
2017
2109
  }
2018
2110
  } else if (token === "--dashboard-url") {
2019
- const value = wrapArgs[j + 1];
2111
+ const value = tail[j + 1];
2020
2112
  if (value !== void 0) {
2021
2113
  dashboardUrl = value;
2022
2114
  j++;
2023
2115
  }
2024
- } else if (token !== void 0) {
2025
- cleaned.push(token);
2116
+ } else if (token === "--api-key") {
2117
+ const value = tail[j + 1];
2118
+ if (value !== void 0) {
2119
+ apiKey = value;
2120
+ j++;
2121
+ }
2122
+ } else {
2123
+ remaining.push(token);
2026
2124
  }
2027
2125
  }
2028
- wrapArgs = cleaned;
2126
+ if (remaining.length === 0) {
2127
+ process.stderr.write("Error: --wrap requires a command to run.\n");
2128
+ process.stderr.write("Example: npx multicorn-proxy --wrap my-mcp-server\n");
2129
+ process.exit(1);
2130
+ }
2131
+ wrapCommand = remaining[0] ?? "";
2132
+ wrapArgs = remaining.slice(1);
2029
2133
  break;
2030
2134
  } else if (arg === "--log-level") {
2031
2135
  const next = args[i + 1];
@@ -2051,6 +2155,12 @@ function parseArgs(argv) {
2051
2155
  agentName = next;
2052
2156
  i++;
2053
2157
  }
2158
+ } else if (arg === "--api-key") {
2159
+ const next = args[i + 1];
2160
+ if (next !== void 0) {
2161
+ apiKey = next;
2162
+ i++;
2163
+ }
2054
2164
  }
2055
2165
  }
2056
2166
  return {
@@ -2061,7 +2171,8 @@ function parseArgs(argv) {
2061
2171
  baseUrl,
2062
2172
  dashboardUrl,
2063
2173
  agentName,
2064
- deleteAgentName
2174
+ deleteAgentName,
2175
+ apiKey
2065
2176
  };
2066
2177
  }
2067
2178
  function printHelp() {
@@ -2084,6 +2195,7 @@ function printHelp() {
2084
2195
  " Shield's permission layer.",
2085
2196
  "",
2086
2197
  "Options:",
2198
+ " --api-key <key> Multicorn API key (overrides MULTICORN_API_KEY env var and config file)",
2087
2199
  " --log-level <level> Log level: debug | info | warn | error (default: info)",
2088
2200
  " --base-url <url> Multicorn API base URL (default: https://api.multicorn.ai)",
2089
2201
  " --dashboard-url <url> Dashboard URL for consent page (default: derived from --base-url)",
@@ -2150,13 +2262,7 @@ async function main() {
2150
2262
  process.exit(1);
2151
2263
  }
2152
2264
  }
2153
- const config = await loadConfig();
2154
- if (config === null) {
2155
- process.stderr.write(
2156
- "No config found. Run `npx multicorn-proxy init` to set up your API key.\n"
2157
- );
2158
- process.exit(1);
2159
- }
2265
+ const config = await resolveWrapConfig(cli, logger);
2160
2266
  const finalBaseUrl = cli.baseUrl !== void 0 && cli.baseUrl.length > 0 ? cli.baseUrl : config.baseUrl;
2161
2267
  if (cli.baseUrl === void 0 || cli.baseUrl.length === 0) {
2162
2268
  if (!isAllowedShieldApiBaseUrl(finalBaseUrl)) {
@@ -2193,6 +2299,31 @@ async function main() {
2193
2299
  });
2194
2300
  await proxy.start();
2195
2301
  }
2302
+ async function resolveWrapConfig(cli, logger) {
2303
+ if (cli.apiKey !== void 0 && cli.apiKey.length > 0) {
2304
+ logger.debug("Using API key from --api-key flag.");
2305
+ return {
2306
+ apiKey: cli.apiKey,
2307
+ baseUrl: cli.baseUrl ?? DEFAULT_SHIELD_API_BASE_URL
2308
+ };
2309
+ }
2310
+ const envKey = process.env["MULTICORN_API_KEY"];
2311
+ if (typeof envKey === "string" && envKey.length > 0) {
2312
+ logger.debug("Using API key from MULTICORN_API_KEY environment variable.");
2313
+ return {
2314
+ apiKey: envKey,
2315
+ baseUrl: cli.baseUrl ?? DEFAULT_SHIELD_API_BASE_URL
2316
+ };
2317
+ }
2318
+ const config = await loadConfig();
2319
+ if (config !== null) {
2320
+ return config;
2321
+ }
2322
+ process.stderr.write(
2323
+ "No API key found. Provide one via the --api-key flag, the MULTICORN_API_KEY environment variable, or run `npx multicorn-proxy init` to set up a config file.\n"
2324
+ );
2325
+ process.exit(1);
2326
+ }
2196
2327
  function resolveWrapAgentName(cli, config) {
2197
2328
  if (cli.agentName.length > 0) {
2198
2329
  return cli.agentName;
@@ -2217,9 +2348,14 @@ function deriveAgentName(command) {
2217
2348
  const base = command.split("/").pop() ?? command;
2218
2349
  return base.replace(/\.[cm]?[jt]s$/, "");
2219
2350
  }
2220
- main().catch((error) => {
2221
- const message = error instanceof Error ? error.message : String(error);
2222
- process.stderr.write(`Fatal error: ${message}
2351
+ var isDirectRun = process.argv[1] !== void 0 && (import.meta.url.endsWith(process.argv[1]) || import.meta.url === `file://${process.argv[1]}` || import.meta.url.endsWith("/multicorn-proxy.js") || import.meta.url.endsWith("/multicorn-proxy.ts"));
2352
+ if (isDirectRun && process.env["VITEST"] === void 0) {
2353
+ main().catch((error) => {
2354
+ const message = error instanceof Error ? error.message : String(error);
2355
+ process.stderr.write(`Fatal error: ${message}
2223
2356
  `);
2224
- process.exit(1);
2225
- });
2357
+ process.exit(1);
2358
+ });
2359
+ }
2360
+
2361
+ export { parseArgs, resolveWrapConfig };
@@ -22358,7 +22358,7 @@ async function writeExtensionBackup(claudeDesktopConfigPath, mcpServers) {
22358
22358
 
22359
22359
  // package.json
22360
22360
  var package_default = {
22361
- version: "0.6.2"};
22361
+ version: "0.8.0"};
22362
22362
 
22363
22363
  // src/package-meta.ts
22364
22364
  var PACKAGE_VERSION = package_default.version;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multicorn-shield",
3
- "version": "0.6.2",
3
+ "version": "0.8.0",
4
4
  "description": "The control layer for AI agents: permissions, consent, spending limits, and audit logging.",
5
5
  "license": "MIT",
6
6
  "type": "module",