multicorn-shield 1.3.6 → 1.4.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/CHANGELOG.md CHANGED
@@ -9,6 +9,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  - Bump `version` in `package.json` before publishing to npm.
11
11
 
12
+ ## [1.4.0] - 2026-05-08
13
+
14
+ ### Added
15
+
16
+ - Hosted proxy wizard now prompts for upstream MCP server authentication (header name and value) when the target server requires credentials
17
+ - Helpful examples shown during hosted proxy setup: common MCP server URLs (GitHub, Supabase, Atlassian, Stripe) with links to where to find tokens
18
+ - Upstream auth headers are stored encrypted and forwarded by the proxy to the target MCP server on every request
19
+
20
+ ### Changed
21
+
22
+ - Target MCP server URL prompt now shows common examples instead of a generic placeholder
23
+ - "govern" replaced with "control" in all user-facing copy
24
+ - "upstream auth" replaced with "server credentials" in all user-facing copy
25
+
26
+ ### Fixed
27
+
28
+ - Hosted proxy connections to MCP servers requiring authentication (e.g. GitHub, Supabase) now work end-to-end - previously the proxy forwarded requests without credentials
29
+
12
30
  ## [1.3.6] - 2026-05-08
13
31
 
14
32
  ### Fixed
@@ -1500,8 +1500,8 @@ async function promptProxyConfig(ask, agentName) {
1500
1500
  while (targetUrl.length === 0) {
1501
1501
  process.stderr.write(
1502
1502
  "\n" + style.bold("Target MCP server URL:") + "\n" + style.dim(
1503
- "The URL of the MCP server you want Shield to protect. Example: https://your-server.example.com/mcp"
1504
- ) + "\n"
1503
+ "This is the URL of the MCP server you want Shield to control. Common examples:"
1504
+ ) + "\n" + style.dim(" GitHub: https://api.githubcopilot.com/mcp/") + "\n" + style.dim(" Supabase: https://mcp.supabase.com/sse") + "\n" + style.dim(" Atlassian: https://mcp.atlassian.com/v1/sse") + "\n" + style.dim(" Stripe: https://mcp.stripe.com/v1/sse") + "\n" + style.dim("Check your MCP server's documentation for the correct URL.") + "\n"
1505
1505
  );
1506
1506
  const input = await ask("URL: ");
1507
1507
  if (input.trim().length === 0) {
@@ -1521,10 +1521,44 @@ async function promptProxyConfig(ask, agentName) {
1521
1521
  targetUrl = input.trim();
1522
1522
  }
1523
1523
  const shortName = normalizeAgentName(agentName) || "shield-mcp";
1524
- return { targetUrl, shortName };
1524
+ process.stderr.write(
1525
+ "\n" + style.bold("Does this MCP server require authentication?") + "\n" + style.dim(
1526
+ "Most MCP servers need a token or API key. Check the server's docs for how to get one:"
1527
+ ) + "\n" + style.dim(" GitHub: Settings > Developer Settings > Personal Access Tokens") + "\n" + style.dim(
1528
+ " Supabase: Project Settings > API > anon or scoped key (service role bypasses RLS; avoid for most MCP)"
1529
+ ) + "\n" + style.dim(" Atlassian: id.atlassian.com > API Tokens") + "\n" + style.dim(" Stripe: Dashboard > Developers > API Keys") + "\n"
1530
+ );
1531
+ const authReply = await ask("(y/N): ");
1532
+ const authNorm = authReply.trim().toLowerCase();
1533
+ const wantsAuth = authNorm === "y" || authNorm === "yes";
1534
+ let upstreamHeaders;
1535
+ if (wantsAuth) {
1536
+ process.stderr.write(
1537
+ "\n" + style.bold("Enter the Authorization header value.") + "\n" + style.dim(" For Bearer tokens: Bearer ghp_xxxxxxxxxxxx") + "\n" + style.dim(" For API keys: Bearer sk-xxxxxxxxxxxx") + "\n"
1538
+ );
1539
+ const headerVal = await ask("Value: ");
1540
+ const trimmed = headerVal.trim();
1541
+ if (trimmed.length > 0) {
1542
+ upstreamHeaders = { Authorization: trimmed };
1543
+ }
1544
+ }
1545
+ return {
1546
+ targetUrl,
1547
+ shortName,
1548
+ ...upstreamHeaders !== void 0 ? { upstreamHeaders } : {}
1549
+ };
1525
1550
  }
1526
- async function createProxyConfig(baseUrl, apiKey, agentName, targetUrl, serverName, platform) {
1551
+ async function createProxyConfig(baseUrl, apiKey, agentName, targetUrl, serverName, platform, upstreamHeaders) {
1527
1552
  let response;
1553
+ const body = {
1554
+ server_name: serverName,
1555
+ target_url: targetUrl,
1556
+ platform,
1557
+ agent_name: agentName
1558
+ };
1559
+ if (upstreamHeaders !== void 0 && Object.keys(upstreamHeaders).length > 0) {
1560
+ body["upstream_headers"] = upstreamHeaders;
1561
+ }
1528
1562
  try {
1529
1563
  response = await fetch(`${baseUrl}/api/v1/proxy/config`, {
1530
1564
  method: "POST",
@@ -1532,12 +1566,7 @@ async function createProxyConfig(baseUrl, apiKey, agentName, targetUrl, serverNa
1532
1566
  "Content-Type": "application/json",
1533
1567
  "X-Multicorn-Key": apiKey
1534
1568
  },
1535
- body: JSON.stringify({
1536
- server_name: serverName,
1537
- target_url: targetUrl,
1538
- platform,
1539
- agent_name: agentName
1540
- }),
1569
+ body: JSON.stringify(body),
1541
1570
  signal: AbortSignal.timeout(1e4)
1542
1571
  });
1543
1572
  } catch (error) {
@@ -2445,7 +2474,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2445
2474
  }
2446
2475
  }
2447
2476
  } else {
2448
- const { targetUrl, shortName } = await promptProxyConfig(ask, agentName);
2477
+ const { targetUrl, shortName, upstreamHeaders } = await promptProxyConfig(ask, agentName);
2449
2478
  let proxyUrl = "";
2450
2479
  let created = false;
2451
2480
  while (!created) {
@@ -2457,7 +2486,8 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2457
2486
  agentName,
2458
2487
  targetUrl,
2459
2488
  shortName,
2460
- selectedPlatform
2489
+ selectedPlatform,
2490
+ upstreamHeaders
2461
2491
  );
2462
2492
  spinner.stop(true, "Proxy config created!");
2463
2493
  created = true;
@@ -2538,7 +2568,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2538
2568
  }
2539
2569
  }
