@atlasharness/atlascode 0.1.80 → 0.1.81
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/cli.js +623 -188
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -19862,7 +19862,7 @@ var init_openai = __esm(() => {
|
|
|
19862
19862
|
});
|
|
19863
19863
|
|
|
19864
19864
|
// src/modelprovider/constants.ts
|
|
19865
|
-
var API_IMAGE_MAX_BASE64_SIZE, IMAGE_TARGET_RAW_SIZE, PDF_TARGET_RAW_SIZE, API_PDF_MAX_PAGES = 100, LLM_TIMEOUT_DEFAULT_MS = 900000, LLM_TIMEOUT_CAP_MS = 1800000, LLM_TIMEOUT_UNIT_WARN_THRESHOLD_MS = 60000, STREAM_IDLE_TIMEOUT_MS = 300000, SUMMARIZE_CONNECTOR_TEXT_BETA_HEADER, AFK_MODE_BETA_HEADER;
|
|
19865
|
+
var API_IMAGE_MAX_BASE64_SIZE, IMAGE_TARGET_RAW_SIZE, PDF_TARGET_RAW_SIZE, API_PDF_MAX_PAGES = 100, LLM_TIMEOUT_DEFAULT_MS = 900000, LLM_TIMEOUT_CAP_MS = 1800000, LLM_TIMEOUT_UNIT_WARN_THRESHOLD_MS = 60000, STREAM_IDLE_TIMEOUT_MS = 300000, STREAM_IDLE_RETURN_GRACE_MS = 1000, SUMMARIZE_CONNECTOR_TEXT_BETA_HEADER, AFK_MODE_BETA_HEADER;
|
|
19866
19866
|
var init_constants2 = __esm(() => {
|
|
19867
19867
|
init_shared();
|
|
19868
19868
|
API_IMAGE_MAX_BASE64_SIZE = 5 * 1024 * 1024;
|
|
@@ -19901,7 +19901,7 @@ var init_clients = __esm(() => {
|
|
|
19901
19901
|
});
|
|
19902
19902
|
|
|
19903
19903
|
// src/modelprovider/streamIdleWatchdog.ts
|
|
19904
|
-
async function* withStreamIdleWatchdog(stream, timeoutMs = STREAM_IDLE_TIMEOUT_MS) {
|
|
19904
|
+
async function* withStreamIdleWatchdog(stream, timeoutMs = STREAM_IDLE_TIMEOUT_MS, returnGraceMs = STREAM_IDLE_RETURN_GRACE_MS) {
|
|
19905
19905
|
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
19906
19906
|
yield* stream;
|
|
19907
19907
|
return;
|
|
@@ -19933,7 +19933,19 @@ async function* withStreamIdleWatchdog(stream, timeoutMs = STREAM_IDLE_TIMEOUT_M
|
|
|
19933
19933
|
}
|
|
19934
19934
|
} finally {
|
|
19935
19935
|
try {
|
|
19936
|
-
|
|
19936
|
+
const ret = iterator.return?.();
|
|
19937
|
+
if (ret) {
|
|
19938
|
+
let graceTimer;
|
|
19939
|
+
const grace = new Promise((resolve) => {
|
|
19940
|
+
graceTimer = setTimeout(resolve, returnGraceMs);
|
|
19941
|
+
if (typeof graceTimer === "object" && graceTimer !== null && "unref" in graceTimer) {
|
|
19942
|
+
graceTimer.unref();
|
|
19943
|
+
}
|
|
19944
|
+
});
|
|
19945
|
+
await Promise.race([ret.then(() => {
|
|
19946
|
+
return;
|
|
19947
|
+
}, () => {}), grace]);
|
|
19948
|
+
}
|
|
19937
19949
|
} catch {}
|
|
19938
19950
|
}
|
|
19939
19951
|
}
|
|
@@ -27201,6 +27213,12 @@ function isQuotaExhaustedMessage(message) {
|
|
|
27201
27213
|
}
|
|
27202
27214
|
return false;
|
|
27203
27215
|
}
|
|
27216
|
+
function parseToolSchemaRejectionError(err) {
|
|
27217
|
+
if (!(err instanceof APIError2) || err.status !== 400)
|
|
27218
|
+
return null;
|
|
27219
|
+
const m = /invalid schema for (?:tool|function) [`'"]?([A-Za-z0-9_.\-]+)[`'"]?/i.exec(err.message);
|
|
27220
|
+
return m ? m[1] : null;
|
|
27221
|
+
}
|
|
27204
27222
|
function classifyAPIError(error) {
|
|
27205
27223
|
if (error instanceof Error && error.message === "Request was aborted.") {
|
|
27206
27224
|
return "aborted";
|
|
@@ -27341,6 +27359,8 @@ function shouldRetryModelError(err, signal) {
|
|
|
27341
27359
|
return false;
|
|
27342
27360
|
if (isClientRequestTimeout(err))
|
|
27343
27361
|
return false;
|
|
27362
|
+
if (parseToolSchemaRejectionError(err))
|
|
27363
|
+
return false;
|
|
27344
27364
|
return isRetryableError(err);
|
|
27345
27365
|
}
|
|
27346
27366
|
function llmTimeoutUnitHint(ms) {
|
|
@@ -29509,8 +29529,8 @@ var SettingsSchema = () => object({
|
|
|
29509
29529
|
mcpServers: record(string2(), any()).optional(),
|
|
29510
29530
|
allowedMcpServers: any().optional(),
|
|
29511
29531
|
deniedMcpServers: any().optional(),
|
|
29512
|
-
enabledMcpjsonServers: array(string2()).optional(),
|
|
29513
|
-
disabledMcpjsonServers: array(string2()).optional(),
|
|
29532
|
+
enabledMcpjsonServers: union([string2(), array(string2())]).transform((v) => Array.isArray(v) ? v : [v]).optional(),
|
|
29533
|
+
disabledMcpjsonServers: union([string2(), array(string2())]).transform((v) => Array.isArray(v) ? v : [v]).optional(),
|
|
29514
29534
|
sandbox: any().optional(),
|
|
29515
29535
|
permissions: any().optional(),
|
|
29516
29536
|
hooks: lazy(() => HooksSchema).optional(),
|
|
@@ -30144,7 +30164,7 @@ var init_filesystem = __esm(() => {
|
|
|
30144
30164
|
|
|
30145
30165
|
// src/permissions/permissionRuleParser.ts
|
|
30146
30166
|
function setLegacyToolNameAliases(map) {
|
|
30147
|
-
legacyToolNameAliases = map;
|
|
30167
|
+
legacyToolNameAliases = Object.assign(Object.create(null), map);
|
|
30148
30168
|
}
|
|
30149
30169
|
function normalizeLegacyToolName(name) {
|
|
30150
30170
|
return legacyToolNameAliases[name] ?? name;
|
|
@@ -30219,7 +30239,7 @@ function findLastUnescapedChar(str, char) {
|
|
|
30219
30239
|
}
|
|
30220
30240
|
var legacyToolNameAliases;
|
|
30221
30241
|
var init_permissionRuleParser = __esm(() => {
|
|
30222
|
-
legacyToolNameAliases =
|
|
30242
|
+
legacyToolNameAliases = Object.create(null);
|
|
30223
30243
|
});
|
|
30224
30244
|
|
|
30225
30245
|
// src/permissions/mcpRuleNames.ts
|
|
@@ -30228,6 +30248,9 @@ function normalizeNameForMCP(name) {
|
|
|
30228
30248
|
const normalized = folded.replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
30229
30249
|
return normalized === "" ? folded : normalized;
|
|
30230
30250
|
}
|
|
30251
|
+
function foldMcpNameForCompare(name) {
|
|
30252
|
+
return name.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_");
|
|
30253
|
+
}
|
|
30231
30254
|
function mcpInfoFromString(toolString) {
|
|
30232
30255
|
const parts = toolString.split("__");
|
|
30233
30256
|
const [mcpPart, serverName, ...toolNameParts] = parts;
|
|
@@ -30297,9 +30320,17 @@ function toolMatchesRule(tool, rule) {
|
|
|
30297
30320
|
if (rule.ruleValue.toolName === nameForRuleMatch) {
|
|
30298
30321
|
return true;
|
|
30299
30322
|
}
|
|
30300
|
-
const
|
|
30301
|
-
const
|
|
30302
|
-
|
|
30323
|
+
const toolInfo = tool.mcpInfo ?? mcpInfoFromString(nameForRuleMatch);
|
|
30324
|
+
const ruleName = rule.ruleValue.toolName;
|
|
30325
|
+
if (!toolInfo || !ruleName.startsWith("mcp__")) {
|
|
30326
|
+
return false;
|
|
30327
|
+
}
|
|
30328
|
+
if (foldMcpNameForCompare(ruleName) === foldMcpNameForCompare(nameForRuleMatch)) {
|
|
30329
|
+
return true;
|
|
30330
|
+
}
|
|
30331
|
+
const rest = ruleName.slice("mcp__".length);
|
|
30332
|
+
const ruleServerRaw = rest.endsWith("__*") ? rest.slice(0, -3) : rest;
|
|
30333
|
+
return foldMcpNameForCompare(ruleServerRaw) === foldMcpNameForCompare(toolInfo.serverName);
|
|
30303
30334
|
}
|
|
30304
30335
|
function toolAlwaysAllowedRule(context, tool) {
|
|
30305
30336
|
return getAllowRules(context).find((rule) => toolMatchesRule(tool, rule)) || null;
|
|
@@ -36851,6 +36882,15 @@ function filterToolsForAgent({
|
|
|
36851
36882
|
function computeChildSpawnDepth(parentOptions) {
|
|
36852
36883
|
return (parentOptions?.spawnDepth ?? 0) + 1;
|
|
36853
36884
|
}
|
|
36885
|
+
function resolveMcpServerDomainTools(toolName, available) {
|
|
36886
|
+
if (typeof toolName !== "string")
|
|
36887
|
+
return null;
|
|
36888
|
+
const info = mcpInfoFromString(toolName);
|
|
36889
|
+
if (!info || info.toolName !== undefined)
|
|
36890
|
+
return null;
|
|
36891
|
+
const prefix = getMcpPrefix(info.serverName);
|
|
36892
|
+
return available.filter((t) => t.name.startsWith(prefix));
|
|
36893
|
+
}
|
|
36854
36894
|
function resolveAgentTools(agentDefinition, availableTools, allowFanOut = false) {
|
|
36855
36895
|
const { tools: agentTools, disallowedTools, source } = agentDefinition;
|
|
36856
36896
|
const filtered = filterToolsForAgent({
|
|
@@ -36881,7 +36921,18 @@ function resolveAgentTools(agentDefinition, availableTools, allowFanOut = false)
|
|
|
36881
36921
|
seen.add(tool);
|
|
36882
36922
|
}
|
|
36883
36923
|
} else {
|
|
36884
|
-
|
|
36924
|
+
const domain = resolveMcpServerDomainTools(toolName, allowed);
|
|
36925
|
+
if (domain && domain.length > 0) {
|
|
36926
|
+
validTools.push(spec);
|
|
36927
|
+
for (const t of domain) {
|
|
36928
|
+
if (!seen.has(t)) {
|
|
36929
|
+
resolved.push(t);
|
|
36930
|
+
seen.add(t);
|
|
36931
|
+
}
|
|
36932
|
+
}
|
|
36933
|
+
} else {
|
|
36934
|
+
invalidTools.push(spec);
|
|
36935
|
+
}
|
|
36885
36936
|
}
|
|
36886
36937
|
}
|
|
36887
36938
|
return { hasWildcard: false, validTools, invalidTools, resolvedTools: resolved };
|
|
@@ -78400,7 +78451,7 @@ function getMcpDiscoveryInput() {
|
|
|
78400
78451
|
return discoveryInput;
|
|
78401
78452
|
}
|
|
78402
78453
|
async function buildMcpServerConfigs(input) {
|
|
78403
|
-
const servers =
|
|
78454
|
+
const servers = Object.create(null);
|
|
78404
78455
|
for (const [name, raw] of Object.entries(input.settingsServers ?? {})) {
|
|
78405
78456
|
const parsed = parseMcpServerConfig(raw);
|
|
78406
78457
|
if (parsed) {
|
|
@@ -78631,6 +78682,7 @@ async function terminateChild(name, child) {
|
|
|
78631
78682
|
function createMcpConnectionManager() {
|
|
78632
78683
|
const connections = new Map;
|
|
78633
78684
|
const pending = new Set;
|
|
78685
|
+
const pendingConnects = new Map;
|
|
78634
78686
|
const connectFailures = new Map;
|
|
78635
78687
|
function fail(name, config, error, authFailure = false) {
|
|
78636
78688
|
const conn = {
|
|
@@ -78643,6 +78695,17 @@ function createMcpConnectionManager() {
|
|
|
78643
78695
|
connections.set(name, conn);
|
|
78644
78696
|
return conn;
|
|
78645
78697
|
}
|
|
78698
|
+
function markBlocked(name, config, reason) {
|
|
78699
|
+
const conn = {
|
|
78700
|
+
name,
|
|
78701
|
+
type: "failed",
|
|
78702
|
+
config,
|
|
78703
|
+
error: `MCP server "${name}" blocked by enterprise policy: ${reason}`,
|
|
78704
|
+
blockedByPolicy: true
|
|
78705
|
+
};
|
|
78706
|
+
connections.set(name, conn);
|
|
78707
|
+
return conn;
|
|
78708
|
+
}
|
|
78646
78709
|
async function connectStdio(name, config, opts) {
|
|
78647
78710
|
const finalCommand = process.env.ATLAS_SHELL_PREFIX || config.command;
|
|
78648
78711
|
const finalArgs = process.env.ATLAS_SHELL_PREFIX ? [[config.command, ...config.args ?? []].join(" ")] : config.args ?? [];
|
|
@@ -78700,7 +78763,7 @@ function createMcpConnectionManager() {
|
|
|
78700
78763
|
};
|
|
78701
78764
|
client.onClose(closeOnDrop);
|
|
78702
78765
|
const initPromise = client.request("initialize", {
|
|
78703
|
-
protocolVersion: "
|
|
78766
|
+
protocolVersion: "2026-07-28",
|
|
78704
78767
|
capabilities: {
|
|
78705
78768
|
elicitation: {},
|
|
78706
78769
|
roots: {}
|
|
@@ -78727,6 +78790,7 @@ function createMcpConnectionManager() {
|
|
|
78727
78790
|
version: init.serverInfo.version
|
|
78728
78791
|
}
|
|
78729
78792
|
} : {},
|
|
78793
|
+
...init.protocolVersion ? { negotiatedProtocolVersion: init.protocolVersion } : {},
|
|
78730
78794
|
...init.instructions ? { instructions: init.instructions } : {},
|
|
78731
78795
|
config,
|
|
78732
78796
|
cleanup: async () => {
|
|
@@ -78753,6 +78817,21 @@ function createMcpConnectionManager() {
|
|
|
78753
78817
|
}
|
|
78754
78818
|
}
|
|
78755
78819
|
async function connect(name, config, opts) {
|
|
78820
|
+
const existing = connections.get(name);
|
|
78821
|
+
if (existing?.type === "connected")
|
|
78822
|
+
return existing;
|
|
78823
|
+
const inflight = pendingConnects.get(name);
|
|
78824
|
+
if (inflight)
|
|
78825
|
+
return inflight;
|
|
78826
|
+
const attempt = connectOnce(name, config, opts);
|
|
78827
|
+
pendingConnects.set(name, attempt);
|
|
78828
|
+
try {
|
|
78829
|
+
return await attempt;
|
|
78830
|
+
} finally {
|
|
78831
|
+
pendingConnects.delete(name);
|
|
78832
|
+
}
|
|
78833
|
+
}
|
|
78834
|
+
async function connectOnce(name, config, opts) {
|
|
78756
78835
|
const existing = connections.get(name);
|
|
78757
78836
|
if (existing?.type === "connected")
|
|
78758
78837
|
return existing;
|
|
@@ -78794,7 +78873,8 @@ function createMcpConnectionManager() {
|
|
|
78794
78873
|
await manager.close(name);
|
|
78795
78874
|
}
|
|
78796
78875
|
},
|
|
78797
|
-
getPendingServerNames: () => [...pending]
|
|
78876
|
+
getPendingServerNames: () => [...pending],
|
|
78877
|
+
markBlocked
|
|
78798
78878
|
};
|
|
78799
78879
|
return manager;
|
|
78800
78880
|
}
|
|
@@ -78809,6 +78889,143 @@ var init_mcpConnectionManager = __esm(() => {
|
|
|
78809
78889
|
init_mcpFetch();
|
|
78810
78890
|
});
|
|
78811
78891
|
|
|
78892
|
+
// src/mcp/mcpPolicy.ts
|
|
78893
|
+
function getMcpPolicyFromSettings(settings) {
|
|
78894
|
+
if (typeof settings !== "object" || settings === null)
|
|
78895
|
+
return {};
|
|
78896
|
+
const rec = settings;
|
|
78897
|
+
return {
|
|
78898
|
+
...rec.allowedMcpServers !== undefined ? { allowedMcpServers: rec.allowedMcpServers } : {},
|
|
78899
|
+
...rec.deniedMcpServers !== undefined ? { deniedMcpServers: rec.deniedMcpServers } : {}
|
|
78900
|
+
};
|
|
78901
|
+
}
|
|
78902
|
+
function getMcpPolicyInput() {
|
|
78903
|
+
return policyInput;
|
|
78904
|
+
}
|
|
78905
|
+
function normalizePolicyEntries(raw) {
|
|
78906
|
+
if (!Array.isArray(raw))
|
|
78907
|
+
return [];
|
|
78908
|
+
const out = [];
|
|
78909
|
+
for (const entry of raw) {
|
|
78910
|
+
if (typeof entry === "string") {
|
|
78911
|
+
out.push({ kind: "name", value: entry });
|
|
78912
|
+
continue;
|
|
78913
|
+
}
|
|
78914
|
+
if (typeof entry !== "object" || entry === null)
|
|
78915
|
+
continue;
|
|
78916
|
+
const rec = entry;
|
|
78917
|
+
if (typeof rec.serverName === "string") {
|
|
78918
|
+
out.push({ kind: "name", value: rec.serverName });
|
|
78919
|
+
} else if (Array.isArray(rec.serverCommand) && rec.serverCommand.every((c) => typeof c === "string")) {
|
|
78920
|
+
out.push({ kind: "command", value: rec.serverCommand });
|
|
78921
|
+
} else if (typeof rec.serverUrl === "string") {
|
|
78922
|
+
out.push({ kind: "url", value: rec.serverUrl });
|
|
78923
|
+
}
|
|
78924
|
+
}
|
|
78925
|
+
return out;
|
|
78926
|
+
}
|
|
78927
|
+
function getServerCommandArray(config) {
|
|
78928
|
+
const t = config.type;
|
|
78929
|
+
if (t !== undefined && t !== "stdio") {
|
|
78930
|
+
return null;
|
|
78931
|
+
}
|
|
78932
|
+
const stdioConfig = config;
|
|
78933
|
+
return [stdioConfig.command, ...stdioConfig.args ?? []];
|
|
78934
|
+
}
|
|
78935
|
+
function commandArraysMatch(a, b) {
|
|
78936
|
+
if (a.length !== b.length) {
|
|
78937
|
+
return false;
|
|
78938
|
+
}
|
|
78939
|
+
return a.every((val, idx) => val === b[idx]);
|
|
78940
|
+
}
|
|
78941
|
+
function getServerUrl(config) {
|
|
78942
|
+
return "url" in config ? config.url : null;
|
|
78943
|
+
}
|
|
78944
|
+
function urlPatternToRegex(pattern) {
|
|
78945
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
78946
|
+
const regexStr = escaped.replace(/\*/g, ".*");
|
|
78947
|
+
return new RegExp(`^${regexStr}$`);
|
|
78948
|
+
}
|
|
78949
|
+
function urlMatchesPattern(url, pattern) {
|
|
78950
|
+
return urlPatternToRegex(pattern).test(url);
|
|
78951
|
+
}
|
|
78952
|
+
function isDeniedByEntries(serverName, config, entries) {
|
|
78953
|
+
for (const entry of entries) {
|
|
78954
|
+
if (entry.kind === "name" && entry.value === serverName)
|
|
78955
|
+
return true;
|
|
78956
|
+
}
|
|
78957
|
+
const serverCommand = getServerCommandArray(config);
|
|
78958
|
+
if (serverCommand) {
|
|
78959
|
+
for (const entry of entries) {
|
|
78960
|
+
if (entry.kind === "command" && commandArraysMatch(entry.value, serverCommand)) {
|
|
78961
|
+
return true;
|
|
78962
|
+
}
|
|
78963
|
+
}
|
|
78964
|
+
}
|
|
78965
|
+
const serverUrl = getServerUrl(config);
|
|
78966
|
+
if (serverUrl) {
|
|
78967
|
+
for (const entry of entries) {
|
|
78968
|
+
if (entry.kind === "url" && urlMatchesPattern(serverUrl, entry.value)) {
|
|
78969
|
+
return true;
|
|
78970
|
+
}
|
|
78971
|
+
}
|
|
78972
|
+
}
|
|
78973
|
+
return false;
|
|
78974
|
+
}
|
|
78975
|
+
function isAllowedByEntries(serverName, config, entries) {
|
|
78976
|
+
const hasCommandEntries = entries.some((e) => e.kind === "command");
|
|
78977
|
+
const hasUrlEntries = entries.some((e) => e.kind === "url");
|
|
78978
|
+
const serverCommand = getServerCommandArray(config);
|
|
78979
|
+
const serverUrl = getServerUrl(config);
|
|
78980
|
+
if (serverCommand) {
|
|
78981
|
+
if (hasCommandEntries) {
|
|
78982
|
+
return entries.some((e) => e.kind === "command" && commandArraysMatch(e.value, serverCommand));
|
|
78983
|
+
}
|
|
78984
|
+
return entries.some((e) => e.kind === "name" && e.value === serverName);
|
|
78985
|
+
}
|
|
78986
|
+
if (serverUrl) {
|
|
78987
|
+
if (hasUrlEntries) {
|
|
78988
|
+
return entries.some((e) => e.kind === "url" && urlMatchesPattern(serverUrl, e.value));
|
|
78989
|
+
}
|
|
78990
|
+
return entries.some((e) => e.kind === "name" && e.value === serverName);
|
|
78991
|
+
}
|
|
78992
|
+
return entries.some((e) => e.kind === "name" && e.value === serverName);
|
|
78993
|
+
}
|
|
78994
|
+
function checkMcpServerPolicy(serverName, config, policy) {
|
|
78995
|
+
const p = policy ?? getMcpPolicyInput() ?? {};
|
|
78996
|
+
const denied = normalizePolicyEntries(p.deniedMcpServers);
|
|
78997
|
+
if (isDeniedByEntries(serverName, config, denied)) {
|
|
78998
|
+
return { blocked: true, reason: "denied by policy (deniedMcpServers)" };
|
|
78999
|
+
}
|
|
79000
|
+
if (!Array.isArray(p.allowedMcpServers))
|
|
79001
|
+
return { blocked: false };
|
|
79002
|
+
if (p.allowedMcpServers.length === 0) {
|
|
79003
|
+
return {
|
|
79004
|
+
blocked: true,
|
|
79005
|
+
reason: "not in allowedMcpServers allowlist (empty allowlist blocks all servers)"
|
|
79006
|
+
};
|
|
79007
|
+
}
|
|
79008
|
+
const allowed = normalizePolicyEntries(p.allowedMcpServers);
|
|
79009
|
+
if (isAllowedByEntries(serverName, config, allowed)) {
|
|
79010
|
+
return { blocked: false };
|
|
79011
|
+
}
|
|
79012
|
+
return { blocked: true, reason: "not in allowedMcpServers allowlist" };
|
|
79013
|
+
}
|
|
79014
|
+
function filterMcpServersByPolicy(configs, policy) {
|
|
79015
|
+
const allowed = {};
|
|
79016
|
+
const blocked = [];
|
|
79017
|
+
for (const [name, config] of Object.entries(configs)) {
|
|
79018
|
+
const verdict = checkMcpServerPolicy(name, config, policy);
|
|
79019
|
+
if (verdict.blocked) {
|
|
79020
|
+
blocked.push({ name, reason: verdict.reason ?? "blocked by policy" });
|
|
79021
|
+
} else {
|
|
79022
|
+
allowed[name] = config;
|
|
79023
|
+
}
|
|
79024
|
+
}
|
|
79025
|
+
return { allowed, blocked };
|
|
79026
|
+
}
|
|
79027
|
+
var policyInput = null;
|
|
79028
|
+
|
|
78812
79029
|
// src/mcp/index.ts
|
|
78813
79030
|
var init_mcp3 = __esm(() => {
|
|
78814
79031
|
init_types6();
|
|
@@ -79909,12 +80126,12 @@ var LEGACY_TOOL_NAME_ALIASES;
|
|
|
79909
80126
|
var init_legacyToolNameAliases = __esm(() => {
|
|
79910
80127
|
init_permissions3();
|
|
79911
80128
|
init_toolNames();
|
|
79912
|
-
LEGACY_TOOL_NAME_ALIASES = {
|
|
80129
|
+
LEGACY_TOOL_NAME_ALIASES = Object.assign(Object.create(null), {
|
|
79913
80130
|
Task: AGENT_TOOL_NAME,
|
|
79914
80131
|
KillShell: TASK_STOP_TOOL_NAME,
|
|
79915
80132
|
AgentOutputTool: TASK_OUTPUT_TOOL_NAME,
|
|
79916
80133
|
BashOutputTool: TASK_OUTPUT_TOOL_NAME
|
|
79917
|
-
};
|
|
80134
|
+
});
|
|
79918
80135
|
setLegacyToolNameAliases(LEGACY_TOOL_NAME_ALIASES);
|
|
79919
80136
|
});
|
|
79920
80137
|
|
|
@@ -82800,6 +83017,8 @@ async function queryAgentLoop(deps, args) {
|
|
|
82800
83017
|
let turns = 0;
|
|
82801
83018
|
let terminated = false;
|
|
82802
83019
|
let lastRound;
|
|
83020
|
+
let activeTools = tools;
|
|
83021
|
+
const degradedTools = new Set;
|
|
82803
83022
|
const maxGoalTurns = args.context?.maxGoalTurns ?? DEFAULT_MAX_GOAL_TURNS;
|
|
82804
83023
|
let goalTurns = 0;
|
|
82805
83024
|
let deferredToolUse;
|
|
@@ -82842,6 +83061,24 @@ async function queryAgentLoop(deps, args) {
|
|
|
82842
83061
|
deps.emit?.({ type: "compacted", turn: turns, messages });
|
|
82843
83062
|
}
|
|
82844
83063
|
}
|
|
83064
|
+
if (deps.refreshRoundContext) {
|
|
83065
|
+
try {
|
|
83066
|
+
const refresh = deps.refreshRoundContext(messages);
|
|
83067
|
+
if (refresh) {
|
|
83068
|
+
if (refresh.tools) {
|
|
83069
|
+
activeTools = degradedTools.size > 0 ? refresh.tools.filter((t) => !degradedTools.has(t.name)) : refresh.tools;
|
|
83070
|
+
}
|
|
83071
|
+
if (refresh.appendedMessages && refresh.appendedMessages.length > 0) {
|
|
83072
|
+
messages = [...messages, ...refresh.appendedMessages];
|
|
83073
|
+
if (deps.transcript) {
|
|
83074
|
+
await deps.transcript.record(messages);
|
|
83075
|
+
}
|
|
83076
|
+
}
|
|
83077
|
+
}
|
|
83078
|
+
} catch (refreshErr) {
|
|
83079
|
+
logForDebugging(`[round-context-refresh] failed: ${errorMessage(refreshErr)}`);
|
|
83080
|
+
}
|
|
83081
|
+
}
|
|
82845
83082
|
deps.emit?.({ type: "round_start", turn: turns });
|
|
82846
83083
|
let reactiveRetried = false;
|
|
82847
83084
|
let effectiveDeps = deps;
|
|
@@ -82849,7 +83086,7 @@ async function queryAgentLoop(deps, args) {
|
|
|
82849
83086
|
for (;; ) {
|
|
82850
83087
|
const roundInputLen = messages.length;
|
|
82851
83088
|
try {
|
|
82852
|
-
lastRound = await queryOneRound(effectiveDeps,
|
|
83089
|
+
lastRound = await queryOneRound(effectiveDeps, activeTools, messages);
|
|
82853
83090
|
} catch (err) {
|
|
82854
83091
|
if (!reactiveRetried && deps.reactiveCompact !== undefined && isReactiveCompactEnabled() && isReactiveCompactRecoverableError(err)) {
|
|
82855
83092
|
reactiveRetried = true;
|
|
@@ -82872,6 +83109,13 @@ async function queryAgentLoop(deps, args) {
|
|
|
82872
83109
|
continue;
|
|
82873
83110
|
}
|
|
82874
83111
|
}
|
|
83112
|
+
const rejectedTool = parseToolSchemaRejectionError(err);
|
|
83113
|
+
if (rejectedTool && !degradedTools.has(rejectedTool) && activeTools.some((t) => t.name === rejectedTool)) {
|
|
83114
|
+
degradedTools.add(rejectedTool);
|
|
83115
|
+
activeTools = activeTools.filter((t) => t.name !== rejectedTool);
|
|
83116
|
+
logForDebugging(`[tool-schema-strip] 网关拒绝工具 '${rejectedTool}' 的 input schema,本会话剥除其参数后续跑(tools ${activeTools.length} 个)`);
|
|
83117
|
+
continue;
|
|
83118
|
+
}
|
|
82875
83119
|
const nextRef = nextFallbackRef(deps.fallbackModels, triedFallbackRefs);
|
|
82876
83120
|
if (nextRef && shouldRetryModelError(err, deps.signal)) {
|
|
82877
83121
|
triedFallbackRefs.add(nextRef);
|
|
@@ -86960,7 +87204,12 @@ async function connectMcpStartup(args) {
|
|
|
86960
87204
|
}) : {};
|
|
86961
87205
|
const dynamicNames = new Set(Object.keys(dynamicConfigs));
|
|
86962
87206
|
const allConfigs = strictMcpConfig ? dynamicConfigs : { ...baseConfigs, ...dynamicConfigs };
|
|
86963
|
-
const
|
|
87207
|
+
const policy = getMcpPolicyInput() ?? getMcpPolicyFromSettings(getSettingsWithErrors().settings);
|
|
87208
|
+
const { allowed, blocked } = filterMcpServersByPolicy(allConfigs, policy);
|
|
87209
|
+
for (const b of blocked) {
|
|
87210
|
+
manager.markBlocked(b.name, allConfigs[b.name], b.reason);
|
|
87211
|
+
}
|
|
87212
|
+
const connectAll = () => Promise.allSettled(Object.entries(allowed).map(([name, config]) => manager.connect(name, config, dynamicNames.has(name) ? { connectionTimeoutMs: 5000 } : undefined)));
|
|
86964
87213
|
const nonBlocking = isMcpConnectionNonBlocking();
|
|
86965
87214
|
if (nonBlocking) {
|
|
86966
87215
|
connectAll();
|
|
@@ -88219,6 +88468,10 @@ async function mapConcurrent(items, fn, concurrency) {
|
|
|
88219
88468
|
return results;
|
|
88220
88469
|
}
|
|
88221
88470
|
async function checkMcpServerHealth(manager, name, server) {
|
|
88471
|
+
const policy = getMcpPolicyInput() ?? getMcpPolicyFromSettings(getSettingsWithErrors().settings);
|
|
88472
|
+
if (checkMcpServerPolicy(name, server, policy).blocked) {
|
|
88473
|
+
return "✗ Blocked by enterprise policy";
|
|
88474
|
+
}
|
|
88222
88475
|
try {
|
|
88223
88476
|
const result = await manager.connect(name, server);
|
|
88224
88477
|
if (result.type === "connected") {
|
|
@@ -88514,6 +88767,7 @@ Warning: The command "${actualCommand}" looks like a URL, but is being interpret
|
|
|
88514
88767
|
}
|
|
88515
88768
|
var init_mcp4 = __esm(() => {
|
|
88516
88769
|
init_mcp3();
|
|
88770
|
+
init_engine();
|
|
88517
88771
|
init_entryInit();
|
|
88518
88772
|
init_mcpConfigWrite();
|
|
88519
88773
|
init_setup();
|
|
@@ -124455,8 +124709,8 @@ var isMcpServerCommandEntry = () => ({}), isMcpServerNameEntry = () => ({}), isM
|
|
|
124455
124709
|
mcpServers: record(string2(), any()).optional(),
|
|
124456
124710
|
allowedMcpServers: any().optional(),
|
|
124457
124711
|
deniedMcpServers: any().optional(),
|
|
124458
|
-
enabledMcpjsonServers: array(string2()).optional(),
|
|
124459
|
-
disabledMcpjsonServers: array(string2()).optional(),
|
|
124712
|
+
enabledMcpjsonServers: union([string2(), array(string2())]).transform((v) => Array.isArray(v) ? v : [v]).optional(),
|
|
124713
|
+
disabledMcpjsonServers: union([string2(), array(string2())]).transform((v) => Array.isArray(v) ? v : [v]).optional(),
|
|
124460
124714
|
enabledPlugins: record(string2(), any()).optional(),
|
|
124461
124715
|
pluginConfigs: any().optional(),
|
|
124462
124716
|
extraKnownMarketplaces: any().optional(),
|
|
@@ -124797,12 +125051,12 @@ function findLastUnescapedChar2(str, char) {
|
|
|
124797
125051
|
var LEGACY_TOOL_NAME_ALIASES2;
|
|
124798
125052
|
var init_permissionRuleParser2 = __esm(() => {
|
|
124799
125053
|
init_constants6();
|
|
124800
|
-
LEGACY_TOOL_NAME_ALIASES2 = {
|
|
125054
|
+
LEGACY_TOOL_NAME_ALIASES2 = Object.assign(Object.create(null), {
|
|
124801
125055
|
Task: AGENT_TOOL_NAME2,
|
|
124802
125056
|
KillShell: TASK_STOP_TOOL_NAME2,
|
|
124803
125057
|
AgentOutputTool: TASK_OUTPUT_TOOL_NAME2,
|
|
124804
125058
|
BashOutputTool: TASK_OUTPUT_TOOL_NAME2
|
|
124805
|
-
};
|
|
125059
|
+
});
|
|
124806
125060
|
});
|
|
124807
125061
|
|
|
124808
125062
|
// src/tui/utils/settings/toolValidationConfig.ts
|
|
@@ -188182,6 +188436,97 @@ var init_streamableHttp = __esm(() => {
|
|
|
188182
188436
|
};
|
|
188183
188437
|
});
|
|
188184
188438
|
|
|
188439
|
+
// src/tui/services/mcp/fetchTimeout.ts
|
|
188440
|
+
function getMcpConnectionTimeoutMs() {
|
|
188441
|
+
return parseInt(process.env.MCP_TIMEOUT || "", 10) || 30000;
|
|
188442
|
+
}
|
|
188443
|
+
function bindBodyReadDeadline(response) {
|
|
188444
|
+
const contentType = response.headers?.get("content-type") ?? "";
|
|
188445
|
+
if (contentType.includes("text/event-stream")) {
|
|
188446
|
+
return response;
|
|
188447
|
+
}
|
|
188448
|
+
const rawBody = response.body;
|
|
188449
|
+
if (!rawBody) {
|
|
188450
|
+
return response;
|
|
188451
|
+
}
|
|
188452
|
+
const reader = rawBody.getReader();
|
|
188453
|
+
let deadlineTimer;
|
|
188454
|
+
const deadline = new Promise((_, reject) => {
|
|
188455
|
+
deadlineTimer = setTimeout(() => reject(new DOMException("The operation timed out.", "TimeoutError")), getMcpConnectionTimeoutMs());
|
|
188456
|
+
deadlineTimer.unref?.();
|
|
188457
|
+
});
|
|
188458
|
+
deadline.catch(() => {});
|
|
188459
|
+
const clearDeadline = () => {
|
|
188460
|
+
if (deadlineTimer) {
|
|
188461
|
+
clearTimeout(deadlineTimer);
|
|
188462
|
+
}
|
|
188463
|
+
};
|
|
188464
|
+
const stream = new ReadableStream({
|
|
188465
|
+
async pull(ctrl) {
|
|
188466
|
+
try {
|
|
188467
|
+
const { done, value } = await Promise.race([reader.read(), deadline]);
|
|
188468
|
+
if (done) {
|
|
188469
|
+
clearDeadline();
|
|
188470
|
+
ctrl.close();
|
|
188471
|
+
} else {
|
|
188472
|
+
ctrl.enqueue(value);
|
|
188473
|
+
}
|
|
188474
|
+
} catch (error) {
|
|
188475
|
+
clearDeadline();
|
|
188476
|
+
reader.cancel().catch(() => {});
|
|
188477
|
+
ctrl.error(error);
|
|
188478
|
+
}
|
|
188479
|
+
},
|
|
188480
|
+
cancel(reason) {
|
|
188481
|
+
clearDeadline();
|
|
188482
|
+
return reader.cancel(reason);
|
|
188483
|
+
}
|
|
188484
|
+
});
|
|
188485
|
+
return new Response(stream, {
|
|
188486
|
+
status: response.status,
|
|
188487
|
+
statusText: response.statusText,
|
|
188488
|
+
headers: response.headers
|
|
188489
|
+
});
|
|
188490
|
+
}
|
|
188491
|
+
function wrapFetchWithTimeout(baseFetch) {
|
|
188492
|
+
return async (url, init) => {
|
|
188493
|
+
const method = (init?.method ?? "GET").toUpperCase();
|
|
188494
|
+
if (method === "GET") {
|
|
188495
|
+
return baseFetch(url, init);
|
|
188496
|
+
}
|
|
188497
|
+
const headers = new Headers(init?.headers);
|
|
188498
|
+
if (!headers.has("accept")) {
|
|
188499
|
+
headers.set("accept", MCP_STREAMABLE_HTTP_ACCEPT);
|
|
188500
|
+
}
|
|
188501
|
+
const controller = new AbortController;
|
|
188502
|
+
const timer = setTimeout((c) => c.abort(new DOMException("The operation timed out.", "TimeoutError")), MCP_REQUEST_TIMEOUT_MS, controller);
|
|
188503
|
+
timer.unref?.();
|
|
188504
|
+
const parentSignal = init?.signal;
|
|
188505
|
+
const abort = () => controller.abort(parentSignal?.reason);
|
|
188506
|
+
parentSignal?.addEventListener("abort", abort);
|
|
188507
|
+
if (parentSignal?.aborted) {
|
|
188508
|
+
controller.abort(parentSignal.reason);
|
|
188509
|
+
}
|
|
188510
|
+
const cleanup = () => {
|
|
188511
|
+
clearTimeout(timer);
|
|
188512
|
+
parentSignal?.removeEventListener("abort", abort);
|
|
188513
|
+
};
|
|
188514
|
+
try {
|
|
188515
|
+
const response = await baseFetch(url, {
|
|
188516
|
+
...init,
|
|
188517
|
+
headers,
|
|
188518
|
+
signal: controller.signal
|
|
188519
|
+
});
|
|
188520
|
+
cleanup();
|
|
188521
|
+
return bindBodyReadDeadline(response);
|
|
188522
|
+
} catch (error) {
|
|
188523
|
+
cleanup();
|
|
188524
|
+
throw error;
|
|
188525
|
+
}
|
|
188526
|
+
};
|
|
188527
|
+
}
|
|
188528
|
+
var MCP_REQUEST_TIMEOUT_MS = 60000, MCP_STREAMABLE_HTTP_ACCEPT = "application/json, text/event-stream";
|
|
188529
|
+
|
|
188185
188530
|
// node_modules/lodash-es/_baseZipObject.js
|
|
188186
188531
|
function baseZipObject(props, values, assignFunc) {
|
|
188187
188532
|
var index = -1, length = props.length, valsLength = values.length, result = {};
|
|
@@ -193521,6 +193866,73 @@ var init_browser = __esm(() => {
|
|
|
193521
193866
|
init_execFileNoThrow2();
|
|
193522
193867
|
});
|
|
193523
193868
|
|
|
193869
|
+
// src/tui/services/mcp/headersHelper.ts
|
|
193870
|
+
function isMcpServerFromProjectOrLocalSettings(config) {
|
|
193871
|
+
return config.scope === "project" || config.scope === "local";
|
|
193872
|
+
}
|
|
193873
|
+
async function getMcpHeadersFromHelper(serverName, config) {
|
|
193874
|
+
if (!config.headersHelper) {
|
|
193875
|
+
return null;
|
|
193876
|
+
}
|
|
193877
|
+
if ("scope" in config && isMcpServerFromProjectOrLocalSettings(config)) {
|
|
193878
|
+
const isNonInteractive = getIsNonInteractiveSession();
|
|
193879
|
+
const explicitTrust = process.env.ATLAS_TRUST_WORKSPACE === "true";
|
|
193880
|
+
const hasTrust = checkHasTrustDialogAccepted() || isNonInteractive && explicitTrust;
|
|
193881
|
+
if (!hasTrust) {
|
|
193882
|
+
const error = new Error(`Security: headersHelper for MCP server '${serverName}' executed before workspace trust is confirmed. If you see this message, post in ${MACRO.FEEDBACK_CHANNEL}.`);
|
|
193883
|
+
logAntError("MCP headersHelper invoked before trust check", error);
|
|
193884
|
+
return null;
|
|
193885
|
+
}
|
|
193886
|
+
}
|
|
193887
|
+
try {
|
|
193888
|
+
logMCPDebug(serverName, "Executing headersHelper to get dynamic headers");
|
|
193889
|
+
const execResult = await execFileNoThrowWithCwd2("sh", ["-c", config.headersHelper], {
|
|
193890
|
+
timeout: 1e4,
|
|
193891
|
+
env: {
|
|
193892
|
+
...process.env,
|
|
193893
|
+
ATLAS_MCP_SERVER_NAME: serverName,
|
|
193894
|
+
ATLAS_MCP_SERVER_URL: config.url
|
|
193895
|
+
}
|
|
193896
|
+
});
|
|
193897
|
+
if (execResult.code !== 0 || !execResult.stdout) {
|
|
193898
|
+
throw new Error(`headersHelper for MCP server '${serverName}' did not return a valid value`);
|
|
193899
|
+
}
|
|
193900
|
+
const result = execResult.stdout.trim();
|
|
193901
|
+
const headers = jsonParse2(result);
|
|
193902
|
+
if (typeof headers !== "object" || headers === null || Array.isArray(headers)) {
|
|
193903
|
+
throw new Error(`headersHelper for MCP server '${serverName}' must return a JSON object with string key-value pairs`);
|
|
193904
|
+
}
|
|
193905
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
193906
|
+
if (typeof value !== "string") {
|
|
193907
|
+
throw new Error(`headersHelper for MCP server '${serverName}' returned non-string value for key "${key}": ${typeof value}`);
|
|
193908
|
+
}
|
|
193909
|
+
}
|
|
193910
|
+
logMCPDebug(serverName, `Successfully retrieved ${Object.keys(headers).length} headers from headersHelper`);
|
|
193911
|
+
return headers;
|
|
193912
|
+
} catch (error) {
|
|
193913
|
+
logMCPError(serverName, `Error getting headers from headersHelper: ${errorMessage2(error)}`);
|
|
193914
|
+
logError3(new Error(`Error getting MCP headers from headersHelper for server '${serverName}': ${errorMessage2(error)}`));
|
|
193915
|
+
return null;
|
|
193916
|
+
}
|
|
193917
|
+
}
|
|
193918
|
+
async function getMcpServerHeaders(serverName, config) {
|
|
193919
|
+
const staticHeaders = config.headers || {};
|
|
193920
|
+
const dynamicHeaders = await getMcpHeadersFromHelper(serverName, config) || {};
|
|
193921
|
+
return {
|
|
193922
|
+
...staticHeaders,
|
|
193923
|
+
...dynamicHeaders
|
|
193924
|
+
};
|
|
193925
|
+
}
|
|
193926
|
+
var init_headersHelper = __esm(() => {
|
|
193927
|
+
init_bootstrap();
|
|
193928
|
+
init_config6();
|
|
193929
|
+
init_debug();
|
|
193930
|
+
init_errors4();
|
|
193931
|
+
init_execFileNoThrow2();
|
|
193932
|
+
init_log5();
|
|
193933
|
+
init_slowOperations();
|
|
193934
|
+
});
|
|
193935
|
+
|
|
193524
193936
|
// src/tui/services/mcp/oauthPort.ts
|
|
193525
193937
|
import { createServer } from "http";
|
|
193526
193938
|
function buildRedirectUri(port = REDIRECT_PORT_FALLBACK) {
|
|
@@ -194028,20 +194440,20 @@ async function writeMcpjsonFile2(config) {
|
|
|
194028
194440
|
throw e;
|
|
194029
194441
|
}
|
|
194030
194442
|
}
|
|
194031
|
-
function
|
|
194443
|
+
function getServerCommandArray2(config) {
|
|
194032
194444
|
if (config.type !== undefined && config.type !== "stdio") {
|
|
194033
194445
|
return null;
|
|
194034
194446
|
}
|
|
194035
194447
|
const stdioConfig = config;
|
|
194036
194448
|
return [stdioConfig.command, ...stdioConfig.args ?? []];
|
|
194037
194449
|
}
|
|
194038
|
-
function
|
|
194450
|
+
function commandArraysMatch2(a, b) {
|
|
194039
194451
|
if (a.length !== b.length) {
|
|
194040
194452
|
return false;
|
|
194041
194453
|
}
|
|
194042
194454
|
return a.every((val, idx) => val === b[idx]);
|
|
194043
194455
|
}
|
|
194044
|
-
function
|
|
194456
|
+
function getServerUrl2(config) {
|
|
194045
194457
|
return "url" in config ? config.url : null;
|
|
194046
194458
|
}
|
|
194047
194459
|
function unwrapCcrProxyUrl(url) {
|
|
@@ -194057,11 +194469,11 @@ function unwrapCcrProxyUrl(url) {
|
|
|
194057
194469
|
}
|
|
194058
194470
|
}
|
|
194059
194471
|
function getMcpServerSignature(config) {
|
|
194060
|
-
const cmd =
|
|
194472
|
+
const cmd = getServerCommandArray2(config);
|
|
194061
194473
|
if (cmd) {
|
|
194062
194474
|
return `stdio:${jsonStringify5(cmd)}`;
|
|
194063
194475
|
}
|
|
194064
|
-
const url =
|
|
194476
|
+
const url = getServerUrl2(config);
|
|
194065
194477
|
if (url) {
|
|
194066
194478
|
return `url:${unwrapCcrProxyUrl(url)}`;
|
|
194067
194479
|
}
|
|
@@ -194123,13 +194535,13 @@ function dedupManagedMcpServers(claudeAiServers, manualServers) {
|
|
|
194123
194535
|
}
|
|
194124
194536
|
return { servers, suppressed };
|
|
194125
194537
|
}
|
|
194126
|
-
function
|
|
194538
|
+
function urlPatternToRegex2(pattern) {
|
|
194127
194539
|
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
194128
194540
|
const regexStr = escaped.replace(/\*/g, ".*");
|
|
194129
194541
|
return new RegExp(`^${regexStr}$`);
|
|
194130
194542
|
}
|
|
194131
|
-
function
|
|
194132
|
-
const regex =
|
|
194543
|
+
function urlMatchesPattern2(url, pattern) {
|
|
194544
|
+
const regex = urlPatternToRegex2(pattern);
|
|
194133
194545
|
return regex.test(url);
|
|
194134
194546
|
}
|
|
194135
194547
|
function getMcpAllowlistSettings() {
|
|
@@ -194152,18 +194564,18 @@ function isMcpServerDenied(serverName, config) {
|
|
|
194152
194564
|
}
|
|
194153
194565
|
}
|
|
194154
194566
|
if (config) {
|
|
194155
|
-
const serverCommand =
|
|
194567
|
+
const serverCommand = getServerCommandArray2(config);
|
|
194156
194568
|
if (serverCommand) {
|
|
194157
194569
|
for (const entry of settings.deniedMcpServers) {
|
|
194158
|
-
if (isMcpServerCommandEntry(entry) &&
|
|
194570
|
+
if (isMcpServerCommandEntry(entry) && commandArraysMatch2(entry.serverCommand, serverCommand)) {
|
|
194159
194571
|
return true;
|
|
194160
194572
|
}
|
|
194161
194573
|
}
|
|
194162
194574
|
}
|
|
194163
|
-
const serverUrl =
|
|
194575
|
+
const serverUrl = getServerUrl2(config);
|
|
194164
194576
|
if (serverUrl) {
|
|
194165
194577
|
for (const entry of settings.deniedMcpServers) {
|
|
194166
|
-
if (isMcpServerUrlEntry(entry) &&
|
|
194578
|
+
if (isMcpServerUrlEntry(entry) && urlMatchesPattern2(serverUrl, entry.serverUrl)) {
|
|
194167
194579
|
return true;
|
|
194168
194580
|
}
|
|
194169
194581
|
}
|
|
@@ -194185,12 +194597,12 @@ function isMcpServerAllowedByPolicy(serverName, config) {
|
|
|
194185
194597
|
const hasCommandEntries = settings.allowedMcpServers.some(isMcpServerCommandEntry);
|
|
194186
194598
|
const hasUrlEntries = settings.allowedMcpServers.some(isMcpServerUrlEntry);
|
|
194187
194599
|
if (config) {
|
|
194188
|
-
const serverCommand =
|
|
194189
|
-
const serverUrl =
|
|
194600
|
+
const serverCommand = getServerCommandArray2(config);
|
|
194601
|
+
const serverUrl = getServerUrl2(config);
|
|
194190
194602
|
if (serverCommand) {
|
|
194191
194603
|
if (hasCommandEntries) {
|
|
194192
194604
|
for (const entry of settings.allowedMcpServers) {
|
|
194193
|
-
if (isMcpServerCommandEntry(entry) &&
|
|
194605
|
+
if (isMcpServerCommandEntry(entry) && commandArraysMatch2(entry.serverCommand, serverCommand)) {
|
|
194194
194606
|
return true;
|
|
194195
194607
|
}
|
|
194196
194608
|
}
|
|
@@ -194206,7 +194618,7 @@ function isMcpServerAllowedByPolicy(serverName, config) {
|
|
|
194206
194618
|
} else if (serverUrl) {
|
|
194207
194619
|
if (hasUrlEntries) {
|
|
194208
194620
|
for (const entry of settings.allowedMcpServers) {
|
|
194209
|
-
if (isMcpServerUrlEntry(entry) &&
|
|
194621
|
+
if (isMcpServerUrlEntry(entry) && urlMatchesPattern2(serverUrl, entry.serverUrl)) {
|
|
194210
194622
|
return true;
|
|
194211
194623
|
}
|
|
194212
194624
|
}
|
|
@@ -194235,7 +194647,7 @@ function isMcpServerAllowedByPolicy(serverName, config) {
|
|
|
194235
194647
|
}
|
|
194236
194648
|
return false;
|
|
194237
194649
|
}
|
|
194238
|
-
function
|
|
194650
|
+
function filterMcpServersByPolicy2(configs) {
|
|
194239
194651
|
const allowed = {};
|
|
194240
194652
|
const blocked = [];
|
|
194241
194653
|
for (const [name, config] of Object.entries(configs)) {
|
|
@@ -194687,7 +195099,7 @@ async function getAllMcpConfigs2() {
|
|
|
194687
195099
|
}
|
|
194688
195100
|
const claudeaiPromise = Promise.resolve({});
|
|
194689
195101
|
const { servers: claudeCodeServers, errors } = await getMcpConfigs({}, claudeaiPromise);
|
|
194690
|
-
const { allowed: claudeaiMcpServers } =
|
|
195102
|
+
const { allowed: claudeaiMcpServers } = filterMcpServersByPolicy2(await claudeaiPromise);
|
|
194691
195103
|
const { servers: dedupedClaudeAi } = dedupManagedMcpServers(claudeaiMcpServers, claudeCodeServers);
|
|
194692
195104
|
const servers = Object.assign({}, dedupedClaudeAi, claudeCodeServers);
|
|
194693
195105
|
return { servers, errors };
|
|
@@ -194792,6 +195204,9 @@ function parseMcpConfigFromFilePath(params) {
|
|
|
194792
195204
|
]
|
|
194793
195205
|
};
|
|
194794
195206
|
}
|
|
195207
|
+
if (!configContent.trim()) {
|
|
195208
|
+
return { config: { mcpServers: {} }, errors: [] };
|
|
195209
|
+
}
|
|
194795
195210
|
const parsedJson = safeParseJSON3(configContent);
|
|
194796
195211
|
if (!parsedJson) {
|
|
194797
195212
|
logForDebugging3(`MCP config is not valid JSON: ${filePath} (scope=${scope}, length=${configContent.length}, first100=${jsonStringify5(configContent.slice(0, 100))})`, { level: "error" });
|
|
@@ -194811,6 +195226,9 @@ function parseMcpConfigFromFilePath(params) {
|
|
|
194811
195226
|
]
|
|
194812
195227
|
};
|
|
194813
195228
|
}
|
|
195229
|
+
if (typeof parsedJson === "object" && parsedJson !== null && !Array.isArray(parsedJson) && Object.keys(parsedJson).length === 0) {
|
|
195230
|
+
return { config: { mcpServers: {} }, errors: [] };
|
|
195231
|
+
}
|
|
194814
195232
|
return parseMcpConfig({
|
|
194815
195233
|
configObject: parsedJson,
|
|
194816
195234
|
expandVars,
|
|
@@ -194941,11 +195359,11 @@ function hashMcpConfig(config) {
|
|
|
194941
195359
|
});
|
|
194942
195360
|
return createHash4("sha256").update(stable).digest("hex").slice(0, 16);
|
|
194943
195361
|
}
|
|
194944
|
-
function excludeStalePluginClients(mcp, configs) {
|
|
195362
|
+
function excludeStalePluginClients(mcp, configs, opts) {
|
|
194945
195363
|
const stale = mcp.clients.filter((c) => {
|
|
194946
195364
|
const fresh = configs[c.name];
|
|
194947
195365
|
if (!fresh)
|
|
194948
|
-
return c.config.scope === "dynamic";
|
|
195366
|
+
return opts?.absentIsStale || c.config.scope === "dynamic";
|
|
194949
195367
|
return hashMcpConfig(c.config) !== hashMcpConfig(fresh);
|
|
194950
195368
|
});
|
|
194951
195369
|
if (stale.length === 0) {
|
|
@@ -195741,6 +196159,53 @@ function createAuthFetch() {
|
|
|
195741
196159
|
}
|
|
195742
196160
|
};
|
|
195743
196161
|
}
|
|
196162
|
+
async function resolveConfiguredMcpHeaders(serverName, serverConfig) {
|
|
196163
|
+
try {
|
|
196164
|
+
return await getMcpServerHeaders(serverName, serverConfig);
|
|
196165
|
+
} catch (error) {
|
|
196166
|
+
logMCPDebug(serverName, `Failed to resolve configured headers for OAuth: ${errorMessage2(error)}`);
|
|
196167
|
+
return {};
|
|
196168
|
+
}
|
|
196169
|
+
}
|
|
196170
|
+
function headersToRecord2(headers) {
|
|
196171
|
+
const out = {};
|
|
196172
|
+
if (!headers)
|
|
196173
|
+
return out;
|
|
196174
|
+
if (headers instanceof Headers) {
|
|
196175
|
+
headers.forEach((v, k) => {
|
|
196176
|
+
out[k] = v;
|
|
196177
|
+
});
|
|
196178
|
+
return out;
|
|
196179
|
+
}
|
|
196180
|
+
if (Array.isArray(headers)) {
|
|
196181
|
+
for (const [k, v] of headers)
|
|
196182
|
+
out[k] = v;
|
|
196183
|
+
return out;
|
|
196184
|
+
}
|
|
196185
|
+
if (typeof headers === "object") {
|
|
196186
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
196187
|
+
out[k] = String(v);
|
|
196188
|
+
}
|
|
196189
|
+
}
|
|
196190
|
+
return out;
|
|
196191
|
+
}
|
|
196192
|
+
function mergeConfiguredHeaders(fetchLike, configured) {
|
|
196193
|
+
if (Object.keys(configured).length === 0)
|
|
196194
|
+
return fetchLike;
|
|
196195
|
+
return (url, init) => {
|
|
196196
|
+
const requestHeaders = headersToRecord2(init?.headers);
|
|
196197
|
+
const requestKeys = new Set(Object.keys(requestHeaders).map((k) => k.toLowerCase()));
|
|
196198
|
+
const configuredNotOverridden = Object.fromEntries(Object.entries(configured).filter(([k]) => !requestKeys.has(k.toLowerCase())));
|
|
196199
|
+
return fetchLike(url, {
|
|
196200
|
+
...init,
|
|
196201
|
+
headers: { ...configuredNotOverridden, ...requestHeaders }
|
|
196202
|
+
});
|
|
196203
|
+
};
|
|
196204
|
+
}
|
|
196205
|
+
async function withConfiguredHeaders(fetchLike, serverName, serverConfig) {
|
|
196206
|
+
const configured = await resolveConfiguredMcpHeaders(serverName, serverConfig);
|
|
196207
|
+
return mergeConfiguredHeaders(fetchLike, configured);
|
|
196208
|
+
}
|
|
195744
196209
|
async function fetchAuthServerMetadata(serverName, serverUrl, configuredMetadataUrl, fetchFn, resourceMetadataUrl) {
|
|
195745
196210
|
if (configuredMetadataUrl) {
|
|
195746
196211
|
if (!configuredMetadataUrl.startsWith("https://")) {
|
|
@@ -195799,12 +196264,14 @@ async function revokeToken({
|
|
|
195799
196264
|
clientId,
|
|
195800
196265
|
clientSecret,
|
|
195801
196266
|
accessToken,
|
|
195802
|
-
authMethod = "client_secret_basic"
|
|
196267
|
+
authMethod = "client_secret_basic",
|
|
196268
|
+
extraHeaders
|
|
195803
196269
|
}) {
|
|
195804
196270
|
const params = new URLSearchParams;
|
|
195805
196271
|
params.set("token", token);
|
|
195806
196272
|
params.set("token_type_hint", tokenTypeHint);
|
|
195807
196273
|
const headers = {
|
|
196274
|
+
...extraHeaders ?? {},
|
|
195808
196275
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
195809
196276
|
};
|
|
195810
196277
|
if (clientId && clientSecret) {
|
|
@@ -195847,7 +196314,8 @@ async function revokeServerTokens(serverName, serverConfig, { preserveStepUpStat
|
|
|
195847
196314
|
if (tokenData?.accessToken || tokenData?.refreshToken) {
|
|
195848
196315
|
try {
|
|
195849
196316
|
const asUrl = tokenData.discoveryState?.authorizationServerUrl ?? serverConfig.url;
|
|
195850
|
-
const
|
|
196317
|
+
const configuredHeaders = await resolveConfiguredMcpHeaders(serverName, serverConfig);
|
|
196318
|
+
const metadata = await fetchAuthServerMetadata(serverName, asUrl, serverConfig.oauth?.authServerMetadataUrl, mergeConfiguredHeaders(createAuthFetch(), configuredHeaders));
|
|
195851
196319
|
if (!metadata) {
|
|
195852
196320
|
logMCPDebug(serverName, "No OAuth metadata found");
|
|
195853
196321
|
} else {
|
|
@@ -195869,7 +196337,8 @@ async function revokeServerTokens(serverName, serverConfig, { preserveStepUpStat
|
|
|
195869
196337
|
clientId: tokenData.clientId,
|
|
195870
196338
|
clientSecret: tokenData.clientSecret,
|
|
195871
196339
|
accessToken: tokenData.accessToken,
|
|
195872
|
-
authMethod
|
|
196340
|
+
authMethod,
|
|
196341
|
+
extraHeaders: configuredHeaders
|
|
195873
196342
|
});
|
|
195874
196343
|
} catch (error) {
|
|
195875
196344
|
logMCPDebug(serverName, `Failed to revoke refresh token: ${errorMessage2(error)}`);
|
|
@@ -195885,7 +196354,8 @@ async function revokeServerTokens(serverName, serverConfig, { preserveStepUpStat
|
|
|
195885
196354
|
clientId: tokenData.clientId,
|
|
195886
196355
|
clientSecret: tokenData.clientSecret,
|
|
195887
196356
|
accessToken: tokenData.accessToken,
|
|
195888
|
-
authMethod
|
|
196357
|
+
authMethod,
|
|
196358
|
+
extraHeaders: configuredHeaders
|
|
195889
196359
|
});
|
|
195890
196360
|
} catch (error) {
|
|
195891
196361
|
logMCPDebug(serverName, `Failed to revoke access token: ${errorMessage2(error)}`);
|
|
@@ -196078,8 +196548,9 @@ async function performMCPOAuthFlow(serverName, serverConfig, onAuthorizationUrl,
|
|
|
196078
196548
|
const redirectUri = buildRedirectUri(port);
|
|
196079
196549
|
logMCPDebug(serverName, `Using redirect port: ${port}${configuredCallbackPort ? " (from config)" : ""}`);
|
|
196080
196550
|
const provider = new ClaudeAuthProvider(serverName, serverConfig, redirectUri, true, onAuthorizationUrl, options?.skipBrowserOpen);
|
|
196551
|
+
const oauthFetch = await withConfiguredHeaders(createAuthFetch(), serverName, serverConfig);
|
|
196081
196552
|
try {
|
|
196082
|
-
const metadata = await fetchAuthServerMetadata(serverName, serverConfig.url, serverConfig.oauth?.authServerMetadataUrl,
|
|
196553
|
+
const metadata = await fetchAuthServerMetadata(serverName, serverConfig.url, serverConfig.oauth?.authServerMetadataUrl, oauthFetch, wwwAuthParams.resourceMetadataUrl);
|
|
196083
196554
|
if (metadata) {
|
|
196084
196555
|
provider.setMetadata(metadata);
|
|
196085
196556
|
logMCPDebug(serverName, `Fetched OAuth metadata with scope: ${getScopeFromMetadata(metadata) || "NONE"}`);
|
|
@@ -196215,7 +196686,8 @@ async function performMCPOAuthFlow(serverName, serverConfig, onAuthorizationUrl,
|
|
|
196215
196686
|
const result = await auth(provider, {
|
|
196216
196687
|
serverUrl: serverConfig.url,
|
|
196217
196688
|
scope: wwwAuthParams.scope,
|
|
196218
|
-
resourceMetadataUrl: wwwAuthParams.resourceMetadataUrl
|
|
196689
|
+
resourceMetadataUrl: wwwAuthParams.resourceMetadataUrl,
|
|
196690
|
+
fetchFn: oauthFetch
|
|
196219
196691
|
});
|
|
196220
196692
|
logMCPDebug(serverName, `Initial auth result: ${result}`);
|
|
196221
196693
|
if (result !== "REDIRECT") {
|
|
@@ -196239,7 +196711,8 @@ async function performMCPOAuthFlow(serverName, serverConfig, onAuthorizationUrl,
|
|
|
196239
196711
|
const result = await auth(provider, {
|
|
196240
196712
|
serverUrl: serverConfig.url,
|
|
196241
196713
|
authorizationCode,
|
|
196242
|
-
resourceMetadataUrl: wwwAuthParams.resourceMetadataUrl
|
|
196714
|
+
resourceMetadataUrl: wwwAuthParams.resourceMetadataUrl,
|
|
196715
|
+
fetchFn: oauthFetch
|
|
196243
196716
|
});
|
|
196244
196717
|
logMCPDebug(serverName, `Auth result: ${result}`);
|
|
196245
196718
|
if (result === "AUTHORIZED") {
|
|
@@ -196746,7 +197219,7 @@ class ClaudeAuthProvider {
|
|
|
196746
197219
|
if (metadataUrl) {
|
|
196747
197220
|
logMCPDebug(this.serverName, `Fetching metadata from configured URL: ${metadataUrl}`);
|
|
196748
197221
|
try {
|
|
196749
|
-
const metadata = await fetchAuthServerMetadata(this.serverName, this.serverConfig.url, metadataUrl);
|
|
197222
|
+
const metadata = await fetchAuthServerMetadata(this.serverName, this.serverConfig.url, metadataUrl, await withConfiguredHeaders(createAuthFetch(), this.serverName, this.serverConfig));
|
|
196750
197223
|
if (metadata) {
|
|
196751
197224
|
return {
|
|
196752
197225
|
authorizationServerUrl: metadata.issuer,
|
|
@@ -196831,7 +197304,7 @@ class ClaudeAuthProvider {
|
|
|
196831
197304
|
for (let attempt = 1;attempt <= MAX_ATTEMPTS; attempt++) {
|
|
196832
197305
|
try {
|
|
196833
197306
|
logMCPDebug(this.serverName, `Starting token refresh`);
|
|
196834
|
-
const authFetch = createAuthFetch();
|
|
197307
|
+
const authFetch = await withConfiguredHeaders(createAuthFetch(), this.serverName, this.serverConfig);
|
|
196835
197308
|
let metadata = this._metadata;
|
|
196836
197309
|
if (!metadata) {
|
|
196837
197310
|
const cached = await this.discoveryState();
|
|
@@ -197007,6 +197480,7 @@ var init_auth3 = __esm(() => {
|
|
|
197007
197480
|
init_secureStorage();
|
|
197008
197481
|
init_macOsKeychainHelpers();
|
|
197009
197482
|
init_slowOperations();
|
|
197483
|
+
init_headersHelper();
|
|
197010
197484
|
init_oauthPort();
|
|
197011
197485
|
init_utils6();
|
|
197012
197486
|
init_xaa();
|
|
@@ -201002,10 +201476,10 @@ function parseProxyResponse(socket) {
|
|
|
201002
201476
|
read();
|
|
201003
201477
|
});
|
|
201004
201478
|
}
|
|
201005
|
-
var
|
|
201479
|
+
var import_debug53, debug;
|
|
201006
201480
|
var init_parse_proxy_response = __esm(() => {
|
|
201007
|
-
|
|
201008
|
-
debug =
|
|
201481
|
+
import_debug53 = __toESM(require_src(), 1);
|
|
201482
|
+
debug = import_debug53.default("https-proxy-agent:parse-proxy-response");
|
|
201009
201483
|
});
|
|
201010
201484
|
|
|
201011
201485
|
// node_modules/proxy-agent-negotiate/dist/index.js
|
|
@@ -201058,7 +201532,7 @@ function omit2(obj, ...keys) {
|
|
|
201058
201532
|
}
|
|
201059
201533
|
return ret;
|
|
201060
201534
|
}
|
|
201061
|
-
var
|
|
201535
|
+
var import_debug54, debug2, setServernameFromNonIpHost = (options) => {
|
|
201062
201536
|
if (options.servername === undefined && options.host && !net2.isIP(options.host)) {
|
|
201063
201537
|
return {
|
|
201064
201538
|
...options,
|
|
@@ -201070,8 +201544,8 @@ var import_debug53, debug2, setServernameFromNonIpHost = (options) => {
|
|
|
201070
201544
|
var init_dist7 = __esm(() => {
|
|
201071
201545
|
init_dist6();
|
|
201072
201546
|
init_parse_proxy_response();
|
|
201073
|
-
|
|
201074
|
-
debug2 =
|
|
201547
|
+
import_debug54 = __toESM(require_src(), 1);
|
|
201548
|
+
debug2 = import_debug54.default("https-proxy-agent");
|
|
201075
201549
|
HttpsProxyAgent2 = class HttpsProxyAgent2 extends Agent2 {
|
|
201076
201550
|
constructor(proxy, opts) {
|
|
201077
201551
|
super(opts);
|
|
@@ -202132,73 +202606,6 @@ var init_classifyForCollapse = __esm(() => {
|
|
|
202132
202606
|
"resources_list"
|
|
202133
202607
|
]);
|
|
202134
202608
|
});
|
|
202135
|
-
|
|
202136
|
-
// src/tui/services/mcp/headersHelper.ts
|
|
202137
|
-
function isMcpServerFromProjectOrLocalSettings(config) {
|
|
202138
|
-
return config.scope === "project" || config.scope === "local";
|
|
202139
|
-
}
|
|
202140
|
-
async function getMcpHeadersFromHelper(serverName, config) {
|
|
202141
|
-
if (!config.headersHelper) {
|
|
202142
|
-
return null;
|
|
202143
|
-
}
|
|
202144
|
-
if ("scope" in config && isMcpServerFromProjectOrLocalSettings(config)) {
|
|
202145
|
-
const isNonInteractive = getIsNonInteractiveSession();
|
|
202146
|
-
const explicitTrust = process.env.ATLAS_TRUST_WORKSPACE === "true";
|
|
202147
|
-
const hasTrust = checkHasTrustDialogAccepted() || isNonInteractive && explicitTrust;
|
|
202148
|
-
if (!hasTrust) {
|
|
202149
|
-
const error = new Error(`Security: headersHelper for MCP server '${serverName}' executed before workspace trust is confirmed. If you see this message, post in ${MACRO.FEEDBACK_CHANNEL}.`);
|
|
202150
|
-
logAntError("MCP headersHelper invoked before trust check", error);
|
|
202151
|
-
return null;
|
|
202152
|
-
}
|
|
202153
|
-
}
|
|
202154
|
-
try {
|
|
202155
|
-
logMCPDebug(serverName, "Executing headersHelper to get dynamic headers");
|
|
202156
|
-
const execResult = await execFileNoThrowWithCwd2("sh", ["-c", config.headersHelper], {
|
|
202157
|
-
timeout: 1e4,
|
|
202158
|
-
env: {
|
|
202159
|
-
...process.env,
|
|
202160
|
-
ATLAS_MCP_SERVER_NAME: serverName,
|
|
202161
|
-
ATLAS_MCP_SERVER_URL: config.url
|
|
202162
|
-
}
|
|
202163
|
-
});
|
|
202164
|
-
if (execResult.code !== 0 || !execResult.stdout) {
|
|
202165
|
-
throw new Error(`headersHelper for MCP server '${serverName}' did not return a valid value`);
|
|
202166
|
-
}
|
|
202167
|
-
const result = execResult.stdout.trim();
|
|
202168
|
-
const headers = jsonParse2(result);
|
|
202169
|
-
if (typeof headers !== "object" || headers === null || Array.isArray(headers)) {
|
|
202170
|
-
throw new Error(`headersHelper for MCP server '${serverName}' must return a JSON object with string key-value pairs`);
|
|
202171
|
-
}
|
|
202172
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
202173
|
-
if (typeof value !== "string") {
|
|
202174
|
-
throw new Error(`headersHelper for MCP server '${serverName}' returned non-string value for key "${key}": ${typeof value}`);
|
|
202175
|
-
}
|
|
202176
|
-
}
|
|
202177
|
-
logMCPDebug(serverName, `Successfully retrieved ${Object.keys(headers).length} headers from headersHelper`);
|
|
202178
|
-
return headers;
|
|
202179
|
-
} catch (error) {
|
|
202180
|
-
logMCPError(serverName, `Error getting headers from headersHelper: ${errorMessage2(error)}`);
|
|
202181
|
-
logError3(new Error(`Error getting MCP headers from headersHelper for server '${serverName}': ${errorMessage2(error)}`));
|
|
202182
|
-
return null;
|
|
202183
|
-
}
|
|
202184
|
-
}
|
|
202185
|
-
async function getMcpServerHeaders(serverName, config) {
|
|
202186
|
-
const staticHeaders = config.headers || {};
|
|
202187
|
-
const dynamicHeaders = await getMcpHeadersFromHelper(serverName, config) || {};
|
|
202188
|
-
return {
|
|
202189
|
-
...staticHeaders,
|
|
202190
|
-
...dynamicHeaders
|
|
202191
|
-
};
|
|
202192
|
-
}
|
|
202193
|
-
var init_headersHelper = __esm(() => {
|
|
202194
|
-
init_bootstrap();
|
|
202195
|
-
init_config6();
|
|
202196
|
-
init_debug();
|
|
202197
|
-
init_errors4();
|
|
202198
|
-
init_execFileNoThrow2();
|
|
202199
|
-
init_log5();
|
|
202200
|
-
init_slowOperations();
|
|
202201
|
-
});
|
|
202202
202609
|
// src/tui/skills/mcpSkills.ts
|
|
202203
202610
|
var exports_mcpSkills = {};
|
|
202204
202611
|
__export(exports_mcpSkills, {
|
|
@@ -209645,6 +210052,11 @@ function isMcpSessionExpiredError(error) {
|
|
|
209645
210052
|
}
|
|
209646
210053
|
return error.message.includes('"code":-32001') || error.message.includes('"code": -32001');
|
|
209647
210054
|
}
|
|
210055
|
+
function truncateMcpDescriptionText(text) {
|
|
210056
|
+
if (!text)
|
|
210057
|
+
return text;
|
|
210058
|
+
return text.length > MAX_MCP_DESCRIPTION_LENGTH ? text.slice(0, MAX_MCP_DESCRIPTION_LENGTH) + "… [truncated]" : text;
|
|
210059
|
+
}
|
|
209648
210060
|
function getMcpToolTimeoutMs() {
|
|
209649
210061
|
return parseInt(process.env.MCP_TOOL_TIMEOUT || "", 10) || DEFAULT_MCP_TOOL_TIMEOUT_MS;
|
|
209650
210062
|
}
|
|
@@ -209693,46 +210105,6 @@ async function createNodeWsClient(url, options) {
|
|
|
209693
210105
|
const WS = wrapper_default;
|
|
209694
210106
|
return new WS(url, ["mcp"], options);
|
|
209695
210107
|
}
|
|
209696
|
-
function getConnectionTimeoutMs2() {
|
|
209697
|
-
return parseInt(process.env.MCP_TIMEOUT || "", 10) || 30000;
|
|
209698
|
-
}
|
|
209699
|
-
function wrapFetchWithTimeout(baseFetch) {
|
|
209700
|
-
return async (url, init) => {
|
|
209701
|
-
const method = (init?.method ?? "GET").toUpperCase();
|
|
209702
|
-
if (method === "GET") {
|
|
209703
|
-
return baseFetch(url, init);
|
|
209704
|
-
}
|
|
209705
|
-
const headers = new Headers(init?.headers);
|
|
209706
|
-
if (!headers.has("accept")) {
|
|
209707
|
-
headers.set("accept", MCP_STREAMABLE_HTTP_ACCEPT);
|
|
209708
|
-
}
|
|
209709
|
-
const controller = new AbortController;
|
|
209710
|
-
const timer = setTimeout((c) => c.abort(new DOMException("The operation timed out.", "TimeoutError")), MCP_REQUEST_TIMEOUT_MS, controller);
|
|
209711
|
-
timer.unref?.();
|
|
209712
|
-
const parentSignal = init?.signal;
|
|
209713
|
-
const abort = () => controller.abort(parentSignal?.reason);
|
|
209714
|
-
parentSignal?.addEventListener("abort", abort);
|
|
209715
|
-
if (parentSignal?.aborted) {
|
|
209716
|
-
controller.abort(parentSignal.reason);
|
|
209717
|
-
}
|
|
209718
|
-
const cleanup = () => {
|
|
209719
|
-
clearTimeout(timer);
|
|
209720
|
-
parentSignal?.removeEventListener("abort", abort);
|
|
209721
|
-
};
|
|
209722
|
-
try {
|
|
209723
|
-
const response = await baseFetch(url, {
|
|
209724
|
-
...init,
|
|
209725
|
-
headers,
|
|
209726
|
-
signal: controller.signal
|
|
209727
|
-
});
|
|
209728
|
-
cleanup();
|
|
209729
|
-
return response;
|
|
209730
|
-
} catch (error) {
|
|
209731
|
-
cleanup();
|
|
209732
|
-
throw error;
|
|
209733
|
-
}
|
|
209734
|
-
};
|
|
209735
|
-
}
|
|
209736
210108
|
function getMcpServerConnectionBatchSize() {
|
|
209737
210109
|
return parseInt(process.env.MCP_SERVER_CONNECTION_BATCH_SIZE || "", 10) || 3;
|
|
209738
210110
|
}
|
|
@@ -210382,7 +210754,7 @@ function extractToolUseId(message) {
|
|
|
210382
210754
|
}
|
|
210383
210755
|
return message.message.content[0].id;
|
|
210384
210756
|
}
|
|
210385
|
-
var fetchMcpSkillsForClient2, McpAuthError, McpSessionExpiredError, McpToolCallError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, DEFAULT_MCP_TOOL_TIMEOUT_MS = 1e8, MAX_MCP_DESCRIPTION_LENGTH =
|
|
210757
|
+
var fetchMcpSkillsForClient2, McpAuthError, McpSessionExpiredError, McpToolCallError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, DEFAULT_MCP_TOOL_TIMEOUT_MS = 1e8, MAX_MCP_DESCRIPTION_LENGTH = 4096, computerUseWrapper, isComputerUseMCPServer2, MCP_AUTH_CACHE_TTL_MS, authCachePromise = null, writeChain, IMAGE_MIME_TYPES, ALLOWED_IDE_TOOLS, connectToServer, MCP_FETCH_CACHE_SIZE2 = 20, fetchToolsForClient2, fetchResourcesForClient2, fetchCommandsForClient2;
|
|
210386
210758
|
var init_client4 = __esm(() => {
|
|
210387
210759
|
init_shared();
|
|
210388
210760
|
init_client3();
|
|
@@ -210674,7 +211046,7 @@ var init_client4 = __esm(() => {
|
|
|
210674
211046
|
]
|
|
210675
211047
|
};
|
|
210676
211048
|
});
|
|
210677
|
-
logMCPDebug(name, `Starting connection with timeout of ${
|
|
211049
|
+
logMCPDebug(name, `Starting connection with timeout of ${getMcpConnectionTimeoutMs()}ms`);
|
|
210678
211050
|
if (serverRef.type === "http") {
|
|
210679
211051
|
logMCPDebug(name, `Testing basic HTTP connectivity to ${serverRef.url}`);
|
|
210680
211052
|
try {
|
|
@@ -210691,13 +211063,13 @@ var init_client4 = __esm(() => {
|
|
|
210691
211063
|
const timeoutPromise = new Promise((_, reject) => {
|
|
210692
211064
|
const timeoutId = setTimeout(() => {
|
|
210693
211065
|
const elapsed = Date.now() - connectStartTime;
|
|
210694
|
-
logMCPDebug(name, `Connection timeout triggered after ${elapsed}ms (limit: ${
|
|
211066
|
+
logMCPDebug(name, `Connection timeout triggered after ${elapsed}ms (limit: ${getMcpConnectionTimeoutMs()}ms)`);
|
|
210695
211067
|
if (inProcessServer) {
|
|
210696
211068
|
inProcessServer.close().catch(() => {});
|
|
210697
211069
|
}
|
|
210698
211070
|
transport.close().catch(() => {});
|
|
210699
|
-
reject(new TelemetrySafeError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS(`MCP server "${name}" connection timed out after ${
|
|
210700
|
-
},
|
|
211071
|
+
reject(new TelemetrySafeError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS(`MCP server "${name}" connection timed out after ${getMcpConnectionTimeoutMs()}ms`, "MCP connection timeout"));
|
|
211072
|
+
}, getMcpConnectionTimeoutMs());
|
|
210701
211073
|
connectPromise.then(() => {
|
|
210702
211074
|
clearTimeout(timeoutId);
|
|
210703
211075
|
}, (_error) => {
|
|
@@ -210745,9 +211117,8 @@ var init_client4 = __esm(() => {
|
|
|
210745
211117
|
const capabilities = client.getServerCapabilities();
|
|
210746
211118
|
const serverVersion = client.getServerVersion();
|
|
210747
211119
|
const rawInstructions = client.getInstructions();
|
|
210748
|
-
|
|
210749
|
-
if (
|
|
210750
|
-
instructions = rawInstructions.slice(0, MAX_MCP_DESCRIPTION_LENGTH) + "… [truncated]";
|
|
211120
|
+
const instructions = truncateMcpDescriptionText(rawInstructions);
|
|
211121
|
+
if (instructions !== rawInstructions) {
|
|
210751
211122
|
logMCPDebug(name, `Server instructions truncated from ${rawInstructions.length} to ${MAX_MCP_DESCRIPTION_LENGTH} chars`);
|
|
210752
211123
|
}
|
|
210753
211124
|
logMCPDebug(name, `Connection established with capabilities: ${jsonStringify5({
|
|
@@ -211035,8 +211406,7 @@ var init_client4 = __esm(() => {
|
|
|
211035
211406
|
return tool.description ?? "";
|
|
211036
211407
|
},
|
|
211037
211408
|
async prompt() {
|
|
211038
|
-
|
|
211039
|
-
return desc.length > MAX_MCP_DESCRIPTION_LENGTH ? desc.slice(0, MAX_MCP_DESCRIPTION_LENGTH) + "… [truncated]" : desc;
|
|
211409
|
+
return truncateMcpDescriptionText(tool.description ?? "");
|
|
211040
211410
|
},
|
|
211041
211411
|
isConcurrencySafe() {
|
|
211042
211412
|
return tool.annotations?.readOnlyHint ?? false;
|
|
@@ -276339,6 +276709,15 @@ function filterToolsForAgent2({
|
|
|
276339
276709
|
function computeChildSpawnDepth2(parentOptions) {
|
|
276340
276710
|
return (parentOptions?.spawnDepth ?? 0) + 1;
|
|
276341
276711
|
}
|
|
276712
|
+
function resolveMcpServerDomainTools2(toolName, available) {
|
|
276713
|
+
if (typeof toolName !== "string")
|
|
276714
|
+
return null;
|
|
276715
|
+
const info = mcpInfoFromString3(toolName);
|
|
276716
|
+
if (!info || info.toolName !== undefined)
|
|
276717
|
+
return null;
|
|
276718
|
+
const prefix = getMcpPrefix3(info.serverName);
|
|
276719
|
+
return available.filter((t) => t.name.startsWith(prefix));
|
|
276720
|
+
}
|
|
276342
276721
|
function resolveAgentTools2(agentDefinition, availableTools, isAsync = false, isMainThread = false, allowFanOut = false) {
|
|
276343
276722
|
const {
|
|
276344
276723
|
tools: agentTools,
|
|
@@ -276395,7 +276774,18 @@ function resolveAgentTools2(agentDefinition, availableTools, isAsync = false, is
|
|
|
276395
276774
|
resolvedToolsSet.add(tool);
|
|
276396
276775
|
}
|
|
276397
276776
|
} else {
|
|
276398
|
-
|
|
276777
|
+
const domain = resolveMcpServerDomainTools2(toolName, allowedAvailableTools);
|
|
276778
|
+
if (domain && domain.length > 0) {
|
|
276779
|
+
validTools.push(toolSpec);
|
|
276780
|
+
for (const t of domain) {
|
|
276781
|
+
if (!resolvedToolsSet.has(t)) {
|
|
276782
|
+
resolved.push(t);
|
|
276783
|
+
resolvedToolsSet.add(t);
|
|
276784
|
+
}
|
|
276785
|
+
}
|
|
276786
|
+
} else {
|
|
276787
|
+
invalidTools.push(toolSpec);
|
|
276788
|
+
}
|
|
276399
276789
|
}
|
|
276400
276790
|
}
|
|
276401
276791
|
return {
|
|
@@ -276652,6 +277042,7 @@ var init_agentToolUtils2 = __esm(() => {
|
|
|
276652
277042
|
init_errors4();
|
|
276653
277043
|
init_messages3();
|
|
276654
277044
|
init_permissionRuleParser2();
|
|
277045
|
+
init_mcpStringUtils();
|
|
276655
277046
|
init_yoloClassifier();
|
|
276656
277047
|
init_sdkProgress();
|
|
276657
277048
|
init_teammateContext3();
|
|
@@ -321769,7 +322160,8 @@ function buildAgentLoopParams(m) {
|
|
|
321769
322160
|
}
|
|
321770
322161
|
},
|
|
321771
322162
|
systemPrompt: asSystemPrompt(appendSystemContext(m.systemPrompt, systemContext)),
|
|
321772
|
-
effortValue: m.effort !== undefined ? String(m.effort) : undefined
|
|
322163
|
+
effortValue: m.effort !== undefined ? String(m.effort) : undefined,
|
|
322164
|
+
refreshRoundContext: m.refreshRoundContext
|
|
321773
322165
|
};
|
|
321774
322166
|
const unboundedTurns = m.unboundedTurns ?? m.maxTurns === undefined;
|
|
321775
322167
|
const args = {
|
|
@@ -322338,7 +322730,8 @@ function getDefaultAppState() {
|
|
|
322338
322730
|
tools: [],
|
|
322339
322731
|
commands: [],
|
|
322340
322732
|
resources: {},
|
|
322341
|
-
pluginReconnectKey: 0
|
|
322733
|
+
pluginReconnectKey: 0,
|
|
322734
|
+
cwdReconnectKey: 0
|
|
322342
322735
|
},
|
|
322343
322736
|
plugins: {
|
|
322344
322737
|
enabled: [],
|
|
@@ -348079,7 +348472,8 @@ async function clearConversation({
|
|
|
348079
348472
|
tools: [],
|
|
348080
348473
|
commands: [],
|
|
348081
348474
|
resources: {},
|
|
348082
|
-
pluginReconnectKey: prev.mcp.pluginReconnectKey
|
|
348475
|
+
pluginReconnectKey: prev.mcp.pluginReconnectKey,
|
|
348476
|
+
cwdReconnectKey: prev.mcp.cwdReconnectKey
|
|
348083
348477
|
}
|
|
348084
348478
|
};
|
|
348085
348479
|
});
|
|
@@ -369468,7 +369862,9 @@ function useManageMCPConnections(dynamicMcpConfig, isStrictMcpConfig = false) {
|
|
|
369468
369862
|
const store = useAppStateStore();
|
|
369469
369863
|
const _authVersion = useAppState((s) => s.authVersion);
|
|
369470
369864
|
const _pluginReconnectKey = useAppState((s) => s.mcp.pluginReconnectKey);
|
|
369865
|
+
const _cwdReconnectKey = useAppState((s) => s.mcp.cwdReconnectKey);
|
|
369471
369866
|
const setAppState = useSetAppState();
|
|
369867
|
+
const lastCwdRef = import_react110.useRef(null);
|
|
369472
369868
|
const reconnectTimersRef = import_react110.useRef(new Map);
|
|
369473
369869
|
const mcpFailureTrackerRef = import_react110.useRef(null);
|
|
369474
369870
|
const notifyMcpConnectionFailure = import_react110.useCallback((serverName, error) => {
|
|
@@ -369695,9 +370091,12 @@ function useManageMCPConnections(dynamicMcpConfig, isStrictMcpConfig = false) {
|
|
|
369695
370091
|
async function initializeServersAsPending() {
|
|
369696
370092
|
const { servers: existingConfigs, errors: mcpErrors } = isStrictMcpConfig ? { servers: {}, errors: [] } : await getMcpConfigs(dynamicMcpConfig);
|
|
369697
370093
|
const configs = { ...existingConfigs, ...dynamicMcpConfig };
|
|
370094
|
+
const currentCwd = getCwd();
|
|
370095
|
+
const cwdChanged = lastCwdRef.current !== null && lastCwdRef.current !== currentCwd;
|
|
370096
|
+
lastCwdRef.current = currentCwd;
|
|
369698
370097
|
addErrorsToAppState(setAppState, mcpErrors);
|
|
369699
370098
|
setAppState((prevState) => {
|
|
369700
|
-
const { stale, ...mcpWithoutStale } = excludeStalePluginClients(prevState.mcp, configs);
|
|
370099
|
+
const { stale, ...mcpWithoutStale } = excludeStalePluginClients(prevState.mcp, configs, { absentIsStale: cwdChanged });
|
|
369701
370100
|
for (const s of stale) {
|
|
369702
370101
|
const timer = reconnectTimersRef.current.get(s.name);
|
|
369703
370102
|
if (timer) {
|
|
@@ -369736,7 +370135,8 @@ function useManageMCPConnections(dynamicMcpConfig, isStrictMcpConfig = false) {
|
|
|
369736
370135
|
dynamicMcpConfig,
|
|
369737
370136
|
setAppState,
|
|
369738
370137
|
sessionId,
|
|
369739
|
-
_pluginReconnectKey
|
|
370138
|
+
_pluginReconnectKey,
|
|
370139
|
+
_cwdReconnectKey
|
|
369740
370140
|
]);
|
|
369741
370141
|
import_react110.useEffect(() => {
|
|
369742
370142
|
let cancelled = false;
|
|
@@ -369753,7 +370153,7 @@ function useManageMCPConnections(dynamicMcpConfig, isStrictMcpConfig = false) {
|
|
|
369753
370153
|
});
|
|
369754
370154
|
let claudeaiConfigs = {};
|
|
369755
370155
|
if (!isStrictMcpConfig) {
|
|
369756
|
-
claudeaiConfigs =
|
|
370156
|
+
claudeaiConfigs = filterMcpServersByPolicy2(await claudeaiPromise).allowed;
|
|
369757
370157
|
if (cancelled)
|
|
369758
370158
|
return;
|
|
369759
370159
|
if (Object.keys(claudeaiConfigs).length > 0) {
|
|
@@ -369819,7 +370219,8 @@ function useManageMCPConnections(dynamicMcpConfig, isStrictMcpConfig = false) {
|
|
|
369819
370219
|
setAppState,
|
|
369820
370220
|
_authVersion,
|
|
369821
370221
|
sessionId,
|
|
369822
|
-
_pluginReconnectKey
|
|
370222
|
+
_pluginReconnectKey,
|
|
370223
|
+
_cwdReconnectKey
|
|
369823
370224
|
]);
|
|
369824
370225
|
import_react110.useEffect(() => {
|
|
369825
370226
|
const timers = reconnectTimersRef.current;
|
|
@@ -412095,7 +412496,7 @@ var exports_cd = {};
|
|
|
412095
412496
|
__export(exports_cd, {
|
|
412096
412497
|
call: () => call46
|
|
412097
412498
|
});
|
|
412098
|
-
var USAGE2 = "Usage: /cd [path] (no argument = show current session cwd)", call46 = async (_args,
|
|
412499
|
+
var USAGE2 = "Usage: /cd [path] (no argument = show current session cwd)", call46 = async (_args, context) => {
|
|
412099
412500
|
const arg = (_args ?? "").trim();
|
|
412100
412501
|
if (arg === "") {
|
|
412101
412502
|
return {
|
|
@@ -412106,6 +412507,10 @@ ${USAGE2}`
|
|
|
412106
412507
|
}
|
|
412107
412508
|
try {
|
|
412108
412509
|
setCwd2(arg, pwd());
|
|
412510
|
+
context.setAppState((prev) => ({
|
|
412511
|
+
...prev,
|
|
412512
|
+
mcp: { ...prev.mcp, cwdReconnectKey: prev.mcp.cwdReconnectKey + 1 }
|
|
412513
|
+
}));
|
|
412109
412514
|
return {
|
|
412110
412515
|
type: "text",
|
|
412111
412516
|
value: `Session working directory changed to: ${pwd()}`
|
|
@@ -428686,7 +429091,7 @@ function getHttpHookPolicy() {
|
|
|
428686
429091
|
allowedEnvVars: settings.httpHookAllowedEnvVars
|
|
428687
429092
|
};
|
|
428688
429093
|
}
|
|
428689
|
-
function
|
|
429094
|
+
function urlMatchesPattern3(url, pattern) {
|
|
428690
429095
|
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
428691
429096
|
const regexStr = escaped.replace(/\*/g, ".*");
|
|
428692
429097
|
return new RegExp(`^${regexStr}$`).test(url);
|
|
@@ -428708,7 +429113,7 @@ function interpolateEnvVars(value, allowedEnvVars) {
|
|
|
428708
429113
|
async function execHttpHook(hook, _hookEvent, jsonInput, signal) {
|
|
428709
429114
|
const policy = getHttpHookPolicy();
|
|
428710
429115
|
if (policy.allowedUrls !== undefined) {
|
|
428711
|
-
const matched = policy.allowedUrls.some((p) =>
|
|
429116
|
+
const matched = policy.allowedUrls.some((p) => urlMatchesPattern3(hook.url, p));
|
|
428712
429117
|
if (!matched) {
|
|
428713
429118
|
const msg = `HTTP hook blocked: ${hook.url} does not match any pattern in allowedHttpHookUrls`;
|
|
428714
429119
|
logForDebugging3(msg, { level: "warn" });
|
|
@@ -470300,6 +470705,32 @@ var init_useMailboxBridge = __esm(() => {
|
|
|
470300
470705
|
|
|
470301
470706
|
// src/tui/replLoopDeps.ts
|
|
470302
470707
|
function buildReplLoopParams(m) {
|
|
470708
|
+
let prevPoolSig = (m.tools ?? []).map((t) => t.name).join(",");
|
|
470709
|
+
const refreshRoundContext = (messages) => {
|
|
470710
|
+
const appState = m.toolUseContext?.getAppState?.();
|
|
470711
|
+
const liveMcpTools = appState?.mcp?.tools;
|
|
470712
|
+
if (!liveMcpTools)
|
|
470713
|
+
return null;
|
|
470714
|
+
const pool = assembleToolPool(m.toolPermissionContext, liveMcpTools);
|
|
470715
|
+
const sig = pool.map((t) => t.name).join(",");
|
|
470716
|
+
const tuiMessages = messages;
|
|
470717
|
+
const atts = [
|
|
470718
|
+
...getDeferredToolsDeltaAttachment(pool, m.mainLoopModel, tuiMessages, {
|
|
470719
|
+
callSite: "round_refresh",
|
|
470720
|
+
querySource: m.querySource
|
|
470721
|
+
}),
|
|
470722
|
+
...getMcpInstructionsDeltaAttachment(m.toolUseContext.options.mcpClients ?? [], pool, m.mainLoopModel, tuiMessages)
|
|
470723
|
+
];
|
|
470724
|
+
if (sig === prevPoolSig && atts.length === 0)
|
|
470725
|
+
return null;
|
|
470726
|
+
prevPoolSig = sig;
|
|
470727
|
+
return {
|
|
470728
|
+
tools: pool,
|
|
470729
|
+
...atts.length > 0 ? {
|
|
470730
|
+
appendedMessages: atts.map((att) => createAttachmentMessage(att))
|
|
470731
|
+
} : {}
|
|
470732
|
+
};
|
|
470733
|
+
};
|
|
470303
470734
|
return buildAgentLoopParams({
|
|
470304
470735
|
messages: m.messages,
|
|
470305
470736
|
userContext: m.userContext,
|
|
@@ -470315,11 +470746,14 @@ function buildReplLoopParams(m) {
|
|
|
470315
470746
|
toolUseContext: m.toolUseContext,
|
|
470316
470747
|
querySource: m.querySource,
|
|
470317
470748
|
unboundedTurns: true,
|
|
470318
|
-
maxGoalTurns: m.maxGoalTurns
|
|
470749
|
+
maxGoalTurns: m.maxGoalTurns,
|
|
470750
|
+
refreshRoundContext
|
|
470319
470751
|
});
|
|
470320
470752
|
}
|
|
470321
470753
|
var init_replLoopDeps = __esm(() => {
|
|
470322
470754
|
init_agentLoopDeps();
|
|
470755
|
+
init_tools3();
|
|
470756
|
+
init_attachments();
|
|
470323
470757
|
});
|
|
470324
470758
|
|
|
470325
470759
|
// src/tui/hooks/useMergedClients.ts
|
|
@@ -493526,7 +493960,7 @@ ${formattedErrors}
|
|
|
493526
493960
|
const {
|
|
493527
493961
|
allowed,
|
|
493528
493962
|
blocked
|
|
493529
|
-
} =
|
|
493963
|
+
} = filterMcpServersByPolicy2(scopedConfigs);
|
|
493530
493964
|
if (blocked.length > 0) {
|
|
493531
493965
|
process.stderr.write(`Warning: MCP ${plural2(blocked.length, "server")} blocked by enterprise policy: ${blocked.join(", ")}
|
|
493532
493966
|
`);
|
|
@@ -494207,7 +494641,8 @@ ${inputPrompt}` : mergePrompt;
|
|
|
494207
494641
|
tools: [],
|
|
494208
494642
|
commands: [],
|
|
494209
494643
|
resources: {},
|
|
494210
|
-
pluginReconnectKey: 0
|
|
494644
|
+
pluginReconnectKey: 0,
|
|
494645
|
+
cwdReconnectKey: 0
|
|
494211
494646
|
},
|
|
494212
494647
|
plugins: {
|
|
494213
494648
|
enabled: [],
|