multicorn-shield 1.3.4 → 1.3.6
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 +12 -0
- package/dist/multicorn-proxy.js +115 -38
- package/dist/multicorn-shield.js +114 -37
- package/dist/shield-extension.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,18 @@ 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.3.6] - 2026-05-08
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Hosted proxy URLs now embed the API key as a query parameter fallback for MCP clients that don't send static Authorization headers (fixes Cursor, Claude Desktop, and other clients that ignore the headers config during discovery)
|
|
17
|
+
|
|
18
|
+
## [1.3.5] - 2026-05-08
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Replace flow no longer shows duplicate agent names (deduplication fix from 1.3.4 was incomplete)
|
|
23
|
+
|
|
12
24
|
## [1.3.3] - 2026-05-08
|
|
13
25
|
|
|
14
26
|
### Fixed
|
package/dist/multicorn-proxy.js
CHANGED
|
@@ -1564,6 +1564,41 @@ async function createProxyConfig(baseUrl, apiKey, agentName, targetUrl, serverNa
|
|
|
1564
1564
|
const data = envelope["data"];
|
|
1565
1565
|
return typeof data?.["proxy_url"] === "string" ? data["proxy_url"] : "";
|
|
1566
1566
|
}
|
|
1567
|
+
function shouldEmbedKeyInHostedProxyUrl(platform) {
|
|
1568
|
+
return HOSTED_PROXY_PLATFORMS_WITH_URL_KEY.has(platform);
|
|
1569
|
+
}
|
|
1570
|
+
function hostedProxyUrlWithKeyParam(proxyUrl, apiKey) {
|
|
1571
|
+
if (apiKey.length === 0) {
|
|
1572
|
+
process.stderr.write(
|
|
1573
|
+
style.yellow("\u26A0") + " Could not add key to proxy URL: API key is empty; using URL without key query parameter.\n"
|
|
1574
|
+
);
|
|
1575
|
+
return proxyUrl;
|
|
1576
|
+
}
|
|
1577
|
+
try {
|
|
1578
|
+
const u = new URL(proxyUrl);
|
|
1579
|
+
u.searchParams.set("key", apiKey);
|
|
1580
|
+
return u.toString();
|
|
1581
|
+
} catch (err) {
|
|
1582
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
1583
|
+
process.stderr.write(
|
|
1584
|
+
style.yellow("\u26A0") + " Could not parse proxy URL to append key query parameter; using URL unchanged. " + style.dim(detail) + "\n"
|
|
1585
|
+
);
|
|
1586
|
+
return proxyUrl;
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
function formatHostedProxyUrlForStderr(platform, proxyUrl, apiKey) {
|
|
1590
|
+
if (!shouldEmbedKeyInHostedProxyUrl(platform) || apiKey.length === 0) {
|
|
1591
|
+
return proxyUrl;
|
|
1592
|
+
}
|
|
1593
|
+
try {
|
|
1594
|
+
const u = new URL(proxyUrl);
|
|
1595
|
+
const redactedLabel = apiKey.length <= 4 ? "****" : `mcs_...${apiKey.slice(-4)}`;
|
|
1596
|
+
u.searchParams.set("key", redactedLabel);
|
|
1597
|
+
return u.toString();
|
|
1598
|
+
} catch {
|
|
1599
|
+
return proxyUrl;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1567
1602
|
function writeMcpAddedLine(shortName, filePath) {
|
|
1568
1603
|
process.stderr.write(
|
|
1569
1604
|
style.green("\u2713") + ' MCP server "' + shortName + '" added to ' + style.cyan(filePath) + "\n"
|
|
@@ -1713,8 +1748,9 @@ function printHostedProxyPostWriteHints(platform, shortName) {
|
|
|
1713
1748
|
}
|
|
1714
1749
|
async function applyHostedProxyMcpConfig(platform, proxyUrl, shortName, apiKey, workspacePath) {
|
|
1715
1750
|
const authHeader = `Bearer ${apiKey}`;
|
|
1751
|
+
const proxyUrlWithKeyWhenNeeded = shouldEmbedKeyInHostedProxyUrl(platform) ? hostedProxyUrlWithKeyParam(proxyUrl, apiKey) : proxyUrl;
|
|
1716
1752
|
if (platform === "gemini-cli") {
|
|
1717
|
-
await mergeGeminiHostedMcpServersIntoSettings(shortName,
|
|
1753
|
+
await mergeGeminiHostedMcpServersIntoSettings(shortName, proxyUrlWithKeyWhenNeeded, apiKey);
|
|
1718
1754
|
process.stderr.write(
|
|
1719
1755
|
style.dim(
|
|
1720
1756
|
"For project-specific config, copy the mcpServers entry into .gemini/settings.json in your project root. Restart Gemini CLI if it is already running."
|
|
@@ -1739,20 +1775,24 @@ async function applyHostedProxyMcpConfig(platform, proxyUrl, shortName, apiKey,
|
|
|
1739
1775
|
let result = "parse-error";
|
|
1740
1776
|
if (platform === "cursor") {
|
|
1741
1777
|
result = await mergeMcpServersObjectStyle(getCursorMcpJsonPath(), shortName, {
|
|
1742
|
-
url:
|
|
1778
|
+
url: proxyUrlWithKeyWhenNeeded,
|
|
1743
1779
|
headers: { Authorization: authHeader }
|
|
1744
1780
|
});
|
|
1745
1781
|
if (result === "parse-error") {
|
|
1746
1782
|
printHostedProxyJsonParseWarning(getCursorMcpJsonPath());
|
|
1747
1783
|
}
|
|
1748
1784
|
} else if (platform === "claude-desktop") {
|
|
1749
|
-
result = await mergeClaudeDesktopHostedMcpRemote(
|
|
1785
|
+
result = await mergeClaudeDesktopHostedMcpRemote(
|
|
1786
|
+
shortName,
|
|
1787
|
+
proxyUrlWithKeyWhenNeeded,
|
|
1788
|
+
apiKey
|
|
1789
|
+
);
|
|
1750
1790
|
if (result === "parse-error") {
|
|
1751
1791
|
printHostedProxyJsonParseWarning(getClaudeDesktopConfigPath());
|
|
1752
1792
|
}
|
|
1753
1793
|
} else if (platform === "windsurf") {
|
|
1754
1794
|
result = await mergeMcpServersObjectStyle(getWindsurfMcpConfigPath(), shortName, {
|
|
1755
|
-
serverUrl:
|
|
1795
|
+
serverUrl: proxyUrlWithKeyWhenNeeded,
|
|
1756
1796
|
headers: { Authorization: authHeader }
|
|
1757
1797
|
});
|
|
1758
1798
|
if (result === "parse-error") {
|
|
@@ -1760,25 +1800,30 @@ async function applyHostedProxyMcpConfig(platform, proxyUrl, shortName, apiKey,
|
|
|
1760
1800
|
}
|
|
1761
1801
|
} else if (platform === "cline") {
|
|
1762
1802
|
result = await mergeMcpServersObjectStyle(getClineMcpSettingsPath(), shortName, {
|
|
1763
|
-
url:
|
|
1803
|
+
url: proxyUrlWithKeyWhenNeeded,
|
|
1764
1804
|
headers: { Authorization: authHeader }
|
|
1765
1805
|
});
|
|
1766
1806
|
if (result === "parse-error") {
|
|
1767
1807
|
printHostedProxyJsonParseWarning(getClineMcpSettingsPath());
|
|
1768
1808
|
}
|
|
1769
1809
|
} else if (platform === "kilo-code") {
|
|
1770
|
-
result = await mergeKiloCodeProjectMcp(
|
|
1810
|
+
result = await mergeKiloCodeProjectMcp(
|
|
1811
|
+
workspacePath,
|
|
1812
|
+
shortName,
|
|
1813
|
+
proxyUrlWithKeyWhenNeeded,
|
|
1814
|
+
apiKey
|
|
1815
|
+
);
|
|
1771
1816
|
if (result === "parse-error") {
|
|
1772
1817
|
printHostedProxyJsonParseWarning(join(workspacePath, ".kilocode", "mcp.json"));
|
|
1773
1818
|
}
|
|
1774
1819
|
} else if (platform === "continue-dev") {
|
|
1775
|
-
result = await mergeContinueHostedMcp(shortName,
|
|
1820
|
+
result = await mergeContinueHostedMcp(shortName, proxyUrlWithKeyWhenNeeded, apiKey);
|
|
1776
1821
|
if (result === "parse-error") {
|
|
1777
1822
|
printHostedProxyJsonParseWarning(getContinueConfigJsonPath());
|
|
1778
1823
|
}
|
|
1779
1824
|
} else {
|
|
1780
1825
|
result = await mergeMcpServersObjectStyle(getCursorMcpJsonPath(), shortName, {
|
|
1781
|
-
url:
|
|
1826
|
+
url: proxyUrlWithKeyWhenNeeded,
|
|
1782
1827
|
headers: { Authorization: authHeader }
|
|
1783
1828
|
});
|
|
1784
1829
|
if (result === "parse-error") {
|
|
@@ -1823,6 +1868,7 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
1823
1868
|
]);
|
|
1824
1869
|
const usesInlineKey = hostedInlinePlatforms.has(platform);
|
|
1825
1870
|
const authHeader = usesInlineKey ? `Bearer ${apiKey}` : "Bearer YOUR_SHIELD_API_KEY";
|
|
1871
|
+
const urlInSnippet = usesInlineKey && shouldEmbedKeyInHostedProxyUrl(platform) ? hostedProxyUrlWithKeyParam(routingToken, apiKey) : routingToken;
|
|
1826
1872
|
let snippetText;
|
|
1827
1873
|
if (platform === "github-copilot") {
|
|
1828
1874
|
snippetText = JSON.stringify(
|
|
@@ -1831,7 +1877,7 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
1831
1877
|
servers: {
|
|
1832
1878
|
[shortName]: {
|
|
1833
1879
|
type: "http",
|
|
1834
|
-
url:
|
|
1880
|
+
url: urlInSnippet,
|
|
1835
1881
|
headers: {
|
|
1836
1882
|
Authorization: authHeader
|
|
1837
1883
|
}
|
|
@@ -1843,13 +1889,13 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
1843
1889
|
2
|
|
1844
1890
|
);
|
|
1845
1891
|
} else if (platform === "goose") {
|
|
1846
|
-
snippetText = gooseHostedProxyYaml(shortName,
|
|
1892
|
+
snippetText = gooseHostedProxyYaml(shortName, urlInSnippet, authHeader);
|
|
1847
1893
|
} else if (platform === "gemini-cli") {
|
|
1848
1894
|
snippetText = JSON.stringify(
|
|
1849
1895
|
{
|
|
1850
1896
|
mcpServers: {
|
|
1851
1897
|
[shortName]: {
|
|
1852
|
-
httpUrl:
|
|
1898
|
+
httpUrl: urlInSnippet,
|
|
1853
1899
|
headers: {
|
|
1854
1900
|
Authorization: authHeader
|
|
1855
1901
|
}
|
|
@@ -1865,7 +1911,7 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
1865
1911
|
mcpServers: {
|
|
1866
1912
|
[shortName]: {
|
|
1867
1913
|
command: "npx",
|
|
1868
|
-
args: ["-y", "mcp-remote",
|
|
1914
|
+
args: ["-y", "mcp-remote", urlInSnippet, "--header", `Authorization: ${authHeader}`]
|
|
1869
1915
|
}
|
|
1870
1916
|
}
|
|
1871
1917
|
},
|
|
@@ -1879,7 +1925,7 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
1879
1925
|
{
|
|
1880
1926
|
name: shortName,
|
|
1881
1927
|
type: "streamable-http",
|
|
1882
|
-
url:
|
|
1928
|
+
url: urlInSnippet,
|
|
1883
1929
|
headers: {
|
|
1884
1930
|
Authorization: authHeader
|
|
1885
1931
|
}
|
|
@@ -1895,7 +1941,7 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
1895
1941
|
{
|
|
1896
1942
|
mcpServers: {
|
|
1897
1943
|
[shortName]: {
|
|
1898
|
-
[urlKey]:
|
|
1944
|
+
[urlKey]: urlInSnippet,
|
|
1899
1945
|
headers: {
|
|
1900
1946
|
Authorization: authHeader
|
|
1901
1947
|
}
|
|
@@ -1988,31 +2034,41 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
1988
2034
|
process.stderr.write(style.dim("Start a new Goose session after updating config.") + "\n");
|
|
1989
2035
|
}
|
|
1990
2036
|
}
|
|
1991
|
-
function
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
2037
|
+
function agentDisplayNameDedupeKey(name) {
|
|
2038
|
+
return name.trim().toLowerCase();
|
|
2039
|
+
}
|
|
2040
|
+
function normalizeAgentEntryForMerge(a) {
|
|
2041
|
+
const name = a.name.trim();
|
|
2042
|
+
const ws = typeof a.workspacePath === "string" && a.workspacePath.length > 0 ? a.workspacePath : void 0;
|
|
2043
|
+
return ws !== void 0 ? { name, platform: a.platform, workspacePath: ws } : { name, platform: a.platform };
|
|
2044
|
+
}
|
|
2045
|
+
function mergeAgentEntryDupPair(first, second) {
|
|
2046
|
+
const name = first.name.trim();
|
|
2047
|
+
const platform = first.platform;
|
|
2048
|
+
const ws = typeof first.workspacePath === "string" && first.workspacePath.length > 0 ? first.workspacePath : typeof second.workspacePath === "string" && second.workspacePath.length > 0 ? second.workspacePath : void 0;
|
|
2049
|
+
return ws !== void 0 ? { name, platform, workspacePath: ws } : { name, platform };
|
|
2050
|
+
}
|
|
2051
|
+
function mergeAgentsForUniqueNames(agents) {
|
|
2052
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2053
|
+
for (const raw of agents) {
|
|
2054
|
+
const key = agentDisplayNameDedupeKey(raw.name);
|
|
2055
|
+
const candidate = normalizeAgentEntryForMerge(raw);
|
|
2056
|
+
const prev = byKey.get(key);
|
|
2057
|
+
byKey.set(key, prev === void 0 ? candidate : mergeAgentEntryDupPair(prev, candidate));
|
|
1998
2058
|
}
|
|
1999
|
-
return
|
|
2059
|
+
return [...byKey.values()];
|
|
2000
2060
|
}
|
|
2001
2061
|
function mergeAgentsForPlatform(localAgents, remoteAgents, selectedPlatform) {
|
|
2002
|
-
const
|
|
2062
|
+
const merged = [];
|
|
2003
2063
|
for (const a of localAgents) {
|
|
2004
2064
|
if (a.platform !== selectedPlatform) continue;
|
|
2005
|
-
|
|
2006
|
-
byName.set(a.name, { ...a });
|
|
2007
|
-
}
|
|
2065
|
+
merged.push(a);
|
|
2008
2066
|
}
|
|
2009
2067
|
for (const r of remoteAgents) {
|
|
2010
2068
|
if (r.platform !== selectedPlatform) continue;
|
|
2011
|
-
|
|
2012
|
-
byName.set(r.name, { name: r.name, platform: selectedPlatform });
|
|
2013
|
-
}
|
|
2069
|
+
merged.push({ name: r.name, platform: selectedPlatform });
|
|
2014
2070
|
}
|
|
2015
|
-
return
|
|
2071
|
+
return mergeAgentsForUniqueNames(merged);
|
|
2016
2072
|
}
|
|
2017
2073
|
async function runInit(explicitBaseUrl, options) {
|
|
2018
2074
|
const verbose = options?.verbose === true;
|
|
@@ -2151,8 +2207,10 @@ async function runInit(explicitBaseUrl, options) {
|
|
|
2151
2207
|
continue;
|
|
2152
2208
|
}
|
|
2153
2209
|
const remoteAccountAgents = await fetchRemoteAgentsSummaries(apiKey, resolvedBaseUrl);
|
|
2154
|
-
const agentsForPlatform =
|
|
2155
|
-
|
|
2210
|
+
const agentsForPlatform = mergeAgentsForPlatform(
|
|
2211
|
+
currentAgents,
|
|
2212
|
+
remoteAccountAgents,
|
|
2213
|
+
selectedPlatform
|
|
2156
2214
|
);
|
|
2157
2215
|
const localForPlatformCount = currentAgents.filter(
|
|
2158
2216
|
(a) => a.platform === selectedPlatform
|
|
@@ -2414,7 +2472,9 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
2414
2472
|
}
|
|
2415
2473
|
if (created && proxyUrl.length > 0) {
|
|
2416
2474
|
process.stderr.write("\n" + style.bold("Your Shield proxy URL:") + "\n");
|
|
2417
|
-
process.stderr.write(
|
|
2475
|
+
process.stderr.write(
|
|
2476
|
+
" " + style.cyan(formatHostedProxyUrlForStderr(selectedPlatform, proxyUrl, apiKey)) + "\n"
|
|
2477
|
+
);
|
|
2418
2478
|
await applyHostedProxyMcpConfig(
|
|
2419
2479
|
selectedPlatform,
|
|
2420
2480
|
proxyUrl,
|
|
@@ -2505,7 +2565,9 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
2505
2565
|
}
|
|
2506
2566
|
if (created && proxyUrl.length > 0) {
|
|
2507
2567
|
process.stderr.write("\n" + style.bold("Your Shield proxy URL:") + "\n");
|
|
2508
|
-
process.stderr.write(
|
|
2568
|
+
process.stderr.write(
|
|
2569
|
+
" " + style.cyan(formatHostedProxyUrlForStderr(selectedPlatform, proxyUrl, apiKey)) + "\n"
|
|
2570
|
+
);
|
|
2509
2571
|
await applyHostedProxyMcpConfig(
|
|
2510
2572
|
selectedPlatform,
|
|
2511
2573
|
proxyUrl,
|
|
@@ -2590,7 +2652,9 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
2590
2652
|
}
|
|
2591
2653
|
if (created && proxyUrl.length > 0) {
|
|
2592
2654
|
process.stderr.write("\n" + style.bold("Your Shield proxy URL:") + "\n");
|
|
2593
|
-
process.stderr.write(
|
|
2655
|
+
process.stderr.write(
|
|
2656
|
+
" " + style.cyan(formatHostedProxyUrlForStderr(selectedPlatform, proxyUrl, apiKey)) + "\n"
|
|
2657
|
+
);
|
|
2594
2658
|
await applyHostedProxyMcpConfig(
|
|
2595
2659
|
selectedPlatform,
|
|
2596
2660
|
proxyUrl,
|
|
@@ -2638,7 +2702,9 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
2638
2702
|
}
|
|
2639
2703
|
if (created && proxyUrl.length > 0) {
|
|
2640
2704
|
process.stderr.write("\n" + style.bold("Your Shield proxy URL:") + "\n");
|
|
2641
|
-
process.stderr.write(
|
|
2705
|
+
process.stderr.write(
|
|
2706
|
+
" " + style.cyan(formatHostedProxyUrlForStderr(selectedPlatform, proxyUrl, apiKey)) + "\n"
|
|
2707
|
+
);
|
|
2642
2708
|
await applyHostedProxyMcpConfig(
|
|
2643
2709
|
selectedPlatform,
|
|
2644
2710
|
proxyUrl,
|
|
@@ -2659,7 +2725,10 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
2659
2725
|
}
|
|
2660
2726
|
if (setupSucceeded) {
|
|
2661
2727
|
if (removeAgentNameBeforeSave !== void 0) {
|
|
2662
|
-
|
|
2728
|
+
const removeKey = agentDisplayNameDedupeKey(removeAgentNameBeforeSave);
|
|
2729
|
+
currentAgents = currentAgents.filter(
|
|
2730
|
+
(a) => agentDisplayNameDedupeKey(a.name) !== removeKey
|
|
2731
|
+
);
|
|
2663
2732
|
}
|
|
2664
2733
|
currentAgents.push({
|
|
2665
2734
|
name: agentName,
|
|
@@ -2816,7 +2885,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
2816
2885
|
}
|
|
2817
2886
|
return lastConfig;
|
|
2818
2887
|
}
|
|
2819
|
-
var SECRET_JSON_FILE_OPTIONS, style, BANNER, NativePluginPrerequisiteMissingError, CONFIG_DIR, CONFIG_PATH, OPENCLAW_CONFIG_PATH, ANSI_PATTERN, OPENCLAW_MIN_VERSION, INIT_WIZARD_PLATFORM_REGISTRY, INIT_WIZARD_MENU_SECTIONS, INIT_WIZARD_SELECTION_MAX, PLATFORM_BY_SELECTION, DEFAULT_SHIELD_API_BASE_URL;
|
|
2888
|
+
var SECRET_JSON_FILE_OPTIONS, style, BANNER, NativePluginPrerequisiteMissingError, CONFIG_DIR, CONFIG_PATH, OPENCLAW_CONFIG_PATH, ANSI_PATTERN, OPENCLAW_MIN_VERSION, INIT_WIZARD_PLATFORM_REGISTRY, INIT_WIZARD_MENU_SECTIONS, INIT_WIZARD_SELECTION_MAX, PLATFORM_BY_SELECTION, HOSTED_PROXY_PLATFORMS_WITH_URL_KEY, DEFAULT_SHIELD_API_BASE_URL;
|
|
2820
2889
|
var init_config = __esm({
|
|
2821
2890
|
"src/proxy/config.ts"() {
|
|
2822
2891
|
init_consent();
|
|
@@ -2907,6 +2976,14 @@ var init_config = __esm({
|
|
|
2907
2976
|
PLATFORM_BY_SELECTION = Object.fromEntries(
|
|
2908
2977
|
INIT_WIZARD_PLATFORM_REGISTRY.map((e, i) => [i + 1, e.slug])
|
|
2909
2978
|
);
|
|
2979
|
+
HOSTED_PROXY_PLATFORMS_WITH_URL_KEY = /* @__PURE__ */ new Set([
|
|
2980
|
+
"cursor",
|
|
2981
|
+
"claude-desktop",
|
|
2982
|
+
"github-copilot",
|
|
2983
|
+
"kilo-code",
|
|
2984
|
+
"continue-dev",
|
|
2985
|
+
"goose"
|
|
2986
|
+
]);
|
|
2910
2987
|
DEFAULT_SHIELD_API_BASE_URL = "https://api.multicorn.ai";
|
|
2911
2988
|
}
|
|
2912
2989
|
});
|
package/dist/multicorn-shield.js
CHANGED
|
@@ -1635,6 +1635,49 @@ async function createProxyConfig(baseUrl, apiKey, agentName, targetUrl, serverNa
|
|
|
1635
1635
|
const data = envelope["data"];
|
|
1636
1636
|
return typeof data?.["proxy_url"] === "string" ? data["proxy_url"] : "";
|
|
1637
1637
|
}
|
|
1638
|
+
var HOSTED_PROXY_PLATFORMS_WITH_URL_KEY = /* @__PURE__ */ new Set([
|
|
1639
|
+
"cursor",
|
|
1640
|
+
"claude-desktop",
|
|
1641
|
+
"github-copilot",
|
|
1642
|
+
"kilo-code",
|
|
1643
|
+
"continue-dev",
|
|
1644
|
+
"goose"
|
|
1645
|
+
]);
|
|
1646
|
+
function shouldEmbedKeyInHostedProxyUrl(platform) {
|
|
1647
|
+
return HOSTED_PROXY_PLATFORMS_WITH_URL_KEY.has(platform);
|
|
1648
|
+
}
|
|
1649
|
+
function hostedProxyUrlWithKeyParam(proxyUrl, apiKey) {
|
|
1650
|
+
if (apiKey.length === 0) {
|
|
1651
|
+
process.stderr.write(
|
|
1652
|
+
style.yellow("\u26A0") + " Could not add key to proxy URL: API key is empty; using URL without key query parameter.\n"
|
|
1653
|
+
);
|
|
1654
|
+
return proxyUrl;
|
|
1655
|
+
}
|
|
1656
|
+
try {
|
|
1657
|
+
const u = new URL(proxyUrl);
|
|
1658
|
+
u.searchParams.set("key", apiKey);
|
|
1659
|
+
return u.toString();
|
|
1660
|
+
} catch (err) {
|
|
1661
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
1662
|
+
process.stderr.write(
|
|
1663
|
+
style.yellow("\u26A0") + " Could not parse proxy URL to append key query parameter; using URL unchanged. " + style.dim(detail) + "\n"
|
|
1664
|
+
);
|
|
1665
|
+
return proxyUrl;
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
function formatHostedProxyUrlForStderr(platform, proxyUrl, apiKey) {
|
|
1669
|
+
if (!shouldEmbedKeyInHostedProxyUrl(platform) || apiKey.length === 0) {
|
|
1670
|
+
return proxyUrl;
|
|
1671
|
+
}
|
|
1672
|
+
try {
|
|
1673
|
+
const u = new URL(proxyUrl);
|
|
1674
|
+
const redactedLabel = apiKey.length <= 4 ? "****" : `mcs_...${apiKey.slice(-4)}`;
|
|
1675
|
+
u.searchParams.set("key", redactedLabel);
|
|
1676
|
+
return u.toString();
|
|
1677
|
+
} catch {
|
|
1678
|
+
return proxyUrl;
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1638
1681
|
function writeMcpAddedLine(shortName, filePath) {
|
|
1639
1682
|
process.stderr.write(
|
|
1640
1683
|
style.green("\u2713") + ' MCP server "' + shortName + '" added to ' + style.cyan(filePath) + "\n"
|
|
@@ -1784,8 +1827,9 @@ function printHostedProxyPostWriteHints(platform, shortName) {
|
|
|
1784
1827
|
}
|
|
1785
1828
|
async function applyHostedProxyMcpConfig(platform, proxyUrl, shortName, apiKey, workspacePath) {
|
|
1786
1829
|
const authHeader = `Bearer ${apiKey}`;
|
|
1830
|
+
const proxyUrlWithKeyWhenNeeded = shouldEmbedKeyInHostedProxyUrl(platform) ? hostedProxyUrlWithKeyParam(proxyUrl, apiKey) : proxyUrl;
|
|
1787
1831
|
if (platform === "gemini-cli") {
|
|
1788
|
-
await mergeGeminiHostedMcpServersIntoSettings(shortName,
|
|
1832
|
+
await mergeGeminiHostedMcpServersIntoSettings(shortName, proxyUrlWithKeyWhenNeeded, apiKey);
|
|
1789
1833
|
process.stderr.write(
|
|
1790
1834
|
style.dim(
|
|
1791
1835
|
"For project-specific config, copy the mcpServers entry into .gemini/settings.json in your project root. Restart Gemini CLI if it is already running."
|
|
@@ -1810,20 +1854,24 @@ async function applyHostedProxyMcpConfig(platform, proxyUrl, shortName, apiKey,
|
|
|
1810
1854
|
let result = "parse-error";
|
|
1811
1855
|
if (platform === "cursor") {
|
|
1812
1856
|
result = await mergeMcpServersObjectStyle(getCursorMcpJsonPath(), shortName, {
|
|
1813
|
-
url:
|
|
1857
|
+
url: proxyUrlWithKeyWhenNeeded,
|
|
1814
1858
|
headers: { Authorization: authHeader }
|
|
1815
1859
|
});
|
|
1816
1860
|
if (result === "parse-error") {
|
|
1817
1861
|
printHostedProxyJsonParseWarning(getCursorMcpJsonPath());
|
|
1818
1862
|
}
|
|
1819
1863
|
} else if (platform === "claude-desktop") {
|
|
1820
|
-
result = await mergeClaudeDesktopHostedMcpRemote(
|
|
1864
|
+
result = await mergeClaudeDesktopHostedMcpRemote(
|
|
1865
|
+
shortName,
|
|
1866
|
+
proxyUrlWithKeyWhenNeeded,
|
|
1867
|
+
apiKey
|
|
1868
|
+
);
|
|
1821
1869
|
if (result === "parse-error") {
|
|
1822
1870
|
printHostedProxyJsonParseWarning(getClaudeDesktopConfigPath());
|
|
1823
1871
|
}
|
|
1824
1872
|
} else if (platform === "windsurf") {
|
|
1825
1873
|
result = await mergeMcpServersObjectStyle(getWindsurfMcpConfigPath(), shortName, {
|
|
1826
|
-
serverUrl:
|
|
1874
|
+
serverUrl: proxyUrlWithKeyWhenNeeded,
|
|
1827
1875
|
headers: { Authorization: authHeader }
|
|
1828
1876
|
});
|
|
1829
1877
|
if (result === "parse-error") {
|
|
@@ -1831,25 +1879,30 @@ async function applyHostedProxyMcpConfig(platform, proxyUrl, shortName, apiKey,
|
|
|
1831
1879
|
}
|
|
1832
1880
|
} else if (platform === "cline") {
|
|
1833
1881
|
result = await mergeMcpServersObjectStyle(getClineMcpSettingsPath(), shortName, {
|
|
1834
|
-
url:
|
|
1882
|
+
url: proxyUrlWithKeyWhenNeeded,
|
|
1835
1883
|
headers: { Authorization: authHeader }
|
|
1836
1884
|
});
|
|
1837
1885
|
if (result === "parse-error") {
|
|
1838
1886
|
printHostedProxyJsonParseWarning(getClineMcpSettingsPath());
|
|
1839
1887
|
}
|
|
1840
1888
|
} else if (platform === "kilo-code") {
|
|
1841
|
-
result = await mergeKiloCodeProjectMcp(
|
|
1889
|
+
result = await mergeKiloCodeProjectMcp(
|
|
1890
|
+
workspacePath,
|
|
1891
|
+
shortName,
|
|
1892
|
+
proxyUrlWithKeyWhenNeeded,
|
|
1893
|
+
apiKey
|
|
1894
|
+
);
|
|
1842
1895
|
if (result === "parse-error") {
|
|
1843
1896
|
printHostedProxyJsonParseWarning(join(workspacePath, ".kilocode", "mcp.json"));
|
|
1844
1897
|
}
|
|
1845
1898
|
} else if (platform === "continue-dev") {
|
|
1846
|
-
result = await mergeContinueHostedMcp(shortName,
|
|
1899
|
+
result = await mergeContinueHostedMcp(shortName, proxyUrlWithKeyWhenNeeded, apiKey);
|
|
1847
1900
|
if (result === "parse-error") {
|
|
1848
1901
|
printHostedProxyJsonParseWarning(getContinueConfigJsonPath());
|
|
1849
1902
|
}
|
|
1850
1903
|
} else {
|
|
1851
1904
|
result = await mergeMcpServersObjectStyle(getCursorMcpJsonPath(), shortName, {
|
|
1852
|
-
url:
|
|
1905
|
+
url: proxyUrlWithKeyWhenNeeded,
|
|
1853
1906
|
headers: { Authorization: authHeader }
|
|
1854
1907
|
});
|
|
1855
1908
|
if (result === "parse-error") {
|
|
@@ -1894,6 +1947,7 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
1894
1947
|
]);
|
|
1895
1948
|
const usesInlineKey = hostedInlinePlatforms.has(platform);
|
|
1896
1949
|
const authHeader = usesInlineKey ? `Bearer ${apiKey}` : "Bearer YOUR_SHIELD_API_KEY";
|
|
1950
|
+
const urlInSnippet = usesInlineKey && shouldEmbedKeyInHostedProxyUrl(platform) ? hostedProxyUrlWithKeyParam(routingToken, apiKey) : routingToken;
|
|
1897
1951
|
let snippetText;
|
|
1898
1952
|
if (platform === "github-copilot") {
|
|
1899
1953
|
snippetText = JSON.stringify(
|
|
@@ -1902,7 +1956,7 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
1902
1956
|
servers: {
|
|
1903
1957
|
[shortName]: {
|
|
1904
1958
|
type: "http",
|
|
1905
|
-
url:
|
|
1959
|
+
url: urlInSnippet,
|
|
1906
1960
|
headers: {
|
|
1907
1961
|
Authorization: authHeader
|
|
1908
1962
|
}
|
|
@@ -1914,13 +1968,13 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
1914
1968
|
2
|
|
1915
1969
|
);
|
|
1916
1970
|
} else if (platform === "goose") {
|
|
1917
|
-
snippetText = gooseHostedProxyYaml(shortName,
|
|
1971
|
+
snippetText = gooseHostedProxyYaml(shortName, urlInSnippet, authHeader);
|
|
1918
1972
|
} else if (platform === "gemini-cli") {
|
|
1919
1973
|
snippetText = JSON.stringify(
|
|
1920
1974
|
{
|
|
1921
1975
|
mcpServers: {
|
|
1922
1976
|
[shortName]: {
|
|
1923
|
-
httpUrl:
|
|
1977
|
+
httpUrl: urlInSnippet,
|
|
1924
1978
|
headers: {
|
|
1925
1979
|
Authorization: authHeader
|
|
1926
1980
|
}
|
|
@@ -1936,7 +1990,7 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
1936
1990
|
mcpServers: {
|
|
1937
1991
|
[shortName]: {
|
|
1938
1992
|
command: "npx",
|
|
1939
|
-
args: ["-y", "mcp-remote",
|
|
1993
|
+
args: ["-y", "mcp-remote", urlInSnippet, "--header", `Authorization: ${authHeader}`]
|
|
1940
1994
|
}
|
|
1941
1995
|
}
|
|
1942
1996
|
},
|
|
@@ -1950,7 +2004,7 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
1950
2004
|
{
|
|
1951
2005
|
name: shortName,
|
|
1952
2006
|
type: "streamable-http",
|
|
1953
|
-
url:
|
|
2007
|
+
url: urlInSnippet,
|
|
1954
2008
|
headers: {
|
|
1955
2009
|
Authorization: authHeader
|
|
1956
2010
|
}
|
|
@@ -1966,7 +2020,7 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
1966
2020
|
{
|
|
1967
2021
|
mcpServers: {
|
|
1968
2022
|
[shortName]: {
|
|
1969
|
-
[urlKey]:
|
|
2023
|
+
[urlKey]: urlInSnippet,
|
|
1970
2024
|
headers: {
|
|
1971
2025
|
Authorization: authHeader
|
|
1972
2026
|
}
|
|
@@ -2059,31 +2113,41 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
2059
2113
|
process.stderr.write(style.dim("Start a new Goose session after updating config.") + "\n");
|
|
2060
2114
|
}
|
|
2061
2115
|
}
|
|
2062
|
-
function
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2116
|
+
function agentDisplayNameDedupeKey(name) {
|
|
2117
|
+
return name.trim().toLowerCase();
|
|
2118
|
+
}
|
|
2119
|
+
function normalizeAgentEntryForMerge(a) {
|
|
2120
|
+
const name = a.name.trim();
|
|
2121
|
+
const ws = typeof a.workspacePath === "string" && a.workspacePath.length > 0 ? a.workspacePath : void 0;
|
|
2122
|
+
return ws !== void 0 ? { name, platform: a.platform, workspacePath: ws } : { name, platform: a.platform };
|
|
2123
|
+
}
|
|
2124
|
+
function mergeAgentEntryDupPair(first, second) {
|
|
2125
|
+
const name = first.name.trim();
|
|
2126
|
+
const platform = first.platform;
|
|
2127
|
+
const ws = typeof first.workspacePath === "string" && first.workspacePath.length > 0 ? first.workspacePath : typeof second.workspacePath === "string" && second.workspacePath.length > 0 ? second.workspacePath : void 0;
|
|
2128
|
+
return ws !== void 0 ? { name, platform, workspacePath: ws } : { name, platform };
|
|
2129
|
+
}
|
|
2130
|
+
function mergeAgentsForUniqueNames(agents) {
|
|
2131
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2132
|
+
for (const raw of agents) {
|
|
2133
|
+
const key = agentDisplayNameDedupeKey(raw.name);
|
|
2134
|
+
const candidate = normalizeAgentEntryForMerge(raw);
|
|
2135
|
+
const prev = byKey.get(key);
|
|
2136
|
+
byKey.set(key, prev === void 0 ? candidate : mergeAgentEntryDupPair(prev, candidate));
|
|
2069
2137
|
}
|
|
2070
|
-
return
|
|
2138
|
+
return [...byKey.values()];
|
|
2071
2139
|
}
|
|
2072
2140
|
function mergeAgentsForPlatform(localAgents, remoteAgents, selectedPlatform) {
|
|
2073
|
-
const
|
|
2141
|
+
const merged = [];
|
|
2074
2142
|
for (const a of localAgents) {
|
|
2075
2143
|
if (a.platform !== selectedPlatform) continue;
|
|
2076
|
-
|
|
2077
|
-
byName.set(a.name, { ...a });
|
|
2078
|
-
}
|
|
2144
|
+
merged.push(a);
|
|
2079
2145
|
}
|
|
2080
2146
|
for (const r of remoteAgents) {
|
|
2081
2147
|
if (r.platform !== selectedPlatform) continue;
|
|
2082
|
-
|
|
2083
|
-
byName.set(r.name, { name: r.name, platform: selectedPlatform });
|
|
2084
|
-
}
|
|
2148
|
+
merged.push({ name: r.name, platform: selectedPlatform });
|
|
2085
2149
|
}
|
|
2086
|
-
return
|
|
2150
|
+
return mergeAgentsForUniqueNames(merged);
|
|
2087
2151
|
}
|
|
2088
2152
|
var DEFAULT_SHIELD_API_BASE_URL = "https://api.multicorn.ai";
|
|
2089
2153
|
async function runInit(explicitBaseUrl, options) {
|
|
@@ -2223,8 +2287,10 @@ async function runInit(explicitBaseUrl, options) {
|
|
|
2223
2287
|
continue;
|
|
2224
2288
|
}
|
|
2225
2289
|
const remoteAccountAgents = await fetchRemoteAgentsSummaries(apiKey, resolvedBaseUrl);
|
|
2226
|
-
const agentsForPlatform =
|
|
2227
|
-
|
|
2290
|
+
const agentsForPlatform = mergeAgentsForPlatform(
|
|
2291
|
+
currentAgents,
|
|
2292
|
+
remoteAccountAgents,
|
|
2293
|
+
selectedPlatform
|
|
2228
2294
|
);
|
|
2229
2295
|
const localForPlatformCount = currentAgents.filter(
|
|
2230
2296
|
(a) => a.platform === selectedPlatform
|
|
@@ -2486,7 +2552,9 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
2486
2552
|
}
|
|
2487
2553
|
if (created && proxyUrl.length > 0) {
|
|
2488
2554
|
process.stderr.write("\n" + style.bold("Your Shield proxy URL:") + "\n");
|
|
2489
|
-
process.stderr.write(
|
|
2555
|
+
process.stderr.write(
|
|
2556
|
+
" " + style.cyan(formatHostedProxyUrlForStderr(selectedPlatform, proxyUrl, apiKey)) + "\n"
|
|
2557
|
+
);
|
|
2490
2558
|
await applyHostedProxyMcpConfig(
|
|
2491
2559
|
selectedPlatform,
|
|
2492
2560
|
proxyUrl,
|
|
@@ -2577,7 +2645,9 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
2577
2645
|
}
|
|
2578
2646
|
if (created && proxyUrl.length > 0) {
|
|
2579
2647
|
process.stderr.write("\n" + style.bold("Your Shield proxy URL:") + "\n");
|
|
2580
|
-
process.stderr.write(
|
|
2648
|
+
process.stderr.write(
|
|
2649
|
+
" " + style.cyan(formatHostedProxyUrlForStderr(selectedPlatform, proxyUrl, apiKey)) + "\n"
|
|
2650
|
+
);
|
|
2581
2651
|
await applyHostedProxyMcpConfig(
|
|
2582
2652
|
selectedPlatform,
|
|
2583
2653
|
proxyUrl,
|
|
@@ -2662,7 +2732,9 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
2662
2732
|
}
|
|
2663
2733
|
if (created && proxyUrl.length > 0) {
|
|
2664
2734
|
process.stderr.write("\n" + style.bold("Your Shield proxy URL:") + "\n");
|
|
2665
|
-
process.stderr.write(
|
|
2735
|
+
process.stderr.write(
|
|
2736
|
+
" " + style.cyan(formatHostedProxyUrlForStderr(selectedPlatform, proxyUrl, apiKey)) + "\n"
|
|
2737
|
+
);
|
|
2666
2738
|
await applyHostedProxyMcpConfig(
|
|
2667
2739
|
selectedPlatform,
|
|
2668
2740
|
proxyUrl,
|
|
@@ -2710,7 +2782,9 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
2710
2782
|
}
|
|
2711
2783
|
if (created && proxyUrl.length > 0) {
|
|
2712
2784
|
process.stderr.write("\n" + style.bold("Your Shield proxy URL:") + "\n");
|
|
2713
|
-
process.stderr.write(
|
|
2785
|
+
process.stderr.write(
|
|
2786
|
+
" " + style.cyan(formatHostedProxyUrlForStderr(selectedPlatform, proxyUrl, apiKey)) + "\n"
|
|
2787
|
+
);
|
|
2714
2788
|
await applyHostedProxyMcpConfig(
|
|
2715
2789
|
selectedPlatform,
|
|
2716
2790
|
proxyUrl,
|
|
@@ -2731,7 +2805,10 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
2731
2805
|
}
|
|
2732
2806
|
if (setupSucceeded) {
|
|
2733
2807
|
if (removeAgentNameBeforeSave !== void 0) {
|
|
2734
|
-
|
|
2808
|
+
const removeKey = agentDisplayNameDedupeKey(removeAgentNameBeforeSave);
|
|
2809
|
+
currentAgents = currentAgents.filter(
|
|
2810
|
+
(a) => agentDisplayNameDedupeKey(a.name) !== removeKey
|
|
2811
|
+
);
|
|
2735
2812
|
}
|
|
2736
2813
|
currentAgents.push({
|
|
2737
2814
|
name: agentName,
|
package/dist/shield-extension.js
CHANGED
|
@@ -22417,7 +22417,7 @@ async function writeExtensionBackup(claudeDesktopConfigPath, mcpServers) {
|
|
|
22417
22417
|
|
|
22418
22418
|
// package.json
|
|
22419
22419
|
var package_default = {
|
|
22420
|
-
version: "1.3.
|
|
22420
|
+
version: "1.3.6"};
|
|
22421
22421
|
|
|
22422
22422
|
// src/package-meta.ts
|
|
22423
22423
|
var PACKAGE_VERSION = package_default.version;
|
package/package.json
CHANGED