2540
2570
  } else {
2541
- const { targetUrl, shortName } = await promptProxyConfig(ask, agentName);
2571
+ const { targetUrl, shortName, upstreamHeaders } = await promptProxyConfig(ask, agentName);
2542
2572
  let proxyUrl = "";
2543
2573
  let created = false;
2544
2574
  while (!created) {
@@ -2550,7 +2580,8 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2550
2580
  agentName,
2551
2581
  targetUrl,
2552
2582
  shortName,
2553
- selectedPlatform
2583
+ selectedPlatform,
2584
+ upstreamHeaders
2554
2585
  );
2555
2586
  spinner.stop(true, "Proxy config created!");
2556
2587
  created = true;
@@ -2625,7 +2656,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2625
2656
  }
2626
2657
  }
2627
2658
  } else {
2628
- const { targetUrl, shortName } = await promptProxyConfig(ask, agentName);
2659
+ const { targetUrl, shortName, upstreamHeaders } = await promptProxyConfig(ask, agentName);
2629
2660
  let proxyUrl = "";
2630
2661
  let created = false;
2631
2662
  while (!created) {
@@ -2637,7 +2668,8 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2637
2668
  agentName,
2638
2669
  targetUrl,
2639
2670
  shortName,
2640
- selectedPlatform
2671
+ selectedPlatform,
2672
+ upstreamHeaders
2641
2673
  );
2642
2674
  spinner.stop(true, "Proxy config created!");
2643
2675
  created = true;
@@ -2675,7 +2707,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2675
2707
  }
2676
2708
  }
