@wuyax/mcps 0.1.0-beta.1 → 0.1.0-beta.3
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/README.md +554 -114
- package/dist/{chunk-XW2KL6W3.js → chunk-BUKA3NPJ.js} +1488 -203
- package/dist/cli.cjs +1425 -246
- package/dist/cli.js +9 -22
- package/dist/index.cjs +1485 -188
- package/dist/index.d.cts +248 -9
- package/dist/index.d.ts +248 -9
- package/dist/index.js +56 -1
- package/package.json +3 -1
package/dist/index.cjs
CHANGED
|
@@ -34,13 +34,23 @@ __export(src_exports, {
|
|
|
34
34
|
DEFAULT_REMOTE_TRANSPORT: () => DEFAULT_REMOTE_TRANSPORT,
|
|
35
35
|
NPX_COMMAND: () => NPX_COMMAND,
|
|
36
36
|
NPX_DASH_Y: () => NPX_DASH_Y,
|
|
37
|
+
SECRET_HEADER_PATTERN: () => SECRET_HEADER_PATTERN,
|
|
38
|
+
SECRET_KEY_PATTERN: () => SECRET_KEY_PATTERN,
|
|
37
39
|
add: () => installMcpServer,
|
|
38
40
|
agentConfigStore: () => agentConfigStore,
|
|
41
|
+
buildLinkedAgentChoices: () => buildLinkedAgentChoices,
|
|
39
42
|
buildMcpServerConfig: () => buildMcpServerConfig,
|
|
40
43
|
createAgentTransform: () => createAgentTransform,
|
|
41
44
|
detectGloballyInstalledMcpAgents: () => detectGloballyInstalledMcpAgents,
|
|
42
45
|
detectProjectInstalledMcpAgents: () => detectProjectInstalledMcpAgents,
|
|
46
|
+
detectUpdateTransition: () => detectUpdateTransition,
|
|
47
|
+
displayServerDetails: () => displayServerDetails,
|
|
43
48
|
extractPackageName: () => extractPackageName,
|
|
49
|
+
formatArgsString: () => formatArgsString,
|
|
50
|
+
formatEnvText: () => formatEnvText,
|
|
51
|
+
formatHeadersText: () => formatHeadersText,
|
|
52
|
+
getCandidateAgentsForScope: () => getCandidateAgentsForScope,
|
|
53
|
+
getCoHostedAgents: () => getCoHostedAgents,
|
|
44
54
|
getMcpAgentConfig: () => getMcpAgentConfig,
|
|
45
55
|
getMcpAgentTypes: () => getMcpAgentTypes,
|
|
46
56
|
getMcpAgentsSupportingProjectScope: () => getMcpAgentsSupportingProjectScope,
|
|
@@ -49,17 +59,22 @@ __export(src_exports, {
|
|
|
49
59
|
installMcpServer: () => installMcpServer,
|
|
50
60
|
installMcpServerForAgent: () => installMcpServerForAgent,
|
|
51
61
|
installMcpServerForAgents: () => installMcpServerForAgents,
|
|
62
|
+
installToCompatibleAgents: () => installToCompatibleAgents,
|
|
52
63
|
isMcpAgentType: () => isMcpAgentType,
|
|
53
64
|
isMcpTransportSupported: () => isMcpTransportSupported,
|
|
54
65
|
isRemoteMcpSource: () => isRemoteMcpSource,
|
|
55
66
|
isRemoteServerConfig: () => isRemoteServerConfig,
|
|
56
67
|
isStdioServerConfig: () => isStdioServerConfig,
|
|
68
|
+
linkedCheckbox: () => linkedCheckbox,
|
|
57
69
|
list: () => listInstalledMcpServers,
|
|
58
70
|
listInstalledMcpServers: () => listInstalledMcpServers,
|
|
59
71
|
listServersInConfigFile: () => listServersInConfigFile,
|
|
60
72
|
mainMenu: () => mainMenu,
|
|
73
|
+
maskSecretHeader: () => maskSecretHeader,
|
|
74
|
+
maskSecretValue: () => maskSecretValue,
|
|
61
75
|
mcpAgentAliases: () => mcpAgentAliases,
|
|
62
76
|
mcpAgents: () => mcpAgents,
|
|
77
|
+
mcpManageCommand: () => mcpManageCommand,
|
|
63
78
|
normalizeServerConfig: () => normalizeServerConfig,
|
|
64
79
|
parseArgsString: () => parseArgsString,
|
|
65
80
|
parseEnvText: () => parseEnvText,
|
|
@@ -68,20 +83,33 @@ __export(src_exports, {
|
|
|
68
83
|
parseServerConfig: () => parseServerConfig,
|
|
69
84
|
parseSource: () => parseMcpSource,
|
|
70
85
|
promptArgsConfig: () => promptArgsConfig,
|
|
86
|
+
promptEditArgs: () => promptEditArgs,
|
|
87
|
+
promptEditEnvConfig: () => promptEditEnvConfig,
|
|
88
|
+
promptEditHeadersConfig: () => promptEditHeadersConfig,
|
|
89
|
+
promptEditKeyValueConfig: () => promptEditKeyValueConfig,
|
|
71
90
|
promptEnvConfig: () => promptEnvConfig,
|
|
72
91
|
promptHeadersConfig: () => promptHeadersConfig,
|
|
73
92
|
promptScope: () => promptScope,
|
|
74
93
|
promptScopeAndAgents: () => promptScopeAndAgents,
|
|
94
|
+
promptSwitchServerType: () => promptSwitchServerType,
|
|
75
95
|
readConfigFile: () => readConfigFile,
|
|
76
96
|
remove: () => removeMcpServer,
|
|
77
97
|
removeMcpServer: () => removeMcpServer,
|
|
78
98
|
removeMcpServerFromAgent: () => removeMcpServerFromAgent,
|
|
79
99
|
removeServerFromConfigFile: () => removeServerFromConfigFile,
|
|
100
|
+
resolveConfigClusters: () => resolveConfigClusters,
|
|
80
101
|
resolveMcpAgentAlias: () => resolveMcpAgentAlias,
|
|
81
102
|
resolveMcpConfigTarget: () => resolveMcpConfigTarget,
|
|
82
103
|
resolveTargetAgents: () => resolveTargetAgents,
|
|
104
|
+
resolveTransport: () => resolveTransport,
|
|
105
|
+
sanitizeUpdatedServerConfig: () => sanitizeUpdatedServerConfig,
|
|
106
|
+
sortAgentsWithClusters: () => sortAgentsWithClusters,
|
|
107
|
+
toRemoteServerConfig: () => toRemoteServerConfig,
|
|
108
|
+
toStdioServerConfig: () => toStdioServerConfig,
|
|
83
109
|
transformServerConfig: () => transformServerConfig,
|
|
84
110
|
transformServerConfigForAgent: () => transformServerConfigForAgent,
|
|
111
|
+
update: () => updateMcpServer,
|
|
112
|
+
updateMcpServer: () => updateMcpServer,
|
|
85
113
|
wizardAdd: () => wizardAdd,
|
|
86
114
|
wizardManage: () => wizardManage,
|
|
87
115
|
wizardRemove: () => wizardRemove,
|
|
@@ -543,9 +571,9 @@ var mcpAgentAliases = {
|
|
|
543
571
|
var getMcpAgentConfig = (agentType) => mcpAgents[agentType];
|
|
544
572
|
var getMcpAgentTypes = () => Object.values(mcpAgents).map((config) => config.name);
|
|
545
573
|
var isMcpAgentType = (value) => value in mcpAgents;
|
|
546
|
-
var resolveMcpAgentAlias = (
|
|
547
|
-
if (isMcpAgentType(
|
|
548
|
-
return mcpAgentAliases[
|
|
574
|
+
var resolveMcpAgentAlias = (input7) => {
|
|
575
|
+
if (isMcpAgentType(input7)) return input7;
|
|
576
|
+
return mcpAgentAliases[input7] ?? null;
|
|
549
577
|
};
|
|
550
578
|
var isMcpTransportSupported = (agent, transport) => agent.supportedTransports.includes(transport);
|
|
551
579
|
var detectProjectInstalledMcpAgents = (cwd) => getMcpAgentTypes().filter(
|
|
@@ -1056,6 +1084,74 @@ var agentConfigStore = new AgentConfigStore();
|
|
|
1056
1084
|
// src/utils/to-error-message.ts
|
|
1057
1085
|
var toErrorMessage = (error, fallback = "Unknown error") => error instanceof Error ? error.message : fallback;
|
|
1058
1086
|
|
|
1087
|
+
// src/resolve-config-clusters.ts
|
|
1088
|
+
var getCandidateAgentsForScope = (options = {}) => {
|
|
1089
|
+
return options.global ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
|
|
1090
|
+
};
|
|
1091
|
+
var getCoHostedAgents = (agentType, options = {}) => {
|
|
1092
|
+
const currentAgent = getMcpAgentConfig(agentType);
|
|
1093
|
+
const currentTarget = resolveMcpConfigTarget(currentAgent, options);
|
|
1094
|
+
const candidates = getCandidateAgentsForScope(options);
|
|
1095
|
+
const coHosted = [];
|
|
1096
|
+
for (const candidateType of candidates) {
|
|
1097
|
+
if (candidateType === agentType) continue;
|
|
1098
|
+
const candidateConfig = getMcpAgentConfig(candidateType);
|
|
1099
|
+
const candidateTarget = resolveMcpConfigTarget(candidateConfig, options);
|
|
1100
|
+
if (candidateTarget.configPath === currentTarget.configPath && candidateTarget.configKey === currentTarget.configKey) {
|
|
1101
|
+
coHosted.push(candidateType);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
return coHosted;
|
|
1105
|
+
};
|
|
1106
|
+
var resolveConfigClusters = (agentTypes, options = {}) => {
|
|
1107
|
+
const clustersByPath = /* @__PURE__ */ new Map();
|
|
1108
|
+
for (const agentType of agentTypes) {
|
|
1109
|
+
const agentConfig = getMcpAgentConfig(agentType);
|
|
1110
|
+
const target = resolveMcpConfigTarget(agentConfig, options);
|
|
1111
|
+
let keyMap = clustersByPath.get(target.configPath);
|
|
1112
|
+
if (!keyMap) {
|
|
1113
|
+
keyMap = /* @__PURE__ */ new Map();
|
|
1114
|
+
clustersByPath.set(target.configPath, keyMap);
|
|
1115
|
+
}
|
|
1116
|
+
let cluster = keyMap.get(target.configKey);
|
|
1117
|
+
if (!cluster) {
|
|
1118
|
+
const allCoHosted = getCoHostedAgents(agentType, options);
|
|
1119
|
+
cluster = {
|
|
1120
|
+
configPath: target.configPath,
|
|
1121
|
+
configKey: target.configKey,
|
|
1122
|
+
targetAgents: [],
|
|
1123
|
+
coHostedAgents: allCoHosted
|
|
1124
|
+
};
|
|
1125
|
+
keyMap.set(target.configKey, cluster);
|
|
1126
|
+
}
|
|
1127
|
+
if (!cluster.targetAgents.includes(agentType)) {
|
|
1128
|
+
cluster.targetAgents.push(agentType);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
const clusters = [];
|
|
1132
|
+
for (const keyMap of clustersByPath.values()) {
|
|
1133
|
+
for (const cluster of keyMap.values()) {
|
|
1134
|
+
cluster.coHostedAgents = cluster.coHostedAgents.filter(
|
|
1135
|
+
(co) => !cluster.targetAgents.includes(co)
|
|
1136
|
+
);
|
|
1137
|
+
clusters.push(cluster);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
return clusters;
|
|
1141
|
+
};
|
|
1142
|
+
var sortAgentsWithClusters = (agentTypes, options = {}) => {
|
|
1143
|
+
const clusters = resolveConfigClusters(agentTypes, options);
|
|
1144
|
+
const sorted = [];
|
|
1145
|
+
for (const cluster of clusters) {
|
|
1146
|
+
for (const agent of cluster.targetAgents) {
|
|
1147
|
+
if (!sorted.includes(agent)) {
|
|
1148
|
+
sorted.push(agent);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
return sorted;
|
|
1153
|
+
};
|
|
1154
|
+
|
|
1059
1155
|
// src/transforms/index.ts
|
|
1060
1156
|
var DIALECT_PRESETS = {
|
|
1061
1157
|
vscode: {
|
|
@@ -1271,12 +1367,18 @@ var installMcpServerForAgent = (serverName, serverConfig, agentType, options = {
|
|
|
1271
1367
|
const agent = getMcpAgentConfig(agentType);
|
|
1272
1368
|
const isGlobal = options.global ?? false;
|
|
1273
1369
|
const { target } = agentConfigStore.resolveTarget(agent, options);
|
|
1370
|
+
const coHosted = getCoHostedAgents(agentType, options);
|
|
1274
1371
|
try {
|
|
1275
1372
|
const transformed = transformServerConfigForAgent(agent, serverName, serverConfig, {
|
|
1276
1373
|
global: isGlobal
|
|
1277
1374
|
});
|
|
1278
1375
|
agentConfigStore.writeServer(agent, serverName, transformed, options);
|
|
1279
|
-
return {
|
|
1376
|
+
return {
|
|
1377
|
+
agent: agentType,
|
|
1378
|
+
success: true,
|
|
1379
|
+
path: target.configPath,
|
|
1380
|
+
coConfiguredAgents: coHosted.length > 0 ? coHosted : void 0
|
|
1381
|
+
};
|
|
1280
1382
|
} catch (error) {
|
|
1281
1383
|
return {
|
|
1282
1384
|
agent: agentType,
|
|
@@ -1286,16 +1388,69 @@ var installMcpServerForAgent = (serverName, serverConfig, agentType, options = {
|
|
|
1286
1388
|
};
|
|
1287
1389
|
}
|
|
1288
1390
|
};
|
|
1289
|
-
var installMcpServerForAgents = (serverName, serverConfig, agentTypes, options = {}) =>
|
|
1290
|
-
|
|
1291
|
-
);
|
|
1391
|
+
var installMcpServerForAgents = (serverName, serverConfig, agentTypes, options = {}) => {
|
|
1392
|
+
const clusters = resolveConfigClusters(agentTypes, options);
|
|
1393
|
+
const resultsByAgent = /* @__PURE__ */ new Map();
|
|
1394
|
+
const isGlobal = options.global ?? false;
|
|
1395
|
+
for (const cluster of clusters) {
|
|
1396
|
+
const primaryAgentType = cluster.targetAgents[0];
|
|
1397
|
+
const primaryAgent = getMcpAgentConfig(primaryAgentType);
|
|
1398
|
+
try {
|
|
1399
|
+
const transformed = transformServerConfigForAgent(primaryAgent, serverName, serverConfig, {
|
|
1400
|
+
global: isGlobal
|
|
1401
|
+
});
|
|
1402
|
+
agentConfigStore.writeServer(primaryAgent, serverName, transformed, options);
|
|
1403
|
+
for (const agentType of cluster.targetAgents) {
|
|
1404
|
+
resultsByAgent.set(agentType, {
|
|
1405
|
+
agent: agentType,
|
|
1406
|
+
success: true,
|
|
1407
|
+
path: cluster.configPath,
|
|
1408
|
+
coConfiguredAgents: cluster.coHostedAgents.length > 0 ? cluster.coHostedAgents : void 0
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
} catch (error) {
|
|
1412
|
+
const errorMsg = toErrorMessage(error);
|
|
1413
|
+
for (const agentType of cluster.targetAgents) {
|
|
1414
|
+
resultsByAgent.set(agentType, {
|
|
1415
|
+
agent: agentType,
|
|
1416
|
+
success: false,
|
|
1417
|
+
path: cluster.configPath,
|
|
1418
|
+
error: errorMsg
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
return agentTypes.map((agentType) => resultsByAgent.get(agentType));
|
|
1424
|
+
};
|
|
1425
|
+
var installToCompatibleAgents = (serverName, serverConfig, options) => {
|
|
1426
|
+
const { allAgents, incompatible = [], global: isGlobal, cwd } = options;
|
|
1427
|
+
const incompatibleMap = new Map(incompatible.map((item) => [item.agent, item.reason]));
|
|
1428
|
+
const compatibleAgents = allAgents.filter((a) => !incompatibleMap.has(a));
|
|
1429
|
+
const installedResults = installMcpServerForAgents(serverName, serverConfig, compatibleAgents, {
|
|
1430
|
+
global: isGlobal,
|
|
1431
|
+
cwd
|
|
1432
|
+
});
|
|
1433
|
+
const installedMap = new Map(installedResults.map((r) => [r.agent, r]));
|
|
1434
|
+
return allAgents.map((agentType) => {
|
|
1435
|
+
const incompatibleReason = incompatibleMap.get(agentType);
|
|
1436
|
+
if (incompatibleReason) {
|
|
1437
|
+
return {
|
|
1438
|
+
agent: agentType,
|
|
1439
|
+
success: false,
|
|
1440
|
+
path: "",
|
|
1441
|
+
error: incompatibleReason
|
|
1442
|
+
};
|
|
1443
|
+
}
|
|
1444
|
+
return installedMap.get(agentType);
|
|
1445
|
+
});
|
|
1446
|
+
};
|
|
1292
1447
|
|
|
1293
1448
|
// src/utils/parse-mcp-agent-list.ts
|
|
1294
|
-
var parseMcpAgentList = (
|
|
1295
|
-
if (!
|
|
1296
|
-
if (
|
|
1449
|
+
var parseMcpAgentList = (input7) => {
|
|
1450
|
+
if (!input7 || input7.length === 0) return void 0;
|
|
1451
|
+
if (input7.includes("*")) return getMcpAgentTypes();
|
|
1297
1452
|
const resolved = [];
|
|
1298
|
-
for (const value of
|
|
1453
|
+
for (const value of input7) {
|
|
1299
1454
|
const agentType = resolveMcpAgentAlias(value);
|
|
1300
1455
|
if (!agentType) throw new Error(`Unknown MCP agent "${value}"`);
|
|
1301
1456
|
resolved.push(agentType);
|
|
@@ -1304,9 +1459,9 @@ var parseMcpAgentList = (input5) => {
|
|
|
1304
1459
|
};
|
|
1305
1460
|
|
|
1306
1461
|
// src/resolve-target-agents.ts
|
|
1307
|
-
var normalizeRequestedAgents = (
|
|
1308
|
-
if (!
|
|
1309
|
-
const rawList = [...
|
|
1462
|
+
var normalizeRequestedAgents = (input7) => {
|
|
1463
|
+
if (!input7 || input7.length === 0) return void 0;
|
|
1464
|
+
const rawList = [...input7];
|
|
1310
1465
|
if (rawList.every((item) => isMcpAgentType(item))) {
|
|
1311
1466
|
return rawList;
|
|
1312
1467
|
}
|
|
@@ -1366,29 +1521,29 @@ var REMOTE_URL_REGEX = /^https?:\/\//i;
|
|
|
1366
1521
|
var HAS_WHITESPACE_REGEX = /\s/;
|
|
1367
1522
|
var PACKAGE_NAME_REGEX = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(?:@[^\s]+)?$/;
|
|
1368
1523
|
var PATH_SEPARATOR_REGEX = /[/\\]/;
|
|
1369
|
-
var stripVersionSuffix = (
|
|
1370
|
-
if (
|
|
1371
|
-
const secondAtIndex =
|
|
1372
|
-
if (secondAtIndex > 0) return
|
|
1373
|
-
return
|
|
1374
|
-
}
|
|
1375
|
-
const atIndex =
|
|
1376
|
-
if (atIndex > 0) return
|
|
1377
|
-
return
|
|
1378
|
-
};
|
|
1379
|
-
var stripScopePrefix = (
|
|
1380
|
-
if (!
|
|
1381
|
-
const parts =
|
|
1382
|
-
return parts[1] ||
|
|
1383
|
-
};
|
|
1384
|
-
var stripPathPrefix = (
|
|
1385
|
-
if (!PATH_SEPARATOR_REGEX.test(
|
|
1386
|
-
const segments =
|
|
1524
|
+
var stripVersionSuffix = (input7) => {
|
|
1525
|
+
if (input7.startsWith("@")) {
|
|
1526
|
+
const secondAtIndex = input7.indexOf("@", 1);
|
|
1527
|
+
if (secondAtIndex > 0) return input7.slice(0, secondAtIndex);
|
|
1528
|
+
return input7;
|
|
1529
|
+
}
|
|
1530
|
+
const atIndex = input7.lastIndexOf("@");
|
|
1531
|
+
if (atIndex > 0) return input7.slice(0, atIndex);
|
|
1532
|
+
return input7;
|
|
1533
|
+
};
|
|
1534
|
+
var stripScopePrefix = (input7) => {
|
|
1535
|
+
if (!input7.startsWith("@") || !input7.includes("/")) return input7;
|
|
1536
|
+
const parts = input7.split("/");
|
|
1537
|
+
return parts[1] || input7;
|
|
1538
|
+
};
|
|
1539
|
+
var stripPathPrefix = (input7) => {
|
|
1540
|
+
if (!PATH_SEPARATOR_REGEX.test(input7)) return input7;
|
|
1541
|
+
const segments = input7.split(PATH_SEPARATOR_REGEX);
|
|
1387
1542
|
const basename = segments[segments.length - 1];
|
|
1388
|
-
return basename ||
|
|
1543
|
+
return basename || input7;
|
|
1389
1544
|
};
|
|
1390
|
-
var extractPackageName = (
|
|
1391
|
-
let name = stripVersionSuffix(
|
|
1545
|
+
var extractPackageName = (input7) => {
|
|
1546
|
+
let name = stripVersionSuffix(input7);
|
|
1392
1547
|
name = stripScopePrefix(name);
|
|
1393
1548
|
name = stripPathPrefix(name);
|
|
1394
1549
|
name = name.replace(SCRIPT_EXTENSION_REGEX, "");
|
|
@@ -1406,9 +1561,9 @@ var extractPackageName = (input5) => {
|
|
|
1406
1561
|
}
|
|
1407
1562
|
return name || MCP_DEFAULT_SERVER_NAME;
|
|
1408
1563
|
};
|
|
1409
|
-
var inferNameFromUrl = (
|
|
1564
|
+
var inferNameFromUrl = (input7) => {
|
|
1410
1565
|
try {
|
|
1411
|
-
const url = new URL(
|
|
1566
|
+
const url = new URL(input7);
|
|
1412
1567
|
const host = url.hostname;
|
|
1413
1568
|
const labels = host.split(".").filter((segment) => segment.length > 0);
|
|
1414
1569
|
if (labels.length === 0) return MCP_DEFAULT_SERVER_NAME;
|
|
@@ -1437,8 +1592,8 @@ var inferNameFromCommand = (command) => {
|
|
|
1437
1592
|
const firstNonFlag = tokens.find((token) => !token.startsWith("-"));
|
|
1438
1593
|
return firstNonFlag ? extractPackageName(firstNonFlag) : MCP_DEFAULT_SERVER_NAME;
|
|
1439
1594
|
};
|
|
1440
|
-
var parseMcpSource = (
|
|
1441
|
-
const trimmed =
|
|
1595
|
+
var parseMcpSource = (input7) => {
|
|
1596
|
+
const trimmed = input7.trim();
|
|
1442
1597
|
if (trimmed.length === 0) {
|
|
1443
1598
|
throw new Error(
|
|
1444
1599
|
"Invalid MCP source: input is empty. Expected a remote URL, an npm package, or a command line."
|
|
@@ -1492,18 +1647,11 @@ var installMcpServer = (options) => {
|
|
|
1492
1647
|
cwd,
|
|
1493
1648
|
transport: requestedTransport
|
|
1494
1649
|
});
|
|
1495
|
-
const
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
agent: agentType,
|
|
1501
|
-
success: false,
|
|
1502
|
-
path: "",
|
|
1503
|
-
error: incompatibleReason
|
|
1504
|
-
};
|
|
1505
|
-
}
|
|
1506
|
-
return installMcpServerForAgent(serverName, serverConfig, agentType, { global: isGlobal, cwd });
|
|
1650
|
+
const results = installToCompatibleAgents(serverName, serverConfig, {
|
|
1651
|
+
allAgents,
|
|
1652
|
+
incompatible,
|
|
1653
|
+
global: isGlobal,
|
|
1654
|
+
cwd
|
|
1507
1655
|
});
|
|
1508
1656
|
return { serverName, config: serverConfig, results };
|
|
1509
1657
|
};
|
|
@@ -1533,9 +1681,15 @@ var listInstalledMcpServers = (options = {}) => {
|
|
|
1533
1681
|
var removeMcpServerFromAgent = (serverName, agentType, options = {}) => {
|
|
1534
1682
|
const agent = getMcpAgentConfig(agentType);
|
|
1535
1683
|
const { target } = agentConfigStore.resolveTarget(agent, options);
|
|
1684
|
+
const coHosted = getCoHostedAgents(agentType, options);
|
|
1536
1685
|
try {
|
|
1537
1686
|
const { removed } = agentConfigStore.removeServer(agent, serverName, options);
|
|
1538
|
-
return {
|
|
1687
|
+
return {
|
|
1688
|
+
agent: agentType,
|
|
1689
|
+
path: target.configPath,
|
|
1690
|
+
removed,
|
|
1691
|
+
coAffectedAgents: removed && coHosted.length > 0 ? coHosted : void 0
|
|
1692
|
+
};
|
|
1539
1693
|
} catch (error) {
|
|
1540
1694
|
return {
|
|
1541
1695
|
agent: agentType,
|
|
@@ -1552,24 +1706,153 @@ var removeMcpServer = (options) => {
|
|
|
1552
1706
|
global: options.global,
|
|
1553
1707
|
cwd: options.cwd
|
|
1554
1708
|
});
|
|
1709
|
+
const clusters = resolveConfigClusters(allAgents, {
|
|
1710
|
+
global: options.global,
|
|
1711
|
+
cwd: options.cwd
|
|
1712
|
+
});
|
|
1555
1713
|
const results = [];
|
|
1556
|
-
for (const
|
|
1557
|
-
const
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1714
|
+
for (const cluster of clusters) {
|
|
1715
|
+
const primaryAgentType = cluster.targetAgents[0];
|
|
1716
|
+
const primaryAgent = getMcpAgentConfig(primaryAgentType);
|
|
1717
|
+
try {
|
|
1718
|
+
const { removed } = agentConfigStore.removeServer(primaryAgent, options.name, {
|
|
1719
|
+
global: options.global,
|
|
1720
|
+
cwd: options.cwd
|
|
1721
|
+
});
|
|
1722
|
+
if (removed) {
|
|
1723
|
+
for (const agentType of cluster.targetAgents) {
|
|
1724
|
+
results.push({
|
|
1725
|
+
agent: agentType,
|
|
1726
|
+
path: cluster.configPath,
|
|
1727
|
+
removed: true,
|
|
1728
|
+
coAffectedAgents: cluster.coHostedAgents.length > 0 ? cluster.coHostedAgents : void 0
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
} catch (error) {
|
|
1733
|
+
const errorMsg = toErrorMessage(error);
|
|
1734
|
+
for (const agentType of cluster.targetAgents) {
|
|
1735
|
+
results.push({
|
|
1736
|
+
agent: agentType,
|
|
1737
|
+
path: cluster.configPath,
|
|
1738
|
+
removed: false,
|
|
1739
|
+
error: errorMsg
|
|
1740
|
+
});
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1562
1743
|
}
|
|
1563
1744
|
return results;
|
|
1564
1745
|
};
|
|
1565
1746
|
|
|
1747
|
+
// src/update-mcp-server.ts
|
|
1748
|
+
var toRemoteServerConfig = (config, defaultTransport = "http") => {
|
|
1749
|
+
const {
|
|
1750
|
+
command: _droppedCommand,
|
|
1751
|
+
args: _droppedArgs,
|
|
1752
|
+
env: _droppedEnv,
|
|
1753
|
+
...remoteConfig
|
|
1754
|
+
} = config;
|
|
1755
|
+
return {
|
|
1756
|
+
...remoteConfig,
|
|
1757
|
+
type: remoteConfig.type ?? defaultTransport
|
|
1758
|
+
};
|
|
1759
|
+
};
|
|
1760
|
+
var toStdioServerConfig = (config) => {
|
|
1761
|
+
const {
|
|
1762
|
+
url: _droppedUrl,
|
|
1763
|
+
type: _droppedType,
|
|
1764
|
+
headers: _droppedHeaders,
|
|
1765
|
+
...stdioConfig
|
|
1766
|
+
} = config;
|
|
1767
|
+
return stdioConfig;
|
|
1768
|
+
};
|
|
1769
|
+
var detectUpdateTransition = (incoming, previous) => {
|
|
1770
|
+
if (!previous) {
|
|
1771
|
+
return incoming.url ? "switch-to-remote" : "switch-to-stdio";
|
|
1772
|
+
}
|
|
1773
|
+
if (incoming.url && !incoming.command) {
|
|
1774
|
+
return "switch-to-remote";
|
|
1775
|
+
}
|
|
1776
|
+
if (incoming.command && !incoming.url) {
|
|
1777
|
+
return "switch-to-stdio";
|
|
1778
|
+
}
|
|
1779
|
+
if (incoming.url || !incoming.command && previous.url) {
|
|
1780
|
+
return "merge-remote";
|
|
1781
|
+
}
|
|
1782
|
+
return "merge-stdio";
|
|
1783
|
+
};
|
|
1784
|
+
var sanitizeUpdatedServerConfig = (incoming, previous) => {
|
|
1785
|
+
const transition = detectUpdateTransition(incoming, previous);
|
|
1786
|
+
const targetTransport = incoming.type ?? previous?.type ?? "http";
|
|
1787
|
+
switch (transition) {
|
|
1788
|
+
case "switch-to-remote": {
|
|
1789
|
+
const cleanBase = previous ? toRemoteServerConfig(previous, targetTransport) : {};
|
|
1790
|
+
return toRemoteServerConfig({ ...cleanBase, ...incoming }, targetTransport);
|
|
1791
|
+
}
|
|
1792
|
+
case "switch-to-stdio": {
|
|
1793
|
+
const cleanBase = previous ? toStdioServerConfig(previous) : {};
|
|
1794
|
+
return toStdioServerConfig({ ...cleanBase, ...incoming });
|
|
1795
|
+
}
|
|
1796
|
+
case "merge-remote": {
|
|
1797
|
+
return toRemoteServerConfig({ ...previous, ...incoming }, targetTransport);
|
|
1798
|
+
}
|
|
1799
|
+
case "merge-stdio": {
|
|
1800
|
+
return toStdioServerConfig({ ...previous, ...incoming });
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
};
|
|
1804
|
+
var updateMcpServer = (options) => {
|
|
1805
|
+
const isGlobal = options.global ?? false;
|
|
1806
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1807
|
+
let previousConfig = options.previousConfig;
|
|
1808
|
+
if (!previousConfig) {
|
|
1809
|
+
const existing = listInstalledMcpServers({
|
|
1810
|
+
global: isGlobal,
|
|
1811
|
+
cwd,
|
|
1812
|
+
agents: options.agents
|
|
1813
|
+
});
|
|
1814
|
+
const found = existing.find((s) => s.serverName === options.serverName && s.serverConfig);
|
|
1815
|
+
if (found) {
|
|
1816
|
+
previousConfig = found.serverConfig;
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
const serverConfig = sanitizeUpdatedServerConfig(options.config, previousConfig);
|
|
1820
|
+
let targetAgents = options.agents;
|
|
1821
|
+
if (!targetAgents || targetAgents.length === 0) {
|
|
1822
|
+
const existing = listInstalledMcpServers({ global: isGlobal, cwd });
|
|
1823
|
+
targetAgents = existing.filter((s) => s.serverName === options.serverName).map((s) => s.agent);
|
|
1824
|
+
}
|
|
1825
|
+
const requestedTransport = serverConfig.url ? serverConfig.type ?? "http" : "stdio";
|
|
1826
|
+
const { allAgents, incompatible } = resolveTargetAgents({
|
|
1827
|
+
requested: targetAgents,
|
|
1828
|
+
global: isGlobal,
|
|
1829
|
+
cwd,
|
|
1830
|
+
transport: requestedTransport
|
|
1831
|
+
});
|
|
1832
|
+
const results = installToCompatibleAgents(options.serverName, serverConfig, {
|
|
1833
|
+
allAgents,
|
|
1834
|
+
incompatible,
|
|
1835
|
+
global: isGlobal,
|
|
1836
|
+
cwd
|
|
1837
|
+
});
|
|
1838
|
+
return {
|
|
1839
|
+
serverName: options.serverName,
|
|
1840
|
+
config: serverConfig,
|
|
1841
|
+
results,
|
|
1842
|
+
incompatible
|
|
1843
|
+
};
|
|
1844
|
+
};
|
|
1845
|
+
|
|
1566
1846
|
// src/interactive/main-menu.ts
|
|
1567
1847
|
var import_prompts10 = require("@inquirer/prompts");
|
|
1568
|
-
var
|
|
1848
|
+
var import_picocolors15 = __toESM(require("picocolors"), 1);
|
|
1569
1849
|
|
|
1570
1850
|
// src/interactive/wizard-add.ts
|
|
1571
1851
|
var import_prompts7 = require("@inquirer/prompts");
|
|
1572
|
-
var
|
|
1852
|
+
var import_picocolors11 = __toESM(require("picocolors"), 1);
|
|
1853
|
+
|
|
1854
|
+
// src/utils/co-hosted-feedback.ts
|
|
1855
|
+
var import_picocolors2 = __toESM(require("picocolors"), 1);
|
|
1573
1856
|
|
|
1574
1857
|
// src/utils/logger.ts
|
|
1575
1858
|
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
@@ -1588,13 +1871,269 @@ var logger = {
|
|
|
1588
1871
|
}
|
|
1589
1872
|
};
|
|
1590
1873
|
|
|
1874
|
+
// src/utils/co-hosted-feedback.ts
|
|
1875
|
+
var formatCoHostedBadge = (kind, agents) => {
|
|
1876
|
+
if (!agents || agents.length === 0) return "";
|
|
1877
|
+
const label = kind === "configured" ? "co-configured" : "co-affected";
|
|
1878
|
+
return ` ${import_picocolors2.default.yellow(`(${label}: ${agents.join(", ")})`)}`;
|
|
1879
|
+
};
|
|
1880
|
+
var logCoHostedNotice = (kind, agents) => {
|
|
1881
|
+
if (!agents || agents.length === 0) return;
|
|
1882
|
+
const actionText = kind === "configured" ? "Also configured for" : "Also affects";
|
|
1883
|
+
logger.info(
|
|
1884
|
+
` ${import_picocolors2.default.dim("Note:")} ${actionText} co-hosted agent(s): ${import_picocolors2.default.yellow(agents.join(", "))}`
|
|
1885
|
+
);
|
|
1886
|
+
};
|
|
1887
|
+
|
|
1591
1888
|
// src/interactive/prompts/agents.ts
|
|
1592
|
-
var
|
|
1889
|
+
var import_picocolors6 = __toESM(require("picocolors"), 1);
|
|
1890
|
+
|
|
1891
|
+
// src/interactive/utils/build-linked-agent-choices.ts
|
|
1593
1892
|
var import_picocolors3 = __toESM(require("picocolors"), 1);
|
|
1893
|
+
var buildLinkedAgentChoices = (options) => {
|
|
1894
|
+
const { agents, checkedAgents, detectedAgents = [], scopeOptions = {} } = options;
|
|
1895
|
+
const alignedCheckedSet = new Set(checkedAgents);
|
|
1896
|
+
for (const agent of checkedAgents) {
|
|
1897
|
+
const coHosted = getCoHostedAgents(agent, scopeOptions);
|
|
1898
|
+
for (const co of coHosted) {
|
|
1899
|
+
if (agents.includes(co)) {
|
|
1900
|
+
alignedCheckedSet.add(co);
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
return agents.map((agent) => {
|
|
1905
|
+
const config = getMcpAgentConfig(agent);
|
|
1906
|
+
const displayName = config?.displayName ?? agent;
|
|
1907
|
+
const isDetected = detectedAgents.includes(agent);
|
|
1908
|
+
const coHosted = getCoHostedAgents(agent, scopeOptions).filter(
|
|
1909
|
+
(co) => agents.includes(co)
|
|
1910
|
+
);
|
|
1911
|
+
const detectedBadge = isDetected ? import_picocolors3.default.green(" [detected]") : "";
|
|
1912
|
+
const sharedBadge = coHosted.length > 0 ? import_picocolors3.default.dim(` [shared: ${coHosted.join(", ")}]`) : "";
|
|
1913
|
+
const label = `${displayName} ${import_picocolors3.default.dim(`(${agent})`)}${detectedBadge}${sharedBadge}`;
|
|
1914
|
+
return {
|
|
1915
|
+
name: label,
|
|
1916
|
+
value: agent,
|
|
1917
|
+
checked: alignedCheckedSet.has(agent),
|
|
1918
|
+
linkedValues: coHosted,
|
|
1919
|
+
description: coHosted.length > 0 ? `Linked with ${coHosted.map((a) => getMcpAgentConfig(a).displayName).join(", ")} (shared configuration)` : void 0
|
|
1920
|
+
};
|
|
1921
|
+
});
|
|
1922
|
+
};
|
|
1923
|
+
|
|
1924
|
+
// src/interactive/prompts/linked-checkbox.ts
|
|
1925
|
+
var import_core = require("@inquirer/core");
|
|
1926
|
+
var import_picocolors4 = __toESM(require("picocolors"), 1);
|
|
1927
|
+
var defaultTheme = {
|
|
1928
|
+
icon: {
|
|
1929
|
+
checked: import_picocolors4.default.green("[x]"),
|
|
1930
|
+
unchecked: import_picocolors4.default.dim("[ ]"),
|
|
1931
|
+
cursor: import_picocolors4.default.cyan(">"),
|
|
1932
|
+
disabledChecked: import_picocolors4.default.dim("[x]"),
|
|
1933
|
+
disabledUnchecked: import_picocolors4.default.dim("[-]")
|
|
1934
|
+
},
|
|
1935
|
+
style: {
|
|
1936
|
+
disabled: (text) => import_picocolors4.default.dim(text),
|
|
1937
|
+
renderSelectedChoices: (selectedChoices) => selectedChoices.map((choice) => choice.short).join(", "),
|
|
1938
|
+
description: (text) => import_picocolors4.default.cyan(text),
|
|
1939
|
+
keysHelpTip: (keys) => keys.map(([key, action]) => `${import_picocolors4.default.bold(key)} ${import_picocolors4.default.dim(action)}`).join(import_picocolors4.default.dim(" | ")),
|
|
1940
|
+
highlight: (text) => import_picocolors4.default.cyan(text)
|
|
1941
|
+
},
|
|
1942
|
+
i18n: {
|
|
1943
|
+
disabledError: "This option is disabled and cannot be toggled."
|
|
1944
|
+
}
|
|
1945
|
+
};
|
|
1946
|
+
function isSelectable(item) {
|
|
1947
|
+
return !import_core.Separator.isSeparator(item) && !item.disabled;
|
|
1948
|
+
}
|
|
1949
|
+
function isNavigable(item) {
|
|
1950
|
+
return !import_core.Separator.isSeparator(item);
|
|
1951
|
+
}
|
|
1952
|
+
function isChecked(item) {
|
|
1953
|
+
return !import_core.Separator.isSeparator(item) && item.checked;
|
|
1954
|
+
}
|
|
1955
|
+
function normalizeChoices(choices) {
|
|
1956
|
+
return choices.map((choice) => {
|
|
1957
|
+
if (import_core.Separator.isSeparator(choice)) {
|
|
1958
|
+
return choice;
|
|
1959
|
+
}
|
|
1960
|
+
if (typeof choice !== "object" || choice === null || !("value" in choice)) {
|
|
1961
|
+
const name2 = String(choice);
|
|
1962
|
+
return {
|
|
1963
|
+
value: choice,
|
|
1964
|
+
name: name2,
|
|
1965
|
+
short: name2,
|
|
1966
|
+
checkedName: name2,
|
|
1967
|
+
disabled: false,
|
|
1968
|
+
checked: false,
|
|
1969
|
+
linkedValues: []
|
|
1970
|
+
};
|
|
1971
|
+
}
|
|
1972
|
+
const name = choice.name ?? String(choice.value);
|
|
1973
|
+
return {
|
|
1974
|
+
value: choice.value,
|
|
1975
|
+
name,
|
|
1976
|
+
short: choice.short ?? name,
|
|
1977
|
+
checkedName: choice.checkedName ?? name,
|
|
1978
|
+
description: choice.description,
|
|
1979
|
+
disabled: choice.disabled ?? false,
|
|
1980
|
+
checked: choice.checked ?? false,
|
|
1981
|
+
linkedValues: choice.linkedValues ?? []
|
|
1982
|
+
};
|
|
1983
|
+
});
|
|
1984
|
+
}
|
|
1985
|
+
var linkedCheckbox = (0, import_core.createPrompt)(
|
|
1986
|
+
(config, done) => {
|
|
1987
|
+
const { pageSize = 10, loop = true, required, validate = () => true } = config;
|
|
1988
|
+
const theme = (0, import_core.makeTheme)(defaultTheme, config.theme);
|
|
1989
|
+
const [status, setStatus] = (0, import_core.useState)("idle");
|
|
1990
|
+
const prefix = (0, import_core.usePrefix)({ status, theme });
|
|
1991
|
+
const [items, setItems] = (0, import_core.useState)(() => normalizeChoices(config.choices));
|
|
1992
|
+
const bounds = (0, import_core.useMemo)(() => {
|
|
1993
|
+
const first = items.findIndex(isNavigable);
|
|
1994
|
+
let last = -1;
|
|
1995
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
1996
|
+
if (isNavigable(items[i])) {
|
|
1997
|
+
last = i;
|
|
1998
|
+
break;
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
if (first === -1 || last === -1) {
|
|
2002
|
+
throw new import_core.ValidationError("[linkedCheckbox prompt] No selectable choices.");
|
|
2003
|
+
}
|
|
2004
|
+
return { first, last };
|
|
2005
|
+
}, [items]);
|
|
2006
|
+
const [active, setActive] = (0, import_core.useState)(bounds.first);
|
|
2007
|
+
const [errorMsg, setError] = (0, import_core.useState)();
|
|
2008
|
+
const toggleWithLinked = (targetIndex) => {
|
|
2009
|
+
const targetItem = items[targetIndex];
|
|
2010
|
+
if (!targetItem || import_core.Separator.isSeparator(targetItem) || targetItem.disabled) {
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
const nextChecked = !targetItem.checked;
|
|
2014
|
+
const targetValue = targetItem.value;
|
|
2015
|
+
const linked = new Set(targetItem.linkedValues);
|
|
2016
|
+
setItems(
|
|
2017
|
+
(prevItems) => prevItems.map((item) => {
|
|
2018
|
+
if (import_core.Separator.isSeparator(item) || item.disabled) {
|
|
2019
|
+
return item;
|
|
2020
|
+
}
|
|
2021
|
+
const isTargetOrLinked = item.value === targetValue || linked.has(item.value) || item.linkedValues.includes(targetValue);
|
|
2022
|
+
if (isTargetOrLinked) {
|
|
2023
|
+
return { ...item, checked: nextChecked };
|
|
2024
|
+
}
|
|
2025
|
+
return item;
|
|
2026
|
+
})
|
|
2027
|
+
);
|
|
2028
|
+
};
|
|
2029
|
+
(0, import_core.useKeypress)(async (key) => {
|
|
2030
|
+
if ((0, import_core.isEnterKey)(key)) {
|
|
2031
|
+
const selection = items.filter(isChecked);
|
|
2032
|
+
const isValid = await validate([...selection]);
|
|
2033
|
+
if (required && selection.length === 0) {
|
|
2034
|
+
setError("At least one choice must be selected");
|
|
2035
|
+
} else if (isValid === true) {
|
|
2036
|
+
setStatus("done");
|
|
2037
|
+
done(selection.map((choice) => choice.value));
|
|
2038
|
+
} else {
|
|
2039
|
+
setError(typeof isValid === "string" ? isValid : "You must select a valid value");
|
|
2040
|
+
}
|
|
2041
|
+
} else if ((0, import_core.isUpKey)(key) || (0, import_core.isDownKey)(key)) {
|
|
2042
|
+
if (errorMsg) setError(void 0);
|
|
2043
|
+
if (loop || (0, import_core.isUpKey)(key) && active !== bounds.first || (0, import_core.isDownKey)(key) && active !== bounds.last) {
|
|
2044
|
+
const offset = (0, import_core.isUpKey)(key) ? -1 : 1;
|
|
2045
|
+
let next = active;
|
|
2046
|
+
do {
|
|
2047
|
+
next = (next + offset + items.length) % items.length;
|
|
2048
|
+
} while (!isNavigable(items[next]));
|
|
2049
|
+
setActive(next);
|
|
2050
|
+
}
|
|
2051
|
+
} else if ((0, import_core.isSpaceKey)(key)) {
|
|
2052
|
+
const activeItem = items[active];
|
|
2053
|
+
if (activeItem && !import_core.Separator.isSeparator(activeItem)) {
|
|
2054
|
+
if (activeItem.disabled) {
|
|
2055
|
+
setError(theme.i18n.disabledError);
|
|
2056
|
+
} else {
|
|
2057
|
+
setError(void 0);
|
|
2058
|
+
toggleWithLinked(active);
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
} else if (key.name === "a") {
|
|
2062
|
+
const hasUnchecked = items.some((choice) => isSelectable(choice) && !choice.checked);
|
|
2063
|
+
setItems(
|
|
2064
|
+
(prevItems) => prevItems.map((item) => isSelectable(item) ? { ...item, checked: hasUnchecked } : item)
|
|
2065
|
+
);
|
|
2066
|
+
} else if ((0, import_core.isNumberKey)(key)) {
|
|
2067
|
+
const selectedIndex = Number(key.name) - 1;
|
|
2068
|
+
let selectableIndex = -1;
|
|
2069
|
+
const position = items.findIndex((item) => {
|
|
2070
|
+
if (import_core.Separator.isSeparator(item)) return false;
|
|
2071
|
+
selectableIndex++;
|
|
2072
|
+
return selectableIndex === selectedIndex;
|
|
2073
|
+
});
|
|
2074
|
+
const selectedItem = items[position];
|
|
2075
|
+
if (selectedItem && isSelectable(selectedItem)) {
|
|
2076
|
+
setActive(position);
|
|
2077
|
+
setError(void 0);
|
|
2078
|
+
toggleWithLinked(position);
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
});
|
|
2082
|
+
const message = theme.style.message(config.message, status);
|
|
2083
|
+
let description;
|
|
2084
|
+
const page = (0, import_core.usePagination)({
|
|
2085
|
+
items,
|
|
2086
|
+
active,
|
|
2087
|
+
renderItem({ item, isActive }) {
|
|
2088
|
+
if (import_core.Separator.isSeparator(item)) {
|
|
2089
|
+
return ` ${item.separator}`;
|
|
2090
|
+
}
|
|
2091
|
+
const cursor = isActive ? theme.icon.cursor : " ";
|
|
2092
|
+
if (item.disabled) {
|
|
2093
|
+
const disabledLabel = typeof item.disabled === "string" ? item.disabled : "(disabled)";
|
|
2094
|
+
const checkbox2 = item.checked ? theme.icon.disabledChecked : theme.icon.disabledUnchecked;
|
|
2095
|
+
return theme.style.disabled(`${cursor} ${checkbox2} ${item.name} ${disabledLabel}`);
|
|
2096
|
+
}
|
|
2097
|
+
if (isActive) {
|
|
2098
|
+
description = item.description;
|
|
2099
|
+
}
|
|
2100
|
+
const checkbox = item.checked ? theme.icon.checked : theme.icon.unchecked;
|
|
2101
|
+
const name = item.checked ? item.checkedName : item.name;
|
|
2102
|
+
const color = isActive ? theme.style.highlight : (x) => x;
|
|
2103
|
+
return color(`${cursor} ${checkbox} ${name}`);
|
|
2104
|
+
},
|
|
2105
|
+
pageSize,
|
|
2106
|
+
loop
|
|
2107
|
+
});
|
|
2108
|
+
if (status === "done") {
|
|
2109
|
+
const selection = items.filter(isChecked);
|
|
2110
|
+
const answer = theme.style.answer(theme.style.renderSelectedChoices(selection, items));
|
|
2111
|
+
return [prefix, message, answer].filter(Boolean).join(" ");
|
|
2112
|
+
}
|
|
2113
|
+
const helpLine = theme.style.keysHelpTip([
|
|
2114
|
+
["up/down", "navigate"],
|
|
2115
|
+
["space", "toggle"],
|
|
2116
|
+
["a", "all"],
|
|
2117
|
+
["enter", "submit"]
|
|
2118
|
+
]);
|
|
2119
|
+
const lines = [
|
|
2120
|
+
[prefix, message].filter(Boolean).join(" "),
|
|
2121
|
+
page,
|
|
2122
|
+
helpLine
|
|
2123
|
+
];
|
|
2124
|
+
if (description) {
|
|
2125
|
+
lines.push(theme.style.description(description));
|
|
2126
|
+
}
|
|
2127
|
+
if (errorMsg) {
|
|
2128
|
+
lines.push(theme.style.error(errorMsg));
|
|
2129
|
+
}
|
|
2130
|
+
return lines.join("\n");
|
|
2131
|
+
}
|
|
2132
|
+
);
|
|
1594
2133
|
|
|
1595
2134
|
// src/interactive/prompts/scope.ts
|
|
1596
2135
|
var import_prompts = require("@inquirer/prompts");
|
|
1597
|
-
var
|
|
2136
|
+
var import_picocolors5 = __toESM(require("picocolors"), 1);
|
|
1598
2137
|
var promptScope = async (options = {}) => {
|
|
1599
2138
|
const initialGlobal = options.defaultGlobal ?? options.global;
|
|
1600
2139
|
if (initialGlobal !== void 0) {
|
|
@@ -1605,11 +2144,11 @@ var promptScope = async (options = {}) => {
|
|
|
1605
2144
|
message: options.message ?? "Select MCP scope:",
|
|
1606
2145
|
choices: [
|
|
1607
2146
|
{
|
|
1608
|
-
name: `Current Project - ${
|
|
2147
|
+
name: `Current Project - ${import_picocolors5.default.dim(cwd)}`,
|
|
1609
2148
|
value: false
|
|
1610
2149
|
},
|
|
1611
2150
|
{
|
|
1612
|
-
name: `Global User Config - ${
|
|
2151
|
+
name: `Global User Config - ${import_picocolors5.default.dim("applies across all projects")}`,
|
|
1613
2152
|
value: true
|
|
1614
2153
|
}
|
|
1615
2154
|
]
|
|
@@ -1629,26 +2168,23 @@ var promptScopeAndAgents = async (options = {}) => {
|
|
|
1629
2168
|
cwd
|
|
1630
2169
|
});
|
|
1631
2170
|
const detected = resolution.detected;
|
|
1632
|
-
const
|
|
2171
|
+
const rawAvailable = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
|
|
2172
|
+
const availableAgentTypes = sortAgentsWithClusters(rawAvailable, { global: isGlobal, cwd });
|
|
1633
2173
|
if (detected.length > 0) {
|
|
1634
2174
|
logger.info(
|
|
1635
|
-
`Detected configured agents: ${
|
|
2175
|
+
`Detected configured agents: ${import_picocolors6.default.cyan(detected.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
|
|
1636
2176
|
);
|
|
1637
2177
|
} else {
|
|
1638
2178
|
logger.warn(`No active ${isGlobal ? "global" : "project"} agents detected`);
|
|
1639
2179
|
}
|
|
1640
2180
|
const defaultChecked = options.defaultAgents && options.defaultAgents.length > 0 ? options.defaultAgents : detected;
|
|
1641
|
-
const choices =
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
name: label,
|
|
1647
|
-
value: agentType,
|
|
1648
|
-
checked: defaultChecked.includes(agentType)
|
|
1649
|
-
};
|
|
2181
|
+
const choices = buildLinkedAgentChoices({
|
|
2182
|
+
agents: availableAgentTypes,
|
|
2183
|
+
checkedAgents: defaultChecked,
|
|
2184
|
+
detectedAgents: detected,
|
|
2185
|
+
scopeOptions: { global: isGlobal, cwd }
|
|
1650
2186
|
});
|
|
1651
|
-
const selectedAgents = await (
|
|
2187
|
+
const selectedAgents = await linkedCheckbox({
|
|
1652
2188
|
message: "Select target agents (Space to select, Enter to confirm):",
|
|
1653
2189
|
choices,
|
|
1654
2190
|
validate: (chosen) => {
|
|
@@ -1665,7 +2201,7 @@ var promptScopeAndAgents = async (options = {}) => {
|
|
|
1665
2201
|
};
|
|
1666
2202
|
|
|
1667
2203
|
// src/interactive/prompts/args.ts
|
|
1668
|
-
var
|
|
2204
|
+
var import_prompts2 = require("@inquirer/prompts");
|
|
1669
2205
|
var parseArgsString = (rawText) => {
|
|
1670
2206
|
const matches = rawText.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g);
|
|
1671
2207
|
if (!matches) return [];
|
|
@@ -1680,32 +2216,67 @@ var promptArgsConfig = async (initialArgs = []) => {
|
|
|
1680
2216
|
if (initialArgs.length > 0) {
|
|
1681
2217
|
return initialArgs;
|
|
1682
2218
|
}
|
|
1683
|
-
const needArgs = await (0,
|
|
2219
|
+
const needArgs = await (0, import_prompts2.confirm)({
|
|
1684
2220
|
message: "Configure command arguments (e.g. file paths, connection strings)?",
|
|
1685
2221
|
default: false
|
|
1686
2222
|
});
|
|
1687
2223
|
if (!needArgs) {
|
|
1688
2224
|
return [];
|
|
1689
2225
|
}
|
|
1690
|
-
const raw = await (0,
|
|
2226
|
+
const raw = await (0, import_prompts2.input)({
|
|
1691
2227
|
message: "Enter command arguments (space-separated, wrap paths with spaces in quotes):",
|
|
1692
2228
|
validate: (val) => val.trim() ? true : "Arguments cannot be empty"
|
|
1693
2229
|
});
|
|
1694
2230
|
return parseArgsString(raw.trim());
|
|
1695
2231
|
};
|
|
2232
|
+
var formatArgsString = (args) => {
|
|
2233
|
+
return args.map((arg) => arg.includes(" ") || arg.includes('"') ? `"${arg.replace(/"/g, '\\"')}"` : arg).join(" ");
|
|
2234
|
+
};
|
|
2235
|
+
var promptEditArgs = async (currentArgs = []) => {
|
|
2236
|
+
const defaultStr = formatArgsString(currentArgs);
|
|
2237
|
+
const raw = await (0, import_prompts2.input)({
|
|
2238
|
+
message: "Edit command arguments (space-separated, wrap paths with spaces in quotes, leave empty to clear):",
|
|
2239
|
+
default: defaultStr
|
|
2240
|
+
});
|
|
2241
|
+
const trimmed = raw.trim();
|
|
2242
|
+
if (!trimmed) {
|
|
2243
|
+
return [];
|
|
2244
|
+
}
|
|
2245
|
+
return parseArgsString(trimmed);
|
|
2246
|
+
};
|
|
1696
2247
|
|
|
1697
2248
|
// src/interactive/prompts/env.ts
|
|
1698
2249
|
var import_prompts5 = require("@inquirer/prompts");
|
|
1699
|
-
var
|
|
2250
|
+
var import_picocolors9 = __toESM(require("picocolors"), 1);
|
|
2251
|
+
|
|
2252
|
+
// src/utils/mask-secret.ts
|
|
2253
|
+
var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
|
|
2254
|
+
var maskSecretValue = (key, value) => {
|
|
2255
|
+
if (!SECRET_KEY_PATTERN.test(key) || value.length <= 4) {
|
|
2256
|
+
return value;
|
|
2257
|
+
}
|
|
2258
|
+
return `${value.slice(0, 2)}***${value.slice(-2)}`;
|
|
2259
|
+
};
|
|
2260
|
+
var SECRET_HEADER_PATTERN = /(authorization|token|key|secret|auth)/i;
|
|
2261
|
+
var maskSecretHeader = (key, value) => {
|
|
2262
|
+
if (!SECRET_HEADER_PATTERN.test(key) || value.length <= 8) {
|
|
2263
|
+
return value;
|
|
2264
|
+
}
|
|
2265
|
+
return `${value.slice(0, 4)}***${value.slice(-3)}`;
|
|
2266
|
+
};
|
|
2267
|
+
|
|
2268
|
+
// src/interactive/prompts/kv.ts
|
|
2269
|
+
var import_prompts4 = require("@inquirer/prompts");
|
|
2270
|
+
var import_picocolors8 = __toESM(require("picocolors"), 1);
|
|
1700
2271
|
|
|
1701
2272
|
// src/interactive/prompts/multiline.ts
|
|
1702
2273
|
var import_node_readline = require("readline");
|
|
1703
|
-
var
|
|
1704
|
-
var
|
|
2274
|
+
var import_prompts3 = require("@inquirer/prompts");
|
|
2275
|
+
var import_picocolors7 = __toESM(require("picocolors"), 1);
|
|
1705
2276
|
var readMultilineTextFromTerminal = async (message, endHint = "When done pasting, enter END on a new line or press Enter twice to finish") => {
|
|
1706
|
-
console.log(
|
|
2277
|
+
console.log(import_picocolors7.default.cyan(`
|
|
1707
2278
|
${message}`));
|
|
1708
|
-
console.log(
|
|
2279
|
+
console.log(import_picocolors7.default.dim(` (Hint: ${endHint})
|
|
1709
2280
|
`));
|
|
1710
2281
|
return new Promise((resolve) => {
|
|
1711
2282
|
const rl = (0, import_node_readline.createInterface)({
|
|
@@ -1749,7 +2320,7 @@ ${message}`));
|
|
|
1749
2320
|
};
|
|
1750
2321
|
var promptEditorText = async (options) => {
|
|
1751
2322
|
try {
|
|
1752
|
-
return await (0,
|
|
2323
|
+
return await (0, import_prompts3.editor)({
|
|
1753
2324
|
message: options.message,
|
|
1754
2325
|
default: options.defaultText ?? "",
|
|
1755
2326
|
postfix: options.postfix
|
|
@@ -1759,8 +2330,157 @@ var promptEditorText = async (options) => {
|
|
|
1759
2330
|
}
|
|
1760
2331
|
};
|
|
1761
2332
|
|
|
2333
|
+
// src/interactive/prompts/kv.ts
|
|
2334
|
+
var promptEditKeyValueConfig = async (currentItems = {}, options) => {
|
|
2335
|
+
let items = { ...currentItems };
|
|
2336
|
+
while (true) {
|
|
2337
|
+
const keys = Object.keys(items);
|
|
2338
|
+
console.log();
|
|
2339
|
+
if (keys.length === 0) {
|
|
2340
|
+
console.log(import_picocolors8.default.dim(` No ${options.itemsNoun} configured.`));
|
|
2341
|
+
} else {
|
|
2342
|
+
console.log(import_picocolors8.default.cyan(import_picocolors8.default.bold(` Configured ${options.title} (${keys.length}):`)));
|
|
2343
|
+
for (const [k, v] of Object.entries(items)) {
|
|
2344
|
+
const sep = options.separator === "=" ? "=" : ": ";
|
|
2345
|
+
console.log(` ${import_picocolors8.default.bold(k)}${sep}${import_picocolors8.default.dim(options.maskValue(k, v))}`);
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
console.log();
|
|
2349
|
+
const choice = await (0, import_prompts4.select)({
|
|
2350
|
+
message: `Manage ${options.itemsNoun}:`,
|
|
2351
|
+
choices: [
|
|
2352
|
+
{
|
|
2353
|
+
name: "Open in system default editor ($EDITOR)",
|
|
2354
|
+
value: "editor"
|
|
2355
|
+
},
|
|
2356
|
+
{
|
|
2357
|
+
name: `Add or modify a ${options.itemNoun}`,
|
|
2358
|
+
value: "upsert"
|
|
2359
|
+
},
|
|
2360
|
+
...keys.length > 0 ? [
|
|
2361
|
+
{
|
|
2362
|
+
name: `Delete a ${options.itemNoun}`,
|
|
2363
|
+
value: "delete"
|
|
2364
|
+
}
|
|
2365
|
+
] : [],
|
|
2366
|
+
{
|
|
2367
|
+
name: `Paste multiline ${options.itemsNoun} into terminal`,
|
|
2368
|
+
value: "paste"
|
|
2369
|
+
},
|
|
2370
|
+
...keys.length > 0 ? [
|
|
2371
|
+
{
|
|
2372
|
+
name: `Clear all ${options.itemsNoun}`,
|
|
2373
|
+
value: "clear"
|
|
2374
|
+
}
|
|
2375
|
+
] : [],
|
|
2376
|
+
{
|
|
2377
|
+
name: `Done (finish editing ${options.itemsNoun})`,
|
|
2378
|
+
value: "done"
|
|
2379
|
+
}
|
|
2380
|
+
]
|
|
2381
|
+
});
|
|
2382
|
+
if (choice === "done") {
|
|
2383
|
+
return items;
|
|
2384
|
+
}
|
|
2385
|
+
if (choice === "editor") {
|
|
2386
|
+
const defaultText = options.formatText(items);
|
|
2387
|
+
const text = await promptEditorText({
|
|
2388
|
+
message: options.editorMessage,
|
|
2389
|
+
postfix: options.editorPostfix,
|
|
2390
|
+
defaultText
|
|
2391
|
+
});
|
|
2392
|
+
const parsed = options.parseText(text);
|
|
2393
|
+
items = parsed;
|
|
2394
|
+
logger.success(`${options.title} updated (${Object.keys(items).length} total)`);
|
|
2395
|
+
} else if (choice === "upsert") {
|
|
2396
|
+
const key = await (0, import_prompts4.input)({
|
|
2397
|
+
message: options.keyPromptMessage,
|
|
2398
|
+
validate: (val) => {
|
|
2399
|
+
const trimmed = val.trim();
|
|
2400
|
+
if (!trimmed) return `${options.itemNoun} name cannot be empty`;
|
|
2401
|
+
if (/\s/.test(trimmed)) return `${options.itemNoun} name cannot contain spaces`;
|
|
2402
|
+
return true;
|
|
2403
|
+
}
|
|
2404
|
+
});
|
|
2405
|
+
const trimmedKey = key.trim();
|
|
2406
|
+
const existingVal = items[trimmedKey];
|
|
2407
|
+
const isSecret = options.isSecretKey(trimmedKey);
|
|
2408
|
+
let newVal;
|
|
2409
|
+
if (isSecret) {
|
|
2410
|
+
newVal = await (0, import_prompts4.password)({
|
|
2411
|
+
message: existingVal !== void 0 ? `New value for (${trimmedKey}) [leave empty to keep current]:` : `${options.valuePromptMessage} for (${trimmedKey}) [sensitive content masked]:`,
|
|
2412
|
+
mask: "*"
|
|
2413
|
+
});
|
|
2414
|
+
if (existingVal !== void 0 && newVal === "") {
|
|
2415
|
+
newVal = existingVal;
|
|
2416
|
+
}
|
|
2417
|
+
} else {
|
|
2418
|
+
newVal = await (0, import_prompts4.input)({
|
|
2419
|
+
message: `${options.valuePromptMessage} for (${trimmedKey}):`,
|
|
2420
|
+
default: existingVal
|
|
2421
|
+
});
|
|
2422
|
+
}
|
|
2423
|
+
items[trimmedKey] = newVal;
|
|
2424
|
+
logger.success(`${existingVal !== void 0 ? "Updated" : "Added"}: ${import_picocolors8.default.cyan(trimmedKey)}`);
|
|
2425
|
+
} else if (choice === "delete") {
|
|
2426
|
+
const toDelete = await (0, import_prompts4.select)({
|
|
2427
|
+
message: `Select ${options.itemNoun} to delete:`,
|
|
2428
|
+
choices: [
|
|
2429
|
+
...keys.map((k) => ({ name: k, value: k })),
|
|
2430
|
+
{ name: "Cancel", value: "__cancel__" }
|
|
2431
|
+
]
|
|
2432
|
+
});
|
|
2433
|
+
if (toDelete !== "__cancel__") {
|
|
2434
|
+
delete items[toDelete];
|
|
2435
|
+
logger.success(`Deleted: ${import_picocolors8.default.cyan(toDelete)}`);
|
|
2436
|
+
}
|
|
2437
|
+
} else if (choice === "paste") {
|
|
2438
|
+
const pasted = await readMultilineTextFromTerminal(options.pasteMessage);
|
|
2439
|
+
const parsed = options.parseText(pasted);
|
|
2440
|
+
const count = Object.keys(parsed).length;
|
|
2441
|
+
if (count === 0) {
|
|
2442
|
+
logger.warn(`No valid ${options.itemsNoun} recognized`);
|
|
2443
|
+
} else {
|
|
2444
|
+
if (keys.length > 0) {
|
|
2445
|
+
const pasteMode = await (0, import_prompts4.select)({
|
|
2446
|
+
message: `How to apply pasted ${options.itemsNoun}?`,
|
|
2447
|
+
choices: [
|
|
2448
|
+
{ name: `Merge with existing ${options.itemsNoun}`, value: "merge" },
|
|
2449
|
+
{ name: `Replace all existing ${options.itemsNoun}`, value: "replace" }
|
|
2450
|
+
]
|
|
2451
|
+
});
|
|
2452
|
+
if (pasteMode === "replace") {
|
|
2453
|
+
items = parsed;
|
|
2454
|
+
} else {
|
|
2455
|
+
Object.assign(items, parsed);
|
|
2456
|
+
}
|
|
2457
|
+
} else {
|
|
2458
|
+
items = parsed;
|
|
2459
|
+
}
|
|
2460
|
+
logger.success(`Successfully applied ${import_picocolors8.default.cyan(String(count))} ${options.itemsNoun}`);
|
|
2461
|
+
}
|
|
2462
|
+
} else if (choice === "clear") {
|
|
2463
|
+
const confirmClear = await (0, import_prompts4.confirm)({
|
|
2464
|
+
message: `Are you sure you want to clear all ${options.itemsNoun}?`,
|
|
2465
|
+
default: false
|
|
2466
|
+
});
|
|
2467
|
+
if (confirmClear) {
|
|
2468
|
+
items = {};
|
|
2469
|
+
logger.success(`Cleared all ${options.itemsNoun}`);
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
};
|
|
2474
|
+
|
|
1762
2475
|
// src/interactive/prompts/env.ts
|
|
1763
|
-
var
|
|
2476
|
+
var formatEnvText = (env) => {
|
|
2477
|
+
return Object.entries(env).map(([key, value]) => {
|
|
2478
|
+
if (/[\s"']/.test(value)) {
|
|
2479
|
+
return `${key}="${value.replace(/"/g, '\\"')}"`;
|
|
2480
|
+
}
|
|
2481
|
+
return `${key}=${value}`;
|
|
2482
|
+
}).join("\n");
|
|
2483
|
+
};
|
|
1764
2484
|
var parseEnvText = (rawText) => {
|
|
1765
2485
|
const result = {};
|
|
1766
2486
|
const lines = rawText.split(/\r?\n/);
|
|
@@ -1786,7 +2506,7 @@ var promptEnvConfig = async (initialEnv = {}) => {
|
|
|
1786
2506
|
const env = { ...initialEnv };
|
|
1787
2507
|
const initialCount = Object.keys(env).length;
|
|
1788
2508
|
if (initialCount > 0) {
|
|
1789
|
-
logger.info(`Includes ${
|
|
2509
|
+
logger.info(`Includes ${import_picocolors9.default.cyan(String(initialCount))} preset environment variables`);
|
|
1790
2510
|
}
|
|
1791
2511
|
const mode = await (0, import_prompts5.select)({
|
|
1792
2512
|
message: "Configure environment variables?",
|
|
@@ -1815,7 +2535,8 @@ var promptEnvConfig = async (initialEnv = {}) => {
|
|
|
1815
2535
|
if (mode === "paste" || mode === "editor") {
|
|
1816
2536
|
const pasted = mode === "editor" ? await promptEditorText({
|
|
1817
2537
|
message: "Paste or edit environment variables in editor, then save and exit:",
|
|
1818
|
-
postfix: ".env"
|
|
2538
|
+
postfix: ".env",
|
|
2539
|
+
defaultText: formatEnvText(env)
|
|
1819
2540
|
}) : await readMultilineTextFromTerminal("Paste .env formatted content (multiline supported):");
|
|
1820
2541
|
const parsed = parseEnvText(pasted);
|
|
1821
2542
|
const count = Object.keys(parsed).length;
|
|
@@ -1823,10 +2544,9 @@ var promptEnvConfig = async (initialEnv = {}) => {
|
|
|
1823
2544
|
logger.warn("No valid KEY=VALUE pairs recognized");
|
|
1824
2545
|
} else {
|
|
1825
2546
|
Object.assign(env, parsed);
|
|
1826
|
-
logger.success(`Successfully parsed ${
|
|
2547
|
+
logger.success(`Successfully parsed ${import_picocolors9.default.cyan(String(count))} environment variables:`);
|
|
1827
2548
|
for (const [k, v] of Object.entries(parsed)) {
|
|
1828
|
-
|
|
1829
|
-
console.log(` ${import_picocolors5.default.bold(k)}=${import_picocolors5.default.dim(masked)}`);
|
|
2549
|
+
console.log(` ${import_picocolors9.default.bold(k)}=${import_picocolors9.default.dim(maskSecretValue(k, v))}`);
|
|
1830
2550
|
}
|
|
1831
2551
|
}
|
|
1832
2552
|
return env;
|
|
@@ -1857,15 +2577,32 @@ var promptEnvConfig = async (initialEnv = {}) => {
|
|
|
1857
2577
|
});
|
|
1858
2578
|
}
|
|
1859
2579
|
env[trimmedKey] = val;
|
|
1860
|
-
logger.success(`Added: ${
|
|
2580
|
+
logger.success(`Added: ${import_picocolors9.default.cyan(trimmedKey)}`);
|
|
1861
2581
|
}
|
|
1862
2582
|
return env;
|
|
1863
2583
|
};
|
|
2584
|
+
var promptEditEnvConfig = async (currentEnv = {}) => promptEditKeyValueConfig(currentEnv, {
|
|
2585
|
+
title: "Environment Variables",
|
|
2586
|
+
itemNoun: "variable",
|
|
2587
|
+
itemsNoun: "environment variables",
|
|
2588
|
+
separator: "=",
|
|
2589
|
+
editorPostfix: ".env",
|
|
2590
|
+
editorMessage: "Edit environment variables in editor, then save and exit:",
|
|
2591
|
+
pasteMessage: "Paste .env formatted content (multiline supported):",
|
|
2592
|
+
keyPromptMessage: "Variable name (Key):",
|
|
2593
|
+
valuePromptMessage: "Value",
|
|
2594
|
+
isSecretKey: (k) => SECRET_KEY_PATTERN.test(k),
|
|
2595
|
+
maskValue: maskSecretValue,
|
|
2596
|
+
formatText: formatEnvText,
|
|
2597
|
+
parseText: parseEnvText
|
|
2598
|
+
});
|
|
1864
2599
|
|
|
1865
2600
|
// src/interactive/prompts/headers.ts
|
|
1866
2601
|
var import_prompts6 = require("@inquirer/prompts");
|
|
1867
|
-
var
|
|
1868
|
-
var
|
|
2602
|
+
var import_picocolors10 = __toESM(require("picocolors"), 1);
|
|
2603
|
+
var formatHeadersText = (headers) => {
|
|
2604
|
+
return Object.entries(headers).map(([key, value]) => `${key}: ${value}`).join("\n");
|
|
2605
|
+
};
|
|
1869
2606
|
var parseHeadersText = (rawText) => {
|
|
1870
2607
|
const result = {};
|
|
1871
2608
|
const lines = rawText.split(/\r?\n/);
|
|
@@ -1921,7 +2658,8 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
|
|
|
1921
2658
|
}
|
|
1922
2659
|
if (mode === "paste" || mode === "editor") {
|
|
1923
2660
|
const pasted = mode === "editor" ? await promptEditorText({
|
|
1924
|
-
message: "Paste or edit HTTP headers in editor, then save and exit:"
|
|
2661
|
+
message: "Paste or edit HTTP headers in editor, then save and exit:",
|
|
2662
|
+
defaultText: formatHeadersText(headers)
|
|
1925
2663
|
}) : await readMultilineTextFromTerminal(
|
|
1926
2664
|
"Paste HTTP headers content (multiline supported, e.g. Authorization: Bearer ...):"
|
|
1927
2665
|
);
|
|
@@ -1931,10 +2669,9 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
|
|
|
1931
2669
|
logger.warn("No valid Key: Value pairs recognized");
|
|
1932
2670
|
} else {
|
|
1933
2671
|
Object.assign(headers, parsed);
|
|
1934
|
-
logger.success(`Successfully parsed ${
|
|
2672
|
+
logger.success(`Successfully parsed ${import_picocolors10.default.cyan(String(count))} headers:`);
|
|
1935
2673
|
for (const [k, v] of Object.entries(parsed)) {
|
|
1936
|
-
|
|
1937
|
-
console.log(` ${import_picocolors6.default.bold(k)}: ${import_picocolors6.default.dim(masked)}`);
|
|
2674
|
+
console.log(` ${import_picocolors10.default.bold(k)}: ${import_picocolors10.default.dim(maskSecretHeader(k, v))}`);
|
|
1938
2675
|
}
|
|
1939
2676
|
}
|
|
1940
2677
|
return headers;
|
|
@@ -1965,15 +2702,29 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
|
|
|
1965
2702
|
});
|
|
1966
2703
|
}
|
|
1967
2704
|
headers[trimmedName] = val;
|
|
1968
|
-
logger.success(`Added: ${
|
|
2705
|
+
logger.success(`Added: ${import_picocolors10.default.cyan(trimmedName)}`);
|
|
1969
2706
|
}
|
|
1970
2707
|
return headers;
|
|
1971
2708
|
};
|
|
2709
|
+
var promptEditHeadersConfig = async (currentHeaders = {}) => promptEditKeyValueConfig(currentHeaders, {
|
|
2710
|
+
title: "HTTP Headers",
|
|
2711
|
+
itemNoun: "header",
|
|
2712
|
+
itemsNoun: "HTTP headers",
|
|
2713
|
+
separator: ":",
|
|
2714
|
+
editorMessage: "Edit HTTP headers in editor, then save and exit:",
|
|
2715
|
+
pasteMessage: "Paste HTTP headers content (multiline supported, e.g. Authorization: Bearer ...):",
|
|
2716
|
+
keyPromptMessage: "Header name (e.g. Authorization):",
|
|
2717
|
+
valuePromptMessage: "Header value",
|
|
2718
|
+
isSecretKey: (k) => SECRET_HEADER_PATTERN.test(k),
|
|
2719
|
+
maskValue: maskSecretHeader,
|
|
2720
|
+
formatText: formatHeadersText,
|
|
2721
|
+
parseText: parseHeadersText
|
|
2722
|
+
});
|
|
1972
2723
|
|
|
1973
2724
|
// src/interactive/wizard-add.ts
|
|
1974
2725
|
var wizardAdd = async (initial = {}) => {
|
|
1975
2726
|
const cwd = initial.cwd ?? process.cwd();
|
|
1976
|
-
logger.info(
|
|
2727
|
+
logger.info(import_picocolors11.default.bold("Welcome to the MCP interactive add wizard"));
|
|
1977
2728
|
let source = initial.source;
|
|
1978
2729
|
if (!source) {
|
|
1979
2730
|
const sourceType = await (0, import_prompts7.select)({
|
|
@@ -1995,7 +2746,7 @@ var wizardAdd = async (initial = {}) => {
|
|
|
1995
2746
|
});
|
|
1996
2747
|
if (sourceType === "npm") {
|
|
1997
2748
|
source = await (0, import_prompts7.input)({
|
|
1998
|
-
message: "Enter npm package name (e.g. @modelcontextprotocol/server-postgres
|
|
2749
|
+
message: "Enter npm package name (e.g. @modelcontextprotocol/server-postgres):",
|
|
1999
2750
|
validate: (val) => val.trim() ? true : "Package name cannot be empty"
|
|
2000
2751
|
});
|
|
2001
2752
|
} else if (sourceType === "remote") {
|
|
@@ -2063,25 +2814,25 @@ var wizardAdd = async (initial = {}) => {
|
|
|
2063
2814
|
if (parsed.type !== "remote") {
|
|
2064
2815
|
env = await promptEnvConfig(env);
|
|
2065
2816
|
}
|
|
2066
|
-
console.log("\n" +
|
|
2067
|
-
console.log(` ${
|
|
2068
|
-
console.log(` ${
|
|
2069
|
-
console.log(` ${
|
|
2070
|
-
console.log(` ${
|
|
2071
|
-
console.log(` ${
|
|
2817
|
+
console.log("\n" + import_picocolors11.default.cyan(import_picocolors11.default.bold("Configuration Preview:")));
|
|
2818
|
+
console.log(` ${import_picocolors11.default.bold("Server Name:")} ${import_picocolors11.default.green(serverName)}`);
|
|
2819
|
+
console.log(` ${import_picocolors11.default.bold("Server Type:")} ${import_picocolors11.default.magenta(parsed.type)}`);
|
|
2820
|
+
console.log(` ${import_picocolors11.default.bold("Source/Command:")} ${import_picocolors11.default.dim(source)}`);
|
|
2821
|
+
console.log(` ${import_picocolors11.default.bold("Scope:")} ${isGlobal ? import_picocolors11.default.yellow("Global") : import_picocolors11.default.blue("Project")}`);
|
|
2822
|
+
console.log(` ${import_picocolors11.default.bold("Target Agents:")} ${import_picocolors11.default.cyan(selectedAgents.join(", "))}`);
|
|
2072
2823
|
if (args.length > 0) {
|
|
2073
|
-
console.log(` ${
|
|
2824
|
+
console.log(` ${import_picocolors11.default.bold("Arguments:")} ${import_picocolors11.default.dim(args.join(" "))}`);
|
|
2074
2825
|
}
|
|
2075
2826
|
if (transport) {
|
|
2076
|
-
console.log(` ${
|
|
2827
|
+
console.log(` ${import_picocolors11.default.bold("Transport:")} ${import_picocolors11.default.magenta(transport)}`);
|
|
2077
2828
|
}
|
|
2078
2829
|
const envKeys = Object.keys(env);
|
|
2079
2830
|
if (envKeys.length > 0) {
|
|
2080
|
-
console.log(` ${
|
|
2831
|
+
console.log(` ${import_picocolors11.default.bold("Environment Variables:")} ${import_picocolors11.default.dim(envKeys.join(", "))} (${envKeys.length})`);
|
|
2081
2832
|
}
|
|
2082
2833
|
const headerKeys = Object.keys(headers);
|
|
2083
2834
|
if (headerKeys.length > 0) {
|
|
2084
|
-
console.log(` ${
|
|
2835
|
+
console.log(` ${import_picocolors11.default.bold("Headers:")} ${import_picocolors11.default.dim(headerKeys.join(", "))} (${headerKeys.length})`);
|
|
2085
2836
|
}
|
|
2086
2837
|
console.log();
|
|
2087
2838
|
const proceed = await (0, import_prompts7.confirm)({
|
|
@@ -2104,41 +2855,103 @@ var wizardAdd = async (initial = {}) => {
|
|
|
2104
2855
|
env
|
|
2105
2856
|
});
|
|
2106
2857
|
logger.info(
|
|
2107
|
-
`Writing ${
|
|
2858
|
+
`Writing ${import_picocolors11.default.bold(result.serverName)} to ${import_picocolors11.default.cyan(String(result.results.length))} agent config files...`
|
|
2108
2859
|
);
|
|
2109
2860
|
let allSuccess = true;
|
|
2110
2861
|
for (const record of result.results) {
|
|
2111
2862
|
if (record.success) {
|
|
2112
|
-
logger.success(
|
|
2863
|
+
logger.success(
|
|
2864
|
+
`${import_picocolors11.default.cyan(record.agent)}: Successfully written to ${import_picocolors11.default.dim(record.path)}${formatCoHostedBadge("configured", record.coConfiguredAgents)}`
|
|
2865
|
+
);
|
|
2113
2866
|
} else {
|
|
2114
2867
|
allSuccess = false;
|
|
2115
|
-
logger.error(`${
|
|
2868
|
+
logger.error(`${import_picocolors11.default.cyan(record.agent)}: Failed to write - ${record.error}`);
|
|
2116
2869
|
}
|
|
2117
2870
|
}
|
|
2118
2871
|
if (allSuccess) {
|
|
2119
|
-
logger.success(
|
|
2872
|
+
logger.success(import_picocolors11.default.bold(`MCP server "${serverName}" configured successfully!`));
|
|
2120
2873
|
}
|
|
2121
2874
|
return allSuccess;
|
|
2122
2875
|
};
|
|
2123
2876
|
|
|
2124
2877
|
// src/interactive/wizard-manage.ts
|
|
2125
2878
|
var import_prompts8 = require("@inquirer/prompts");
|
|
2126
|
-
var
|
|
2879
|
+
var import_picocolors13 = __toESM(require("picocolors"), 1);
|
|
2880
|
+
|
|
2881
|
+
// src/utils/display-server-details.ts
|
|
2882
|
+
var import_picocolors12 = __toESM(require("picocolors"), 1);
|
|
2883
|
+
var displayServerDetails = ({
|
|
2884
|
+
serverName,
|
|
2885
|
+
config,
|
|
2886
|
+
agents,
|
|
2887
|
+
hasDivergence,
|
|
2888
|
+
global: isGlobal,
|
|
2889
|
+
titlePrefix = "MCP Server Details"
|
|
2890
|
+
}) => {
|
|
2891
|
+
console.log("\n" + import_picocolors12.default.cyan(import_picocolors12.default.bold(`${titlePrefix}: [${serverName}]`)));
|
|
2892
|
+
if (isGlobal !== void 0) {
|
|
2893
|
+
console.log(` ${import_picocolors12.default.bold("Scope:")} ${isGlobal ? "Global" : "Project"}`);
|
|
2894
|
+
}
|
|
2895
|
+
if (agents && agents.length > 0) {
|
|
2896
|
+
console.log(
|
|
2897
|
+
` ${import_picocolors12.default.bold("Configured Agents:")} ${import_picocolors12.default.green(agents.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
|
|
2898
|
+
);
|
|
2899
|
+
}
|
|
2900
|
+
if (hasDivergence) {
|
|
2901
|
+
console.log(
|
|
2902
|
+
` ${import_picocolors12.default.yellow(import_picocolors12.default.bold("Notice:"))} ${import_picocolors12.default.yellow("Configurations differ across installed agents. Showing configuration from the first agent.")}`
|
|
2903
|
+
);
|
|
2904
|
+
}
|
|
2905
|
+
const isRemote = Boolean(config.url && config.url.length > 0);
|
|
2906
|
+
if (isRemote) {
|
|
2907
|
+
console.log(` ${import_picocolors12.default.bold("Transport:")} ${import_picocolors12.default.magenta(config.type ?? "http")}`);
|
|
2908
|
+
console.log(` ${import_picocolors12.default.bold("URL:")} ${import_picocolors12.default.dim(config.url ?? "")}`);
|
|
2909
|
+
const headerKeys = Object.keys(config.headers ?? {});
|
|
2910
|
+
if (headerKeys.length > 0) {
|
|
2911
|
+
console.log(` ${import_picocolors12.default.bold("Headers:")} ${import_picocolors12.default.cyan(String(headerKeys.length))}`);
|
|
2912
|
+
for (const [k, v] of Object.entries(config.headers ?? {})) {
|
|
2913
|
+
console.log(` ${import_picocolors12.default.bold(k)}: ${import_picocolors12.default.dim(maskSecretHeader(k, v))}`);
|
|
2914
|
+
}
|
|
2915
|
+
} else {
|
|
2916
|
+
console.log(` ${import_picocolors12.default.bold("Headers:")} ${import_picocolors12.default.dim("(none)")}`);
|
|
2917
|
+
}
|
|
2918
|
+
} else {
|
|
2919
|
+
console.log(` ${import_picocolors12.default.bold("Command:")} ${import_picocolors12.default.magenta(config.command ?? "")}`);
|
|
2920
|
+
const argsStr = config.args && config.args.length > 0 ? config.args.join(" ") : "(none)";
|
|
2921
|
+
console.log(` ${import_picocolors12.default.bold("Arguments:")} ${import_picocolors12.default.dim(argsStr)}`);
|
|
2922
|
+
const envKeys = Object.keys(config.env ?? {});
|
|
2923
|
+
if (envKeys.length > 0) {
|
|
2924
|
+
console.log(` ${import_picocolors12.default.bold("Environment Variables:")} ${import_picocolors12.default.cyan(String(envKeys.length))}`);
|
|
2925
|
+
for (const [k, v] of Object.entries(config.env ?? {})) {
|
|
2926
|
+
console.log(` ${import_picocolors12.default.bold(k)}=${import_picocolors12.default.dim(maskSecretValue(k, v))}`);
|
|
2927
|
+
}
|
|
2928
|
+
} else {
|
|
2929
|
+
console.log(` ${import_picocolors12.default.bold("Environment Variables:")} ${import_picocolors12.default.dim("(none)")}`);
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
console.log();
|
|
2933
|
+
};
|
|
2127
2934
|
|
|
2128
2935
|
// src/interactive/utils/group-installed-servers.ts
|
|
2129
2936
|
var normalizeServerConfig = parseServerConfig;
|
|
2130
2937
|
var groupInstalledServersByName = (installed) => {
|
|
2131
2938
|
const grouped = /* @__PURE__ */ new Map();
|
|
2132
2939
|
for (const item of installed) {
|
|
2940
|
+
const itemConfig = normalizeServerConfig(item.config);
|
|
2133
2941
|
let entry = grouped.get(item.serverName);
|
|
2134
2942
|
if (!entry) {
|
|
2135
2943
|
entry = {
|
|
2136
2944
|
serverName: item.serverName,
|
|
2137
2945
|
agents: [],
|
|
2138
2946
|
paths: [],
|
|
2139
|
-
config:
|
|
2947
|
+
config: itemConfig,
|
|
2948
|
+
hasDivergence: false
|
|
2140
2949
|
};
|
|
2141
2950
|
grouped.set(item.serverName, entry);
|
|
2951
|
+
} else if (!entry.hasDivergence) {
|
|
2952
|
+
if (JSON.stringify(entry.config) !== JSON.stringify(itemConfig)) {
|
|
2953
|
+
entry.hasDivergence = true;
|
|
2954
|
+
}
|
|
2142
2955
|
}
|
|
2143
2956
|
if (!entry.agents.includes(item.agent)) {
|
|
2144
2957
|
entry.agents.push(item.agent);
|
|
@@ -2151,6 +2964,221 @@ var groupInstalledServersByName = (installed) => {
|
|
|
2151
2964
|
};
|
|
2152
2965
|
|
|
2153
2966
|
// src/interactive/wizard-manage.ts
|
|
2967
|
+
var promptSwitchServerType = async (currentConfig, serverName) => {
|
|
2968
|
+
const isRemote = Boolean(currentConfig.url && currentConfig.url.length > 0);
|
|
2969
|
+
if (isRemote) {
|
|
2970
|
+
const newCmd = await (0, import_prompts8.input)({
|
|
2971
|
+
message: "Executable command (e.g. node, npx):",
|
|
2972
|
+
validate: (val) => val.trim() ? true : "Command cannot be empty"
|
|
2973
|
+
});
|
|
2974
|
+
const newArgs = await promptEditArgs([]);
|
|
2975
|
+
const newEnv = await promptEditEnvConfig({});
|
|
2976
|
+
logger.success(`Switched [${serverName}] configuration to stdio mode`);
|
|
2977
|
+
return {
|
|
2978
|
+
command: newCmd.trim(),
|
|
2979
|
+
args: newArgs.length > 0 ? newArgs : void 0,
|
|
2980
|
+
env: Object.keys(newEnv).length > 0 ? newEnv : void 0
|
|
2981
|
+
};
|
|
2982
|
+
}
|
|
2983
|
+
const newUrl = await (0, import_prompts8.input)({
|
|
2984
|
+
message: "Remote server URL:",
|
|
2985
|
+
validate: (val) => {
|
|
2986
|
+
const trimmed = val.trim();
|
|
2987
|
+
if (!trimmed) return "URL cannot be empty";
|
|
2988
|
+
if (!/^https?:\/\//i.test(trimmed)) {
|
|
2989
|
+
return "Please enter a valid URL starting with http:// or https://";
|
|
2990
|
+
}
|
|
2991
|
+
return true;
|
|
2992
|
+
}
|
|
2993
|
+
});
|
|
2994
|
+
const transport = await (0, import_prompts8.select)({
|
|
2995
|
+
message: "Select remote transport protocol:",
|
|
2996
|
+
choices: [
|
|
2997
|
+
{ name: "HTTP", value: "http" },
|
|
2998
|
+
{ name: "SSE (Server-Sent Events)", value: "sse" }
|
|
2999
|
+
],
|
|
3000
|
+
default: "http"
|
|
3001
|
+
});
|
|
3002
|
+
const newHeaders = await promptEditHeadersConfig({});
|
|
3003
|
+
logger.success(`Switched [${serverName}] configuration to remote mode`);
|
|
3004
|
+
return {
|
|
3005
|
+
url: newUrl.trim(),
|
|
3006
|
+
type: transport,
|
|
3007
|
+
headers: Object.keys(newHeaders).length > 0 ? newHeaders : void 0
|
|
3008
|
+
};
|
|
3009
|
+
};
|
|
3010
|
+
var handleEditServerConfig = async (options) => {
|
|
3011
|
+
const { targetGroup } = options;
|
|
3012
|
+
const isGlobal = options.global ?? false;
|
|
3013
|
+
const cwd = options.cwd ?? process.cwd();
|
|
3014
|
+
const serverName = targetGroup.serverName;
|
|
3015
|
+
let workingConfig = {
|
|
3016
|
+
...targetGroup.config,
|
|
3017
|
+
args: targetGroup.config.args ? [...targetGroup.config.args] : void 0,
|
|
3018
|
+
env: targetGroup.config.env ? { ...targetGroup.config.env } : void 0,
|
|
3019
|
+
headers: targetGroup.config.headers ? { ...targetGroup.config.headers } : void 0
|
|
3020
|
+
};
|
|
3021
|
+
while (true) {
|
|
3022
|
+
const isRemote = Boolean(workingConfig.url && workingConfig.url.length > 0);
|
|
3023
|
+
displayServerDetails({
|
|
3024
|
+
serverName,
|
|
3025
|
+
config: workingConfig,
|
|
3026
|
+
titlePrefix: "Edit Server Configuration"
|
|
3027
|
+
});
|
|
3028
|
+
const editChoices = isRemote ? [
|
|
3029
|
+
{ name: "Edit HTTP Headers (headers)", value: "headers" },
|
|
3030
|
+
{ name: "Edit Remote URL (url)", value: "url" },
|
|
3031
|
+
{ name: "Edit Transport Protocol (type)", value: "transport" },
|
|
3032
|
+
{ name: "Switch to local command (stdio)", value: "switch_type" },
|
|
3033
|
+
{ name: "Reset changes to original", value: "reset" },
|
|
3034
|
+
{ name: "Save and apply changes", value: "save" },
|
|
3035
|
+
{ name: "Cancel (discard changes)", value: "cancel" }
|
|
3036
|
+
] : [
|
|
3037
|
+
{ name: "Edit Environment Variables (env)", value: "env" },
|
|
3038
|
+
{ name: "Edit Command Arguments (args)", value: "args" },
|
|
3039
|
+
{ name: "Edit Executable Command (command)", value: "command" },
|
|
3040
|
+
{ name: "Switch to remote server (HTTP/SSE)", value: "switch_type" },
|
|
3041
|
+
{ name: "Reset changes to original", value: "reset" },
|
|
3042
|
+
{ name: "Save and apply changes", value: "save" },
|
|
3043
|
+
{ name: "Cancel (discard changes)", value: "cancel" }
|
|
3044
|
+
];
|
|
3045
|
+
const editAction = await (0, import_prompts8.select)({
|
|
3046
|
+
message: `What would you like to modify in [${serverName}]?`,
|
|
3047
|
+
choices: editChoices
|
|
3048
|
+
});
|
|
3049
|
+
if (editAction === "cancel") {
|
|
3050
|
+
logger.info("Modification cancelled; changes discarded");
|
|
3051
|
+
return;
|
|
3052
|
+
}
|
|
3053
|
+
if (editAction === "reset") {
|
|
3054
|
+
workingConfig = {
|
|
3055
|
+
...targetGroup.config,
|
|
3056
|
+
args: targetGroup.config.args ? [...targetGroup.config.args] : void 0,
|
|
3057
|
+
env: targetGroup.config.env ? { ...targetGroup.config.env } : void 0,
|
|
3058
|
+
headers: targetGroup.config.headers ? { ...targetGroup.config.headers } : void 0
|
|
3059
|
+
};
|
|
3060
|
+
logger.info("Configuration reset to original");
|
|
3061
|
+
continue;
|
|
3062
|
+
}
|
|
3063
|
+
if (editAction === "switch_type") {
|
|
3064
|
+
workingConfig = await promptSwitchServerType(workingConfig, serverName);
|
|
3065
|
+
continue;
|
|
3066
|
+
}
|
|
3067
|
+
if (editAction === "env") {
|
|
3068
|
+
workingConfig.env = await promptEditEnvConfig(workingConfig.env ?? {});
|
|
3069
|
+
} else if (editAction === "args") {
|
|
3070
|
+
workingConfig.args = await promptEditArgs(workingConfig.args ?? []);
|
|
3071
|
+
} else if (editAction === "command") {
|
|
3072
|
+
const newCmd = await (0, import_prompts8.input)({
|
|
3073
|
+
message: "Executable command:",
|
|
3074
|
+
default: workingConfig.command,
|
|
3075
|
+
validate: (val) => val.trim() ? true : "Command cannot be empty"
|
|
3076
|
+
});
|
|
3077
|
+
workingConfig.command = newCmd.trim();
|
|
3078
|
+
} else if (editAction === "headers") {
|
|
3079
|
+
workingConfig.headers = await promptEditHeadersConfig(workingConfig.headers ?? {});
|
|
3080
|
+
} else if (editAction === "url") {
|
|
3081
|
+
const newUrl = await (0, import_prompts8.input)({
|
|
3082
|
+
message: "Remote server URL:",
|
|
3083
|
+
default: workingConfig.url,
|
|
3084
|
+
validate: (val) => {
|
|
3085
|
+
const trimmed = val.trim();
|
|
3086
|
+
if (!trimmed) return "URL cannot be empty";
|
|
3087
|
+
if (!/^https?:\/\//i.test(trimmed)) {
|
|
3088
|
+
return "Please enter a valid URL starting with http:// or https://";
|
|
3089
|
+
}
|
|
3090
|
+
return true;
|
|
3091
|
+
}
|
|
3092
|
+
});
|
|
3093
|
+
workingConfig.url = newUrl.trim();
|
|
3094
|
+
} else if (editAction === "transport") {
|
|
3095
|
+
workingConfig.type = await (0, import_prompts8.select)({
|
|
3096
|
+
message: "Select remote transport protocol:",
|
|
3097
|
+
choices: [
|
|
3098
|
+
{ name: "HTTP", value: "http" },
|
|
3099
|
+
{ name: "SSE (Server-Sent Events)", value: "sse" }
|
|
3100
|
+
],
|
|
3101
|
+
default: workingConfig.type === "sse" ? "sse" : "http"
|
|
3102
|
+
});
|
|
3103
|
+
} else if (editAction === "save") {
|
|
3104
|
+
let targetAgents = targetGroup.agents;
|
|
3105
|
+
if (targetGroup.agents.length > 1) {
|
|
3106
|
+
const sortedAgents = sortAgentsWithClusters(targetGroup.agents, { global: isGlobal, cwd });
|
|
3107
|
+
const choices = buildLinkedAgentChoices({
|
|
3108
|
+
agents: sortedAgents,
|
|
3109
|
+
checkedAgents: sortedAgents,
|
|
3110
|
+
scopeOptions: { global: isGlobal, cwd }
|
|
3111
|
+
});
|
|
3112
|
+
targetAgents = await linkedCheckbox({
|
|
3113
|
+
message: "Select agents to update configuration (Space to toggle):",
|
|
3114
|
+
choices,
|
|
3115
|
+
loop: false,
|
|
3116
|
+
validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
|
|
3117
|
+
});
|
|
3118
|
+
if (targetAgents.length < targetGroup.agents.length) {
|
|
3119
|
+
const unselected = targetGroup.agents.filter((a) => !targetAgents.includes(a));
|
|
3120
|
+
const unselectedNames = unselected.map((a) => getMcpAgentConfig(a).displayName).join(", ");
|
|
3121
|
+
logger.info(
|
|
3122
|
+
`Note: Updating only a subset of agents. Server configurations will diverge from: ${unselectedNames}.`
|
|
3123
|
+
);
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
const requestedTransport = workingConfig.url ? workingConfig.type ?? "http" : "stdio";
|
|
3127
|
+
const resolution = resolveTargetAgents({
|
|
3128
|
+
requested: targetAgents,
|
|
3129
|
+
global: isGlobal,
|
|
3130
|
+
cwd,
|
|
3131
|
+
transport: requestedTransport
|
|
3132
|
+
});
|
|
3133
|
+
if (resolution.incompatible.length > 0) {
|
|
3134
|
+
for (const item of resolution.incompatible) {
|
|
3135
|
+
logger.warn(`Skipping ${import_picocolors13.default.cyan(item.agent)}: ${item.reason}`);
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
if (resolution.compatibleAgents.length === 0) {
|
|
3139
|
+
logger.error(
|
|
3140
|
+
`None of the selected agents support ${requestedTransport} transport. Cannot update.`
|
|
3141
|
+
);
|
|
3142
|
+
continue;
|
|
3143
|
+
}
|
|
3144
|
+
const agentNames = resolution.compatibleAgents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
|
|
3145
|
+
const confirmed = await (0, import_prompts8.confirm)({
|
|
3146
|
+
message: `Confirm updating configuration for [${serverName}] across: ${agentNames}?`,
|
|
3147
|
+
default: true
|
|
3148
|
+
});
|
|
3149
|
+
if (!confirmed) {
|
|
3150
|
+
logger.warn("Update cancelled");
|
|
3151
|
+
continue;
|
|
3152
|
+
}
|
|
3153
|
+
const updateResult = updateMcpServer({
|
|
3154
|
+
serverName,
|
|
3155
|
+
config: workingConfig,
|
|
3156
|
+
previousConfig: targetGroup.config,
|
|
3157
|
+
agents: resolution.compatibleAgents,
|
|
3158
|
+
global: isGlobal,
|
|
3159
|
+
cwd
|
|
3160
|
+
});
|
|
3161
|
+
let updatedAny = false;
|
|
3162
|
+
const succeededAgents = [];
|
|
3163
|
+
for (const res of updateResult.results) {
|
|
3164
|
+
if (res.success) {
|
|
3165
|
+
updatedAny = true;
|
|
3166
|
+
succeededAgents.push(res.agent);
|
|
3167
|
+
logger.success(
|
|
3168
|
+
`${import_picocolors13.default.cyan(res.agent)}: Successfully updated configuration in ${import_picocolors13.default.dim(res.path)}${formatCoHostedBadge("configured", res.coConfiguredAgents)}`
|
|
3169
|
+
);
|
|
3170
|
+
} else {
|
|
3171
|
+
logger.error(`${import_picocolors13.default.cyan(res.agent)}: Update failed - ${res.error}`);
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
3174
|
+
if (updatedAny) {
|
|
3175
|
+
targetGroup.config = updateResult.config;
|
|
3176
|
+
logger.success(`Configuration for [${serverName}] updated successfully!`);
|
|
3177
|
+
return;
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
}
|
|
3181
|
+
};
|
|
2154
3182
|
var wizardManage = async (options = {}) => {
|
|
2155
3183
|
const cwd = options.cwd ?? process.cwd();
|
|
2156
3184
|
const isGlobal = await promptScope({
|
|
@@ -2164,51 +3192,57 @@ var wizardManage = async (options = {}) => {
|
|
|
2164
3192
|
return;
|
|
2165
3193
|
}
|
|
2166
3194
|
const grouped = groupInstalledServersByName(installed);
|
|
3195
|
+
let pendingServerName = options.serverName;
|
|
3196
|
+
const refreshGroupedServers = () => {
|
|
3197
|
+
const freshInstalled = listInstalledMcpServers({ global: isGlobal, cwd });
|
|
3198
|
+
const freshGrouped = groupInstalledServersByName(freshInstalled);
|
|
3199
|
+
grouped.clear();
|
|
3200
|
+
for (const [name, grp] of freshGrouped) {
|
|
3201
|
+
grouped.set(name, grp);
|
|
3202
|
+
}
|
|
3203
|
+
};
|
|
2167
3204
|
while (true) {
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
choices
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
3205
|
+
let chosenServerName;
|
|
3206
|
+
if (pendingServerName && grouped.has(pendingServerName)) {
|
|
3207
|
+
chosenServerName = pendingServerName;
|
|
3208
|
+
pendingServerName = void 0;
|
|
3209
|
+
} else {
|
|
3210
|
+
pendingServerName = void 0;
|
|
3211
|
+
const choices = Array.from(grouped.values()).map((g) => {
|
|
3212
|
+
const agentNames = g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
|
|
3213
|
+
return {
|
|
3214
|
+
name: `${import_picocolors13.default.bold(g.serverName)} ${import_picocolors13.default.dim(`(configured in: ${agentNames})`)}`,
|
|
3215
|
+
value: g.serverName
|
|
3216
|
+
};
|
|
3217
|
+
});
|
|
3218
|
+
choices.push({
|
|
3219
|
+
name: `Back`,
|
|
3220
|
+
value: "__back__"
|
|
3221
|
+
});
|
|
3222
|
+
chosenServerName = await (0, import_prompts8.select)({
|
|
3223
|
+
message: "Select MCP server to manage or sync:",
|
|
3224
|
+
choices
|
|
3225
|
+
});
|
|
3226
|
+
if (chosenServerName === "__back__") {
|
|
3227
|
+
return;
|
|
3228
|
+
}
|
|
2185
3229
|
}
|
|
2186
3230
|
const targetGroup = grouped.get(chosenServerName);
|
|
2187
3231
|
if (!targetGroup) continue;
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
console.log(` ${import_picocolors8.default.bold("URL:")} ${import_picocolors8.default.dim(cfg.url)} (${cfg.type})`);
|
|
2196
|
-
if (cfg.headers && Object.keys(cfg.headers).length > 0) {
|
|
2197
|
-
console.log(` ${import_picocolors8.default.bold("Headers:")} ${Object.keys(cfg.headers).join(", ")}`);
|
|
2198
|
-
}
|
|
2199
|
-
} else if (isStdioServerConfig(cfg)) {
|
|
2200
|
-
console.log(` ${import_picocolors8.default.bold("Command:")} ${import_picocolors8.default.magenta(cfg.command)}`);
|
|
2201
|
-
if (cfg.args && cfg.args.length > 0) {
|
|
2202
|
-
console.log(` ${import_picocolors8.default.bold("Arguments:")} ${import_picocolors8.default.dim(cfg.args.join(" "))}`);
|
|
2203
|
-
}
|
|
2204
|
-
if (cfg.env && Object.keys(cfg.env).length > 0) {
|
|
2205
|
-
console.log(` ${import_picocolors8.default.bold("Environment Variables:")} ${import_picocolors8.default.dim(Object.keys(cfg.env).join(", "))}`);
|
|
2206
|
-
}
|
|
2207
|
-
}
|
|
2208
|
-
console.log();
|
|
3232
|
+
displayServerDetails({
|
|
3233
|
+
serverName: chosenServerName,
|
|
3234
|
+
config: targetGroup.config,
|
|
3235
|
+
agents: targetGroup.agents,
|
|
3236
|
+
global: isGlobal,
|
|
3237
|
+
hasDivergence: targetGroup.hasDivergence
|
|
3238
|
+
});
|
|
2209
3239
|
const action = await (0, import_prompts8.select)({
|
|
2210
3240
|
message: `What would you like to do with [${chosenServerName}]?`,
|
|
2211
3241
|
choices: [
|
|
3242
|
+
{
|
|
3243
|
+
name: "Edit server configuration",
|
|
3244
|
+
value: "edit"
|
|
3245
|
+
},
|
|
2212
3246
|
{
|
|
2213
3247
|
name: "Sync / clone to other agents",
|
|
2214
3248
|
value: "sync"
|
|
@@ -2220,20 +3254,34 @@ var wizardManage = async (options = {}) => {
|
|
|
2220
3254
|
]
|
|
2221
3255
|
});
|
|
2222
3256
|
if (action === "back") continue;
|
|
3257
|
+
if (action === "edit") {
|
|
3258
|
+
await handleEditServerConfig({
|
|
3259
|
+
targetGroup,
|
|
3260
|
+
global: isGlobal,
|
|
3261
|
+
cwd
|
|
3262
|
+
});
|
|
3263
|
+
refreshGroupedServers();
|
|
3264
|
+
continue;
|
|
3265
|
+
}
|
|
2223
3266
|
if (action === "sync") {
|
|
2224
3267
|
const allAllowedAgents = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
|
|
2225
|
-
const
|
|
2226
|
-
if (
|
|
2227
|
-
logger.info(
|
|
3268
|
+
const rawCandidateAgents = allAllowedAgents.filter((a) => !targetGroup.agents.includes(a));
|
|
3269
|
+
if (rawCandidateAgents.length === 0) {
|
|
3270
|
+
logger.info(
|
|
3271
|
+
"All supported agents in this scope already have this MCP server configured; no sync needed"
|
|
3272
|
+
);
|
|
2228
3273
|
continue;
|
|
2229
3274
|
}
|
|
2230
|
-
const
|
|
3275
|
+
const candidateAgents = sortAgentsWithClusters(rawCandidateAgents, { global: isGlobal, cwd });
|
|
3276
|
+
const choices = buildLinkedAgentChoices({
|
|
3277
|
+
agents: candidateAgents,
|
|
3278
|
+
checkedAgents: [],
|
|
3279
|
+
scopeOptions: { global: isGlobal, cwd }
|
|
3280
|
+
});
|
|
3281
|
+
const selectedToSync = await linkedCheckbox({
|
|
2231
3282
|
message: "Select target agents to sync to (Space to select):",
|
|
2232
|
-
choices
|
|
2233
|
-
|
|
2234
|
-
value: a,
|
|
2235
|
-
checked: false
|
|
2236
|
-
})),
|
|
3283
|
+
choices,
|
|
3284
|
+
loop: false,
|
|
2237
3285
|
validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
|
|
2238
3286
|
});
|
|
2239
3287
|
const confirmed = await (0, import_prompts8.confirm)({
|
|
@@ -2244,25 +3292,37 @@ var wizardManage = async (options = {}) => {
|
|
|
2244
3292
|
logger.warn("Sync cancelled");
|
|
2245
3293
|
continue;
|
|
2246
3294
|
}
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
3295
|
+
const syncResult = updateMcpServer({
|
|
3296
|
+
serverName: chosenServerName,
|
|
3297
|
+
config: targetGroup.config,
|
|
3298
|
+
agents: selectedToSync,
|
|
3299
|
+
global: isGlobal,
|
|
3300
|
+
cwd
|
|
3301
|
+
});
|
|
3302
|
+
for (const item of syncResult.incompatible) {
|
|
3303
|
+
logger.warn(`Skipping ${import_picocolors13.default.cyan(item.agent)}: ${item.reason}`);
|
|
3304
|
+
}
|
|
3305
|
+
for (const res of syncResult.results) {
|
|
3306
|
+
if (syncResult.incompatible.some((i) => i.agent === res.agent)) {
|
|
3307
|
+
continue;
|
|
3308
|
+
}
|
|
2252
3309
|
if (res.success) {
|
|
2253
|
-
logger.success(
|
|
2254
|
-
|
|
3310
|
+
logger.success(
|
|
3311
|
+
`${import_picocolors13.default.cyan(res.agent)}: Successfully synced to ${import_picocolors13.default.dim(res.path)}${formatCoHostedBadge("configured", res.coConfiguredAgents)}`
|
|
3312
|
+
);
|
|
3313
|
+
targetGroup.agents.push(res.agent);
|
|
2255
3314
|
} else {
|
|
2256
|
-
logger.error(`${
|
|
3315
|
+
logger.error(`${import_picocolors13.default.cyan(res.agent)}: Sync failed - ${res.error}`);
|
|
2257
3316
|
}
|
|
2258
3317
|
}
|
|
3318
|
+
refreshGroupedServers();
|
|
2259
3319
|
}
|
|
2260
3320
|
}
|
|
2261
3321
|
};
|
|
2262
3322
|
|
|
2263
3323
|
// src/interactive/wizard-remove.ts
|
|
2264
3324
|
var import_prompts9 = require("@inquirer/prompts");
|
|
2265
|
-
var
|
|
3325
|
+
var import_picocolors14 = __toESM(require("picocolors"), 1);
|
|
2266
3326
|
var wizardRemove = async (options = {}) => {
|
|
2267
3327
|
const cwd = options.cwd ?? process.cwd();
|
|
2268
3328
|
const isGlobal = await promptScope({
|
|
@@ -2279,7 +3339,7 @@ var wizardRemove = async (options = {}) => {
|
|
|
2279
3339
|
let serverName = options.name;
|
|
2280
3340
|
if (!serverName) {
|
|
2281
3341
|
const choices = Array.from(serverMap.values()).map((g) => ({
|
|
2282
|
-
name: `${
|
|
3342
|
+
name: `${import_picocolors14.default.bold(g.serverName)} ${import_picocolors14.default.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
|
|
2283
3343
|
value: g.serverName
|
|
2284
3344
|
}));
|
|
2285
3345
|
serverName = await (0, import_prompts9.select)({
|
|
@@ -2287,20 +3347,22 @@ var wizardRemove = async (options = {}) => {
|
|
|
2287
3347
|
choices
|
|
2288
3348
|
});
|
|
2289
3349
|
}
|
|
2290
|
-
const
|
|
2291
|
-
if (
|
|
3350
|
+
const rawInstalledAgents = serverMap.get(serverName)?.agents || [];
|
|
3351
|
+
if (rawInstalledAgents.length === 0) {
|
|
2292
3352
|
logger.warn(`No agents found with [${serverName}] installed`);
|
|
2293
3353
|
return false;
|
|
2294
3354
|
}
|
|
3355
|
+
const installedAgents = sortAgentsWithClusters(rawInstalledAgents, { global: isGlobal, cwd });
|
|
2295
3356
|
let targetAgents = options.agents;
|
|
2296
3357
|
if (!targetAgents || targetAgents.length === 0) {
|
|
2297
|
-
|
|
3358
|
+
const choices = buildLinkedAgentChoices({
|
|
3359
|
+
agents: installedAgents,
|
|
3360
|
+
checkedAgents: installedAgents,
|
|
3361
|
+
scopeOptions: { global: isGlobal, cwd }
|
|
3362
|
+
});
|
|
3363
|
+
targetAgents = await linkedCheckbox({
|
|
2298
3364
|
message: `Select agents to remove [${serverName}] from:`,
|
|
2299
|
-
choices
|
|
2300
|
-
name: `${getMcpAgentConfig(agent)?.displayName ?? agent} (${agent})`,
|
|
2301
|
-
value: agent,
|
|
2302
|
-
checked: true
|
|
2303
|
-
})),
|
|
3365
|
+
choices,
|
|
2304
3366
|
validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
|
|
2305
3367
|
});
|
|
2306
3368
|
} else {
|
|
@@ -2328,10 +3390,12 @@ var wizardRemove = async (options = {}) => {
|
|
|
2328
3390
|
let removedCount = 0;
|
|
2329
3391
|
for (const res of results) {
|
|
2330
3392
|
if (res.removed) {
|
|
2331
|
-
logger.success(
|
|
3393
|
+
logger.success(
|
|
3394
|
+
`${import_picocolors14.default.cyan(res.agent)}: Successfully removed from ${import_picocolors14.default.dim(res.path)}${formatCoHostedBadge("affected", res.coAffectedAgents)}`
|
|
3395
|
+
);
|
|
2332
3396
|
removedCount++;
|
|
2333
3397
|
} else if (res.error) {
|
|
2334
|
-
logger.error(`${
|
|
3398
|
+
logger.error(`${import_picocolors14.default.cyan(res.agent)}: Failed to remove - ${res.error}`);
|
|
2335
3399
|
}
|
|
2336
3400
|
}
|
|
2337
3401
|
if (removedCount > 0) {
|
|
@@ -2345,8 +3409,8 @@ var wizardRemove = async (options = {}) => {
|
|
|
2345
3409
|
// src/interactive/main-menu.ts
|
|
2346
3410
|
var mainMenu = async () => {
|
|
2347
3411
|
console.log();
|
|
2348
|
-
console.log(
|
|
2349
|
-
console.log(
|
|
3412
|
+
console.log(import_picocolors15.default.bold(import_picocolors15.default.cyan("mcps - Cross-Platform MCP Manager for AI Coding Agents")));
|
|
3413
|
+
console.log(import_picocolors15.default.dim("Cross-platform MCP server configuration & synchronization tool"));
|
|
2350
3414
|
console.log();
|
|
2351
3415
|
while (true) {
|
|
2352
3416
|
try {
|
|
@@ -2372,7 +3436,7 @@ var mainMenu = async () => {
|
|
|
2372
3436
|
]
|
|
2373
3437
|
});
|
|
2374
3438
|
if (action === "exit") {
|
|
2375
|
-
console.log(
|
|
3439
|
+
console.log(import_picocolors15.default.dim("Goodbye!"));
|
|
2376
3440
|
break;
|
|
2377
3441
|
}
|
|
2378
3442
|
if (action === "add") {
|
|
@@ -2385,26 +3449,241 @@ var mainMenu = async () => {
|
|
|
2385
3449
|
console.log();
|
|
2386
3450
|
} catch (error) {
|
|
2387
3451
|
if (error?.name === "ExitPromptError") {
|
|
2388
|
-
console.log("\n" +
|
|
3452
|
+
console.log("\n" + import_picocolors15.default.dim("Exited."));
|
|
2389
3453
|
break;
|
|
2390
3454
|
}
|
|
2391
3455
|
throw error;
|
|
2392
3456
|
}
|
|
2393
3457
|
}
|
|
2394
3458
|
};
|
|
3459
|
+
|
|
3460
|
+
// src/utils/resolve-transport.ts
|
|
3461
|
+
var resolveTransport = (input7) => {
|
|
3462
|
+
if (!input7) return void 0;
|
|
3463
|
+
if (input7 === "http" || input7 === "sse") return input7;
|
|
3464
|
+
throw new Error(`Unsupported transport "${input7}" (expected: http, sse)`);
|
|
3465
|
+
};
|
|
3466
|
+
|
|
3467
|
+
// src/cli/manage.ts
|
|
3468
|
+
var import_commander = require("commander");
|
|
3469
|
+
var import_picocolors16 = __toESM(require("picocolors"), 1);
|
|
3470
|
+
|
|
3471
|
+
// src/utils/parse-key-value-list.ts
|
|
3472
|
+
var parseKeyValueList = (entries, separator) => {
|
|
3473
|
+
if (!entries || entries.length === 0) return {};
|
|
3474
|
+
const result = {};
|
|
3475
|
+
for (const entry of entries) {
|
|
3476
|
+
const splitIndex = entry.indexOf(separator);
|
|
3477
|
+
if (splitIndex === -1) {
|
|
3478
|
+
throw new Error(`Invalid entry "${entry}": expected "${separator}" separator`);
|
|
3479
|
+
}
|
|
3480
|
+
const key = entry.slice(0, splitIndex).trim();
|
|
3481
|
+
const value = entry.slice(splitIndex + separator.length).trim();
|
|
3482
|
+
if (!key) throw new Error(`Invalid entry "${entry}": empty key`);
|
|
3483
|
+
result[key] = value;
|
|
3484
|
+
}
|
|
3485
|
+
return result;
|
|
3486
|
+
};
|
|
3487
|
+
|
|
3488
|
+
// src/cli/manage.ts
|
|
3489
|
+
var requireTargetServerGroup = (serverName, scope) => {
|
|
3490
|
+
const installed = listInstalledMcpServers(scope);
|
|
3491
|
+
const grouped = groupInstalledServersByName(installed);
|
|
3492
|
+
const targetGroup = grouped.get(serverName);
|
|
3493
|
+
if (!targetGroup) {
|
|
3494
|
+
logger.error(
|
|
3495
|
+
`MCP server "${serverName}" is not configured in ${scope.global ? "global" : "project"} scope.`
|
|
3496
|
+
);
|
|
3497
|
+
process.exitCode = 1;
|
|
3498
|
+
return void 0;
|
|
3499
|
+
}
|
|
3500
|
+
return targetGroup;
|
|
3501
|
+
};
|
|
3502
|
+
var mcpManageCommand = new import_commander.Command("manage").description("Inspect, modify, and sync installed MCP servers across coding agents").argument("[server-name]", "Optional server name to inspect or manage").option("-a, --agent <agents...>", "Target specific agents for update").option("-g, --global", "Manage global scope servers instead of project").option("-t, --transport <type>", "Transport type for remote servers (http or sse)").option("--header <header...>", "HTTP header (Header: Value), repeatable").option("--clear-headers", "Clear all HTTP headers for remote servers").option("--env <env...>", "Env var for stdio servers (KEY=VALUE), repeatable").option("--clear-env", "Clear all environment variables for stdio servers").option("--args <args...>", "CLI arguments for stdio/package servers").option("--clear-args", "Clear all arguments for stdio/package servers").option("--command <command>", "Executable command for stdio servers").option("--url <url>", "Remote endpoint URL").option("-y, --yes", "Skip interactive prompts").action(async (serverName, options) => {
|
|
3503
|
+
try {
|
|
3504
|
+
const cwd = process.cwd();
|
|
3505
|
+
const isGlobal = Boolean(options.global);
|
|
3506
|
+
const hasModifications = options.command !== void 0 || options.args !== void 0 || Boolean(options.clearArgs) || options.env !== void 0 || Boolean(options.clearEnv) || options.header !== void 0 || Boolean(options.clearHeaders) || options.url !== void 0 || options.transport !== void 0;
|
|
3507
|
+
const isInteractive = Boolean(process.stdin.isTTY && !options.yes);
|
|
3508
|
+
if (hasModifications) {
|
|
3509
|
+
if (options.url !== void 0 && options.command !== void 0) {
|
|
3510
|
+
logger.error('Cannot specify both "--url" (remote) and "--command" (stdio) simultaneously.');
|
|
3511
|
+
process.exitCode = 1;
|
|
3512
|
+
return;
|
|
3513
|
+
}
|
|
3514
|
+
if (!serverName) {
|
|
3515
|
+
logger.error('Missing required argument: "server-name" when passing modification flags.');
|
|
3516
|
+
process.exitCode = 1;
|
|
3517
|
+
return;
|
|
3518
|
+
}
|
|
3519
|
+
const targetGroup = requireTargetServerGroup(serverName, { global: isGlobal, cwd });
|
|
3520
|
+
if (!targetGroup) {
|
|
3521
|
+
return;
|
|
3522
|
+
}
|
|
3523
|
+
const isCurrentRemote = Boolean(targetGroup.config.url && targetGroup.config.url.length > 0);
|
|
3524
|
+
const willBeRemote = options.url !== void 0 ? true : options.command !== void 0 ? false : isCurrentRemote;
|
|
3525
|
+
if (willBeRemote) {
|
|
3526
|
+
const ignoredStdioFlags = [];
|
|
3527
|
+
if (options.env !== void 0) ignoredStdioFlags.push("--env");
|
|
3528
|
+
if (options.clearEnv) ignoredStdioFlags.push("--clear-env");
|
|
3529
|
+
if (options.args !== void 0) ignoredStdioFlags.push("--args");
|
|
3530
|
+
if (options.clearArgs) ignoredStdioFlags.push("--clear-args");
|
|
3531
|
+
if (ignoredStdioFlags.length > 0) {
|
|
3532
|
+
const hint = options.url !== void 0 ? "When configuring a remote server, stdio flags are ignored." : "Use --command to switch to stdio mode.";
|
|
3533
|
+
logger.warn(
|
|
3534
|
+
`Server "${serverName}" is a remote server. The following stdio flags will be ignored: ${ignoredStdioFlags.join(", ")}. ${hint}`
|
|
3535
|
+
);
|
|
3536
|
+
}
|
|
3537
|
+
} else {
|
|
3538
|
+
const ignoredRemoteFlags = [];
|
|
3539
|
+
if (options.header !== void 0) ignoredRemoteFlags.push("--header");
|
|
3540
|
+
if (options.clearHeaders) ignoredRemoteFlags.push("--clear-headers");
|
|
3541
|
+
if (options.transport !== void 0) ignoredRemoteFlags.push("--transport");
|
|
3542
|
+
if (ignoredRemoteFlags.length > 0) {
|
|
3543
|
+
const hint = options.command !== void 0 ? "When configuring a stdio server, remote flags are ignored." : "Use --url to switch to remote mode.";
|
|
3544
|
+
logger.warn(
|
|
3545
|
+
`Server "${serverName}" is a stdio server. The following remote flags will be ignored: ${ignoredRemoteFlags.join(", ")}. ${hint}`
|
|
3546
|
+
);
|
|
3547
|
+
}
|
|
3548
|
+
}
|
|
3549
|
+
const incomingDelta = {};
|
|
3550
|
+
if (options.command !== void 0) {
|
|
3551
|
+
incomingDelta.command = options.command;
|
|
3552
|
+
}
|
|
3553
|
+
if (options.clearArgs) {
|
|
3554
|
+
incomingDelta.args = void 0;
|
|
3555
|
+
}
|
|
3556
|
+
if (options.args !== void 0) {
|
|
3557
|
+
incomingDelta.args = options.args;
|
|
3558
|
+
}
|
|
3559
|
+
if (options.url !== void 0) {
|
|
3560
|
+
incomingDelta.url = options.url;
|
|
3561
|
+
}
|
|
3562
|
+
if (options.transport !== void 0) {
|
|
3563
|
+
incomingDelta.type = resolveTransport(options.transport);
|
|
3564
|
+
}
|
|
3565
|
+
if (options.clearEnv) {
|
|
3566
|
+
incomingDelta.env = void 0;
|
|
3567
|
+
}
|
|
3568
|
+
if (options.env !== void 0) {
|
|
3569
|
+
const parsedEnv = parseKeyValueList(options.env, "=");
|
|
3570
|
+
const baseEnv = options.clearEnv ? {} : targetGroup.config.env ?? {};
|
|
3571
|
+
incomingDelta.env = { ...baseEnv, ...parsedEnv };
|
|
3572
|
+
}
|
|
3573
|
+
if (options.clearHeaders) {
|
|
3574
|
+
incomingDelta.headers = void 0;
|
|
3575
|
+
}
|
|
3576
|
+
if (options.header !== void 0) {
|
|
3577
|
+
const parsedHeaders = parseKeyValueList(options.header, ":");
|
|
3578
|
+
const baseHeaders = options.clearHeaders ? {} : targetGroup.config.headers ?? {};
|
|
3579
|
+
incomingDelta.headers = { ...baseHeaders, ...parsedHeaders };
|
|
3580
|
+
}
|
|
3581
|
+
let targetAgents = targetGroup.agents;
|
|
3582
|
+
if (options.agent !== void 0) {
|
|
3583
|
+
const parsed = parseMcpAgentList(options.agent);
|
|
3584
|
+
if (!parsed || parsed.length === 0) {
|
|
3585
|
+
logger.error(`No valid agents recognized from: "${options.agent.join(", ")}".`);
|
|
3586
|
+
process.exitCode = 1;
|
|
3587
|
+
return;
|
|
3588
|
+
}
|
|
3589
|
+
targetAgents = parsed;
|
|
3590
|
+
}
|
|
3591
|
+
const updateResult = updateMcpServer({
|
|
3592
|
+
serverName,
|
|
3593
|
+
config: incomingDelta,
|
|
3594
|
+
previousConfig: targetGroup.config,
|
|
3595
|
+
agents: targetAgents,
|
|
3596
|
+
global: isGlobal,
|
|
3597
|
+
cwd
|
|
3598
|
+
});
|
|
3599
|
+
for (const item of updateResult.incompatible) {
|
|
3600
|
+
logger.warn(`Skipping ${import_picocolors16.default.cyan(item.agent)}: ${item.reason}`);
|
|
3601
|
+
}
|
|
3602
|
+
const attemptedResults = updateResult.results.filter(
|
|
3603
|
+
(r) => !updateResult.incompatible.some((i) => i.agent === r.agent)
|
|
3604
|
+
);
|
|
3605
|
+
if (attemptedResults.length === 0) {
|
|
3606
|
+
const requestedTransport = updateResult.config.url ? updateResult.config.type ?? "http" : "stdio";
|
|
3607
|
+
logger.error(
|
|
3608
|
+
`None of the target agents support ${requestedTransport} transport. Update aborted.`
|
|
3609
|
+
);
|
|
3610
|
+
process.exitCode = 1;
|
|
3611
|
+
return;
|
|
3612
|
+
}
|
|
3613
|
+
logger.info(
|
|
3614
|
+
`Updating ${import_picocolors16.default.bold(serverName)} across ${import_picocolors16.default.cyan(String(attemptedResults.length))} agent(s)...`
|
|
3615
|
+
);
|
|
3616
|
+
let allSuccess = true;
|
|
3617
|
+
for (const res of attemptedResults) {
|
|
3618
|
+
if (res.success) {
|
|
3619
|
+
logger.success(`${import_picocolors16.default.cyan(res.agent)}: Successfully updated in ${import_picocolors16.default.dim(res.path)}`);
|
|
3620
|
+
logCoHostedNotice("configured", res.coConfiguredAgents);
|
|
3621
|
+
} else {
|
|
3622
|
+
allSuccess = false;
|
|
3623
|
+
logger.error(`${import_picocolors16.default.cyan(res.agent)}: Update failed - ${res.error}`);
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
if (!allSuccess) {
|
|
3627
|
+
process.exitCode = 1;
|
|
3628
|
+
}
|
|
3629
|
+
return;
|
|
3630
|
+
}
|
|
3631
|
+
if (!isInteractive) {
|
|
3632
|
+
if (!serverName) {
|
|
3633
|
+
logger.error(
|
|
3634
|
+
'Missing required argument: "server-name" for non-interactive manage command. Specify a server name or use interactive terminal.'
|
|
3635
|
+
);
|
|
3636
|
+
process.exitCode = 1;
|
|
3637
|
+
return;
|
|
3638
|
+
}
|
|
3639
|
+
const targetGroup = requireTargetServerGroup(serverName, { global: isGlobal, cwd });
|
|
3640
|
+
if (!targetGroup) {
|
|
3641
|
+
return;
|
|
3642
|
+
}
|
|
3643
|
+
displayServerDetails({
|
|
3644
|
+
serverName,
|
|
3645
|
+
config: targetGroup.config,
|
|
3646
|
+
agents: targetGroup.agents,
|
|
3647
|
+
global: isGlobal,
|
|
3648
|
+
hasDivergence: targetGroup.hasDivergence
|
|
3649
|
+
});
|
|
3650
|
+
return;
|
|
3651
|
+
}
|
|
3652
|
+
await wizardManage({
|
|
3653
|
+
global: options.global,
|
|
3654
|
+
serverName
|
|
3655
|
+
});
|
|
3656
|
+
} catch (error) {
|
|
3657
|
+
if (error && typeof error === "object" && "name" in error && error.name === "ExitPromptError") {
|
|
3658
|
+
process.exit(0);
|
|
3659
|
+
}
|
|
3660
|
+
logger.error(toErrorMessage(error));
|
|
3661
|
+
process.exitCode = 1;
|
|
3662
|
+
}
|
|
3663
|
+
});
|
|
2395
3664
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2396
3665
|
0 && (module.exports = {
|
|
2397
3666
|
AgentConfigStore,
|
|
2398
3667
|
DEFAULT_REMOTE_TRANSPORT,
|
|
2399
3668
|
NPX_COMMAND,
|
|
2400
3669
|
NPX_DASH_Y,
|
|
3670
|
+
SECRET_HEADER_PATTERN,
|
|
3671
|
+
SECRET_KEY_PATTERN,
|
|
2401
3672
|
add,
|
|
2402
3673
|
agentConfigStore,
|
|
3674
|
+
buildLinkedAgentChoices,
|
|
2403
3675
|
buildMcpServerConfig,
|
|
2404
3676
|
createAgentTransform,
|
|
2405
3677
|
detectGloballyInstalledMcpAgents,
|
|
2406
3678
|
detectProjectInstalledMcpAgents,
|
|
3679
|
+
detectUpdateTransition,
|
|
3680
|
+
displayServerDetails,
|
|
2407
3681
|
extractPackageName,
|
|
3682
|
+
formatArgsString,
|
|
3683
|
+
formatEnvText,
|
|
3684
|
+
formatHeadersText,
|
|
3685
|
+
getCandidateAgentsForScope,
|
|
3686
|
+
getCoHostedAgents,
|
|
2408
3687
|
getMcpAgentConfig,
|
|
2409
3688
|
getMcpAgentTypes,
|
|
2410
3689
|
getMcpAgentsSupportingProjectScope,
|
|
@@ -2413,17 +3692,22 @@ var mainMenu = async () => {
|
|
|
2413
3692
|
installMcpServer,
|
|
2414
3693
|
installMcpServerForAgent,
|
|
2415
3694
|
installMcpServerForAgents,
|
|
3695
|
+
installToCompatibleAgents,
|
|
2416
3696
|
isMcpAgentType,
|
|
2417
3697
|
isMcpTransportSupported,
|
|
2418
3698
|
isRemoteMcpSource,
|
|
2419
3699
|
isRemoteServerConfig,
|
|
2420
3700
|
isStdioServerConfig,
|
|
3701
|
+
linkedCheckbox,
|
|
2421
3702
|
list,
|
|
2422
3703
|
listInstalledMcpServers,
|
|
2423
3704
|
listServersInConfigFile,
|
|
2424
3705
|
mainMenu,
|
|
3706
|
+
maskSecretHeader,
|
|
3707
|
+
maskSecretValue,
|
|
2425
3708
|
mcpAgentAliases,
|
|
2426
3709
|
mcpAgents,
|
|
3710
|
+
mcpManageCommand,
|
|
2427
3711
|
normalizeServerConfig,
|
|
2428
3712
|
parseArgsString,
|
|
2429
3713
|
parseEnvText,
|
|
@@ -2432,20 +3716,33 @@ var mainMenu = async () => {
|
|
|
2432
3716
|
parseServerConfig,
|
|
2433
3717
|
parseSource,
|
|
2434
3718
|
promptArgsConfig,
|
|
3719
|
+
promptEditArgs,
|
|
3720
|
+
promptEditEnvConfig,
|
|
3721
|
+
promptEditHeadersConfig,
|
|
3722
|
+
promptEditKeyValueConfig,
|
|
2435
3723
|
promptEnvConfig,
|
|
2436
3724
|
promptHeadersConfig,
|
|
2437
3725
|
promptScope,
|
|
2438
3726
|
promptScopeAndAgents,
|
|
3727
|
+
promptSwitchServerType,
|
|
2439
3728
|
readConfigFile,
|
|
2440
3729
|
remove,
|
|
2441
3730
|
removeMcpServer,
|
|
2442
3731
|
removeMcpServerFromAgent,
|
|
2443
3732
|
removeServerFromConfigFile,
|
|
3733
|
+
resolveConfigClusters,
|
|
2444
3734
|
resolveMcpAgentAlias,
|
|
2445
3735
|
resolveMcpConfigTarget,
|
|
2446
3736
|
resolveTargetAgents,
|
|
3737
|
+
resolveTransport,
|
|
3738
|
+
sanitizeUpdatedServerConfig,
|
|
3739
|
+
sortAgentsWithClusters,
|
|
3740
|
+
toRemoteServerConfig,
|
|
3741
|
+
toStdioServerConfig,
|
|
2447
3742
|
transformServerConfig,
|
|
2448
3743
|
transformServerConfigForAgent,
|
|
3744
|
+
update,
|
|
3745
|
+
updateMcpServer,
|
|
2449
3746
|
wizardAdd,
|
|
2450
3747
|
wizardManage,
|
|
2451
3748
|
wizardRemove,
|