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 +11 -7
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +11 -7
- package/dist/multicorn-proxy.js +186 -50
- package/dist/shield-extension.js +1 -1
- package/package.json +1 -1
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: '
|
|
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
|
-
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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
|
-
|
|
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
|
|
package/dist/multicorn-proxy.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { existsSync } from 'fs';
|
|
3
|
-
import {
|
|
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
|
-
|
|
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.
|
|
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-
|
|
425
|
+
const input = await ask("Select (1-5): ");
|
|
399
426
|
const num = parseInt(input.trim(), 10);
|
|
400
|
-
if (num >= 1 && num <=
|
|
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
|
|
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
|
-
|
|
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 (
|
|
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
|
|
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
|
|
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}
|
|
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 \
|
|
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("
|
|
928
|
+
if (configuredPlatforms.has("windsurf")) {
|
|
853
929
|
blocks.push(
|
|
854
|
-
"\n" + style.bold("To complete your
|
|
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
|
-
|
|
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
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
2025
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
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
|
-
|
|
2225
|
-
});
|
|
2357
|
+
process.exit(1);
|
|
2358
|
+
});
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
export { parseArgs, resolveWrapConfig };
|
package/dist/shield-extension.js
CHANGED
|
@@ -22358,7 +22358,7 @@ async function writeExtensionBackup(claudeDesktopConfigPath, mcpServers) {
|
|
|
22358
22358
|
|
|
22359
22359
|
// package.json
|
|
22360
22360
|
var package_default = {
|
|
22361
|
-
version: "0.
|
|
22361
|
+
version: "0.8.0"};
|
|
22362
22362
|
|
|
22363
22363
|
// src/package-meta.ts
|
|
22364
22364
|
var PACKAGE_VERSION = package_default.version;
|