@wuyax/mcps 0.1.0-beta.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +22 -14
- package/dist/chunk-AWD3VQ3S.js +1624 -0
- package/dist/chunk-O3BRJFEC.js +1898 -0
- package/dist/cli.cjs +1057 -979
- package/dist/cli.js +188 -17
- package/dist/index.cjs +702 -2478
- package/dist/index.d.cts +152 -452
- package/dist/index.d.ts +152 -452
- package/dist/index.js +9 -85
- package/dist/{chunk-BUKA3NPJ.js → interactive.cjs} +1555 -1779
- package/dist/interactive.d.cts +228 -0
- package/dist/interactive.d.ts +228 -0
- package/dist/interactive.js +53 -0
- package/dist/types-lEP3zGvf.d.cts +128 -0
- package/dist/types-lEP3zGvf.d.ts +128 -0
- package/package.json +31 -1
package/dist/index.cjs
CHANGED
|
@@ -32,30 +32,21 @@ var src_exports = {};
|
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
AgentConfigStore: () => AgentConfigStore,
|
|
34
34
|
DEFAULT_REMOTE_TRANSPORT: () => DEFAULT_REMOTE_TRANSPORT,
|
|
35
|
-
NPX_COMMAND: () => NPX_COMMAND,
|
|
36
|
-
NPX_DASH_Y: () => NPX_DASH_Y,
|
|
37
35
|
SECRET_HEADER_PATTERN: () => SECRET_HEADER_PATTERN,
|
|
38
36
|
SECRET_KEY_PATTERN: () => SECRET_KEY_PATTERN,
|
|
39
|
-
add: () => installMcpServer,
|
|
40
37
|
agentConfigStore: () => agentConfigStore,
|
|
41
|
-
|
|
38
|
+
applyServerConfigDelta: () => applyServerConfigDelta,
|
|
42
39
|
buildMcpServerConfig: () => buildMcpServerConfig,
|
|
43
40
|
createAgentTransform: () => createAgentTransform,
|
|
44
41
|
detectGloballyInstalledMcpAgents: () => detectGloballyInstalledMcpAgents,
|
|
45
42
|
detectProjectInstalledMcpAgents: () => detectProjectInstalledMcpAgents,
|
|
46
43
|
detectUpdateTransition: () => detectUpdateTransition,
|
|
47
|
-
displayServerDetails: () => displayServerDetails,
|
|
48
44
|
extractPackageName: () => extractPackageName,
|
|
49
|
-
formatArgsString: () => formatArgsString,
|
|
50
|
-
formatEnvText: () => formatEnvText,
|
|
51
|
-
formatHeadersText: () => formatHeadersText,
|
|
52
45
|
getCandidateAgentsForScope: () => getCandidateAgentsForScope,
|
|
53
46
|
getCoHostedAgents: () => getCoHostedAgents,
|
|
54
47
|
getMcpAgentConfig: () => getMcpAgentConfig,
|
|
55
48
|
getMcpAgentTypes: () => getMcpAgentTypes,
|
|
56
49
|
getMcpAgentsSupportingProjectScope: () => getMcpAgentsSupportingProjectScope,
|
|
57
|
-
groupInstalledServersByName: () => groupInstalledServersByName,
|
|
58
|
-
install: () => installMcpServer,
|
|
59
50
|
installMcpServer: () => installMcpServer,
|
|
60
51
|
installMcpServerForAgent: () => installMcpServerForAgent,
|
|
61
52
|
installMcpServerForAgents: () => installMcpServerForAgents,
|
|
@@ -65,55 +56,23 @@ __export(src_exports, {
|
|
|
65
56
|
isRemoteMcpSource: () => isRemoteMcpSource,
|
|
66
57
|
isRemoteServerConfig: () => isRemoteServerConfig,
|
|
67
58
|
isStdioServerConfig: () => isStdioServerConfig,
|
|
68
|
-
linkedCheckbox: () => linkedCheckbox,
|
|
69
|
-
list: () => listInstalledMcpServers,
|
|
70
59
|
listInstalledMcpServers: () => listInstalledMcpServers,
|
|
71
|
-
listServersInConfigFile: () => listServersInConfigFile,
|
|
72
|
-
mainMenu: () => mainMenu,
|
|
73
60
|
maskSecretHeader: () => maskSecretHeader,
|
|
74
61
|
maskSecretValue: () => maskSecretValue,
|
|
75
|
-
mcpAgentAliases: () => mcpAgentAliases,
|
|
76
|
-
mcpAgents: () => mcpAgents,
|
|
77
|
-
mcpManageCommand: () => mcpManageCommand,
|
|
78
|
-
normalizeServerConfig: () => normalizeServerConfig,
|
|
79
|
-
parseArgsString: () => parseArgsString,
|
|
80
|
-
parseEnvText: () => parseEnvText,
|
|
81
|
-
parseHeadersText: () => parseHeadersText,
|
|
82
62
|
parseMcpSource: () => parseMcpSource,
|
|
83
63
|
parseServerConfig: () => parseServerConfig,
|
|
84
|
-
|
|
85
|
-
promptArgsConfig: () => promptArgsConfig,
|
|
86
|
-
promptEditArgs: () => promptEditArgs,
|
|
87
|
-
promptEditEnvConfig: () => promptEditEnvConfig,
|
|
88
|
-
promptEditHeadersConfig: () => promptEditHeadersConfig,
|
|
89
|
-
promptEditKeyValueConfig: () => promptEditKeyValueConfig,
|
|
90
|
-
promptEnvConfig: () => promptEnvConfig,
|
|
91
|
-
promptHeadersConfig: () => promptHeadersConfig,
|
|
92
|
-
promptScope: () => promptScope,
|
|
93
|
-
promptScopeAndAgents: () => promptScopeAndAgents,
|
|
94
|
-
promptSwitchServerType: () => promptSwitchServerType,
|
|
95
|
-
readConfigFile: () => readConfigFile,
|
|
96
|
-
remove: () => removeMcpServer,
|
|
64
|
+
queryGroupedInstalledServers: () => queryGroupedInstalledServers,
|
|
97
65
|
removeMcpServer: () => removeMcpServer,
|
|
98
|
-
removeMcpServerFromAgent: () => removeMcpServerFromAgent,
|
|
99
|
-
removeServerFromConfigFile: () => removeServerFromConfigFile,
|
|
100
66
|
resolveConfigClusters: () => resolveConfigClusters,
|
|
101
67
|
resolveMcpAgentAlias: () => resolveMcpAgentAlias,
|
|
102
68
|
resolveMcpConfigTarget: () => resolveMcpConfigTarget,
|
|
103
69
|
resolveTargetAgents: () => resolveTargetAgents,
|
|
104
|
-
resolveTransport: () => resolveTransport,
|
|
105
70
|
sanitizeUpdatedServerConfig: () => sanitizeUpdatedServerConfig,
|
|
106
|
-
|
|
71
|
+
sortAgentsByClusters: () => sortAgentsByClusters,
|
|
107
72
|
toRemoteServerConfig: () => toRemoteServerConfig,
|
|
108
73
|
toStdioServerConfig: () => toStdioServerConfig,
|
|
109
|
-
transformServerConfig: () => transformServerConfig,
|
|
110
74
|
transformServerConfigForAgent: () => transformServerConfigForAgent,
|
|
111
|
-
|
|
112
|
-
updateMcpServer: () => updateMcpServer,
|
|
113
|
-
wizardAdd: () => wizardAdd,
|
|
114
|
-
wizardManage: () => wizardManage,
|
|
115
|
-
wizardRemove: () => wizardRemove,
|
|
116
|
-
writeServerToConfigFile: () => writeServerToConfigFile
|
|
75
|
+
updateMcpServer: () => updateMcpServer
|
|
117
76
|
});
|
|
118
77
|
module.exports = __toCommonJS(src_exports);
|
|
119
78
|
|
|
@@ -571,9 +530,9 @@ var mcpAgentAliases = {
|
|
|
571
530
|
var getMcpAgentConfig = (agentType) => mcpAgents[agentType];
|
|
572
531
|
var getMcpAgentTypes = () => Object.values(mcpAgents).map((config) => config.name);
|
|
573
532
|
var isMcpAgentType = (value) => value in mcpAgents;
|
|
574
|
-
var resolveMcpAgentAlias = (
|
|
575
|
-
if (isMcpAgentType(
|
|
576
|
-
return mcpAgentAliases[
|
|
533
|
+
var resolveMcpAgentAlias = (input) => {
|
|
534
|
+
if (isMcpAgentType(input)) return input;
|
|
535
|
+
return mcpAgentAliases[input] ?? null;
|
|
577
536
|
};
|
|
578
537
|
var isMcpTransportSupported = (agent, transport) => agent.supportedTransports.includes(transport);
|
|
579
538
|
var detectProjectInstalledMcpAgents = (cwd) => getMcpAgentTypes().filter(
|
|
@@ -625,7 +584,9 @@ var KNOWN_COMMAND_RUNNERS = /* @__PURE__ */ new Set([
|
|
|
625
584
|
]);
|
|
626
585
|
var SCRIPT_EXTENSION_REGEX = /\.(?:js|ts|mjs|cjs|py|sh|rb|go)$/i;
|
|
627
586
|
|
|
628
|
-
// src/
|
|
587
|
+
// src/server-config.ts
|
|
588
|
+
var isRemoteServerConfig = (config) => typeof config.url === "string" && config.url.length > 0;
|
|
589
|
+
var isStdioServerConfig = (config) => typeof config.command === "string" && config.command.length > 0;
|
|
629
590
|
var buildMcpServerConfig = (parsed, options = {}) => {
|
|
630
591
|
if (parsed.type === "remote") {
|
|
631
592
|
const config2 = {
|
|
@@ -663,10 +624,6 @@ var buildMcpServerConfig = (parsed, options = {}) => {
|
|
|
663
624
|
}
|
|
664
625
|
return config;
|
|
665
626
|
};
|
|
666
|
-
|
|
667
|
-
// src/parse-server-config.ts
|
|
668
|
-
var isRemoteServerConfig = (config) => typeof config.url === "string" && config.url.length > 0;
|
|
669
|
-
var isStdioServerConfig = (config) => typeof config.command === "string" && config.command.length > 0;
|
|
670
627
|
var parseServerConfig = (raw) => {
|
|
671
628
|
if (!raw || typeof raw !== "object") return {};
|
|
672
629
|
const data = raw;
|
|
@@ -693,6 +650,237 @@ var parseServerConfig = (raw) => {
|
|
|
693
650
|
}
|
|
694
651
|
return {};
|
|
695
652
|
};
|
|
653
|
+
var toRemoteServerConfig = (config, defaultTransport = "http") => {
|
|
654
|
+
const {
|
|
655
|
+
command: _droppedCommand,
|
|
656
|
+
args: _droppedArgs,
|
|
657
|
+
env: _droppedEnv,
|
|
658
|
+
...remoteConfig
|
|
659
|
+
} = config;
|
|
660
|
+
return {
|
|
661
|
+
...remoteConfig,
|
|
662
|
+
type: remoteConfig.type ?? defaultTransport
|
|
663
|
+
};
|
|
664
|
+
};
|
|
665
|
+
var toStdioServerConfig = (config) => {
|
|
666
|
+
const {
|
|
667
|
+
url: _droppedUrl,
|
|
668
|
+
type: _droppedType,
|
|
669
|
+
headers: _droppedHeaders,
|
|
670
|
+
...stdioConfig
|
|
671
|
+
} = config;
|
|
672
|
+
return stdioConfig;
|
|
673
|
+
};
|
|
674
|
+
var detectUpdateTransition = (incoming, previous) => {
|
|
675
|
+
if (!previous) {
|
|
676
|
+
return incoming.url ? "switch-to-remote" : "switch-to-stdio";
|
|
677
|
+
}
|
|
678
|
+
const previousIsRemote = Boolean(previous.url && previous.url.length > 0);
|
|
679
|
+
if (previousIsRemote) {
|
|
680
|
+
if (incoming.command && !incoming.url) {
|
|
681
|
+
return "switch-to-stdio";
|
|
682
|
+
}
|
|
683
|
+
return "merge-remote";
|
|
684
|
+
}
|
|
685
|
+
if (incoming.url && !incoming.command) {
|
|
686
|
+
return "switch-to-remote";
|
|
687
|
+
}
|
|
688
|
+
return "merge-stdio";
|
|
689
|
+
};
|
|
690
|
+
var sanitizeUpdatedServerConfig = (incoming, previous) => {
|
|
691
|
+
const transition = detectUpdateTransition(incoming, previous);
|
|
692
|
+
const targetTransport = incoming.type ?? previous?.type ?? "http";
|
|
693
|
+
switch (transition) {
|
|
694
|
+
case "switch-to-remote": {
|
|
695
|
+
const cleanBase = previous ? toRemoteServerConfig(previous, targetTransport) : {};
|
|
696
|
+
return toRemoteServerConfig({ ...cleanBase, ...incoming }, targetTransport);
|
|
697
|
+
}
|
|
698
|
+
case "switch-to-stdio": {
|
|
699
|
+
const cleanBase = previous ? toStdioServerConfig(previous) : {};
|
|
700
|
+
return toStdioServerConfig({ ...cleanBase, ...incoming });
|
|
701
|
+
}
|
|
702
|
+
case "merge-remote": {
|
|
703
|
+
return toRemoteServerConfig({ ...previous, ...incoming }, targetTransport);
|
|
704
|
+
}
|
|
705
|
+
case "merge-stdio":
|
|
706
|
+
default: {
|
|
707
|
+
return toStdioServerConfig({ ...previous, ...incoming });
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
var applyServerConfigDelta = (previousConfig, options) => {
|
|
712
|
+
if (options.url !== void 0 && options.command !== void 0) {
|
|
713
|
+
throw new Error('Cannot specify both "--url" (remote) and "--command" (stdio) simultaneously.');
|
|
714
|
+
}
|
|
715
|
+
const isCurrentRemote = Boolean(previousConfig?.url && previousConfig.url.length > 0);
|
|
716
|
+
const willBeRemote = options.url !== void 0 ? true : options.command !== void 0 ? false : isCurrentRemote;
|
|
717
|
+
const protocol = willBeRemote ? "remote" : "stdio";
|
|
718
|
+
const ignoredFlags = [];
|
|
719
|
+
if (willBeRemote) {
|
|
720
|
+
if (options.env !== void 0) ignoredFlags.push("--env");
|
|
721
|
+
if (options.clearEnv) ignoredFlags.push("--clear-env");
|
|
722
|
+
if (options.args !== void 0) ignoredFlags.push("--args");
|
|
723
|
+
if (options.clearArgs) ignoredFlags.push("--clear-args");
|
|
724
|
+
} else {
|
|
725
|
+
if (options.headers !== void 0) ignoredFlags.push("--header");
|
|
726
|
+
if (options.clearHeaders) ignoredFlags.push("--clear-headers");
|
|
727
|
+
if (options.transport !== void 0) ignoredFlags.push("--transport");
|
|
728
|
+
}
|
|
729
|
+
const incomingDelta = {};
|
|
730
|
+
if (options.command !== void 0) {
|
|
731
|
+
incomingDelta.command = options.command;
|
|
732
|
+
}
|
|
733
|
+
if (options.clearArgs) {
|
|
734
|
+
incomingDelta.args = void 0;
|
|
735
|
+
}
|
|
736
|
+
if (options.args !== void 0) {
|
|
737
|
+
incomingDelta.args = options.args;
|
|
738
|
+
}
|
|
739
|
+
if (options.url !== void 0) {
|
|
740
|
+
incomingDelta.url = options.url;
|
|
741
|
+
}
|
|
742
|
+
if (options.transport !== void 0) {
|
|
743
|
+
incomingDelta.type = options.transport;
|
|
744
|
+
}
|
|
745
|
+
if (options.clearEnv) {
|
|
746
|
+
incomingDelta.env = void 0;
|
|
747
|
+
}
|
|
748
|
+
if (options.env !== void 0) {
|
|
749
|
+
const baseEnv = options.clearEnv ? {} : previousConfig?.env ?? {};
|
|
750
|
+
incomingDelta.env = { ...baseEnv, ...options.env };
|
|
751
|
+
}
|
|
752
|
+
if (options.clearHeaders) {
|
|
753
|
+
incomingDelta.headers = void 0;
|
|
754
|
+
}
|
|
755
|
+
if (options.headers !== void 0) {
|
|
756
|
+
const baseHeaders = options.clearHeaders ? {} : previousConfig?.headers ?? {};
|
|
757
|
+
incomingDelta.headers = { ...baseHeaders, ...options.headers };
|
|
758
|
+
}
|
|
759
|
+
const transition = detectUpdateTransition(incomingDelta, previousConfig);
|
|
760
|
+
const cleanConfig = sanitizeUpdatedServerConfig(incomingDelta, previousConfig);
|
|
761
|
+
return {
|
|
762
|
+
config: cleanConfig,
|
|
763
|
+
transition,
|
|
764
|
+
protocol,
|
|
765
|
+
ignoredFlags
|
|
766
|
+
};
|
|
767
|
+
};
|
|
768
|
+
|
|
769
|
+
// src/source-parser.ts
|
|
770
|
+
var REMOTE_URL_REGEX = /^https?:\/\//i;
|
|
771
|
+
var HAS_WHITESPACE_REGEX = /\s/;
|
|
772
|
+
var PACKAGE_NAME_REGEX = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(?:@[^\s]+)?$/;
|
|
773
|
+
var PATH_SEPARATOR_REGEX = /[/\\]/;
|
|
774
|
+
var stripVersionSuffix = (input) => {
|
|
775
|
+
if (input.startsWith("@")) {
|
|
776
|
+
const secondAtIndex = input.indexOf("@", 1);
|
|
777
|
+
if (secondAtIndex > 0) return input.slice(0, secondAtIndex);
|
|
778
|
+
return input;
|
|
779
|
+
}
|
|
780
|
+
const atIndex = input.lastIndexOf("@");
|
|
781
|
+
if (atIndex > 0) return input.slice(0, atIndex);
|
|
782
|
+
return input;
|
|
783
|
+
};
|
|
784
|
+
var stripScopePrefix = (input) => {
|
|
785
|
+
if (!input.startsWith("@") || !input.includes("/")) return input;
|
|
786
|
+
const parts = input.split("/");
|
|
787
|
+
return parts[1] || input;
|
|
788
|
+
};
|
|
789
|
+
var stripPathPrefix = (input) => {
|
|
790
|
+
if (!PATH_SEPARATOR_REGEX.test(input)) return input;
|
|
791
|
+
const segments = input.split(PATH_SEPARATOR_REGEX);
|
|
792
|
+
const basename = segments[segments.length - 1];
|
|
793
|
+
return basename || input;
|
|
794
|
+
};
|
|
795
|
+
var extractPackageName = (input) => {
|
|
796
|
+
let name = stripVersionSuffix(input);
|
|
797
|
+
name = stripScopePrefix(name);
|
|
798
|
+
name = stripPathPrefix(name);
|
|
799
|
+
name = name.replace(SCRIPT_EXTENSION_REGEX, "");
|
|
800
|
+
for (const prefix of PACKAGE_NAME_PREFIX_STRIP) {
|
|
801
|
+
if (name.startsWith(prefix)) {
|
|
802
|
+
name = name.slice(prefix.length);
|
|
803
|
+
break;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
for (const suffix of PACKAGE_NAME_SUFFIX_STRIP) {
|
|
807
|
+
if (name.endsWith(suffix)) {
|
|
808
|
+
name = name.slice(0, -suffix.length);
|
|
809
|
+
break;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
return name || MCP_DEFAULT_SERVER_NAME;
|
|
813
|
+
};
|
|
814
|
+
var inferNameFromUrl = (input) => {
|
|
815
|
+
try {
|
|
816
|
+
const url = new URL(input);
|
|
817
|
+
const host = url.hostname;
|
|
818
|
+
const labels = host.split(".").filter((segment) => segment.length > 0);
|
|
819
|
+
if (labels.length === 0) return MCP_DEFAULT_SERVER_NAME;
|
|
820
|
+
const meaningfulLabels = labels.filter((label) => {
|
|
821
|
+
const lower = label.toLowerCase();
|
|
822
|
+
if (COMMON_TLD_LABELS.has(lower)) return false;
|
|
823
|
+
if (GENERIC_HOST_PREFIXES.has(lower)) return false;
|
|
824
|
+
return true;
|
|
825
|
+
});
|
|
826
|
+
if (meaningfulLabels.length > 0) return meaningfulLabels[0];
|
|
827
|
+
if (labels.length >= 2) return labels[labels.length - 2];
|
|
828
|
+
return labels[labels.length - 1] || MCP_DEFAULT_SERVER_NAME;
|
|
829
|
+
} catch {
|
|
830
|
+
return MCP_DEFAULT_SERVER_NAME;
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
var inferNameFromCommand = (command) => {
|
|
834
|
+
const tokens = command.trim().split(/\s+/);
|
|
835
|
+
const runnerBase = tokens[0]?.split(PATH_SEPARATOR_REGEX).pop() ?? "";
|
|
836
|
+
const startIndex = KNOWN_COMMAND_RUNNERS.has(runnerBase) ? 1 : 0;
|
|
837
|
+
for (let tokenIndex = startIndex; tokenIndex < tokens.length; tokenIndex += 1) {
|
|
838
|
+
const token = tokens[tokenIndex];
|
|
839
|
+
if (!token || token.startsWith("-")) continue;
|
|
840
|
+
return extractPackageName(token);
|
|
841
|
+
}
|
|
842
|
+
const firstNonFlag = tokens.find((token) => !token.startsWith("-"));
|
|
843
|
+
return firstNonFlag ? extractPackageName(firstNonFlag) : MCP_DEFAULT_SERVER_NAME;
|
|
844
|
+
};
|
|
845
|
+
var parseMcpSource = (input) => {
|
|
846
|
+
const trimmed = input.trim();
|
|
847
|
+
if (trimmed.length === 0) {
|
|
848
|
+
throw new Error(
|
|
849
|
+
"Invalid MCP source: input is empty. Expected a remote URL, an npm package, or a command line."
|
|
850
|
+
);
|
|
851
|
+
}
|
|
852
|
+
if (REMOTE_URL_REGEX.test(trimmed)) {
|
|
853
|
+
return {
|
|
854
|
+
type: "remote",
|
|
855
|
+
value: trimmed,
|
|
856
|
+
inferredName: inferNameFromUrl(trimmed)
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
if (HAS_WHITESPACE_REGEX.test(trimmed)) {
|
|
860
|
+
return {
|
|
861
|
+
type: "command",
|
|
862
|
+
value: trimmed,
|
|
863
|
+
inferredName: inferNameFromCommand(trimmed)
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
if (PACKAGE_NAME_REGEX.test(trimmed)) {
|
|
867
|
+
return {
|
|
868
|
+
type: "package",
|
|
869
|
+
value: trimmed,
|
|
870
|
+
inferredName: extractPackageName(trimmed)
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
return {
|
|
874
|
+
type: "command",
|
|
875
|
+
value: trimmed,
|
|
876
|
+
inferredName: inferNameFromCommand(trimmed)
|
|
877
|
+
};
|
|
878
|
+
};
|
|
879
|
+
var isRemoteMcpSource = (parsed) => parsed.type === "remote";
|
|
880
|
+
|
|
881
|
+
// src/config-store.ts
|
|
882
|
+
var import_node_fs6 = require("fs");
|
|
883
|
+
var import_node_path3 = require("path");
|
|
696
884
|
|
|
697
885
|
// src/utils/is-plain-object.ts
|
|
698
886
|
var isPlainObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -977,220 +1165,45 @@ var listServersInConfigFile = (filePath, format, dottedKey) => {
|
|
|
977
1165
|
return isPlainObject(entries) ? entries : {};
|
|
978
1166
|
};
|
|
979
1167
|
|
|
980
|
-
// src/
|
|
981
|
-
var
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
serverName
|
|
1020
|
-
);
|
|
1021
|
-
}
|
|
1022
|
-
listServers(target) {
|
|
1023
|
-
if (!target.dottedKey) return {};
|
|
1024
|
-
return listServersInConfigFile(target.filePath, target.format, target.dottedKey);
|
|
1025
|
-
}
|
|
1026
|
-
};
|
|
1027
|
-
var AgentConfigStore = class {
|
|
1028
|
-
constructor(adapter = new FsConfigStoreAdapter()) {
|
|
1029
|
-
this.adapter = adapter;
|
|
1030
|
-
}
|
|
1031
|
-
adapter;
|
|
1032
|
-
getAdapter() {
|
|
1033
|
-
return this.adapter;
|
|
1034
|
-
}
|
|
1035
|
-
resolveTarget(agent, options = {}) {
|
|
1036
|
-
const agentConfig = typeof agent === "string" ? getMcpAgentConfig(agent) : agent;
|
|
1037
|
-
const target = resolveMcpConfigTarget(agentConfig, options);
|
|
1038
|
-
return { agent: agentConfig, target };
|
|
1039
|
-
}
|
|
1040
|
-
resolveDescriptor(agent, options = {}) {
|
|
1041
|
-
const { agent: agentConfig, target } = this.resolveTarget(agent, options);
|
|
1042
|
-
return {
|
|
1043
|
-
filePath: target.configPath,
|
|
1044
|
-
format: agentConfig.format,
|
|
1045
|
-
dottedKey: target.configKey
|
|
1046
|
-
};
|
|
1047
|
-
}
|
|
1048
|
-
writeServer(agent, serverName, serverConfig, options = {}) {
|
|
1049
|
-
const descriptor = this.resolveDescriptor(agent, options);
|
|
1050
|
-
this.adapter.writeServer(descriptor, serverName, serverConfig);
|
|
1051
|
-
return { path: descriptor.filePath };
|
|
1052
|
-
}
|
|
1053
|
-
removeServer(agent, serverName, options = {}) {
|
|
1054
|
-
const descriptor = this.resolveDescriptor(agent, options);
|
|
1055
|
-
if (!this.adapter.exists(descriptor.filePath)) {
|
|
1056
|
-
return { path: descriptor.filePath, removed: false };
|
|
1057
|
-
}
|
|
1058
|
-
const removed = this.adapter.removeServer(descriptor, serverName);
|
|
1059
|
-
return { path: descriptor.filePath, removed };
|
|
1060
|
-
}
|
|
1061
|
-
listServers(agent, options = {}) {
|
|
1062
|
-
const descriptor = this.resolveDescriptor(agent, options);
|
|
1063
|
-
if (!this.adapter.exists(descriptor.filePath)) {
|
|
1064
|
-
return { path: descriptor.filePath, exists: false, servers: {} };
|
|
1065
|
-
}
|
|
1066
|
-
const servers = this.adapter.listServers(descriptor);
|
|
1067
|
-
return { path: descriptor.filePath, exists: true, servers };
|
|
1068
|
-
}
|
|
1069
|
-
read(agent, options = {}) {
|
|
1070
|
-
const descriptor = this.resolveDescriptor(agent, options);
|
|
1071
|
-
if (!this.adapter.exists(descriptor.filePath)) {
|
|
1072
|
-
return {};
|
|
1073
|
-
}
|
|
1074
|
-
return this.adapter.read(descriptor);
|
|
1075
|
-
}
|
|
1076
|
-
readServer(agent, serverName, options = {}) {
|
|
1077
|
-
const { exists, servers } = this.listServers(agent, options);
|
|
1078
|
-
if (!exists) return void 0;
|
|
1079
|
-
return servers[serverName];
|
|
1080
|
-
}
|
|
1081
|
-
};
|
|
1082
|
-
var agentConfigStore = new AgentConfigStore();
|
|
1083
|
-
|
|
1084
|
-
// src/utils/to-error-message.ts
|
|
1085
|
-
var toErrorMessage = (error, fallback = "Unknown error") => error instanceof Error ? error.message : fallback;
|
|
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
|
-
|
|
1155
|
-
// src/transforms/index.ts
|
|
1156
|
-
var DIALECT_PRESETS = {
|
|
1157
|
-
vscode: {
|
|
1158
|
-
stdioTransport: "type-stdio",
|
|
1159
|
-
remoteTransport: "type-http-sse"
|
|
1160
|
-
},
|
|
1161
|
-
augment: {
|
|
1162
|
-
stdioTransport: "none",
|
|
1163
|
-
remoteTransport: "type-http-sse"
|
|
1164
|
-
},
|
|
1165
|
-
amp: {
|
|
1166
|
-
stdioTransport: "none",
|
|
1167
|
-
remoteTransport: "none"
|
|
1168
|
-
},
|
|
1169
|
-
trae: {
|
|
1170
|
-
stdioTransport: "none",
|
|
1171
|
-
remoteTransport: "sse-only-type"
|
|
1172
|
-
},
|
|
1173
|
-
grok: {
|
|
1174
|
-
stdioTransport: "none",
|
|
1175
|
-
remoteTransport: "sse-only-type"
|
|
1176
|
-
},
|
|
1177
|
-
cline: {
|
|
1178
|
-
stdioTransport: "none",
|
|
1179
|
-
remoteTransport: "streamableHttp"
|
|
1180
|
-
},
|
|
1181
|
-
goose: {
|
|
1182
|
-
stdioTransport: "type-stdio",
|
|
1183
|
-
remoteTransport: "streamable_http",
|
|
1184
|
-
commandField: "cmd",
|
|
1185
|
-
envField: "envs",
|
|
1186
|
-
urlField: "uri",
|
|
1187
|
-
defaultEnvEmpty: true,
|
|
1188
|
-
defaultHeadersEmpty: true,
|
|
1189
|
-
includeServerName: true,
|
|
1190
|
-
timeoutSeconds: GOOSE_TIMEOUT_SECONDS,
|
|
1191
|
-
extraFields: {
|
|
1192
|
-
description: "",
|
|
1193
|
-
enabled: true
|
|
1168
|
+
// src/transforms/index.ts
|
|
1169
|
+
var DIALECT_PRESETS = {
|
|
1170
|
+
vscode: {
|
|
1171
|
+
stdioTransport: "type-stdio",
|
|
1172
|
+
remoteTransport: "type-http-sse"
|
|
1173
|
+
},
|
|
1174
|
+
augment: {
|
|
1175
|
+
stdioTransport: "none",
|
|
1176
|
+
remoteTransport: "type-http-sse"
|
|
1177
|
+
},
|
|
1178
|
+
amp: {
|
|
1179
|
+
stdioTransport: "none",
|
|
1180
|
+
remoteTransport: "none"
|
|
1181
|
+
},
|
|
1182
|
+
trae: {
|
|
1183
|
+
stdioTransport: "none",
|
|
1184
|
+
remoteTransport: "sse-only-type"
|
|
1185
|
+
},
|
|
1186
|
+
grok: {
|
|
1187
|
+
stdioTransport: "none",
|
|
1188
|
+
remoteTransport: "sse-only-type"
|
|
1189
|
+
},
|
|
1190
|
+
cline: {
|
|
1191
|
+
stdioTransport: "none",
|
|
1192
|
+
remoteTransport: "streamableHttp"
|
|
1193
|
+
},
|
|
1194
|
+
goose: {
|
|
1195
|
+
stdioTransport: "type-stdio",
|
|
1196
|
+
remoteTransport: "streamable_http",
|
|
1197
|
+
commandField: "cmd",
|
|
1198
|
+
envField: "envs",
|
|
1199
|
+
urlField: "uri",
|
|
1200
|
+
defaultEnvEmpty: true,
|
|
1201
|
+
defaultHeadersEmpty: true,
|
|
1202
|
+
includeServerName: true,
|
|
1203
|
+
timeoutSeconds: GOOSE_TIMEOUT_SECONDS,
|
|
1204
|
+
extraFields: {
|
|
1205
|
+
description: "",
|
|
1206
|
+
enabled: true
|
|
1194
1207
|
}
|
|
1195
1208
|
},
|
|
1196
1209
|
"kimi-code": {
|
|
@@ -1362,115 +1375,323 @@ var transformServerConfigForAgent = (agent, serverName, config, context = { glob
|
|
|
1362
1375
|
return config;
|
|
1363
1376
|
};
|
|
1364
1377
|
|
|
1365
|
-
// src/
|
|
1366
|
-
var
|
|
1367
|
-
|
|
1378
|
+
// src/utils/to-error-message.ts
|
|
1379
|
+
var toErrorMessage = (error, fallback = "Unknown error") => error instanceof Error ? error.message : fallback;
|
|
1380
|
+
|
|
1381
|
+
// src/config-store.ts
|
|
1382
|
+
var resolveMcpConfigTarget = (agent, options = {}) => {
|
|
1368
1383
|
const isGlobal = options.global ?? false;
|
|
1369
|
-
const
|
|
1370
|
-
const
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1384
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1385
|
+
const configPath = agent.resolveConfigPath ? agent.resolveConfigPath({ global: isGlobal, cwd }) : !isGlobal && agent.projectConfigPath ? (0, import_node_path3.join)(cwd, agent.projectConfigPath) : agent.globalConfigPath;
|
|
1386
|
+
const configKey = !isGlobal && agent.projectConfigKey ? agent.projectConfigKey : agent.configKey;
|
|
1387
|
+
return { configPath, configKey };
|
|
1388
|
+
};
|
|
1389
|
+
var getCandidateAgentsForScope = (options = {}) => {
|
|
1390
|
+
return options.global ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
|
|
1391
|
+
};
|
|
1392
|
+
var FsConfigStoreAdapter = class {
|
|
1393
|
+
exists(filePath) {
|
|
1394
|
+
return (0, import_node_fs6.existsSync)(filePath);
|
|
1395
|
+
}
|
|
1396
|
+
read(target) {
|
|
1397
|
+
return readConfigFile(target.filePath, target.format);
|
|
1398
|
+
}
|
|
1399
|
+
writeServer(target, serverName, serverConfig) {
|
|
1400
|
+
if (!target.dottedKey) {
|
|
1401
|
+
throw new Error(`Cannot write server: missing dottedKey for ${target.filePath}`);
|
|
1402
|
+
}
|
|
1403
|
+
writeServerToConfigFile(
|
|
1404
|
+
target.filePath,
|
|
1405
|
+
target.format,
|
|
1406
|
+
target.dottedKey,
|
|
1407
|
+
serverName,
|
|
1408
|
+
serverConfig
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1411
|
+
removeServer(target, serverName) {
|
|
1412
|
+
if (!target.dottedKey) return false;
|
|
1413
|
+
return removeServerFromConfigFile(
|
|
1414
|
+
target.filePath,
|
|
1415
|
+
target.format,
|
|
1416
|
+
target.dottedKey,
|
|
1417
|
+
serverName
|
|
1418
|
+
);
|
|
1419
|
+
}
|
|
1420
|
+
listServers(target) {
|
|
1421
|
+
if (!target.dottedKey) return {};
|
|
1422
|
+
return listServersInConfigFile(target.filePath, target.format, target.dottedKey);
|
|
1423
|
+
}
|
|
1424
|
+
};
|
|
1425
|
+
var AgentConfigStore = class {
|
|
1426
|
+
constructor(adapter = new FsConfigStoreAdapter()) {
|
|
1427
|
+
this.adapter = adapter;
|
|
1428
|
+
}
|
|
1429
|
+
adapter;
|
|
1430
|
+
getAdapter() {
|
|
1431
|
+
return this.adapter;
|
|
1432
|
+
}
|
|
1433
|
+
// ---- Single-agent primitives ----
|
|
1434
|
+
resolveTarget(agent, options = {}) {
|
|
1435
|
+
const agentConfig = typeof agent === "string" ? getMcpAgentConfig(agent) : agent;
|
|
1436
|
+
const target = resolveMcpConfigTarget(agentConfig, options);
|
|
1437
|
+
return { agent: agentConfig, target };
|
|
1438
|
+
}
|
|
1439
|
+
resolveDescriptor(agent, options = {}) {
|
|
1440
|
+
const { agent: agentConfig, target } = this.resolveTarget(agent, options);
|
|
1383
1441
|
return {
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
error: toErrorMessage(error)
|
|
1442
|
+
filePath: target.configPath,
|
|
1443
|
+
format: agentConfig.format,
|
|
1444
|
+
dottedKey: target.configKey
|
|
1388
1445
|
};
|
|
1389
1446
|
}
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
const
|
|
1397
|
-
|
|
1398
|
-
|
|
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
|
-
}
|
|
1447
|
+
writeServer(agent, serverName, serverConfig, options = {}) {
|
|
1448
|
+
const descriptor = this.resolveDescriptor(agent, options);
|
|
1449
|
+
this.adapter.writeServer(descriptor, serverName, serverConfig);
|
|
1450
|
+
return { path: descriptor.filePath };
|
|
1451
|
+
}
|
|
1452
|
+
removeServer(agent, serverName, options = {}) {
|
|
1453
|
+
const descriptor = this.resolveDescriptor(agent, options);
|
|
1454
|
+
if (!this.adapter.exists(descriptor.filePath)) {
|
|
1455
|
+
return { path: descriptor.filePath, removed: false };
|
|
1421
1456
|
}
|
|
1457
|
+
const removed = this.adapter.removeServer(descriptor, serverName);
|
|
1458
|
+
return { path: descriptor.filePath, removed };
|
|
1422
1459
|
}
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1460
|
+
listServers(agent, options = {}) {
|
|
1461
|
+
const descriptor = this.resolveDescriptor(agent, options);
|
|
1462
|
+
if (!this.adapter.exists(descriptor.filePath)) {
|
|
1463
|
+
return { path: descriptor.filePath, exists: false, servers: {} };
|
|
1464
|
+
}
|
|
1465
|
+
const servers = this.adapter.listServers(descriptor);
|
|
1466
|
+
return { path: descriptor.filePath, exists: true, servers };
|
|
1467
|
+
}
|
|
1468
|
+
/**
|
|
1469
|
+
* Batch lists servers for multiple agents, caching adapter reads for co-hosted
|
|
1470
|
+
* agents that share the exact same physical configuration file and dotted key.
|
|
1471
|
+
*/
|
|
1472
|
+
listServersForAgents(agents, options = {}) {
|
|
1473
|
+
const readCache = /* @__PURE__ */ new Map();
|
|
1474
|
+
return agents.map((agentType) => {
|
|
1475
|
+
const descriptor = this.resolveDescriptor(agentType, options);
|
|
1476
|
+
const cacheKey = `${descriptor.filePath}::${descriptor.dottedKey ?? ""}`;
|
|
1477
|
+
let cached = readCache.get(cacheKey);
|
|
1478
|
+
if (!cached) {
|
|
1479
|
+
cached = this.listServers(agentType, options);
|
|
1480
|
+
readCache.set(cacheKey, cached);
|
|
1481
|
+
}
|
|
1437
1482
|
return {
|
|
1438
1483
|
agent: agentType,
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1484
|
+
path: cached.path,
|
|
1485
|
+
exists: cached.exists,
|
|
1486
|
+
servers: cached.servers
|
|
1442
1487
|
};
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
read(agent, options = {}) {
|
|
1491
|
+
const descriptor = this.resolveDescriptor(agent, options);
|
|
1492
|
+
if (!this.adapter.exists(descriptor.filePath)) {
|
|
1493
|
+
return {};
|
|
1443
1494
|
}
|
|
1444
|
-
return
|
|
1445
|
-
});
|
|
1446
|
-
};
|
|
1447
|
-
|
|
1448
|
-
// src/utils/parse-mcp-agent-list.ts
|
|
1449
|
-
var parseMcpAgentList = (input7) => {
|
|
1450
|
-
if (!input7 || input7.length === 0) return void 0;
|
|
1451
|
-
if (input7.includes("*")) return getMcpAgentTypes();
|
|
1452
|
-
const resolved = [];
|
|
1453
|
-
for (const value of input7) {
|
|
1454
|
-
const agentType = resolveMcpAgentAlias(value);
|
|
1455
|
-
if (!agentType) throw new Error(`Unknown MCP agent "${value}"`);
|
|
1456
|
-
resolved.push(agentType);
|
|
1495
|
+
return this.adapter.read(descriptor);
|
|
1457
1496
|
}
|
|
1458
|
-
|
|
1459
|
-
};
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
var normalizeRequestedAgents = (input7) => {
|
|
1463
|
-
if (!input7 || input7.length === 0) return void 0;
|
|
1464
|
-
const rawList = [...input7];
|
|
1465
|
-
if (rawList.every((item) => isMcpAgentType(item))) {
|
|
1466
|
-
return rawList;
|
|
1497
|
+
readServer(agent, serverName, options = {}) {
|
|
1498
|
+
const { exists, servers } = this.listServers(agent, options);
|
|
1499
|
+
if (!exists) return void 0;
|
|
1500
|
+
return servers[serverName];
|
|
1467
1501
|
}
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1502
|
+
// ---- Cluster & co-hosted awareness ----
|
|
1503
|
+
/**
|
|
1504
|
+
* Returns all other agents sharing the exact same physical configuration target
|
|
1505
|
+
* (same configPath and configKey) for the given scope.
|
|
1506
|
+
*/
|
|
1507
|
+
getCoHostedAgents(agentType, options = {}) {
|
|
1508
|
+
const currentAgent = getMcpAgentConfig(agentType);
|
|
1509
|
+
const currentTarget = resolveMcpConfigTarget(currentAgent, options);
|
|
1510
|
+
const candidates = getCandidateAgentsForScope(options);
|
|
1511
|
+
const coHosted = [];
|
|
1512
|
+
for (const candidateType of candidates) {
|
|
1513
|
+
if (candidateType === agentType) continue;
|
|
1514
|
+
const candidateConfig = getMcpAgentConfig(candidateType);
|
|
1515
|
+
const candidateTarget = resolveMcpConfigTarget(candidateConfig, options);
|
|
1516
|
+
if (candidateTarget.configPath === currentTarget.configPath && candidateTarget.configKey === currentTarget.configKey) {
|
|
1517
|
+
coHosted.push(candidateType);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
return coHosted;
|
|
1521
|
+
}
|
|
1522
|
+
/**
|
|
1523
|
+
* Resolves configuration clusters for a given list of requested agents.
|
|
1524
|
+
* Groups requested agents sharing the same physical config path, and tracks
|
|
1525
|
+
* any remaining co-hosted agents sharing the same target that were not in the request.
|
|
1526
|
+
*/
|
|
1527
|
+
resolveConfigClusters(agentTypes, options = {}) {
|
|
1528
|
+
const clustersByPath = /* @__PURE__ */ new Map();
|
|
1529
|
+
for (const agentType of agentTypes) {
|
|
1530
|
+
const agentConfig = getMcpAgentConfig(agentType);
|
|
1531
|
+
const target = resolveMcpConfigTarget(agentConfig, options);
|
|
1532
|
+
let keyMap = clustersByPath.get(target.configPath);
|
|
1533
|
+
if (!keyMap) {
|
|
1534
|
+
keyMap = /* @__PURE__ */ new Map();
|
|
1535
|
+
clustersByPath.set(target.configPath, keyMap);
|
|
1536
|
+
}
|
|
1537
|
+
let cluster = keyMap.get(target.configKey);
|
|
1538
|
+
if (!cluster) {
|
|
1539
|
+
const allCoHosted = this.getCoHostedAgents(agentType, options);
|
|
1540
|
+
cluster = {
|
|
1541
|
+
configPath: target.configPath,
|
|
1542
|
+
configKey: target.configKey,
|
|
1543
|
+
targetAgents: [],
|
|
1544
|
+
coHostedAgents: allCoHosted
|
|
1545
|
+
};
|
|
1546
|
+
keyMap.set(target.configKey, cluster);
|
|
1547
|
+
}
|
|
1548
|
+
if (!cluster.targetAgents.includes(agentType)) {
|
|
1549
|
+
cluster.targetAgents.push(agentType);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
const clusters = [];
|
|
1553
|
+
for (const keyMap of clustersByPath.values()) {
|
|
1554
|
+
for (const cluster of keyMap.values()) {
|
|
1555
|
+
cluster.coHostedAgents = cluster.coHostedAgents.filter(
|
|
1556
|
+
(co) => !cluster.targetAgents.includes(co)
|
|
1557
|
+
);
|
|
1558
|
+
clusters.push(cluster);
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
return clusters;
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Sorts agent types so that agents sharing the same physical config target
|
|
1565
|
+
* appear adjacent to each other in the returned array.
|
|
1566
|
+
*/
|
|
1567
|
+
sortAgentsByClusters(agentTypes, options = {}) {
|
|
1568
|
+
const clusters = this.resolveConfigClusters(agentTypes, options);
|
|
1569
|
+
const sorted = [];
|
|
1570
|
+
for (const cluster of clusters) {
|
|
1571
|
+
for (const agent of cluster.targetAgents) {
|
|
1572
|
+
if (!sorted.includes(agent)) {
|
|
1573
|
+
sorted.push(agent);
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
return sorted;
|
|
1578
|
+
}
|
|
1579
|
+
/**
|
|
1580
|
+
* Alias for sortAgentsByClusters for backward compatibility.
|
|
1581
|
+
*/
|
|
1582
|
+
sortAgentsWithClusters(agentTypes, options = {}) {
|
|
1583
|
+
return this.sortAgentsByClusters(agentTypes, options);
|
|
1584
|
+
}
|
|
1585
|
+
// ---- Batch operations with automatic clustering & dialect transforms ----
|
|
1586
|
+
/**
|
|
1587
|
+
* Batch write: transforms and writes a server config to multiple agents,
|
|
1588
|
+
* with automatic cluster deduplication, dialect transform, and co-hosted awareness.
|
|
1589
|
+
* Callers pass standard McpServerConfig; the Store applies per-Agent dialect transforms
|
|
1590
|
+
* internally before persisting.
|
|
1591
|
+
*/
|
|
1592
|
+
writeServers(agents, serverName, serverConfig, options = {}) {
|
|
1593
|
+
const clusters = this.resolveConfigClusters(agents, options);
|
|
1594
|
+
const resultsByAgent = /* @__PURE__ */ new Map();
|
|
1595
|
+
const isGlobal = options.global ?? false;
|
|
1596
|
+
for (const cluster of clusters) {
|
|
1597
|
+
const primaryAgentType = cluster.targetAgents[0];
|
|
1598
|
+
const primaryAgent = getMcpAgentConfig(primaryAgentType);
|
|
1599
|
+
try {
|
|
1600
|
+
const transformed = transformServerConfigForAgent(primaryAgent, serverName, serverConfig, {
|
|
1601
|
+
global: isGlobal
|
|
1602
|
+
});
|
|
1603
|
+
const descriptor = this.resolveDescriptor(primaryAgent, options);
|
|
1604
|
+
this.adapter.writeServer(descriptor, serverName, transformed);
|
|
1605
|
+
for (const agentType of cluster.targetAgents) {
|
|
1606
|
+
resultsByAgent.set(agentType, {
|
|
1607
|
+
agent: agentType,
|
|
1608
|
+
success: true,
|
|
1609
|
+
path: cluster.configPath,
|
|
1610
|
+
coConfiguredAgents: cluster.coHostedAgents.length > 0 ? cluster.coHostedAgents : void 0
|
|
1611
|
+
});
|
|
1612
|
+
}
|
|
1613
|
+
} catch (error) {
|
|
1614
|
+
const errorMsg = toErrorMessage(error);
|
|
1615
|
+
for (const agentType of cluster.targetAgents) {
|
|
1616
|
+
resultsByAgent.set(agentType, {
|
|
1617
|
+
agent: agentType,
|
|
1618
|
+
success: false,
|
|
1619
|
+
path: cluster.configPath,
|
|
1620
|
+
error: errorMsg
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
return agents.map((agentType) => resultsByAgent.get(agentType));
|
|
1626
|
+
}
|
|
1627
|
+
/**
|
|
1628
|
+
* Batch remove: removes a server from multiple agents' configs,
|
|
1629
|
+
* with automatic cluster deduplication and co-hosted awareness.
|
|
1630
|
+
*/
|
|
1631
|
+
removeServers(agents, serverName, options = {}) {
|
|
1632
|
+
const clusters = this.resolveConfigClusters(agents, options);
|
|
1633
|
+
const resultsByAgent = /* @__PURE__ */ new Map();
|
|
1634
|
+
for (const cluster of clusters) {
|
|
1635
|
+
const primaryAgentType = cluster.targetAgents[0];
|
|
1636
|
+
const primaryAgent = getMcpAgentConfig(primaryAgentType);
|
|
1637
|
+
try {
|
|
1638
|
+
const { removed } = this.removeServer(primaryAgent, serverName, options);
|
|
1639
|
+
for (const agentType of cluster.targetAgents) {
|
|
1640
|
+
resultsByAgent.set(agentType, {
|
|
1641
|
+
agent: agentType,
|
|
1642
|
+
path: cluster.configPath,
|
|
1643
|
+
removed,
|
|
1644
|
+
coAffectedAgents: removed && cluster.coHostedAgents.length > 0 ? cluster.coHostedAgents : void 0
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
} catch (error) {
|
|
1648
|
+
const errorMsg = toErrorMessage(error);
|
|
1649
|
+
for (const agentType of cluster.targetAgents) {
|
|
1650
|
+
resultsByAgent.set(agentType, {
|
|
1651
|
+
agent: agentType,
|
|
1652
|
+
path: cluster.configPath,
|
|
1653
|
+
removed: false,
|
|
1654
|
+
error: errorMsg
|
|
1655
|
+
});
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
return agents.map((agentType) => resultsByAgent.get(agentType));
|
|
1660
|
+
}
|
|
1661
|
+
};
|
|
1662
|
+
var agentConfigStore = new AgentConfigStore();
|
|
1663
|
+
|
|
1664
|
+
// src/resolve-config-clusters.ts
|
|
1665
|
+
var getCoHostedAgents = (agentType, options = {}) => agentConfigStore.getCoHostedAgents(agentType, options);
|
|
1666
|
+
var resolveConfigClusters = (agentTypes, options = {}) => agentConfigStore.resolveConfigClusters(agentTypes, options);
|
|
1667
|
+
var sortAgentsByClusters = (agentTypes, options = {}) => agentConfigStore.sortAgentsByClusters(agentTypes, options);
|
|
1668
|
+
|
|
1669
|
+
// src/utils/parse-mcp-agent-list.ts
|
|
1670
|
+
var parseMcpAgentList = (input) => {
|
|
1671
|
+
if (!input || input.length === 0) return void 0;
|
|
1672
|
+
if (input.includes("*")) return getMcpAgentTypes();
|
|
1673
|
+
const resolved = [];
|
|
1674
|
+
for (const value of input) {
|
|
1675
|
+
const agentType = resolveMcpAgentAlias(value);
|
|
1676
|
+
if (!agentType) throw new Error(`Unknown MCP agent "${value}"`);
|
|
1677
|
+
resolved.push(agentType);
|
|
1678
|
+
}
|
|
1679
|
+
return resolved;
|
|
1680
|
+
};
|
|
1681
|
+
|
|
1682
|
+
// src/resolve-target-agents.ts
|
|
1683
|
+
var normalizeRequestedAgents = (input) => {
|
|
1684
|
+
if (!input || input.length === 0) return void 0;
|
|
1685
|
+
const rawList = [...input];
|
|
1686
|
+
if (rawList.every((item) => isMcpAgentType(item))) {
|
|
1687
|
+
return rawList;
|
|
1688
|
+
}
|
|
1689
|
+
return parseMcpAgentList(rawList);
|
|
1690
|
+
};
|
|
1691
|
+
var resolveTargetAgents = (query = {}) => {
|
|
1692
|
+
const cwd = query.cwd ?? process.cwd();
|
|
1693
|
+
const isGlobal = query.global ?? false;
|
|
1694
|
+
let explicitAgents = normalizeRequestedAgents(query.requested);
|
|
1474
1695
|
if (query.all) {
|
|
1475
1696
|
explicitAgents = getMcpAgentTypes();
|
|
1476
1697
|
}
|
|
@@ -1516,117 +1737,41 @@ var resolveTargetAgents = (query = {}) => {
|
|
|
1516
1737
|
};
|
|
1517
1738
|
};
|
|
1518
1739
|
|
|
1519
|
-
// src/
|
|
1520
|
-
var
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
var PATH_SEPARATOR_REGEX = /[/\\]/;
|
|
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);
|
|
1542
|
-
const basename = segments[segments.length - 1];
|
|
1543
|
-
return basename || input7;
|
|
1740
|
+
// src/install-compat.ts
|
|
1741
|
+
var installMcpServerForAgent = (serverName, serverConfig, agentType, options = {}) => {
|
|
1742
|
+
const results = agentConfigStore.writeServers([agentType], serverName, serverConfig, options);
|
|
1743
|
+
return results[0];
|
|
1544
1744
|
};
|
|
1545
|
-
var
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1745
|
+
var installMcpServerForAgents = (serverName, serverConfig, agentTypes, options = {}) => {
|
|
1746
|
+
return agentConfigStore.writeServers(agentTypes, serverName, serverConfig, options);
|
|
1747
|
+
};
|
|
1748
|
+
var installToCompatibleAgents = (serverName, serverConfig, options) => {
|
|
1749
|
+
const { allAgents, incompatible = [], global: isGlobal, cwd } = options;
|
|
1750
|
+
const incompatibleMap = new Map(incompatible.map((item) => [item.agent, item.reason]));
|
|
1751
|
+
const compatibleAgents = allAgents.filter((a) => !incompatibleMap.has(a));
|
|
1752
|
+
const installedResults = agentConfigStore.writeServers(
|
|
1753
|
+
compatibleAgents,
|
|
1754
|
+
serverName,
|
|
1755
|
+
serverConfig,
|
|
1756
|
+
{
|
|
1757
|
+
global: isGlobal,
|
|
1758
|
+
cwd
|
|
1554
1759
|
}
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1760
|
+
);
|
|
1761
|
+
const installedMap = new Map(installedResults.map((r) => [r.agent, r]));
|
|
1762
|
+
return allAgents.map((agentType) => {
|
|
1763
|
+
const incompatibleReason = incompatibleMap.get(agentType);
|
|
1764
|
+
if (incompatibleReason) {
|
|
1765
|
+
return {
|
|
1766
|
+
agent: agentType,
|
|
1767
|
+
success: false,
|
|
1768
|
+
path: "",
|
|
1769
|
+
error: incompatibleReason
|
|
1770
|
+
};
|
|
1560
1771
|
}
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
};
|
|
1564
|
-
var inferNameFromUrl = (input7) => {
|
|
1565
|
-
try {
|
|
1566
|
-
const url = new URL(input7);
|
|
1567
|
-
const host = url.hostname;
|
|
1568
|
-
const labels = host.split(".").filter((segment) => segment.length > 0);
|
|
1569
|
-
if (labels.length === 0) return MCP_DEFAULT_SERVER_NAME;
|
|
1570
|
-
const meaningfulLabels = labels.filter((label) => {
|
|
1571
|
-
const lower = label.toLowerCase();
|
|
1572
|
-
if (COMMON_TLD_LABELS.has(lower)) return false;
|
|
1573
|
-
if (GENERIC_HOST_PREFIXES.has(lower)) return false;
|
|
1574
|
-
return true;
|
|
1575
|
-
});
|
|
1576
|
-
if (meaningfulLabels.length > 0) return meaningfulLabels[0];
|
|
1577
|
-
if (labels.length >= 2) return labels[labels.length - 2];
|
|
1578
|
-
return labels[labels.length - 1] || MCP_DEFAULT_SERVER_NAME;
|
|
1579
|
-
} catch {
|
|
1580
|
-
return MCP_DEFAULT_SERVER_NAME;
|
|
1581
|
-
}
|
|
1582
|
-
};
|
|
1583
|
-
var inferNameFromCommand = (command) => {
|
|
1584
|
-
const tokens = command.trim().split(/\s+/);
|
|
1585
|
-
const runnerBase = tokens[0]?.split(PATH_SEPARATOR_REGEX).pop() ?? "";
|
|
1586
|
-
const startIndex = KNOWN_COMMAND_RUNNERS.has(runnerBase) ? 1 : 0;
|
|
1587
|
-
for (let tokenIndex = startIndex; tokenIndex < tokens.length; tokenIndex += 1) {
|
|
1588
|
-
const token = tokens[tokenIndex];
|
|
1589
|
-
if (!token || token.startsWith("-")) continue;
|
|
1590
|
-
return extractPackageName(token);
|
|
1591
|
-
}
|
|
1592
|
-
const firstNonFlag = tokens.find((token) => !token.startsWith("-"));
|
|
1593
|
-
return firstNonFlag ? extractPackageName(firstNonFlag) : MCP_DEFAULT_SERVER_NAME;
|
|
1594
|
-
};
|
|
1595
|
-
var parseMcpSource = (input7) => {
|
|
1596
|
-
const trimmed = input7.trim();
|
|
1597
|
-
if (trimmed.length === 0) {
|
|
1598
|
-
throw new Error(
|
|
1599
|
-
"Invalid MCP source: input is empty. Expected a remote URL, an npm package, or a command line."
|
|
1600
|
-
);
|
|
1601
|
-
}
|
|
1602
|
-
if (REMOTE_URL_REGEX.test(trimmed)) {
|
|
1603
|
-
return {
|
|
1604
|
-
type: "remote",
|
|
1605
|
-
value: trimmed,
|
|
1606
|
-
inferredName: inferNameFromUrl(trimmed)
|
|
1607
|
-
};
|
|
1608
|
-
}
|
|
1609
|
-
if (HAS_WHITESPACE_REGEX.test(trimmed)) {
|
|
1610
|
-
return {
|
|
1611
|
-
type: "command",
|
|
1612
|
-
value: trimmed,
|
|
1613
|
-
inferredName: inferNameFromCommand(trimmed)
|
|
1614
|
-
};
|
|
1615
|
-
}
|
|
1616
|
-
if (PACKAGE_NAME_REGEX.test(trimmed)) {
|
|
1617
|
-
return {
|
|
1618
|
-
type: "package",
|
|
1619
|
-
value: trimmed,
|
|
1620
|
-
inferredName: extractPackageName(trimmed)
|
|
1621
|
-
};
|
|
1622
|
-
}
|
|
1623
|
-
return {
|
|
1624
|
-
type: "command",
|
|
1625
|
-
value: trimmed,
|
|
1626
|
-
inferredName: inferNameFromCommand(trimmed)
|
|
1627
|
-
};
|
|
1772
|
+
return installedMap.get(agentType);
|
|
1773
|
+
});
|
|
1628
1774
|
};
|
|
1629
|
-
var isRemoteMcpSource = (parsed) => parsed.type === "remote";
|
|
1630
1775
|
|
|
1631
1776
|
// src/install-mcp-server.ts
|
|
1632
1777
|
var installMcpServer = (options) => {
|
|
@@ -1660,15 +1805,14 @@ var installMcpServer = (options) => {
|
|
|
1660
1805
|
var listInstalledMcpServers = (options = {}) => {
|
|
1661
1806
|
const agentTypes = options.agents ?? getMcpAgentTypes();
|
|
1662
1807
|
const collected = [];
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
for (const [serverName, rawConfig] of Object.entries(servers)) {
|
|
1808
|
+
const results = agentConfigStore.listServersForAgents(agentTypes, options);
|
|
1809
|
+
for (const item of results) {
|
|
1810
|
+
if (!item.exists) continue;
|
|
1811
|
+
for (const [serverName, rawConfig] of Object.entries(item.servers)) {
|
|
1668
1812
|
collected.push({
|
|
1669
1813
|
serverName,
|
|
1670
|
-
agent:
|
|
1671
|
-
path,
|
|
1814
|
+
agent: item.agent,
|
|
1815
|
+
path: item.path,
|
|
1672
1816
|
config: rawConfig,
|
|
1673
1817
|
serverConfig: parseServerConfig(rawConfig)
|
|
1674
1818
|
});
|
|
@@ -1676,29 +1820,83 @@ var listInstalledMcpServers = (options = {}) => {
|
|
|
1676
1820
|
}
|
|
1677
1821
|
return collected;
|
|
1678
1822
|
};
|
|
1823
|
+
var groupInstalledServersByName = (installed) => {
|
|
1824
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
1825
|
+
for (const item of installed) {
|
|
1826
|
+
const itemConfig = item.serverConfig ?? parseServerConfig(item.config);
|
|
1827
|
+
let entry = grouped.get(item.serverName);
|
|
1828
|
+
if (!entry) {
|
|
1829
|
+
entry = {
|
|
1830
|
+
serverName: item.serverName,
|
|
1831
|
+
agents: [],
|
|
1832
|
+
paths: [],
|
|
1833
|
+
config: itemConfig,
|
|
1834
|
+
hasDivergence: false
|
|
1835
|
+
};
|
|
1836
|
+
grouped.set(item.serverName, entry);
|
|
1837
|
+
} else if (!entry.hasDivergence) {
|
|
1838
|
+
if (JSON.stringify(entry.config) !== JSON.stringify(itemConfig)) {
|
|
1839
|
+
entry.hasDivergence = true;
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
if (!entry.agents.includes(item.agent)) {
|
|
1843
|
+
entry.agents.push(item.agent);
|
|
1844
|
+
}
|
|
1845
|
+
if (!entry.paths.includes(item.path)) {
|
|
1846
|
+
entry.paths.push(item.path);
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
return grouped;
|
|
1850
|
+
};
|
|
1851
|
+
var queryGroupedInstalledServers = (options = {}) => {
|
|
1852
|
+
const installed = listInstalledMcpServers(options);
|
|
1853
|
+
return groupInstalledServersByName(installed);
|
|
1854
|
+
};
|
|
1679
1855
|
|
|
1680
|
-
// src/
|
|
1681
|
-
var
|
|
1682
|
-
const
|
|
1683
|
-
const
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
const
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
};
|
|
1856
|
+
// src/update-mcp-server.ts
|
|
1857
|
+
var updateMcpServer = (options) => {
|
|
1858
|
+
const isGlobal = options.global ?? false;
|
|
1859
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1860
|
+
let previousConfig = options.previousConfig;
|
|
1861
|
+
if (!previousConfig) {
|
|
1862
|
+
const existing = listInstalledMcpServers({
|
|
1863
|
+
global: isGlobal,
|
|
1864
|
+
cwd,
|
|
1865
|
+
agents: options.agents
|
|
1866
|
+
});
|
|
1867
|
+
const found = existing.find((s) => s.serverName === options.serverName && s.serverConfig);
|
|
1868
|
+
if (found) {
|
|
1869
|
+
previousConfig = found.serverConfig;
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
const serverConfig = sanitizeUpdatedServerConfig(options.config, previousConfig);
|
|
1873
|
+
let targetAgents = options.agents;
|
|
1874
|
+
if (!targetAgents || targetAgents.length === 0) {
|
|
1875
|
+
const existing = listInstalledMcpServers({ global: isGlobal, cwd });
|
|
1876
|
+
targetAgents = existing.filter((s) => s.serverName === options.serverName).map((s) => s.agent);
|
|
1700
1877
|
}
|
|
1878
|
+
const requestedTransport = serverConfig.url ? serverConfig.type ?? "http" : "stdio";
|
|
1879
|
+
const { allAgents, incompatible } = resolveTargetAgents({
|
|
1880
|
+
requested: targetAgents,
|
|
1881
|
+
global: isGlobal,
|
|
1882
|
+
cwd,
|
|
1883
|
+
transport: requestedTransport
|
|
1884
|
+
});
|
|
1885
|
+
const results = installToCompatibleAgents(options.serverName, serverConfig, {
|
|
1886
|
+
allAgents,
|
|
1887
|
+
incompatible,
|
|
1888
|
+
global: isGlobal,
|
|
1889
|
+
cwd
|
|
1890
|
+
});
|
|
1891
|
+
return {
|
|
1892
|
+
serverName: options.serverName,
|
|
1893
|
+
config: serverConfig,
|
|
1894
|
+
results,
|
|
1895
|
+
incompatible
|
|
1896
|
+
};
|
|
1701
1897
|
};
|
|
1898
|
+
|
|
1899
|
+
// src/remove.ts
|
|
1702
1900
|
var removeMcpServer = (options) => {
|
|
1703
1901
|
const { allAgents } = resolveTargetAgents({
|
|
1704
1902
|
requested: options.agents,
|
|
@@ -1706,549 +1904,13 @@ var removeMcpServer = (options) => {
|
|
|
1706
1904
|
global: options.global,
|
|
1707
1905
|
cwd: options.cwd
|
|
1708
1906
|
});
|
|
1709
|
-
const
|
|
1907
|
+
const storeResults = agentConfigStore.removeServers(allAgents, options.name, {
|
|
1710
1908
|
global: options.global,
|
|
1711
1909
|
cwd: options.cwd
|
|
1712
1910
|
});
|
|
1713
|
-
|
|
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
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
return results;
|
|
1911
|
+
return storeResults.filter((r) => r.removed || Boolean(r.error));
|
|
1745
1912
|
};
|
|
1746
1913
|
|
|
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
|
-
|
|
1846
|
-
// src/interactive/main-menu.ts
|
|
1847
|
-
var import_prompts10 = require("@inquirer/prompts");
|
|
1848
|
-
var import_picocolors15 = __toESM(require("picocolors"), 1);
|
|
1849
|
-
|
|
1850
|
-
// src/interactive/wizard-add.ts
|
|
1851
|
-
var import_prompts7 = require("@inquirer/prompts");
|
|
1852
|
-
var import_picocolors11 = __toESM(require("picocolors"), 1);
|
|
1853
|
-
|
|
1854
|
-
// src/utils/co-hosted-feedback.ts
|
|
1855
|
-
var import_picocolors2 = __toESM(require("picocolors"), 1);
|
|
1856
|
-
|
|
1857
|
-
// src/utils/logger.ts
|
|
1858
|
-
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
1859
|
-
var logger = {
|
|
1860
|
-
info: (message) => {
|
|
1861
|
-
console.log(import_picocolors.default.cyan("i"), message);
|
|
1862
|
-
},
|
|
1863
|
-
success: (message) => {
|
|
1864
|
-
console.log(import_picocolors.default.green("\u221A"), message);
|
|
1865
|
-
},
|
|
1866
|
-
warn: (message) => {
|
|
1867
|
-
console.log(import_picocolors.default.yellow("!"), message);
|
|
1868
|
-
},
|
|
1869
|
-
error: (message) => {
|
|
1870
|
-
console.error(import_picocolors.default.red("x"), message);
|
|
1871
|
-
}
|
|
1872
|
-
};
|
|
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
|
-
|
|
1888
|
-
// src/interactive/prompts/agents.ts
|
|
1889
|
-
var import_picocolors6 = __toESM(require("picocolors"), 1);
|
|
1890
|
-
|
|
1891
|
-
// src/interactive/utils/build-linked-agent-choices.ts
|
|
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
|
-
);
|
|
2133
|
-
|
|
2134
|
-
// src/interactive/prompts/scope.ts
|
|
2135
|
-
var import_prompts = require("@inquirer/prompts");
|
|
2136
|
-
var import_picocolors5 = __toESM(require("picocolors"), 1);
|
|
2137
|
-
var promptScope = async (options = {}) => {
|
|
2138
|
-
const initialGlobal = options.defaultGlobal ?? options.global;
|
|
2139
|
-
if (initialGlobal !== void 0) {
|
|
2140
|
-
return initialGlobal;
|
|
2141
|
-
}
|
|
2142
|
-
const cwd = options.cwd ?? process.cwd();
|
|
2143
|
-
return (0, import_prompts.select)({
|
|
2144
|
-
message: options.message ?? "Select MCP scope:",
|
|
2145
|
-
choices: [
|
|
2146
|
-
{
|
|
2147
|
-
name: `Current Project - ${import_picocolors5.default.dim(cwd)}`,
|
|
2148
|
-
value: false
|
|
2149
|
-
},
|
|
2150
|
-
{
|
|
2151
|
-
name: `Global User Config - ${import_picocolors5.default.dim("applies across all projects")}`,
|
|
2152
|
-
value: true
|
|
2153
|
-
}
|
|
2154
|
-
]
|
|
2155
|
-
});
|
|
2156
|
-
};
|
|
2157
|
-
|
|
2158
|
-
// src/interactive/prompts/agents.ts
|
|
2159
|
-
var promptScopeAndAgents = async (options = {}) => {
|
|
2160
|
-
const cwd = options.cwd ?? process.cwd();
|
|
2161
|
-
const isGlobal = await promptScope({
|
|
2162
|
-
cwd,
|
|
2163
|
-
defaultGlobal: options.defaultGlobal,
|
|
2164
|
-
message: "Select MCP installation scope:"
|
|
2165
|
-
});
|
|
2166
|
-
const resolution = resolveTargetAgents({
|
|
2167
|
-
global: isGlobal,
|
|
2168
|
-
cwd
|
|
2169
|
-
});
|
|
2170
|
-
const detected = resolution.detected;
|
|
2171
|
-
const rawAvailable = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
|
|
2172
|
-
const availableAgentTypes = sortAgentsWithClusters(rawAvailable, { global: isGlobal, cwd });
|
|
2173
|
-
if (detected.length > 0) {
|
|
2174
|
-
logger.info(
|
|
2175
|
-
`Detected configured agents: ${import_picocolors6.default.cyan(detected.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
|
|
2176
|
-
);
|
|
2177
|
-
} else {
|
|
2178
|
-
logger.warn(`No active ${isGlobal ? "global" : "project"} agents detected`);
|
|
2179
|
-
}
|
|
2180
|
-
const defaultChecked = options.defaultAgents && options.defaultAgents.length > 0 ? options.defaultAgents : detected;
|
|
2181
|
-
const choices = buildLinkedAgentChoices({
|
|
2182
|
-
agents: availableAgentTypes,
|
|
2183
|
-
checkedAgents: defaultChecked,
|
|
2184
|
-
detectedAgents: detected,
|
|
2185
|
-
scopeOptions: { global: isGlobal, cwd }
|
|
2186
|
-
});
|
|
2187
|
-
const selectedAgents = await linkedCheckbox({
|
|
2188
|
-
message: "Select target agents (Space to select, Enter to confirm):",
|
|
2189
|
-
choices,
|
|
2190
|
-
validate: (chosen) => {
|
|
2191
|
-
if (chosen.length === 0) {
|
|
2192
|
-
return "Please select at least one agent";
|
|
2193
|
-
}
|
|
2194
|
-
return true;
|
|
2195
|
-
}
|
|
2196
|
-
});
|
|
2197
|
-
return {
|
|
2198
|
-
global: isGlobal,
|
|
2199
|
-
agents: selectedAgents
|
|
2200
|
-
};
|
|
2201
|
-
};
|
|
2202
|
-
|
|
2203
|
-
// src/interactive/prompts/args.ts
|
|
2204
|
-
var import_prompts2 = require("@inquirer/prompts");
|
|
2205
|
-
var parseArgsString = (rawText) => {
|
|
2206
|
-
const matches = rawText.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g);
|
|
2207
|
-
if (!matches) return [];
|
|
2208
|
-
return matches.map((arg) => {
|
|
2209
|
-
if (arg.startsWith('"') && arg.endsWith('"') || arg.startsWith("'") && arg.endsWith("'")) {
|
|
2210
|
-
return arg.slice(1, -1);
|
|
2211
|
-
}
|
|
2212
|
-
return arg;
|
|
2213
|
-
});
|
|
2214
|
-
};
|
|
2215
|
-
var promptArgsConfig = async (initialArgs = []) => {
|
|
2216
|
-
if (initialArgs.length > 0) {
|
|
2217
|
-
return initialArgs;
|
|
2218
|
-
}
|
|
2219
|
-
const needArgs = await (0, import_prompts2.confirm)({
|
|
2220
|
-
message: "Configure command arguments (e.g. file paths, connection strings)?",
|
|
2221
|
-
default: false
|
|
2222
|
-
});
|
|
2223
|
-
if (!needArgs) {
|
|
2224
|
-
return [];
|
|
2225
|
-
}
|
|
2226
|
-
const raw = await (0, import_prompts2.input)({
|
|
2227
|
-
message: "Enter command arguments (space-separated, wrap paths with spaces in quotes):",
|
|
2228
|
-
validate: (val) => val.trim() ? true : "Arguments cannot be empty"
|
|
2229
|
-
});
|
|
2230
|
-
return parseArgsString(raw.trim());
|
|
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
|
-
};
|
|
2247
|
-
|
|
2248
|
-
// src/interactive/prompts/env.ts
|
|
2249
|
-
var import_prompts5 = require("@inquirer/prompts");
|
|
2250
|
-
var import_picocolors9 = __toESM(require("picocolors"), 1);
|
|
2251
|
-
|
|
2252
1914
|
// src/utils/mask-secret.ts
|
|
2253
1915
|
var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
|
|
2254
1916
|
var maskSecretValue = (key, value) => {
|
|
@@ -2264,1431 +1926,25 @@ var maskSecretHeader = (key, value) => {
|
|
|
2264
1926
|
}
|
|
2265
1927
|
return `${value.slice(0, 4)}***${value.slice(-3)}`;
|
|
2266
1928
|
};
|
|
2267
|
-
|
|
2268
|
-
// src/interactive/prompts/kv.ts
|
|
2269
|
-
var import_prompts4 = require("@inquirer/prompts");
|
|
2270
|
-
var import_picocolors8 = __toESM(require("picocolors"), 1);
|
|
2271
|
-
|
|
2272
|
-
// src/interactive/prompts/multiline.ts
|
|
2273
|
-
var import_node_readline = require("readline");
|
|
2274
|
-
var import_prompts3 = require("@inquirer/prompts");
|
|
2275
|
-
var import_picocolors7 = __toESM(require("picocolors"), 1);
|
|
2276
|
-
var readMultilineTextFromTerminal = async (message, endHint = "When done pasting, enter END on a new line or press Enter twice to finish") => {
|
|
2277
|
-
console.log(import_picocolors7.default.cyan(`
|
|
2278
|
-
${message}`));
|
|
2279
|
-
console.log(import_picocolors7.default.dim(` (Hint: ${endHint})
|
|
2280
|
-
`));
|
|
2281
|
-
return new Promise((resolve) => {
|
|
2282
|
-
const rl = (0, import_node_readline.createInterface)({
|
|
2283
|
-
input: process.stdin,
|
|
2284
|
-
output: process.stdout
|
|
2285
|
-
});
|
|
2286
|
-
const lines = [];
|
|
2287
|
-
let consecutiveEmpty = 0;
|
|
2288
|
-
const cleanup = () => {
|
|
2289
|
-
rl.removeAllListeners();
|
|
2290
|
-
rl.close();
|
|
2291
|
-
};
|
|
2292
|
-
rl.on("line", (line) => {
|
|
2293
|
-
const trimmed = line.trim();
|
|
2294
|
-
if (trimmed === "END") {
|
|
2295
|
-
cleanup();
|
|
2296
|
-
resolve(lines.join("\n"));
|
|
2297
|
-
return;
|
|
2298
|
-
}
|
|
2299
|
-
if (line === "") {
|
|
2300
|
-
consecutiveEmpty++;
|
|
2301
|
-
if (lines.length > 0) {
|
|
2302
|
-
cleanup();
|
|
2303
|
-
resolve(lines.join("\n"));
|
|
2304
|
-
return;
|
|
2305
|
-
}
|
|
2306
|
-
if (consecutiveEmpty >= 2) {
|
|
2307
|
-
cleanup();
|
|
2308
|
-
resolve("");
|
|
2309
|
-
return;
|
|
2310
|
-
}
|
|
2311
|
-
} else {
|
|
2312
|
-
consecutiveEmpty = 0;
|
|
2313
|
-
lines.push(line);
|
|
2314
|
-
}
|
|
2315
|
-
});
|
|
2316
|
-
rl.on("close", () => {
|
|
2317
|
-
resolve(lines.join("\n"));
|
|
2318
|
-
});
|
|
2319
|
-
});
|
|
2320
|
-
};
|
|
2321
|
-
var promptEditorText = async (options) => {
|
|
2322
|
-
try {
|
|
2323
|
-
return await (0, import_prompts3.editor)({
|
|
2324
|
-
message: options.message,
|
|
2325
|
-
default: options.defaultText ?? "",
|
|
2326
|
-
postfix: options.postfix
|
|
2327
|
-
});
|
|
2328
|
-
} catch {
|
|
2329
|
-
return readMultilineTextFromTerminal(options.message);
|
|
2330
|
-
}
|
|
2331
|
-
};
|
|
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
|
-
|
|
2475
|
-
// src/interactive/prompts/env.ts
|
|
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
|
-
};
|
|
2484
|
-
var parseEnvText = (rawText) => {
|
|
2485
|
-
const result = {};
|
|
2486
|
-
const lines = rawText.split(/\r?\n/);
|
|
2487
|
-
for (const rawLine of lines) {
|
|
2488
|
-
let line = rawLine.trim();
|
|
2489
|
-
if (!line || line.startsWith("#")) continue;
|
|
2490
|
-
if (line.startsWith("export ")) {
|
|
2491
|
-
line = line.slice(7).trim();
|
|
2492
|
-
}
|
|
2493
|
-
const eqIndex = line.indexOf("=");
|
|
2494
|
-
if (eqIndex === -1) continue;
|
|
2495
|
-
const key = line.slice(0, eqIndex).trim();
|
|
2496
|
-
let value = line.slice(eqIndex + 1).trim();
|
|
2497
|
-
if (!key) continue;
|
|
2498
|
-
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
2499
|
-
value = value.slice(1, -1);
|
|
2500
|
-
}
|
|
2501
|
-
result[key] = value;
|
|
2502
|
-
}
|
|
2503
|
-
return result;
|
|
2504
|
-
};
|
|
2505
|
-
var promptEnvConfig = async (initialEnv = {}) => {
|
|
2506
|
-
const env = { ...initialEnv };
|
|
2507
|
-
const initialCount = Object.keys(env).length;
|
|
2508
|
-
if (initialCount > 0) {
|
|
2509
|
-
logger.info(`Includes ${import_picocolors9.default.cyan(String(initialCount))} preset environment variables`);
|
|
2510
|
-
}
|
|
2511
|
-
const mode = await (0, import_prompts5.select)({
|
|
2512
|
-
message: "Configure environment variables?",
|
|
2513
|
-
choices: [
|
|
2514
|
-
{
|
|
2515
|
-
name: "Skip / None",
|
|
2516
|
-
value: "skip"
|
|
2517
|
-
},
|
|
2518
|
-
{
|
|
2519
|
-
name: "Paste multiline .env text into terminal",
|
|
2520
|
-
value: "paste"
|
|
2521
|
-
},
|
|
2522
|
-
{
|
|
2523
|
-
name: "Open in system default editor ($EDITOR)",
|
|
2524
|
-
value: "editor"
|
|
2525
|
-
},
|
|
2526
|
-
{
|
|
2527
|
-
name: "Enter key-value pairs one by one",
|
|
2528
|
-
value: "manual"
|
|
2529
|
-
}
|
|
2530
|
-
]
|
|
2531
|
-
});
|
|
2532
|
-
if (mode === "skip") {
|
|
2533
|
-
return env;
|
|
2534
|
-
}
|
|
2535
|
-
if (mode === "paste" || mode === "editor") {
|
|
2536
|
-
const pasted = mode === "editor" ? await promptEditorText({
|
|
2537
|
-
message: "Paste or edit environment variables in editor, then save and exit:",
|
|
2538
|
-
postfix: ".env",
|
|
2539
|
-
defaultText: formatEnvText(env)
|
|
2540
|
-
}) : await readMultilineTextFromTerminal("Paste .env formatted content (multiline supported):");
|
|
2541
|
-
const parsed = parseEnvText(pasted);
|
|
2542
|
-
const count = Object.keys(parsed).length;
|
|
2543
|
-
if (count === 0) {
|
|
2544
|
-
logger.warn("No valid KEY=VALUE pairs recognized");
|
|
2545
|
-
} else {
|
|
2546
|
-
Object.assign(env, parsed);
|
|
2547
|
-
logger.success(`Successfully parsed ${import_picocolors9.default.cyan(String(count))} environment variables:`);
|
|
2548
|
-
for (const [k, v] of Object.entries(parsed)) {
|
|
2549
|
-
console.log(` ${import_picocolors9.default.bold(k)}=${import_picocolors9.default.dim(maskSecretValue(k, v))}`);
|
|
2550
|
-
}
|
|
2551
|
-
}
|
|
2552
|
-
return env;
|
|
2553
|
-
}
|
|
2554
|
-
logger.info("Entering environment variables (leave key empty and press enter to finish):");
|
|
2555
|
-
while (true) {
|
|
2556
|
-
const key = await (0, import_prompts5.input)({
|
|
2557
|
-
message: "Variable name (Key, leave empty to finish):",
|
|
2558
|
-
validate: (val2) => {
|
|
2559
|
-
const trimmed = val2.trim();
|
|
2560
|
-
if (!trimmed) return true;
|
|
2561
|
-
if (/\s/.test(trimmed)) return "Variable name cannot contain spaces";
|
|
2562
|
-
return true;
|
|
2563
|
-
}
|
|
2564
|
-
});
|
|
2565
|
-
const trimmedKey = key.trim();
|
|
2566
|
-
if (!trimmedKey) break;
|
|
2567
|
-
const isSecret = SECRET_KEY_PATTERN.test(trimmedKey);
|
|
2568
|
-
let val;
|
|
2569
|
-
if (isSecret) {
|
|
2570
|
-
val = await (0, import_prompts5.password)({
|
|
2571
|
-
message: `Value for (${trimmedKey}) [secret masked]:`,
|
|
2572
|
-
mask: "*"
|
|
2573
|
-
});
|
|
2574
|
-
} else {
|
|
2575
|
-
val = await (0, import_prompts5.input)({
|
|
2576
|
-
message: `Value for (${trimmedKey}):`
|
|
2577
|
-
});
|
|
2578
|
-
}
|
|
2579
|
-
env[trimmedKey] = val;
|
|
2580
|
-
logger.success(`Added: ${import_picocolors9.default.cyan(trimmedKey)}`);
|
|
2581
|
-
}
|
|
2582
|
-
return env;
|
|
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
|
-
});
|
|
2599
|
-
|
|
2600
|
-
// src/interactive/prompts/headers.ts
|
|
2601
|
-
var import_prompts6 = require("@inquirer/prompts");
|
|
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
|
-
};
|
|
2606
|
-
var parseHeadersText = (rawText) => {
|
|
2607
|
-
const result = {};
|
|
2608
|
-
const lines = rawText.split(/\r?\n/);
|
|
2609
|
-
for (const rawLine of lines) {
|
|
2610
|
-
const line = rawLine.trim();
|
|
2611
|
-
if (!line || line.startsWith("#")) continue;
|
|
2612
|
-
const colonIndex = line.indexOf(":");
|
|
2613
|
-
const equalIndex = line.indexOf("=");
|
|
2614
|
-
let splitIndex = -1;
|
|
2615
|
-
if (colonIndex !== -1 && equalIndex !== -1) {
|
|
2616
|
-
splitIndex = Math.min(colonIndex, equalIndex);
|
|
2617
|
-
} else if (colonIndex !== -1) {
|
|
2618
|
-
splitIndex = colonIndex;
|
|
2619
|
-
} else {
|
|
2620
|
-
splitIndex = equalIndex;
|
|
2621
|
-
}
|
|
2622
|
-
if (splitIndex === -1) continue;
|
|
2623
|
-
const key = line.slice(0, splitIndex).trim();
|
|
2624
|
-
let value = line.slice(splitIndex + 1).trim();
|
|
2625
|
-
if (!key) continue;
|
|
2626
|
-
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
2627
|
-
value = value.slice(1, -1);
|
|
2628
|
-
}
|
|
2629
|
-
result[key] = value;
|
|
2630
|
-
}
|
|
2631
|
-
return result;
|
|
2632
|
-
};
|
|
2633
|
-
var promptHeadersConfig = async (initialHeaders = {}) => {
|
|
2634
|
-
const headers = { ...initialHeaders };
|
|
2635
|
-
const mode = await (0, import_prompts6.select)({
|
|
2636
|
-
message: "Select HTTP headers configuration method:",
|
|
2637
|
-
choices: [
|
|
2638
|
-
{
|
|
2639
|
-
name: "Paste multiline headers into terminal (Key: Value format)",
|
|
2640
|
-
value: "paste"
|
|
2641
|
-
},
|
|
2642
|
-
{
|
|
2643
|
-
name: "Open in system default editor ($EDITOR)",
|
|
2644
|
-
value: "editor"
|
|
2645
|
-
},
|
|
2646
|
-
{
|
|
2647
|
-
name: "Enter headers one by one (e.g. Authorization: Bearer ...)",
|
|
2648
|
-
value: "manual"
|
|
2649
|
-
},
|
|
2650
|
-
{
|
|
2651
|
-
name: "Skip / None",
|
|
2652
|
-
value: "skip"
|
|
2653
|
-
}
|
|
2654
|
-
]
|
|
2655
|
-
});
|
|
2656
|
-
if (mode === "skip") {
|
|
2657
|
-
return headers;
|
|
2658
|
-
}
|
|
2659
|
-
if (mode === "paste" || mode === "editor") {
|
|
2660
|
-
const pasted = mode === "editor" ? await promptEditorText({
|
|
2661
|
-
message: "Paste or edit HTTP headers in editor, then save and exit:",
|
|
2662
|
-
defaultText: formatHeadersText(headers)
|
|
2663
|
-
}) : await readMultilineTextFromTerminal(
|
|
2664
|
-
"Paste HTTP headers content (multiline supported, e.g. Authorization: Bearer ...):"
|
|
2665
|
-
);
|
|
2666
|
-
const parsed = parseHeadersText(pasted);
|
|
2667
|
-
const count = Object.keys(parsed).length;
|
|
2668
|
-
if (count === 0) {
|
|
2669
|
-
logger.warn("No valid Key: Value pairs recognized");
|
|
2670
|
-
} else {
|
|
2671
|
-
Object.assign(headers, parsed);
|
|
2672
|
-
logger.success(`Successfully parsed ${import_picocolors10.default.cyan(String(count))} headers:`);
|
|
2673
|
-
for (const [k, v] of Object.entries(parsed)) {
|
|
2674
|
-
console.log(` ${import_picocolors10.default.bold(k)}: ${import_picocolors10.default.dim(maskSecretHeader(k, v))}`);
|
|
2675
|
-
}
|
|
2676
|
-
}
|
|
2677
|
-
return headers;
|
|
2678
|
-
}
|
|
2679
|
-
logger.info("Entering HTTP headers (leave header name empty and press enter to finish):");
|
|
2680
|
-
while (true) {
|
|
2681
|
-
const name = await (0, import_prompts6.input)({
|
|
2682
|
-
message: "Header name (e.g. Authorization, leave empty to finish):",
|
|
2683
|
-
validate: (val2) => {
|
|
2684
|
-
const trimmed = val2.trim();
|
|
2685
|
-
if (!trimmed) return true;
|
|
2686
|
-
if (/\s/.test(trimmed)) return "Header name cannot contain spaces";
|
|
2687
|
-
return true;
|
|
2688
|
-
}
|
|
2689
|
-
});
|
|
2690
|
-
const trimmedName = name.trim();
|
|
2691
|
-
if (!trimmedName) break;
|
|
2692
|
-
const isSecret = SECRET_HEADER_PATTERN.test(trimmedName);
|
|
2693
|
-
let val;
|
|
2694
|
-
if (isSecret) {
|
|
2695
|
-
val = await (0, import_prompts6.password)({
|
|
2696
|
-
message: `Header value for (${trimmedName}) [sensitive content masked]:`,
|
|
2697
|
-
mask: "*"
|
|
2698
|
-
});
|
|
2699
|
-
} else {
|
|
2700
|
-
val = await (0, import_prompts6.input)({
|
|
2701
|
-
message: `Header value for (${trimmedName}):`
|
|
2702
|
-
});
|
|
2703
|
-
}
|
|
2704
|
-
headers[trimmedName] = val;
|
|
2705
|
-
logger.success(`Added: ${import_picocolors10.default.cyan(trimmedName)}`);
|
|
2706
|
-
}
|
|
2707
|
-
return headers;
|
|
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
|
-
});
|
|
2723
|
-
|
|
2724
|
-
// src/interactive/wizard-add.ts
|
|
2725
|
-
var wizardAdd = async (initial = {}) => {
|
|
2726
|
-
const cwd = initial.cwd ?? process.cwd();
|
|
2727
|
-
logger.info(import_picocolors11.default.bold("Welcome to the MCP interactive add wizard"));
|
|
2728
|
-
let source = initial.source;
|
|
2729
|
-
if (!source) {
|
|
2730
|
-
const sourceType = await (0, import_prompts7.select)({
|
|
2731
|
-
message: "Select MCP server type:",
|
|
2732
|
-
choices: [
|
|
2733
|
-
{
|
|
2734
|
-
name: "npm package (run via npx)",
|
|
2735
|
-
value: "npm"
|
|
2736
|
-
},
|
|
2737
|
-
{
|
|
2738
|
-
name: "Remote MCP server (via HTTP / SSE URL)",
|
|
2739
|
-
value: "remote"
|
|
2740
|
-
},
|
|
2741
|
-
{
|
|
2742
|
-
name: "Local command / script / Docker (stdio)",
|
|
2743
|
-
value: "command"
|
|
2744
|
-
}
|
|
2745
|
-
]
|
|
2746
|
-
});
|
|
2747
|
-
if (sourceType === "npm") {
|
|
2748
|
-
source = await (0, import_prompts7.input)({
|
|
2749
|
-
message: "Enter npm package name (e.g. @modelcontextprotocol/server-postgres):",
|
|
2750
|
-
validate: (val) => val.trim() ? true : "Package name cannot be empty"
|
|
2751
|
-
});
|
|
2752
|
-
} else if (sourceType === "remote") {
|
|
2753
|
-
source = await (0, import_prompts7.input)({
|
|
2754
|
-
message: "Enter remote server URL (e.g. https://mcp.example.com/sse):",
|
|
2755
|
-
validate: (val) => {
|
|
2756
|
-
const trimmed = val.trim();
|
|
2757
|
-
if (!trimmed) return "URL cannot be empty";
|
|
2758
|
-
if (!/^https?:\/\//i.test(trimmed)) return "Please enter a valid URL starting with http:// or https://";
|
|
2759
|
-
return true;
|
|
2760
|
-
}
|
|
2761
|
-
});
|
|
2762
|
-
} else {
|
|
2763
|
-
source = await (0, import_prompts7.input)({
|
|
2764
|
-
message: "Enter command and arguments (e.g. python -m my_mcp_server or docker run ...):",
|
|
2765
|
-
validate: (val) => val.trim() ? true : "Command cannot be empty"
|
|
2766
|
-
});
|
|
2767
|
-
}
|
|
2768
|
-
}
|
|
2769
|
-
source = source.trim();
|
|
2770
|
-
const parsed = parseMcpSource(source);
|
|
2771
|
-
let serverName = initial.name;
|
|
2772
|
-
if (!serverName) {
|
|
2773
|
-
serverName = await (0, import_prompts7.input)({
|
|
2774
|
-
message: "MCP server name:",
|
|
2775
|
-
default: parsed.inferredName,
|
|
2776
|
-
validate: (val) => val.trim() ? true : "Server name cannot be empty"
|
|
2777
|
-
});
|
|
2778
|
-
}
|
|
2779
|
-
serverName = serverName.trim();
|
|
2780
|
-
let transport = initial.transport;
|
|
2781
|
-
let headers = initial.headers ?? {};
|
|
2782
|
-
if (parsed.type === "remote") {
|
|
2783
|
-
if (!transport) {
|
|
2784
|
-
const isSseUrl = /\/sse\b/i.test(parsed.value);
|
|
2785
|
-
transport = await (0, import_prompts7.select)({
|
|
2786
|
-
message: "Select remote transport protocol:",
|
|
2787
|
-
choices: [
|
|
2788
|
-
{ name: "HTTP", value: "http" },
|
|
2789
|
-
{ name: "SSE (Server-Sent Events)", value: "sse" }
|
|
2790
|
-
],
|
|
2791
|
-
default: isSseUrl ? "sse" : "http"
|
|
2792
|
-
});
|
|
2793
|
-
}
|
|
2794
|
-
if (Object.keys(headers).length === 0) {
|
|
2795
|
-
const needHeader = await (0, import_prompts7.confirm)({
|
|
2796
|
-
message: "Configure HTTP headers (e.g. Authorization Bearer token)?",
|
|
2797
|
-
default: false
|
|
2798
|
-
});
|
|
2799
|
-
if (needHeader) {
|
|
2800
|
-
headers = await promptHeadersConfig();
|
|
2801
|
-
}
|
|
2802
|
-
}
|
|
2803
|
-
}
|
|
2804
|
-
const { global: isGlobal, agents: selectedAgents } = await promptScopeAndAgents({
|
|
2805
|
-
cwd,
|
|
2806
|
-
defaultGlobal: initial.global,
|
|
2807
|
-
defaultAgents: initial.agents
|
|
2808
|
-
});
|
|
2809
|
-
let args = initial.args ?? [];
|
|
2810
|
-
if (parsed.type !== "remote") {
|
|
2811
|
-
args = await promptArgsConfig(args);
|
|
2812
|
-
}
|
|
2813
|
-
let env = initial.env ?? {};
|
|
2814
|
-
if (parsed.type !== "remote") {
|
|
2815
|
-
env = await promptEnvConfig(env);
|
|
2816
|
-
}
|
|
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(", "))}`);
|
|
2823
|
-
if (args.length > 0) {
|
|
2824
|
-
console.log(` ${import_picocolors11.default.bold("Arguments:")} ${import_picocolors11.default.dim(args.join(" "))}`);
|
|
2825
|
-
}
|
|
2826
|
-
if (transport) {
|
|
2827
|
-
console.log(` ${import_picocolors11.default.bold("Transport:")} ${import_picocolors11.default.magenta(transport)}`);
|
|
2828
|
-
}
|
|
2829
|
-
const envKeys = Object.keys(env);
|
|
2830
|
-
if (envKeys.length > 0) {
|
|
2831
|
-
console.log(` ${import_picocolors11.default.bold("Environment Variables:")} ${import_picocolors11.default.dim(envKeys.join(", "))} (${envKeys.length})`);
|
|
2832
|
-
}
|
|
2833
|
-
const headerKeys = Object.keys(headers);
|
|
2834
|
-
if (headerKeys.length > 0) {
|
|
2835
|
-
console.log(` ${import_picocolors11.default.bold("Headers:")} ${import_picocolors11.default.dim(headerKeys.join(", "))} (${headerKeys.length})`);
|
|
2836
|
-
}
|
|
2837
|
-
console.log();
|
|
2838
|
-
const proceed = await (0, import_prompts7.confirm)({
|
|
2839
|
-
message: "Confirm installation with this configuration?",
|
|
2840
|
-
default: true
|
|
2841
|
-
});
|
|
2842
|
-
if (!proceed) {
|
|
2843
|
-
logger.warn("Operation cancelled");
|
|
2844
|
-
return false;
|
|
2845
|
-
}
|
|
2846
|
-
const result = installMcpServer({
|
|
2847
|
-
source,
|
|
2848
|
-
name: serverName,
|
|
2849
|
-
agents: selectedAgents,
|
|
2850
|
-
args,
|
|
2851
|
-
global: isGlobal,
|
|
2852
|
-
cwd,
|
|
2853
|
-
transport,
|
|
2854
|
-
headers,
|
|
2855
|
-
env
|
|
2856
|
-
});
|
|
2857
|
-
logger.info(
|
|
2858
|
-
`Writing ${import_picocolors11.default.bold(result.serverName)} to ${import_picocolors11.default.cyan(String(result.results.length))} agent config files...`
|
|
2859
|
-
);
|
|
2860
|
-
let allSuccess = true;
|
|
2861
|
-
for (const record of result.results) {
|
|
2862
|
-
if (record.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
|
-
);
|
|
2866
|
-
} else {
|
|
2867
|
-
allSuccess = false;
|
|
2868
|
-
logger.error(`${import_picocolors11.default.cyan(record.agent)}: Failed to write - ${record.error}`);
|
|
2869
|
-
}
|
|
2870
|
-
}
|
|
2871
|
-
if (allSuccess) {
|
|
2872
|
-
logger.success(import_picocolors11.default.bold(`MCP server "${serverName}" configured successfully!`));
|
|
2873
|
-
}
|
|
2874
|
-
return allSuccess;
|
|
2875
|
-
};
|
|
2876
|
-
|
|
2877
|
-
// src/interactive/wizard-manage.ts
|
|
2878
|
-
var import_prompts8 = require("@inquirer/prompts");
|
|
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
|
-
};
|
|
2934
|
-
|
|
2935
|
-
// src/interactive/utils/group-installed-servers.ts
|
|
2936
|
-
var normalizeServerConfig = parseServerConfig;
|
|
2937
|
-
var groupInstalledServersByName = (installed) => {
|
|
2938
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
2939
|
-
for (const item of installed) {
|
|
2940
|
-
const itemConfig = normalizeServerConfig(item.config);
|
|
2941
|
-
let entry = grouped.get(item.serverName);
|
|
2942
|
-
if (!entry) {
|
|
2943
|
-
entry = {
|
|
2944
|
-
serverName: item.serverName,
|
|
2945
|
-
agents: [],
|
|
2946
|
-
paths: [],
|
|
2947
|
-
config: itemConfig,
|
|
2948
|
-
hasDivergence: false
|
|
2949
|
-
};
|
|
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
|
-
}
|
|
2955
|
-
}
|
|
2956
|
-
if (!entry.agents.includes(item.agent)) {
|
|
2957
|
-
entry.agents.push(item.agent);
|
|
2958
|
-
}
|
|
2959
|
-
if (!entry.paths.includes(item.path)) {
|
|
2960
|
-
entry.paths.push(item.path);
|
|
2961
|
-
}
|
|
2962
|
-
}
|
|
2963
|
-
return grouped;
|
|
2964
|
-
};
|
|
2965
|
-
|
|
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
|
-
};
|
|
3182
|
-
var wizardManage = async (options = {}) => {
|
|
3183
|
-
const cwd = options.cwd ?? process.cwd();
|
|
3184
|
-
const isGlobal = await promptScope({
|
|
3185
|
-
cwd,
|
|
3186
|
-
defaultGlobal: options.global,
|
|
3187
|
-
message: "Select MCP scope to inspect and manage:"
|
|
3188
|
-
});
|
|
3189
|
-
const installed = listInstalledMcpServers({ global: isGlobal, cwd });
|
|
3190
|
-
if (installed.length === 0) {
|
|
3191
|
-
logger.warn(`No configured MCP servers found in ${isGlobal ? "global" : "project"} scope`);
|
|
3192
|
-
return;
|
|
3193
|
-
}
|
|
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
|
-
};
|
|
3204
|
-
while (true) {
|
|
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
|
-
}
|
|
3229
|
-
}
|
|
3230
|
-
const targetGroup = grouped.get(chosenServerName);
|
|
3231
|
-
if (!targetGroup) continue;
|
|
3232
|
-
displayServerDetails({
|
|
3233
|
-
serverName: chosenServerName,
|
|
3234
|
-
config: targetGroup.config,
|
|
3235
|
-
agents: targetGroup.agents,
|
|
3236
|
-
global: isGlobal,
|
|
3237
|
-
hasDivergence: targetGroup.hasDivergence
|
|
3238
|
-
});
|
|
3239
|
-
const action = await (0, import_prompts8.select)({
|
|
3240
|
-
message: `What would you like to do with [${chosenServerName}]?`,
|
|
3241
|
-
choices: [
|
|
3242
|
-
{
|
|
3243
|
-
name: "Edit server configuration",
|
|
3244
|
-
value: "edit"
|
|
3245
|
-
},
|
|
3246
|
-
{
|
|
3247
|
-
name: "Sync / clone to other agents",
|
|
3248
|
-
value: "sync"
|
|
3249
|
-
},
|
|
3250
|
-
{
|
|
3251
|
-
name: "Back to list",
|
|
3252
|
-
value: "back"
|
|
3253
|
-
}
|
|
3254
|
-
]
|
|
3255
|
-
});
|
|
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
|
-
}
|
|
3266
|
-
if (action === "sync") {
|
|
3267
|
-
const allAllowedAgents = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
|
|
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
|
-
);
|
|
3273
|
-
continue;
|
|
3274
|
-
}
|
|
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({
|
|
3282
|
-
message: "Select target agents to sync to (Space to select):",
|
|
3283
|
-
choices,
|
|
3284
|
-
loop: false,
|
|
3285
|
-
validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
|
|
3286
|
-
});
|
|
3287
|
-
const confirmed = await (0, import_prompts8.confirm)({
|
|
3288
|
-
message: `Confirm syncing configuration of [${chosenServerName}] to: ${selectedToSync.join(", ")}?`,
|
|
3289
|
-
default: true
|
|
3290
|
-
});
|
|
3291
|
-
if (!confirmed) {
|
|
3292
|
-
logger.warn("Sync cancelled");
|
|
3293
|
-
continue;
|
|
3294
|
-
}
|
|
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
|
-
}
|
|
3309
|
-
if (res.success) {
|
|
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);
|
|
3314
|
-
} else {
|
|
3315
|
-
logger.error(`${import_picocolors13.default.cyan(res.agent)}: Sync failed - ${res.error}`);
|
|
3316
|
-
}
|
|
3317
|
-
}
|
|
3318
|
-
refreshGroupedServers();
|
|
3319
|
-
}
|
|
3320
|
-
}
|
|
3321
|
-
};
|
|
3322
|
-
|
|
3323
|
-
// src/interactive/wizard-remove.ts
|
|
3324
|
-
var import_prompts9 = require("@inquirer/prompts");
|
|
3325
|
-
var import_picocolors14 = __toESM(require("picocolors"), 1);
|
|
3326
|
-
var wizardRemove = async (options = {}) => {
|
|
3327
|
-
const cwd = options.cwd ?? process.cwd();
|
|
3328
|
-
const isGlobal = await promptScope({
|
|
3329
|
-
cwd,
|
|
3330
|
-
defaultGlobal: options.global,
|
|
3331
|
-
message: "Select scope to remove MCP server from:"
|
|
3332
|
-
});
|
|
3333
|
-
const installed = listInstalledMcpServers({ global: isGlobal, cwd });
|
|
3334
|
-
if (installed.length === 0) {
|
|
3335
|
-
logger.warn(`No installed MCP servers found in ${isGlobal ? "global" : "project"} scope`);
|
|
3336
|
-
return false;
|
|
3337
|
-
}
|
|
3338
|
-
const serverMap = groupInstalledServersByName(installed);
|
|
3339
|
-
let serverName = options.name;
|
|
3340
|
-
if (!serverName) {
|
|
3341
|
-
const choices = Array.from(serverMap.values()).map((g) => ({
|
|
3342
|
-
name: `${import_picocolors14.default.bold(g.serverName)} ${import_picocolors14.default.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
|
|
3343
|
-
value: g.serverName
|
|
3344
|
-
}));
|
|
3345
|
-
serverName = await (0, import_prompts9.select)({
|
|
3346
|
-
message: "Select MCP server to remove:",
|
|
3347
|
-
choices
|
|
3348
|
-
});
|
|
3349
|
-
}
|
|
3350
|
-
const rawInstalledAgents = serverMap.get(serverName)?.agents || [];
|
|
3351
|
-
if (rawInstalledAgents.length === 0) {
|
|
3352
|
-
logger.warn(`No agents found with [${serverName}] installed`);
|
|
3353
|
-
return false;
|
|
3354
|
-
}
|
|
3355
|
-
const installedAgents = sortAgentsWithClusters(rawInstalledAgents, { global: isGlobal, cwd });
|
|
3356
|
-
let targetAgents = options.agents;
|
|
3357
|
-
if (!targetAgents || targetAgents.length === 0) {
|
|
3358
|
-
const choices = buildLinkedAgentChoices({
|
|
3359
|
-
agents: installedAgents,
|
|
3360
|
-
checkedAgents: installedAgents,
|
|
3361
|
-
scopeOptions: { global: isGlobal, cwd }
|
|
3362
|
-
});
|
|
3363
|
-
targetAgents = await linkedCheckbox({
|
|
3364
|
-
message: `Select agents to remove [${serverName}] from:`,
|
|
3365
|
-
choices,
|
|
3366
|
-
validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
|
|
3367
|
-
});
|
|
3368
|
-
} else {
|
|
3369
|
-
const validAgents = targetAgents.filter((agent) => installedAgents.includes(agent));
|
|
3370
|
-
if (validAgents.length === 0) {
|
|
3371
|
-
logger.warn(`None of the specified agents (${targetAgents.join(", ")}) have [${serverName}] installed`);
|
|
3372
|
-
return false;
|
|
3373
|
-
}
|
|
3374
|
-
targetAgents = validAgents;
|
|
3375
|
-
}
|
|
3376
|
-
const confirmed = await (0, import_prompts9.confirm)({
|
|
3377
|
-
message: `Confirm removing MCP server [${serverName}] from ${targetAgents.join(", ")}?`,
|
|
3378
|
-
default: true
|
|
3379
|
-
});
|
|
3380
|
-
if (!confirmed) {
|
|
3381
|
-
logger.warn("Operation cancelled");
|
|
3382
|
-
return false;
|
|
3383
|
-
}
|
|
3384
|
-
const results = removeMcpServer({
|
|
3385
|
-
name: serverName,
|
|
3386
|
-
agents: targetAgents,
|
|
3387
|
-
global: isGlobal,
|
|
3388
|
-
cwd
|
|
3389
|
-
});
|
|
3390
|
-
let removedCount = 0;
|
|
3391
|
-
for (const res of results) {
|
|
3392
|
-
if (res.removed) {
|
|
3393
|
-
logger.success(
|
|
3394
|
-
`${import_picocolors14.default.cyan(res.agent)}: Successfully removed from ${import_picocolors14.default.dim(res.path)}${formatCoHostedBadge("affected", res.coAffectedAgents)}`
|
|
3395
|
-
);
|
|
3396
|
-
removedCount++;
|
|
3397
|
-
} else if (res.error) {
|
|
3398
|
-
logger.error(`${import_picocolors14.default.cyan(res.agent)}: Failed to remove - ${res.error}`);
|
|
3399
|
-
}
|
|
3400
|
-
}
|
|
3401
|
-
if (removedCount > 0) {
|
|
3402
|
-
logger.success(`Successfully removed [${serverName}] from ${removedCount} agent(s)`);
|
|
3403
|
-
return true;
|
|
3404
|
-
}
|
|
3405
|
-
logger.warn(`Failed to remove [${serverName}] from specified agents`);
|
|
3406
|
-
return false;
|
|
3407
|
-
};
|
|
3408
|
-
|
|
3409
|
-
// src/interactive/main-menu.ts
|
|
3410
|
-
var mainMenu = async () => {
|
|
3411
|
-
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"));
|
|
3414
|
-
console.log();
|
|
3415
|
-
while (true) {
|
|
3416
|
-
try {
|
|
3417
|
-
const action = await (0, import_prompts10.select)({
|
|
3418
|
-
message: "Select an action:",
|
|
3419
|
-
choices: [
|
|
3420
|
-
{
|
|
3421
|
-
name: "Add MCP Server",
|
|
3422
|
-
value: "add"
|
|
3423
|
-
},
|
|
3424
|
-
{
|
|
3425
|
-
name: "Manage & Sync Installed MCP Servers",
|
|
3426
|
-
value: "manage"
|
|
3427
|
-
},
|
|
3428
|
-
{
|
|
3429
|
-
name: "Remove MCP Server",
|
|
3430
|
-
value: "remove"
|
|
3431
|
-
},
|
|
3432
|
-
{
|
|
3433
|
-
name: "Exit",
|
|
3434
|
-
value: "exit"
|
|
3435
|
-
}
|
|
3436
|
-
]
|
|
3437
|
-
});
|
|
3438
|
-
if (action === "exit") {
|
|
3439
|
-
console.log(import_picocolors15.default.dim("Goodbye!"));
|
|
3440
|
-
break;
|
|
3441
|
-
}
|
|
3442
|
-
if (action === "add") {
|
|
3443
|
-
await wizardAdd();
|
|
3444
|
-
} else if (action === "manage") {
|
|
3445
|
-
await wizardManage();
|
|
3446
|
-
} else if (action === "remove") {
|
|
3447
|
-
await wizardRemove();
|
|
3448
|
-
}
|
|
3449
|
-
console.log();
|
|
3450
|
-
} catch (error) {
|
|
3451
|
-
if (error?.name === "ExitPromptError") {
|
|
3452
|
-
console.log("\n" + import_picocolors15.default.dim("Exited."));
|
|
3453
|
-
break;
|
|
3454
|
-
}
|
|
3455
|
-
throw error;
|
|
3456
|
-
}
|
|
3457
|
-
}
|
|
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
|
-
});
|
|
3664
1929
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3665
1930
|
0 && (module.exports = {
|
|
3666
1931
|
AgentConfigStore,
|
|
3667
1932
|
DEFAULT_REMOTE_TRANSPORT,
|
|
3668
|
-
NPX_COMMAND,
|
|
3669
|
-
NPX_DASH_Y,
|
|
3670
1933
|
SECRET_HEADER_PATTERN,
|
|
3671
1934
|
SECRET_KEY_PATTERN,
|
|
3672
|
-
add,
|
|
3673
1935
|
agentConfigStore,
|
|
3674
|
-
|
|
1936
|
+
applyServerConfigDelta,
|
|
3675
1937
|
buildMcpServerConfig,
|
|
3676
1938
|
createAgentTransform,
|
|
3677
1939
|
detectGloballyInstalledMcpAgents,
|
|
3678
1940
|
detectProjectInstalledMcpAgents,
|
|
3679
1941
|
detectUpdateTransition,
|
|
3680
|
-
displayServerDetails,
|
|
3681
1942
|
extractPackageName,
|
|
3682
|
-
formatArgsString,
|
|
3683
|
-
formatEnvText,
|
|
3684
|
-
formatHeadersText,
|
|
3685
1943
|
getCandidateAgentsForScope,
|
|
3686
1944
|
getCoHostedAgents,
|
|
3687
1945
|
getMcpAgentConfig,
|
|
3688
1946
|
getMcpAgentTypes,
|
|
3689
1947
|
getMcpAgentsSupportingProjectScope,
|
|
3690
|
-
groupInstalledServersByName,
|
|
3691
|
-
install,
|
|
3692
1948
|
installMcpServer,
|
|
3693
1949
|
installMcpServerForAgent,
|
|
3694
1950
|
installMcpServerForAgents,
|
|
@@ -3698,53 +1954,21 @@ var mcpManageCommand = new import_commander.Command("manage").description("Inspe
|
|
|
3698
1954
|
isRemoteMcpSource,
|
|
3699
1955
|
isRemoteServerConfig,
|
|
3700
1956
|
isStdioServerConfig,
|
|
3701
|
-
linkedCheckbox,
|
|
3702
|
-
list,
|
|
3703
1957
|
listInstalledMcpServers,
|
|
3704
|
-
listServersInConfigFile,
|
|
3705
|
-
mainMenu,
|
|
3706
1958
|
maskSecretHeader,
|
|
3707
1959
|
maskSecretValue,
|
|
3708
|
-
mcpAgentAliases,
|
|
3709
|
-
mcpAgents,
|
|
3710
|
-
mcpManageCommand,
|
|
3711
|
-
normalizeServerConfig,
|
|
3712
|
-
parseArgsString,
|
|
3713
|
-
parseEnvText,
|
|
3714
|
-
parseHeadersText,
|
|
3715
1960
|
parseMcpSource,
|
|
3716
1961
|
parseServerConfig,
|
|
3717
|
-
|
|
3718
|
-
promptArgsConfig,
|
|
3719
|
-
promptEditArgs,
|
|
3720
|
-
promptEditEnvConfig,
|
|
3721
|
-
promptEditHeadersConfig,
|
|
3722
|
-
promptEditKeyValueConfig,
|
|
3723
|
-
promptEnvConfig,
|
|
3724
|
-
promptHeadersConfig,
|
|
3725
|
-
promptScope,
|
|
3726
|
-
promptScopeAndAgents,
|
|
3727
|
-
promptSwitchServerType,
|
|
3728
|
-
readConfigFile,
|
|
3729
|
-
remove,
|
|
1962
|
+
queryGroupedInstalledServers,
|
|
3730
1963
|
removeMcpServer,
|
|
3731
|
-
removeMcpServerFromAgent,
|
|
3732
|
-
removeServerFromConfigFile,
|
|
3733
1964
|
resolveConfigClusters,
|
|
3734
1965
|
resolveMcpAgentAlias,
|
|
3735
1966
|
resolveMcpConfigTarget,
|
|
3736
1967
|
resolveTargetAgents,
|
|
3737
|
-
resolveTransport,
|
|
3738
1968
|
sanitizeUpdatedServerConfig,
|
|
3739
|
-
|
|
1969
|
+
sortAgentsByClusters,
|
|
3740
1970
|
toRemoteServerConfig,
|
|
3741
1971
|
toStdioServerConfig,
|
|
3742
|
-
transformServerConfig,
|
|
3743
1972
|
transformServerConfigForAgent,
|
|
3744
|
-
|
|
3745
|
-
updateMcpServer,
|
|
3746
|
-
wizardAdd,
|
|
3747
|
-
wizardManage,
|
|
3748
|
-
wizardRemove,
|
|
3749
|
-
writeServerToConfigFile
|
|
1973
|
+
updateMcpServer
|
|
3750
1974
|
});
|