2677
2709
  } else {
2678
- const { targetUrl, shortName } = await promptProxyConfig(ask, agentName);
2710
+ const { targetUrl, shortName, upstreamHeaders } = await promptProxyConfig(ask, agentName);
2679
2711
  let proxyUrl = "";
2680
2712
  let created = false;
2681
2713
  while (!created) {
@@ -2687,7 +2719,8 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2687
2719
  agentName,
2688
2720
  targetUrl,
2689
2721
  shortName,
2690
- selectedPlatform
2722
+ selectedPlatform,
2723
+ upstreamHeaders
2691
2724
  );
2692
2725
  spinner.stop(true, "Proxy config created!");
2693
2726
  created = true;
@@ -1571,8 +1571,8 @@ async function promptProxyConfig(ask, agentName) {
1571
1571
  while (targetUrl.length === 0) {
1572
1572
  process.stderr.write(
1573
1573
  "\n" + style.bold("Target MCP server URL:") + "\n" + style.dim(
1574
- "The URL of the MCP server you want Shield to protect. Example: https://your-server.example.com/mcp"
1575
- ) + "\n"
1574
+ "This is the URL of the MCP server you want Shield to control. Common examples:"
1575
+ ) + "\n" + style.dim(" GitHub: https://api.githubcopilot.com/mcp/") + "\n" + style.dim(" Supabase: https://mcp.supabase.com/sse") + "\n" + style.dim(" Atlassian: https://mcp.atlassian.com/v1/sse") + "\n" + style.dim(" Stripe: https://mcp.stripe.com/v1/sse") + "\n" + style.dim("Check your MCP server's documentation for the correct URL.") + "\n"
1576
1576
  );
1577
1577
  const input = await ask("URL: ");
1578
1578
  if (input.trim().length === 0) {
@@ -1592,10 +1592,44 @@ async function promptProxyConfig(ask, agentName) {
1592
1592
  targetUrl = input.trim();
1593
1593
  }
1594
1594
  const shortName = normalizeAgentName(agentName) || "shield-mcp";
1595
- return { targetUrl, shortName };
1595
+ process.stderr.write(
1596
+ "\n" + style.bold("Does this MCP server require authentication?") + "\n" + style.dim(
1597
+ "Most MCP servers need a token or API key. Check the server's docs for how to get one:"
1598
+ ) + "\n" + style.dim(" GitHub: Settings > Developer Settings > Personal Access Tokens") + "\n" + style.dim(
1599
+ " Supabase: Project Settings > API > anon or scoped key (service role bypasses RLS; avoid for most MCP)"
1600
+ ) + "\n" + style.dim(" Atlassian: id.atlassian.com > API Tokens") + "\n" + style.dim(" Stripe: Dashboard > Developers > API Keys") + "\n"
1601
+ );
1602
+ const authReply = await ask("(y/N): ");
1603
+ const authNorm = authReply.trim().toLowerCase();
1604
+ const wantsAuth = authNorm === "y" || authNorm === "yes";
1605
+ let upstreamHeaders;
1606
+ if (wantsAuth) {
1607
+ process.stderr.write(
1608
+ "\n" + style.bold("Enter the Authorization header value.") + "\n" + style.dim(" For Bearer tokens: Bearer ghp_xxxxxxxxxxxx") + "\n" + style.dim(" For API keys: Bearer sk-xxxxxxxxxxxx") + "\n"
1609
+ );
1610
+ const headerVal = await ask("Value: ");
1611
+ const trimmed = headerVal.trim();
1612
+ if (trimmed.length > 0) {
1613
+ upstreamHeaders = { Authorization: trimmed };
1614
+ }
1615
+ }
1616
+ return {
1617
+ targetUrl,
1618
+ shortName,
1619
+ ...upstreamHeaders !== void 0 ? { upstreamHeaders } : {}
1620
+ };
1596
1621
  }
1597
- async function createProxyConfig(baseUrl, apiKey, agentName, targetUrl, serverName, platform) {
1622
+ async function createProxyConfig(baseUrl, apiKey, agentName, targetUrl, serverName, platform, upstreamHeaders) {
1598
1623
  let response;
1624
+ const body = {
1625
+ server_name: serverName,
1626
+ target_url: targetUrl,
1627
+ platform,
1628
+ agent_name: agentName
1629
+ };
1630
+ if (upstreamHeaders !== void 0 && Object.keys(upstreamHeaders).length > 0) {
1631
+ body["upstream_headers"] = upstreamHeaders;
1632
+ }
1599
1633
  try {
1600
1634
  response = await fetch(`${baseUrl}/api/v1/proxy/config`, {
1601
1635
  method: "POST",
@@ -1603,12 +1637,7 @@ async function createProxyConfig(baseUrl, apiKey, agentName, targetUrl, serverNa
1603
1637
  "Content-Type": "application/json",
1604
1638
  "X-Multicorn-Key": apiKey
1605
1639
  },
1606
- body: JSON.stringify({
1607
- server_name: serverName,
1608
- target_url: targetUrl,
1609
- platform,
1610
- agent_name: agentName
1611
- }),
1640
+ body: JSON.stringify(body),
1612
1641
  signal: AbortSignal.timeout(1e4)
1613
1642
  });
1614
1643
  } catch (error) {
@@ -2525,7 +2554,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2525
2554
  }
2526
2555
  }
2527
2556
  } else {
2528
- const { targetUrl, shortName } = await promptProxyConfig(ask, agentName);
2557
+ const { targetUrl, shortName, upstreamHeaders } = await promptProxyConfig(ask, agentName);
2529
2558
  let proxyUrl = "";
2530
2559
  let created = false;
2531
2560
  while (!created) {
@@ -2537,7 +2566,8 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2537
2566
  agentName,
2538
2567
  targetUrl,
2539
2568
  shortName,
2540
- selectedPlatform
2569
+ selectedPlatform,
2570
+ upstreamHeaders
2541
2571
  );
2542
2572
  spinner.stop(true, "Proxy config created!");
2543
2573
  created = true;
@@ -2618,7 +2648,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2618
2648
  }
2619
2649
  }
2620
2650
  } else {
2621
- const { targetUrl, shortName } = await promptProxyConfig(ask, agentName);
2651
+ const { targetUrl, shortName, upstreamHeaders } = await promptProxyConfig(ask, agentName);
2622
2652
  let proxyUrl = "";
2623
2653
  let created = false;
2624
2654
  while (!created) {
@@ -2630,7 +2660,8 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2630
2660
  agentName,
2631
2661
  targetUrl,
2632
2662
  shortName,
2633
- selectedPlatform
2663
+ selectedPlatform,
2664
+ upstreamHeaders
2634
2665
  );
2635
2666
  spinner.stop(true, "Proxy config created!");
2636
2667
  created = true;
@@ -2705,7 +2736,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2705
2736
  }
2706
2737
  }
2707
2738
  } else {
2708
- const { targetUrl, shortName } = await promptProxyConfig(ask, agentName);
2739
+ const { targetUrl, shortName, upstreamHeaders } = await promptProxyConfig(ask, agentName);
2709
2740
  let proxyUrl = "";
2710
2741
  let created = false;
2711
2742
  while (!created) {
@@ -2717,7 +2748,8 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2717
2748
  agentName,
2718
2749
  targetUrl,
2719
2750
  shortName,
2720
- selectedPlatform
2751
+ selectedPlatform,
2752
+ upstreamHeaders
2721
2753
  );
2722
2754
  spinner.stop(true, "Proxy config created!");
2723
2755
  created = true;
@@ -2755,7 +2787,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2755
2787
  }
2756
2788
  }
2757
2789
  } else {
2758
- const { targetUrl, shortName } = await promptProxyConfig(ask, agentName);
2790
+ const { targetUrl, shortName, upstreamHeaders } = await promptProxyConfig(ask, agentName);
2759
2791
  let proxyUrl = "";
2760
2792
  let created = false;
2761
2793
  while (!created) {
@@ -2767,7 +2799,8 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2767
2799
  agentName,
2768
2800
  targetUrl,
2769
2801
  shortName,
2770
- selectedPlatform
2802
+ selectedPlatform,
2803
+ upstreamHeaders
2771
2804
  );
2772
2805
  spinner.stop(true, "Proxy config created!");
2773
2806
  created = true;
@@ -22417,7 +22417,7 @@ async function writeExtensionBackup(claudeDesktopConfigPath, mcpServers) {
22417
22417
 
22418
22418
  // package.json
22419
22419
  var package_default = {
22420
- version: "1.3.6"};
22420
+ version: "1.4.0"};
22421
22421
 
22422
22422
  // src/package-meta.ts
22423
22423
  var PACKAGE_VERSION = package_default.version;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multicorn-shield",
3
- "version": "1.3.6",
3
+ "version": "1.4.0",
4
4
  "description": "The control layer for AI agents: permissions, consent, spending limits, and audit logging.",
5
5
  "license": "MIT",
6
6
  "author": "Multicorn AI Pty Ltd",