@wuyax/mcps 0.1.0-beta.2 → 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 +244 -20
- package/dist/chunk-AWD3VQ3S.js +1624 -0
- package/dist/chunk-O3BRJFEC.js +1898 -0
- package/dist/cli.cjs +1553 -852
- package/dist/cli.js +186 -16
- package/dist/index.cjs +678 -1755
- package/dist/index.d.cts +162 -299
- package/dist/index.d.ts +162 -299
- package/dist/index.js +29 -74
- package/dist/{chunk-7V5XL4RI.js → interactive.cjs} +1649 -1172
- 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 +33 -1
package/dist/index.cjs
CHANGED
|
@@ -32,73 +32,47 @@ var src_exports = {};
|
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
AgentConfigStore: () => AgentConfigStore,
|
|
34
34
|
DEFAULT_REMOTE_TRANSPORT: () => DEFAULT_REMOTE_TRANSPORT,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
add: () => installMcpServer,
|
|
35
|
+
SECRET_HEADER_PATTERN: () => SECRET_HEADER_PATTERN,
|
|
36
|
+
SECRET_KEY_PATTERN: () => SECRET_KEY_PATTERN,
|
|
38
37
|
agentConfigStore: () => agentConfigStore,
|
|
38
|
+
applyServerConfigDelta: () => applyServerConfigDelta,
|
|
39
39
|
buildMcpServerConfig: () => buildMcpServerConfig,
|
|
40
40
|
createAgentTransform: () => createAgentTransform,
|
|
41
41
|
detectGloballyInstalledMcpAgents: () => detectGloballyInstalledMcpAgents,
|
|
42
42
|
detectProjectInstalledMcpAgents: () => detectProjectInstalledMcpAgents,
|
|
43
|
-
|
|
43
|
+
detectUpdateTransition: () => detectUpdateTransition,
|
|
44
44
|
extractPackageName: () => extractPackageName,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
formatHeadersText: () => formatHeadersText,
|
|
45
|
+
getCandidateAgentsForScope: () => getCandidateAgentsForScope,
|
|
46
|
+
getCoHostedAgents: () => getCoHostedAgents,
|
|
48
47
|
getMcpAgentConfig: () => getMcpAgentConfig,
|
|
49
48
|
getMcpAgentTypes: () => getMcpAgentTypes,
|
|
50
49
|
getMcpAgentsSupportingProjectScope: () => getMcpAgentsSupportingProjectScope,
|
|
51
|
-
groupInstalledServersByName: () => groupInstalledServersByName,
|
|
52
|
-
install: () => installMcpServer,
|
|
53
50
|
installMcpServer: () => installMcpServer,
|
|
54
51
|
installMcpServerForAgent: () => installMcpServerForAgent,
|
|
55
52
|
installMcpServerForAgents: () => installMcpServerForAgents,
|
|
53
|
+
installToCompatibleAgents: () => installToCompatibleAgents,
|
|
56
54
|
isMcpAgentType: () => isMcpAgentType,
|
|
57
55
|
isMcpTransportSupported: () => isMcpTransportSupported,
|
|
58
56
|
isRemoteMcpSource: () => isRemoteMcpSource,
|
|
59
57
|
isRemoteServerConfig: () => isRemoteServerConfig,
|
|
60
58
|
isStdioServerConfig: () => isStdioServerConfig,
|
|
61
|
-
list: () => listInstalledMcpServers,
|
|
62
59
|
listInstalledMcpServers: () => listInstalledMcpServers,
|
|
63
|
-
listServersInConfigFile: () => listServersInConfigFile,
|
|
64
|
-
mainMenu: () => mainMenu,
|
|
65
60
|
maskSecretHeader: () => maskSecretHeader,
|
|
66
61
|
maskSecretValue: () => maskSecretValue,
|
|
67
|
-
mcpAgentAliases: () => mcpAgentAliases,
|
|
68
|
-
mcpAgents: () => mcpAgents,
|
|
69
|
-
mcpManageCommand: () => mcpManageCommand,
|
|
70
|
-
normalizeServerConfig: () => normalizeServerConfig,
|
|
71
|
-
parseArgsString: () => parseArgsString,
|
|
72
|
-
parseEnvText: () => parseEnvText,
|
|
73
|
-
parseHeadersText: () => parseHeadersText,
|
|
74
62
|
parseMcpSource: () => parseMcpSource,
|
|
75
63
|
parseServerConfig: () => parseServerConfig,
|
|
76
|
-
|
|
77
|
-
promptArgsConfig: () => promptArgsConfig,
|
|
78
|
-
promptEditArgs: () => promptEditArgs,
|
|
79
|
-
promptEditEnvConfig: () => promptEditEnvConfig,
|
|
80
|
-
promptEditHeadersConfig: () => promptEditHeadersConfig,
|
|
81
|
-
promptEditKeyValueConfig: () => promptEditKeyValueConfig,
|
|
82
|
-
promptEnvConfig: () => promptEnvConfig,
|
|
83
|
-
promptHeadersConfig: () => promptHeadersConfig,
|
|
84
|
-
promptScope: () => promptScope,
|
|
85
|
-
promptScopeAndAgents: () => promptScopeAndAgents,
|
|
86
|
-
readConfigFile: () => readConfigFile,
|
|
87
|
-
remove: () => removeMcpServer,
|
|
64
|
+
queryGroupedInstalledServers: () => queryGroupedInstalledServers,
|
|
88
65
|
removeMcpServer: () => removeMcpServer,
|
|
89
|
-
|
|
90
|
-
removeServerFromConfigFile: () => removeServerFromConfigFile,
|
|
66
|
+
resolveConfigClusters: () => resolveConfigClusters,
|
|
91
67
|
resolveMcpAgentAlias: () => resolveMcpAgentAlias,
|
|
92
68
|
resolveMcpConfigTarget: () => resolveMcpConfigTarget,
|
|
93
69
|
resolveTargetAgents: () => resolveTargetAgents,
|
|
94
|
-
|
|
70
|
+
sanitizeUpdatedServerConfig: () => sanitizeUpdatedServerConfig,
|
|
71
|
+
sortAgentsByClusters: () => sortAgentsByClusters,
|
|
72
|
+
toRemoteServerConfig: () => toRemoteServerConfig,
|
|
73
|
+
toStdioServerConfig: () => toStdioServerConfig,
|
|
95
74
|
transformServerConfigForAgent: () => transformServerConfigForAgent,
|
|
96
|
-
|
|
97
|
-
updateMcpServerForAgents: () => installMcpServerForAgents,
|
|
98
|
-
wizardAdd: () => wizardAdd,
|
|
99
|
-
wizardManage: () => wizardManage,
|
|
100
|
-
wizardRemove: () => wizardRemove,
|
|
101
|
-
writeServerToConfigFile: () => writeServerToConfigFile
|
|
75
|
+
updateMcpServer: () => updateMcpServer
|
|
102
76
|
});
|
|
103
77
|
module.exports = __toCommonJS(src_exports);
|
|
104
78
|
|
|
@@ -556,9 +530,9 @@ var mcpAgentAliases = {
|
|
|
556
530
|
var getMcpAgentConfig = (agentType) => mcpAgents[agentType];
|
|
557
531
|
var getMcpAgentTypes = () => Object.values(mcpAgents).map((config) => config.name);
|
|
558
532
|
var isMcpAgentType = (value) => value in mcpAgents;
|
|
559
|
-
var resolveMcpAgentAlias = (
|
|
560
|
-
if (isMcpAgentType(
|
|
561
|
-
return mcpAgentAliases[
|
|
533
|
+
var resolveMcpAgentAlias = (input) => {
|
|
534
|
+
if (isMcpAgentType(input)) return input;
|
|
535
|
+
return mcpAgentAliases[input] ?? null;
|
|
562
536
|
};
|
|
563
537
|
var isMcpTransportSupported = (agent, transport) => agent.supportedTransports.includes(transport);
|
|
564
538
|
var detectProjectInstalledMcpAgents = (cwd) => getMcpAgentTypes().filter(
|
|
@@ -610,7 +584,9 @@ var KNOWN_COMMAND_RUNNERS = /* @__PURE__ */ new Set([
|
|
|
610
584
|
]);
|
|
611
585
|
var SCRIPT_EXTENSION_REGEX = /\.(?:js|ts|mjs|cjs|py|sh|rb|go)$/i;
|
|
612
586
|
|
|
613
|
-
// 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;
|
|
614
590
|
var buildMcpServerConfig = (parsed, options = {}) => {
|
|
615
591
|
if (parsed.type === "remote") {
|
|
616
592
|
const config2 = {
|
|
@@ -648,10 +624,6 @@ var buildMcpServerConfig = (parsed, options = {}) => {
|
|
|
648
624
|
}
|
|
649
625
|
return config;
|
|
650
626
|
};
|
|
651
|
-
|
|
652
|
-
// src/parse-server-config.ts
|
|
653
|
-
var isRemoteServerConfig = (config) => typeof config.url === "string" && config.url.length > 0;
|
|
654
|
-
var isStdioServerConfig = (config) => typeof config.command === "string" && config.command.length > 0;
|
|
655
627
|
var parseServerConfig = (raw) => {
|
|
656
628
|
if (!raw || typeof raw !== "object") return {};
|
|
657
629
|
const data = raw;
|
|
@@ -678,6 +650,237 @@ var parseServerConfig = (raw) => {
|
|
|
678
650
|
}
|
|
679
651
|
return {};
|
|
680
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");
|
|
681
884
|
|
|
682
885
|
// src/utils/is-plain-object.ts
|
|
683
886
|
var isPlainObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -962,113 +1165,6 @@ var listServersInConfigFile = (filePath, format, dottedKey) => {
|
|
|
962
1165
|
return isPlainObject(entries) ? entries : {};
|
|
963
1166
|
};
|
|
964
1167
|
|
|
965
|
-
// src/config-store.ts
|
|
966
|
-
var import_node_fs6 = require("fs");
|
|
967
|
-
|
|
968
|
-
// src/resolve-config-target.ts
|
|
969
|
-
var import_node_path3 = require("path");
|
|
970
|
-
var resolveMcpConfigTarget = (agent, options = {}) => {
|
|
971
|
-
const isGlobal = options.global ?? false;
|
|
972
|
-
const cwd = options.cwd ?? process.cwd();
|
|
973
|
-
const configPath = agent.resolveConfigPath ? agent.resolveConfigPath({ global: isGlobal, cwd }) : !isGlobal && agent.projectConfigPath ? (0, import_node_path3.join)(cwd, agent.projectConfigPath) : agent.globalConfigPath;
|
|
974
|
-
const configKey = !isGlobal && agent.projectConfigKey ? agent.projectConfigKey : agent.configKey;
|
|
975
|
-
return { configPath, configKey };
|
|
976
|
-
};
|
|
977
|
-
|
|
978
|
-
// src/config-store.ts
|
|
979
|
-
var FsConfigStoreAdapter = class {
|
|
980
|
-
exists(filePath) {
|
|
981
|
-
return (0, import_node_fs6.existsSync)(filePath);
|
|
982
|
-
}
|
|
983
|
-
read(target) {
|
|
984
|
-
return readConfigFile(target.filePath, target.format);
|
|
985
|
-
}
|
|
986
|
-
writeServer(target, serverName, serverConfig) {
|
|
987
|
-
if (!target.dottedKey) {
|
|
988
|
-
throw new Error(`Cannot write server: missing dottedKey for ${target.filePath}`);
|
|
989
|
-
}
|
|
990
|
-
writeServerToConfigFile(
|
|
991
|
-
target.filePath,
|
|
992
|
-
target.format,
|
|
993
|
-
target.dottedKey,
|
|
994
|
-
serverName,
|
|
995
|
-
serverConfig
|
|
996
|
-
);
|
|
997
|
-
}
|
|
998
|
-
removeServer(target, serverName) {
|
|
999
|
-
if (!target.dottedKey) return false;
|
|
1000
|
-
return removeServerFromConfigFile(
|
|
1001
|
-
target.filePath,
|
|
1002
|
-
target.format,
|
|
1003
|
-
target.dottedKey,
|
|
1004
|
-
serverName
|
|
1005
|
-
);
|
|
1006
|
-
}
|
|
1007
|
-
listServers(target) {
|
|
1008
|
-
if (!target.dottedKey) return {};
|
|
1009
|
-
return listServersInConfigFile(target.filePath, target.format, target.dottedKey);
|
|
1010
|
-
}
|
|
1011
|
-
};
|
|
1012
|
-
var AgentConfigStore = class {
|
|
1013
|
-
constructor(adapter = new FsConfigStoreAdapter()) {
|
|
1014
|
-
this.adapter = adapter;
|
|
1015
|
-
}
|
|
1016
|
-
adapter;
|
|
1017
|
-
getAdapter() {
|
|
1018
|
-
return this.adapter;
|
|
1019
|
-
}
|
|
1020
|
-
resolveTarget(agent, options = {}) {
|
|
1021
|
-
const agentConfig = typeof agent === "string" ? getMcpAgentConfig(agent) : agent;
|
|
1022
|
-
const target = resolveMcpConfigTarget(agentConfig, options);
|
|
1023
|
-
return { agent: agentConfig, target };
|
|
1024
|
-
}
|
|
1025
|
-
resolveDescriptor(agent, options = {}) {
|
|
1026
|
-
const { agent: agentConfig, target } = this.resolveTarget(agent, options);
|
|
1027
|
-
return {
|
|
1028
|
-
filePath: target.configPath,
|
|
1029
|
-
format: agentConfig.format,
|
|
1030
|
-
dottedKey: target.configKey
|
|
1031
|
-
};
|
|
1032
|
-
}
|
|
1033
|
-
writeServer(agent, serverName, serverConfig, options = {}) {
|
|
1034
|
-
const descriptor = this.resolveDescriptor(agent, options);
|
|
1035
|
-
this.adapter.writeServer(descriptor, serverName, serverConfig);
|
|
1036
|
-
return { path: descriptor.filePath };
|
|
1037
|
-
}
|
|
1038
|
-
removeServer(agent, serverName, options = {}) {
|
|
1039
|
-
const descriptor = this.resolveDescriptor(agent, options);
|
|
1040
|
-
if (!this.adapter.exists(descriptor.filePath)) {
|
|
1041
|
-
return { path: descriptor.filePath, removed: false };
|
|
1042
|
-
}
|
|
1043
|
-
const removed = this.adapter.removeServer(descriptor, serverName);
|
|
1044
|
-
return { path: descriptor.filePath, removed };
|
|
1045
|
-
}
|
|
1046
|
-
listServers(agent, options = {}) {
|
|
1047
|
-
const descriptor = this.resolveDescriptor(agent, options);
|
|
1048
|
-
if (!this.adapter.exists(descriptor.filePath)) {
|
|
1049
|
-
return { path: descriptor.filePath, exists: false, servers: {} };
|
|
1050
|
-
}
|
|
1051
|
-
const servers = this.adapter.listServers(descriptor);
|
|
1052
|
-
return { path: descriptor.filePath, exists: true, servers };
|
|
1053
|
-
}
|
|
1054
|
-
read(agent, options = {}) {
|
|
1055
|
-
const descriptor = this.resolveDescriptor(agent, options);
|
|
1056
|
-
if (!this.adapter.exists(descriptor.filePath)) {
|
|
1057
|
-
return {};
|
|
1058
|
-
}
|
|
1059
|
-
return this.adapter.read(descriptor);
|
|
1060
|
-
}
|
|
1061
|
-
readServer(agent, serverName, options = {}) {
|
|
1062
|
-
const { exists, servers } = this.listServers(agent, options);
|
|
1063
|
-
if (!exists) return void 0;
|
|
1064
|
-
return servers[serverName];
|
|
1065
|
-
}
|
|
1066
|
-
};
|
|
1067
|
-
var agentConfigStore = new AgentConfigStore();
|
|
1068
|
-
|
|
1069
|
-
// src/utils/to-error-message.ts
|
|
1070
|
-
var toErrorMessage = (error, fallback = "Unknown error") => error instanceof Error ? error.message : fallback;
|
|
1071
|
-
|
|
1072
1168
|
// src/transforms/index.ts
|
|
1073
1169
|
var DIALECT_PRESETS = {
|
|
1074
1170
|
vscode: {
|
|
@@ -1279,47 +1375,314 @@ var transformServerConfigForAgent = (agent, serverName, config, context = { glob
|
|
|
1279
1375
|
return config;
|
|
1280
1376
|
};
|
|
1281
1377
|
|
|
1282
|
-
// src/
|
|
1283
|
-
var
|
|
1284
|
-
|
|
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 = {}) => {
|
|
1285
1383
|
const isGlobal = options.global ?? false;
|
|
1286
|
-
const
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
});
|
|
1291
|
-
agentConfigStore.writeServer(agent, serverName, transformed, options);
|
|
1292
|
-
return { agent: agentType, success: true, path: target.configPath };
|
|
1293
|
-
} catch (error) {
|
|
1294
|
-
return {
|
|
1295
|
-
agent: agentType,
|
|
1296
|
-
success: false,
|
|
1297
|
-
path: target.configPath,
|
|
1298
|
-
error: toErrorMessage(error)
|
|
1299
|
-
};
|
|
1300
|
-
}
|
|
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 };
|
|
1301
1388
|
};
|
|
1302
|
-
var
|
|
1303
|
-
(
|
|
1304
|
-
);
|
|
1305
|
-
|
|
1306
|
-
// src/utils/parse-mcp-agent-list.ts
|
|
1307
|
-
var parseMcpAgentList = (input7) => {
|
|
1308
|
-
if (!input7 || input7.length === 0) return void 0;
|
|
1309
|
-
if (input7.includes("*")) return getMcpAgentTypes();
|
|
1310
|
-
const resolved = [];
|
|
1311
|
-
for (const value of input7) {
|
|
1312
|
-
const agentType = resolveMcpAgentAlias(value);
|
|
1313
|
-
if (!agentType) throw new Error(`Unknown MCP agent "${value}"`);
|
|
1314
|
-
resolved.push(agentType);
|
|
1315
|
-
}
|
|
1316
|
-
return resolved;
|
|
1389
|
+
var getCandidateAgentsForScope = (options = {}) => {
|
|
1390
|
+
return options.global ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
|
|
1317
1391
|
};
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
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);
|
|
1441
|
+
return {
|
|
1442
|
+
filePath: target.configPath,
|
|
1443
|
+
format: agentConfig.format,
|
|
1444
|
+
dottedKey: target.configKey
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
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 };
|
|
1456
|
+
}
|
|
1457
|
+
const removed = this.adapter.removeServer(descriptor, serverName);
|
|
1458
|
+
return { path: descriptor.filePath, removed };
|
|
1459
|
+
}
|
|
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
|
+
}
|
|
1482
|
+
return {
|
|
1483
|
+
agent: agentType,
|
|
1484
|
+
path: cached.path,
|
|
1485
|
+
exists: cached.exists,
|
|
1486
|
+
servers: cached.servers
|
|
1487
|
+
};
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
read(agent, options = {}) {
|
|
1491
|
+
const descriptor = this.resolveDescriptor(agent, options);
|
|
1492
|
+
if (!this.adapter.exists(descriptor.filePath)) {
|
|
1493
|
+
return {};
|
|
1494
|
+
}
|
|
1495
|
+
return this.adapter.read(descriptor);
|
|
1496
|
+
}
|
|
1497
|
+
readServer(agent, serverName, options = {}) {
|
|
1498
|
+
const { exists, servers } = this.listServers(agent, options);
|
|
1499
|
+
if (!exists) return void 0;
|
|
1500
|
+
return servers[serverName];
|
|
1501
|
+
}
|
|
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];
|
|
1323
1686
|
if (rawList.every((item) => isMcpAgentType(item))) {
|
|
1324
1687
|
return rawList;
|
|
1325
1688
|
}
|
|
@@ -1374,117 +1737,41 @@ var resolveTargetAgents = (query = {}) => {
|
|
|
1374
1737
|
};
|
|
1375
1738
|
};
|
|
1376
1739
|
|
|
1377
|
-
// src/
|
|
1378
|
-
var
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
var PATH_SEPARATOR_REGEX = /[/\\]/;
|
|
1382
|
-
var stripVersionSuffix = (input7) => {
|
|
1383
|
-
if (input7.startsWith("@")) {
|
|
1384
|
-
const secondAtIndex = input7.indexOf("@", 1);
|
|
1385
|
-
if (secondAtIndex > 0) return input7.slice(0, secondAtIndex);
|
|
1386
|
-
return input7;
|
|
1387
|
-
}
|
|
1388
|
-
const atIndex = input7.lastIndexOf("@");
|
|
1389
|
-
if (atIndex > 0) return input7.slice(0, atIndex);
|
|
1390
|
-
return input7;
|
|
1391
|
-
};
|
|
1392
|
-
var stripScopePrefix = (input7) => {
|
|
1393
|
-
if (!input7.startsWith("@") || !input7.includes("/")) return input7;
|
|
1394
|
-
const parts = input7.split("/");
|
|
1395
|
-
return parts[1] || input7;
|
|
1396
|
-
};
|
|
1397
|
-
var stripPathPrefix = (input7) => {
|
|
1398
|
-
if (!PATH_SEPARATOR_REGEX.test(input7)) return input7;
|
|
1399
|
-
const segments = input7.split(PATH_SEPARATOR_REGEX);
|
|
1400
|
-
const basename = segments[segments.length - 1];
|
|
1401
|
-
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];
|
|
1402
1744
|
};
|
|
1403
|
-
var
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
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
|
|
1412
1759
|
}
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
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
|
+
};
|
|
1418
1771
|
}
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
};
|
|
1422
|
-
var inferNameFromUrl = (input7) => {
|
|
1423
|
-
try {
|
|
1424
|
-
const url = new URL(input7);
|
|
1425
|
-
const host = url.hostname;
|
|
1426
|
-
const labels = host.split(".").filter((segment) => segment.length > 0);
|
|
1427
|
-
if (labels.length === 0) return MCP_DEFAULT_SERVER_NAME;
|
|
1428
|
-
const meaningfulLabels = labels.filter((label) => {
|
|
1429
|
-
const lower = label.toLowerCase();
|
|
1430
|
-
if (COMMON_TLD_LABELS.has(lower)) return false;
|
|
1431
|
-
if (GENERIC_HOST_PREFIXES.has(lower)) return false;
|
|
1432
|
-
return true;
|
|
1433
|
-
});
|
|
1434
|
-
if (meaningfulLabels.length > 0) return meaningfulLabels[0];
|
|
1435
|
-
if (labels.length >= 2) return labels[labels.length - 2];
|
|
1436
|
-
return labels[labels.length - 1] || MCP_DEFAULT_SERVER_NAME;
|
|
1437
|
-
} catch {
|
|
1438
|
-
return MCP_DEFAULT_SERVER_NAME;
|
|
1439
|
-
}
|
|
1440
|
-
};
|
|
1441
|
-
var inferNameFromCommand = (command) => {
|
|
1442
|
-
const tokens = command.trim().split(/\s+/);
|
|
1443
|
-
const runnerBase = tokens[0]?.split(PATH_SEPARATOR_REGEX).pop() ?? "";
|
|
1444
|
-
const startIndex = KNOWN_COMMAND_RUNNERS.has(runnerBase) ? 1 : 0;
|
|
1445
|
-
for (let tokenIndex = startIndex; tokenIndex < tokens.length; tokenIndex += 1) {
|
|
1446
|
-
const token = tokens[tokenIndex];
|
|
1447
|
-
if (!token || token.startsWith("-")) continue;
|
|
1448
|
-
return extractPackageName(token);
|
|
1449
|
-
}
|
|
1450
|
-
const firstNonFlag = tokens.find((token) => !token.startsWith("-"));
|
|
1451
|
-
return firstNonFlag ? extractPackageName(firstNonFlag) : MCP_DEFAULT_SERVER_NAME;
|
|
1452
|
-
};
|
|
1453
|
-
var parseMcpSource = (input7) => {
|
|
1454
|
-
const trimmed = input7.trim();
|
|
1455
|
-
if (trimmed.length === 0) {
|
|
1456
|
-
throw new Error(
|
|
1457
|
-
"Invalid MCP source: input is empty. Expected a remote URL, an npm package, or a command line."
|
|
1458
|
-
);
|
|
1459
|
-
}
|
|
1460
|
-
if (REMOTE_URL_REGEX.test(trimmed)) {
|
|
1461
|
-
return {
|
|
1462
|
-
type: "remote",
|
|
1463
|
-
value: trimmed,
|
|
1464
|
-
inferredName: inferNameFromUrl(trimmed)
|
|
1465
|
-
};
|
|
1466
|
-
}
|
|
1467
|
-
if (HAS_WHITESPACE_REGEX.test(trimmed)) {
|
|
1468
|
-
return {
|
|
1469
|
-
type: "command",
|
|
1470
|
-
value: trimmed,
|
|
1471
|
-
inferredName: inferNameFromCommand(trimmed)
|
|
1472
|
-
};
|
|
1473
|
-
}
|
|
1474
|
-
if (PACKAGE_NAME_REGEX.test(trimmed)) {
|
|
1475
|
-
return {
|
|
1476
|
-
type: "package",
|
|
1477
|
-
value: trimmed,
|
|
1478
|
-
inferredName: extractPackageName(trimmed)
|
|
1479
|
-
};
|
|
1480
|
-
}
|
|
1481
|
-
return {
|
|
1482
|
-
type: "command",
|
|
1483
|
-
value: trimmed,
|
|
1484
|
-
inferredName: inferNameFromCommand(trimmed)
|
|
1485
|
-
};
|
|
1772
|
+
return installedMap.get(agentType);
|
|
1773
|
+
});
|
|
1486
1774
|
};
|
|
1487
|
-
var isRemoteMcpSource = (parsed) => parsed.type === "remote";
|
|
1488
1775
|
|
|
1489
1776
|
// src/install-mcp-server.ts
|
|
1490
1777
|
var installMcpServer = (options) => {
|
|
@@ -1505,18 +1792,11 @@ var installMcpServer = (options) => {
|
|
|
1505
1792
|
cwd,
|
|
1506
1793
|
transport: requestedTransport
|
|
1507
1794
|
});
|
|
1508
|
-
const
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
agent: agentType,
|
|
1514
|
-
success: false,
|
|
1515
|
-
path: "",
|
|
1516
|
-
error: incompatibleReason
|
|
1517
|
-
};
|
|
1518
|
-
}
|
|
1519
|
-
return installMcpServerForAgent(serverName, serverConfig, agentType, { global: isGlobal, cwd });
|
|
1795
|
+
const results = installToCompatibleAgents(serverName, serverConfig, {
|
|
1796
|
+
allAgents,
|
|
1797
|
+
incompatible,
|
|
1798
|
+
global: isGlobal,
|
|
1799
|
+
cwd
|
|
1520
1800
|
});
|
|
1521
1801
|
return { serverName, config: serverConfig, results };
|
|
1522
1802
|
};
|
|
@@ -1525,15 +1805,14 @@ var installMcpServer = (options) => {
|
|
|
1525
1805
|
var listInstalledMcpServers = (options = {}) => {
|
|
1526
1806
|
const agentTypes = options.agents ?? getMcpAgentTypes();
|
|
1527
1807
|
const collected = [];
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
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)) {
|
|
1533
1812
|
collected.push({
|
|
1534
1813
|
serverName,
|
|
1535
|
-
agent:
|
|
1536
|
-
path,
|
|
1814
|
+
agent: item.agent,
|
|
1815
|
+
path: item.path,
|
|
1537
1816
|
config: rawConfig,
|
|
1538
1817
|
serverConfig: parseServerConfig(rawConfig)
|
|
1539
1818
|
});
|
|
@@ -1541,828 +1820,24 @@ var listInstalledMcpServers = (options = {}) => {
|
|
|
1541
1820
|
}
|
|
1542
1821
|
return collected;
|
|
1543
1822
|
};
|
|
1544
|
-
|
|
1545
|
-
// src/remove.ts
|
|
1546
|
-
var removeMcpServerFromAgent = (serverName, agentType, options = {}) => {
|
|
1547
|
-
const agent = getMcpAgentConfig(agentType);
|
|
1548
|
-
const { target } = agentConfigStore.resolveTarget(agent, options);
|
|
1549
|
-
try {
|
|
1550
|
-
const { removed } = agentConfigStore.removeServer(agent, serverName, options);
|
|
1551
|
-
return { agent: agentType, path: target.configPath, removed };
|
|
1552
|
-
} catch (error) {
|
|
1553
|
-
return {
|
|
1554
|
-
agent: agentType,
|
|
1555
|
-
path: target.configPath,
|
|
1556
|
-
removed: false,
|
|
1557
|
-
error: toErrorMessage(error)
|
|
1558
|
-
};
|
|
1559
|
-
}
|
|
1560
|
-
};
|
|
1561
|
-
var removeMcpServer = (options) => {
|
|
1562
|
-
const { allAgents } = resolveTargetAgents({
|
|
1563
|
-
requested: options.agents,
|
|
1564
|
-
all: !options.agents,
|
|
1565
|
-
global: options.global,
|
|
1566
|
-
cwd: options.cwd
|
|
1567
|
-
});
|
|
1568
|
-
const results = [];
|
|
1569
|
-
for (const agentType of allAgents) {
|
|
1570
|
-
const result = removeMcpServerFromAgent(options.name, agentType, {
|
|
1571
|
-
global: options.global,
|
|
1572
|
-
cwd: options.cwd
|
|
1573
|
-
});
|
|
1574
|
-
if (result.removed || result.error) results.push(result);
|
|
1575
|
-
}
|
|
1576
|
-
return results;
|
|
1577
|
-
};
|
|
1578
|
-
|
|
1579
|
-
// src/interactive/main-menu.ts
|
|
1580
|
-
var import_prompts11 = require("@inquirer/prompts");
|
|
1581
|
-
var import_picocolors11 = __toESM(require("picocolors"), 1);
|
|
1582
|
-
|
|
1583
|
-
// src/interactive/wizard-add.ts
|
|
1584
|
-
var import_prompts8 = require("@inquirer/prompts");
|
|
1585
|
-
var import_picocolors8 = __toESM(require("picocolors"), 1);
|
|
1586
|
-
|
|
1587
|
-
// src/utils/logger.ts
|
|
1588
|
-
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
1589
|
-
var logger = {
|
|
1590
|
-
info: (message) => {
|
|
1591
|
-
console.log(import_picocolors.default.cyan("i"), message);
|
|
1592
|
-
},
|
|
1593
|
-
success: (message) => {
|
|
1594
|
-
console.log(import_picocolors.default.green("\u221A"), message);
|
|
1595
|
-
},
|
|
1596
|
-
warn: (message) => {
|
|
1597
|
-
console.log(import_picocolors.default.yellow("!"), message);
|
|
1598
|
-
},
|
|
1599
|
-
error: (message) => {
|
|
1600
|
-
console.error(import_picocolors.default.red("x"), message);
|
|
1601
|
-
}
|
|
1602
|
-
};
|
|
1603
|
-
|
|
1604
|
-
// src/interactive/prompts/agents.ts
|
|
1605
|
-
var import_prompts2 = require("@inquirer/prompts");
|
|
1606
|
-
var import_picocolors3 = __toESM(require("picocolors"), 1);
|
|
1607
|
-
|
|
1608
|
-
// src/interactive/prompts/scope.ts
|
|
1609
|
-
var import_prompts = require("@inquirer/prompts");
|
|
1610
|
-
var import_picocolors2 = __toESM(require("picocolors"), 1);
|
|
1611
|
-
var promptScope = async (options = {}) => {
|
|
1612
|
-
const initialGlobal = options.defaultGlobal ?? options.global;
|
|
1613
|
-
if (initialGlobal !== void 0) {
|
|
1614
|
-
return initialGlobal;
|
|
1615
|
-
}
|
|
1616
|
-
const cwd = options.cwd ?? process.cwd();
|
|
1617
|
-
return (0, import_prompts.select)({
|
|
1618
|
-
message: options.message ?? "Select MCP scope:",
|
|
1619
|
-
choices: [
|
|
1620
|
-
{
|
|
1621
|
-
name: `Current Project - ${import_picocolors2.default.dim(cwd)}`,
|
|
1622
|
-
value: false
|
|
1623
|
-
},
|
|
1624
|
-
{
|
|
1625
|
-
name: `Global User Config - ${import_picocolors2.default.dim("applies across all projects")}`,
|
|
1626
|
-
value: true
|
|
1627
|
-
}
|
|
1628
|
-
]
|
|
1629
|
-
});
|
|
1630
|
-
};
|
|
1631
|
-
|
|
1632
|
-
// src/interactive/prompts/agents.ts
|
|
1633
|
-
var promptScopeAndAgents = async (options = {}) => {
|
|
1634
|
-
const cwd = options.cwd ?? process.cwd();
|
|
1635
|
-
const isGlobal = await promptScope({
|
|
1636
|
-
cwd,
|
|
1637
|
-
defaultGlobal: options.defaultGlobal,
|
|
1638
|
-
message: "Select MCP installation scope:"
|
|
1639
|
-
});
|
|
1640
|
-
const resolution = resolveTargetAgents({
|
|
1641
|
-
global: isGlobal,
|
|
1642
|
-
cwd
|
|
1643
|
-
});
|
|
1644
|
-
const detected = resolution.detected;
|
|
1645
|
-
const availableAgentTypes = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
|
|
1646
|
-
if (detected.length > 0) {
|
|
1647
|
-
logger.info(
|
|
1648
|
-
`Detected configured agents: ${import_picocolors3.default.cyan(detected.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
|
|
1649
|
-
);
|
|
1650
|
-
} else {
|
|
1651
|
-
logger.warn(`No active ${isGlobal ? "global" : "project"} agents detected`);
|
|
1652
|
-
}
|
|
1653
|
-
const defaultChecked = options.defaultAgents && options.defaultAgents.length > 0 ? options.defaultAgents : detected;
|
|
1654
|
-
const choices = availableAgentTypes.map((agentType) => {
|
|
1655
|
-
const config = getMcpAgentConfig(agentType);
|
|
1656
|
-
const isDetected = detected.includes(agentType);
|
|
1657
|
-
const label = `${config.displayName} ${import_picocolors3.default.dim(`(${agentType})`)}${isDetected ? import_picocolors3.default.green(" [detected]") : ""}`;
|
|
1658
|
-
return {
|
|
1659
|
-
name: label,
|
|
1660
|
-
value: agentType,
|
|
1661
|
-
checked: defaultChecked.includes(agentType)
|
|
1662
|
-
};
|
|
1663
|
-
});
|
|
1664
|
-
const selectedAgents = await (0, import_prompts2.checkbox)({
|
|
1665
|
-
message: "Select target agents (Space to select, Enter to confirm):",
|
|
1666
|
-
choices,
|
|
1667
|
-
validate: (chosen) => {
|
|
1668
|
-
if (chosen.length === 0) {
|
|
1669
|
-
return "Please select at least one agent";
|
|
1670
|
-
}
|
|
1671
|
-
return true;
|
|
1672
|
-
}
|
|
1673
|
-
});
|
|
1674
|
-
return {
|
|
1675
|
-
global: isGlobal,
|
|
1676
|
-
agents: selectedAgents
|
|
1677
|
-
};
|
|
1678
|
-
};
|
|
1679
|
-
|
|
1680
|
-
// src/interactive/prompts/args.ts
|
|
1681
|
-
var import_prompts3 = require("@inquirer/prompts");
|
|
1682
|
-
var parseArgsString = (rawText) => {
|
|
1683
|
-
const matches = rawText.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g);
|
|
1684
|
-
if (!matches) return [];
|
|
1685
|
-
return matches.map((arg) => {
|
|
1686
|
-
if (arg.startsWith('"') && arg.endsWith('"') || arg.startsWith("'") && arg.endsWith("'")) {
|
|
1687
|
-
return arg.slice(1, -1);
|
|
1688
|
-
}
|
|
1689
|
-
return arg;
|
|
1690
|
-
});
|
|
1691
|
-
};
|
|
1692
|
-
var promptArgsConfig = async (initialArgs = []) => {
|
|
1693
|
-
if (initialArgs.length > 0) {
|
|
1694
|
-
return initialArgs;
|
|
1695
|
-
}
|
|
1696
|
-
const needArgs = await (0, import_prompts3.confirm)({
|
|
1697
|
-
message: "Configure command arguments (e.g. file paths, connection strings)?",
|
|
1698
|
-
default: false
|
|
1699
|
-
});
|
|
1700
|
-
if (!needArgs) {
|
|
1701
|
-
return [];
|
|
1702
|
-
}
|
|
1703
|
-
const raw = await (0, import_prompts3.input)({
|
|
1704
|
-
message: "Enter command arguments (space-separated, wrap paths with spaces in quotes):",
|
|
1705
|
-
validate: (val) => val.trim() ? true : "Arguments cannot be empty"
|
|
1706
|
-
});
|
|
1707
|
-
return parseArgsString(raw.trim());
|
|
1708
|
-
};
|
|
1709
|
-
var formatArgsString = (args) => {
|
|
1710
|
-
return args.map((arg) => arg.includes(" ") || arg.includes('"') ? `"${arg.replace(/"/g, '\\"')}"` : arg).join(" ");
|
|
1711
|
-
};
|
|
1712
|
-
var promptEditArgs = async (currentArgs = []) => {
|
|
1713
|
-
const defaultStr = formatArgsString(currentArgs);
|
|
1714
|
-
const raw = await (0, import_prompts3.input)({
|
|
1715
|
-
message: "Edit command arguments (space-separated, wrap paths with spaces in quotes, leave empty to clear):",
|
|
1716
|
-
default: defaultStr
|
|
1717
|
-
});
|
|
1718
|
-
const trimmed = raw.trim();
|
|
1719
|
-
if (!trimmed) {
|
|
1720
|
-
return [];
|
|
1721
|
-
}
|
|
1722
|
-
return parseArgsString(trimmed);
|
|
1723
|
-
};
|
|
1724
|
-
|
|
1725
|
-
// src/interactive/prompts/env.ts
|
|
1726
|
-
var import_prompts6 = require("@inquirer/prompts");
|
|
1727
|
-
var import_picocolors6 = __toESM(require("picocolors"), 1);
|
|
1728
|
-
|
|
1729
|
-
// src/interactive/prompts/multiline.ts
|
|
1730
|
-
var import_node_readline = require("readline");
|
|
1731
|
-
var import_prompts4 = require("@inquirer/prompts");
|
|
1732
|
-
var import_picocolors4 = __toESM(require("picocolors"), 1);
|
|
1733
|
-
var readMultilineTextFromTerminal = async (message, endHint = "When done pasting, enter END on a new line or press Enter twice to finish") => {
|
|
1734
|
-
console.log(import_picocolors4.default.cyan(`
|
|
1735
|
-
${message}`));
|
|
1736
|
-
console.log(import_picocolors4.default.dim(` (Hint: ${endHint})
|
|
1737
|
-
`));
|
|
1738
|
-
return new Promise((resolve) => {
|
|
1739
|
-
const rl = (0, import_node_readline.createInterface)({
|
|
1740
|
-
input: process.stdin,
|
|
1741
|
-
output: process.stdout
|
|
1742
|
-
});
|
|
1743
|
-
const lines = [];
|
|
1744
|
-
let consecutiveEmpty = 0;
|
|
1745
|
-
const cleanup = () => {
|
|
1746
|
-
rl.removeAllListeners();
|
|
1747
|
-
rl.close();
|
|
1748
|
-
};
|
|
1749
|
-
rl.on("line", (line) => {
|
|
1750
|
-
const trimmed = line.trim();
|
|
1751
|
-
if (trimmed === "END") {
|
|
1752
|
-
cleanup();
|
|
1753
|
-
resolve(lines.join("\n"));
|
|
1754
|
-
return;
|
|
1755
|
-
}
|
|
1756
|
-
if (line === "") {
|
|
1757
|
-
consecutiveEmpty++;
|
|
1758
|
-
if (lines.length > 0) {
|
|
1759
|
-
cleanup();
|
|
1760
|
-
resolve(lines.join("\n"));
|
|
1761
|
-
return;
|
|
1762
|
-
}
|
|
1763
|
-
if (consecutiveEmpty >= 2) {
|
|
1764
|
-
cleanup();
|
|
1765
|
-
resolve("");
|
|
1766
|
-
return;
|
|
1767
|
-
}
|
|
1768
|
-
} else {
|
|
1769
|
-
consecutiveEmpty = 0;
|
|
1770
|
-
lines.push(line);
|
|
1771
|
-
}
|
|
1772
|
-
});
|
|
1773
|
-
rl.on("close", () => {
|
|
1774
|
-
resolve(lines.join("\n"));
|
|
1775
|
-
});
|
|
1776
|
-
});
|
|
1777
|
-
};
|
|
1778
|
-
var promptEditorText = async (options) => {
|
|
1779
|
-
try {
|
|
1780
|
-
return await (0, import_prompts4.editor)({
|
|
1781
|
-
message: options.message,
|
|
1782
|
-
default: options.defaultText ?? "",
|
|
1783
|
-
postfix: options.postfix
|
|
1784
|
-
});
|
|
1785
|
-
} catch {
|
|
1786
|
-
return readMultilineTextFromTerminal(options.message);
|
|
1787
|
-
}
|
|
1788
|
-
};
|
|
1789
|
-
|
|
1790
|
-
// src/interactive/prompts/kv.ts
|
|
1791
|
-
var import_prompts5 = require("@inquirer/prompts");
|
|
1792
|
-
var import_picocolors5 = __toESM(require("picocolors"), 1);
|
|
1793
|
-
var promptEditKeyValueConfig = async (currentItems = {}, options) => {
|
|
1794
|
-
let items = { ...currentItems };
|
|
1795
|
-
while (true) {
|
|
1796
|
-
const keys = Object.keys(items);
|
|
1797
|
-
console.log();
|
|
1798
|
-
if (keys.length === 0) {
|
|
1799
|
-
console.log(import_picocolors5.default.dim(` No ${options.itemsNoun} configured.`));
|
|
1800
|
-
} else {
|
|
1801
|
-
console.log(import_picocolors5.default.cyan(import_picocolors5.default.bold(` Configured ${options.title} (${keys.length}):`)));
|
|
1802
|
-
for (const [k, v] of Object.entries(items)) {
|
|
1803
|
-
const sep = options.separator === "=" ? "=" : ": ";
|
|
1804
|
-
console.log(` ${import_picocolors5.default.bold(k)}${sep}${import_picocolors5.default.dim(options.maskValue(k, v))}`);
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
|
-
console.log();
|
|
1808
|
-
const choice = await (0, import_prompts5.select)({
|
|
1809
|
-
message: `Manage ${options.itemsNoun}:`,
|
|
1810
|
-
choices: [
|
|
1811
|
-
{
|
|
1812
|
-
name: "Open in system default editor ($EDITOR)",
|
|
1813
|
-
value: "editor"
|
|
1814
|
-
},
|
|
1815
|
-
{
|
|
1816
|
-
name: `Add or modify a ${options.itemNoun}`,
|
|
1817
|
-
value: "upsert"
|
|
1818
|
-
},
|
|
1819
|
-
...keys.length > 0 ? [
|
|
1820
|
-
{
|
|
1821
|
-
name: `Delete a ${options.itemNoun}`,
|
|
1822
|
-
value: "delete"
|
|
1823
|
-
}
|
|
1824
|
-
] : [],
|
|
1825
|
-
{
|
|
1826
|
-
name: `Paste multiline ${options.itemsNoun} into terminal`,
|
|
1827
|
-
value: "paste"
|
|
1828
|
-
},
|
|
1829
|
-
...keys.length > 0 ? [
|
|
1830
|
-
{
|
|
1831
|
-
name: `Clear all ${options.itemsNoun}`,
|
|
1832
|
-
value: "clear"
|
|
1833
|
-
}
|
|
1834
|
-
] : [],
|
|
1835
|
-
{
|
|
1836
|
-
name: `Done (finish editing ${options.itemsNoun})`,
|
|
1837
|
-
value: "done"
|
|
1838
|
-
}
|
|
1839
|
-
]
|
|
1840
|
-
});
|
|
1841
|
-
if (choice === "done") {
|
|
1842
|
-
return items;
|
|
1843
|
-
}
|
|
1844
|
-
if (choice === "editor") {
|
|
1845
|
-
const defaultText = options.formatText(items);
|
|
1846
|
-
const text = await promptEditorText({
|
|
1847
|
-
message: options.editorMessage,
|
|
1848
|
-
postfix: options.editorPostfix,
|
|
1849
|
-
defaultText
|
|
1850
|
-
});
|
|
1851
|
-
const parsed = options.parseText(text);
|
|
1852
|
-
items = parsed;
|
|
1853
|
-
logger.success(`${options.title} updated (${Object.keys(items).length} total)`);
|
|
1854
|
-
} else if (choice === "upsert") {
|
|
1855
|
-
const key = await (0, import_prompts5.input)({
|
|
1856
|
-
message: options.keyPromptMessage,
|
|
1857
|
-
validate: (val) => {
|
|
1858
|
-
const trimmed = val.trim();
|
|
1859
|
-
if (!trimmed) return `${options.itemNoun} name cannot be empty`;
|
|
1860
|
-
if (/\s/.test(trimmed)) return `${options.itemNoun} name cannot contain spaces`;
|
|
1861
|
-
return true;
|
|
1862
|
-
}
|
|
1863
|
-
});
|
|
1864
|
-
const trimmedKey = key.trim();
|
|
1865
|
-
const existingVal = items[trimmedKey];
|
|
1866
|
-
const isSecret = options.isSecretKey(trimmedKey);
|
|
1867
|
-
let newVal;
|
|
1868
|
-
if (isSecret) {
|
|
1869
|
-
newVal = await (0, import_prompts5.password)({
|
|
1870
|
-
message: existingVal !== void 0 ? `New value for (${trimmedKey}) [leave empty to keep current]:` : `${options.valuePromptMessage} for (${trimmedKey}) [sensitive content masked]:`,
|
|
1871
|
-
mask: "*"
|
|
1872
|
-
});
|
|
1873
|
-
if (existingVal !== void 0 && newVal === "") {
|
|
1874
|
-
newVal = existingVal;
|
|
1875
|
-
}
|
|
1876
|
-
} else {
|
|
1877
|
-
newVal = await (0, import_prompts5.input)({
|
|
1878
|
-
message: `${options.valuePromptMessage} for (${trimmedKey}):`,
|
|
1879
|
-
default: existingVal
|
|
1880
|
-
});
|
|
1881
|
-
}
|
|
1882
|
-
items[trimmedKey] = newVal;
|
|
1883
|
-
logger.success(`${existingVal !== void 0 ? "Updated" : "Added"}: ${import_picocolors5.default.cyan(trimmedKey)}`);
|
|
1884
|
-
} else if (choice === "delete") {
|
|
1885
|
-
const toDelete = await (0, import_prompts5.select)({
|
|
1886
|
-
message: `Select ${options.itemNoun} to delete:`,
|
|
1887
|
-
choices: [
|
|
1888
|
-
...keys.map((k) => ({ name: k, value: k })),
|
|
1889
|
-
{ name: "Cancel", value: "__cancel__" }
|
|
1890
|
-
]
|
|
1891
|
-
});
|
|
1892
|
-
if (toDelete !== "__cancel__") {
|
|
1893
|
-
delete items[toDelete];
|
|
1894
|
-
logger.success(`Deleted: ${import_picocolors5.default.cyan(toDelete)}`);
|
|
1895
|
-
}
|
|
1896
|
-
} else if (choice === "paste") {
|
|
1897
|
-
const pasted = await readMultilineTextFromTerminal(options.pasteMessage);
|
|
1898
|
-
const parsed = options.parseText(pasted);
|
|
1899
|
-
const count = Object.keys(parsed).length;
|
|
1900
|
-
if (count === 0) {
|
|
1901
|
-
logger.warn(`No valid ${options.itemsNoun} recognized`);
|
|
1902
|
-
} else {
|
|
1903
|
-
if (keys.length > 0) {
|
|
1904
|
-
const pasteMode = await (0, import_prompts5.select)({
|
|
1905
|
-
message: `How to apply pasted ${options.itemsNoun}?`,
|
|
1906
|
-
choices: [
|
|
1907
|
-
{ name: `Merge with existing ${options.itemsNoun}`, value: "merge" },
|
|
1908
|
-
{ name: `Replace all existing ${options.itemsNoun}`, value: "replace" }
|
|
1909
|
-
]
|
|
1910
|
-
});
|
|
1911
|
-
if (pasteMode === "replace") {
|
|
1912
|
-
items = parsed;
|
|
1913
|
-
} else {
|
|
1914
|
-
Object.assign(items, parsed);
|
|
1915
|
-
}
|
|
1916
|
-
} else {
|
|
1917
|
-
items = parsed;
|
|
1918
|
-
}
|
|
1919
|
-
logger.success(`Successfully applied ${import_picocolors5.default.cyan(String(count))} ${options.itemsNoun}`);
|
|
1920
|
-
}
|
|
1921
|
-
} else if (choice === "clear") {
|
|
1922
|
-
const confirmClear = await (0, import_prompts5.confirm)({
|
|
1923
|
-
message: `Are you sure you want to clear all ${options.itemsNoun}?`,
|
|
1924
|
-
default: false
|
|
1925
|
-
});
|
|
1926
|
-
if (confirmClear) {
|
|
1927
|
-
items = {};
|
|
1928
|
-
logger.success(`Cleared all ${options.itemsNoun}`);
|
|
1929
|
-
}
|
|
1930
|
-
}
|
|
1931
|
-
}
|
|
1932
|
-
};
|
|
1933
|
-
|
|
1934
|
-
// src/interactive/prompts/env.ts
|
|
1935
|
-
var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
|
|
1936
|
-
var maskSecretValue = (key, value) => {
|
|
1937
|
-
if (!SECRET_KEY_PATTERN.test(key) || value.length <= 4) {
|
|
1938
|
-
return value;
|
|
1939
|
-
}
|
|
1940
|
-
return `${value.slice(0, 2)}***${value.slice(-2)}`;
|
|
1941
|
-
};
|
|
1942
|
-
var formatEnvText = (env) => {
|
|
1943
|
-
return Object.entries(env).map(([key, value]) => {
|
|
1944
|
-
if (/[\s"']/.test(value)) {
|
|
1945
|
-
return `${key}="${value.replace(/"/g, '\\"')}"`;
|
|
1946
|
-
}
|
|
1947
|
-
return `${key}=${value}`;
|
|
1948
|
-
}).join("\n");
|
|
1949
|
-
};
|
|
1950
|
-
var parseEnvText = (rawText) => {
|
|
1951
|
-
const result = {};
|
|
1952
|
-
const lines = rawText.split(/\r?\n/);
|
|
1953
|
-
for (const rawLine of lines) {
|
|
1954
|
-
let line = rawLine.trim();
|
|
1955
|
-
if (!line || line.startsWith("#")) continue;
|
|
1956
|
-
if (line.startsWith("export ")) {
|
|
1957
|
-
line = line.slice(7).trim();
|
|
1958
|
-
}
|
|
1959
|
-
const eqIndex = line.indexOf("=");
|
|
1960
|
-
if (eqIndex === -1) continue;
|
|
1961
|
-
const key = line.slice(0, eqIndex).trim();
|
|
1962
|
-
let value = line.slice(eqIndex + 1).trim();
|
|
1963
|
-
if (!key) continue;
|
|
1964
|
-
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
1965
|
-
value = value.slice(1, -1);
|
|
1966
|
-
}
|
|
1967
|
-
result[key] = value;
|
|
1968
|
-
}
|
|
1969
|
-
return result;
|
|
1970
|
-
};
|
|
1971
|
-
var promptEnvConfig = async (initialEnv = {}) => {
|
|
1972
|
-
const env = { ...initialEnv };
|
|
1973
|
-
const initialCount = Object.keys(env).length;
|
|
1974
|
-
if (initialCount > 0) {
|
|
1975
|
-
logger.info(`Includes ${import_picocolors6.default.cyan(String(initialCount))} preset environment variables`);
|
|
1976
|
-
}
|
|
1977
|
-
const mode = await (0, import_prompts6.select)({
|
|
1978
|
-
message: "Configure environment variables?",
|
|
1979
|
-
choices: [
|
|
1980
|
-
{
|
|
1981
|
-
name: "Skip / None",
|
|
1982
|
-
value: "skip"
|
|
1983
|
-
},
|
|
1984
|
-
{
|
|
1985
|
-
name: "Paste multiline .env text into terminal",
|
|
1986
|
-
value: "paste"
|
|
1987
|
-
},
|
|
1988
|
-
{
|
|
1989
|
-
name: "Open in system default editor ($EDITOR)",
|
|
1990
|
-
value: "editor"
|
|
1991
|
-
},
|
|
1992
|
-
{
|
|
1993
|
-
name: "Enter key-value pairs one by one",
|
|
1994
|
-
value: "manual"
|
|
1995
|
-
}
|
|
1996
|
-
]
|
|
1997
|
-
});
|
|
1998
|
-
if (mode === "skip") {
|
|
1999
|
-
return env;
|
|
2000
|
-
}
|
|
2001
|
-
if (mode === "paste" || mode === "editor") {
|
|
2002
|
-
const pasted = mode === "editor" ? await promptEditorText({
|
|
2003
|
-
message: "Paste or edit environment variables in editor, then save and exit:",
|
|
2004
|
-
postfix: ".env",
|
|
2005
|
-
defaultText: formatEnvText(env)
|
|
2006
|
-
}) : await readMultilineTextFromTerminal("Paste .env formatted content (multiline supported):");
|
|
2007
|
-
const parsed = parseEnvText(pasted);
|
|
2008
|
-
const count = Object.keys(parsed).length;
|
|
2009
|
-
if (count === 0) {
|
|
2010
|
-
logger.warn("No valid KEY=VALUE pairs recognized");
|
|
2011
|
-
} else {
|
|
2012
|
-
Object.assign(env, parsed);
|
|
2013
|
-
logger.success(`Successfully parsed ${import_picocolors6.default.cyan(String(count))} environment variables:`);
|
|
2014
|
-
for (const [k, v] of Object.entries(parsed)) {
|
|
2015
|
-
console.log(` ${import_picocolors6.default.bold(k)}=${import_picocolors6.default.dim(maskSecretValue(k, v))}`);
|
|
2016
|
-
}
|
|
2017
|
-
}
|
|
2018
|
-
return env;
|
|
2019
|
-
}
|
|
2020
|
-
logger.info("Entering environment variables (leave key empty and press enter to finish):");
|
|
2021
|
-
while (true) {
|
|
2022
|
-
const key = await (0, import_prompts6.input)({
|
|
2023
|
-
message: "Variable name (Key, leave empty to finish):",
|
|
2024
|
-
validate: (val2) => {
|
|
2025
|
-
const trimmed = val2.trim();
|
|
2026
|
-
if (!trimmed) return true;
|
|
2027
|
-
if (/\s/.test(trimmed)) return "Variable name cannot contain spaces";
|
|
2028
|
-
return true;
|
|
2029
|
-
}
|
|
2030
|
-
});
|
|
2031
|
-
const trimmedKey = key.trim();
|
|
2032
|
-
if (!trimmedKey) break;
|
|
2033
|
-
const isSecret = SECRET_KEY_PATTERN.test(trimmedKey);
|
|
2034
|
-
let val;
|
|
2035
|
-
if (isSecret) {
|
|
2036
|
-
val = await (0, import_prompts6.password)({
|
|
2037
|
-
message: `Value for (${trimmedKey}) [secret masked]:`,
|
|
2038
|
-
mask: "*"
|
|
2039
|
-
});
|
|
2040
|
-
} else {
|
|
2041
|
-
val = await (0, import_prompts6.input)({
|
|
2042
|
-
message: `Value for (${trimmedKey}):`
|
|
2043
|
-
});
|
|
2044
|
-
}
|
|
2045
|
-
env[trimmedKey] = val;
|
|
2046
|
-
logger.success(`Added: ${import_picocolors6.default.cyan(trimmedKey)}`);
|
|
2047
|
-
}
|
|
2048
|
-
return env;
|
|
2049
|
-
};
|
|
2050
|
-
var promptEditEnvConfig = async (currentEnv = {}) => promptEditKeyValueConfig(currentEnv, {
|
|
2051
|
-
title: "Environment Variables",
|
|
2052
|
-
itemNoun: "variable",
|
|
2053
|
-
itemsNoun: "environment variables",
|
|
2054
|
-
separator: "=",
|
|
2055
|
-
editorPostfix: ".env",
|
|
2056
|
-
editorMessage: "Edit environment variables in editor, then save and exit:",
|
|
2057
|
-
pasteMessage: "Paste .env formatted content (multiline supported):",
|
|
2058
|
-
keyPromptMessage: "Variable name (Key):",
|
|
2059
|
-
valuePromptMessage: "Value",
|
|
2060
|
-
isSecretKey: (k) => SECRET_KEY_PATTERN.test(k),
|
|
2061
|
-
maskValue: maskSecretValue,
|
|
2062
|
-
formatText: formatEnvText,
|
|
2063
|
-
parseText: parseEnvText
|
|
2064
|
-
});
|
|
2065
|
-
|
|
2066
|
-
// src/interactive/prompts/headers.ts
|
|
2067
|
-
var import_prompts7 = require("@inquirer/prompts");
|
|
2068
|
-
var import_picocolors7 = __toESM(require("picocolors"), 1);
|
|
2069
|
-
var SECRET_HEADER_PATTERN = /(authorization|token|key|secret|auth)/i;
|
|
2070
|
-
var maskSecretHeader = (key, value) => {
|
|
2071
|
-
if (!SECRET_HEADER_PATTERN.test(key) || value.length <= 8) {
|
|
2072
|
-
return value;
|
|
2073
|
-
}
|
|
2074
|
-
return `${value.slice(0, 4)}***${value.slice(-3)}`;
|
|
2075
|
-
};
|
|
2076
|
-
var formatHeadersText = (headers) => {
|
|
2077
|
-
return Object.entries(headers).map(([key, value]) => `${key}: ${value}`).join("\n");
|
|
2078
|
-
};
|
|
2079
|
-
var parseHeadersText = (rawText) => {
|
|
2080
|
-
const result = {};
|
|
2081
|
-
const lines = rawText.split(/\r?\n/);
|
|
2082
|
-
for (const rawLine of lines) {
|
|
2083
|
-
const line = rawLine.trim();
|
|
2084
|
-
if (!line || line.startsWith("#")) continue;
|
|
2085
|
-
const colonIndex = line.indexOf(":");
|
|
2086
|
-
const equalIndex = line.indexOf("=");
|
|
2087
|
-
let splitIndex = -1;
|
|
2088
|
-
if (colonIndex !== -1 && equalIndex !== -1) {
|
|
2089
|
-
splitIndex = Math.min(colonIndex, equalIndex);
|
|
2090
|
-
} else if (colonIndex !== -1) {
|
|
2091
|
-
splitIndex = colonIndex;
|
|
2092
|
-
} else {
|
|
2093
|
-
splitIndex = equalIndex;
|
|
2094
|
-
}
|
|
2095
|
-
if (splitIndex === -1) continue;
|
|
2096
|
-
const key = line.slice(0, splitIndex).trim();
|
|
2097
|
-
let value = line.slice(splitIndex + 1).trim();
|
|
2098
|
-
if (!key) continue;
|
|
2099
|
-
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
2100
|
-
value = value.slice(1, -1);
|
|
2101
|
-
}
|
|
2102
|
-
result[key] = value;
|
|
2103
|
-
}
|
|
2104
|
-
return result;
|
|
2105
|
-
};
|
|
2106
|
-
var promptHeadersConfig = async (initialHeaders = {}) => {
|
|
2107
|
-
const headers = { ...initialHeaders };
|
|
2108
|
-
const mode = await (0, import_prompts7.select)({
|
|
2109
|
-
message: "Select HTTP headers configuration method:",
|
|
2110
|
-
choices: [
|
|
2111
|
-
{
|
|
2112
|
-
name: "Paste multiline headers into terminal (Key: Value format)",
|
|
2113
|
-
value: "paste"
|
|
2114
|
-
},
|
|
2115
|
-
{
|
|
2116
|
-
name: "Open in system default editor ($EDITOR)",
|
|
2117
|
-
value: "editor"
|
|
2118
|
-
},
|
|
2119
|
-
{
|
|
2120
|
-
name: "Enter headers one by one (e.g. Authorization: Bearer ...)",
|
|
2121
|
-
value: "manual"
|
|
2122
|
-
},
|
|
2123
|
-
{
|
|
2124
|
-
name: "Skip / None",
|
|
2125
|
-
value: "skip"
|
|
2126
|
-
}
|
|
2127
|
-
]
|
|
2128
|
-
});
|
|
2129
|
-
if (mode === "skip") {
|
|
2130
|
-
return headers;
|
|
2131
|
-
}
|
|
2132
|
-
if (mode === "paste" || mode === "editor") {
|
|
2133
|
-
const pasted = mode === "editor" ? await promptEditorText({
|
|
2134
|
-
message: "Paste or edit HTTP headers in editor, then save and exit:",
|
|
2135
|
-
defaultText: formatHeadersText(headers)
|
|
2136
|
-
}) : await readMultilineTextFromTerminal(
|
|
2137
|
-
"Paste HTTP headers content (multiline supported, e.g. Authorization: Bearer ...):"
|
|
2138
|
-
);
|
|
2139
|
-
const parsed = parseHeadersText(pasted);
|
|
2140
|
-
const count = Object.keys(parsed).length;
|
|
2141
|
-
if (count === 0) {
|
|
2142
|
-
logger.warn("No valid Key: Value pairs recognized");
|
|
2143
|
-
} else {
|
|
2144
|
-
Object.assign(headers, parsed);
|
|
2145
|
-
logger.success(`Successfully parsed ${import_picocolors7.default.cyan(String(count))} headers:`);
|
|
2146
|
-
for (const [k, v] of Object.entries(parsed)) {
|
|
2147
|
-
console.log(` ${import_picocolors7.default.bold(k)}: ${import_picocolors7.default.dim(maskSecretHeader(k, v))}`);
|
|
2148
|
-
}
|
|
2149
|
-
}
|
|
2150
|
-
return headers;
|
|
2151
|
-
}
|
|
2152
|
-
logger.info("Entering HTTP headers (leave header name empty and press enter to finish):");
|
|
2153
|
-
while (true) {
|
|
2154
|
-
const name = await (0, import_prompts7.input)({
|
|
2155
|
-
message: "Header name (e.g. Authorization, leave empty to finish):",
|
|
2156
|
-
validate: (val2) => {
|
|
2157
|
-
const trimmed = val2.trim();
|
|
2158
|
-
if (!trimmed) return true;
|
|
2159
|
-
if (/\s/.test(trimmed)) return "Header name cannot contain spaces";
|
|
2160
|
-
return true;
|
|
2161
|
-
}
|
|
2162
|
-
});
|
|
2163
|
-
const trimmedName = name.trim();
|
|
2164
|
-
if (!trimmedName) break;
|
|
2165
|
-
const isSecret = SECRET_HEADER_PATTERN.test(trimmedName);
|
|
2166
|
-
let val;
|
|
2167
|
-
if (isSecret) {
|
|
2168
|
-
val = await (0, import_prompts7.password)({
|
|
2169
|
-
message: `Header value for (${trimmedName}) [sensitive content masked]:`,
|
|
2170
|
-
mask: "*"
|
|
2171
|
-
});
|
|
2172
|
-
} else {
|
|
2173
|
-
val = await (0, import_prompts7.input)({
|
|
2174
|
-
message: `Header value for (${trimmedName}):`
|
|
2175
|
-
});
|
|
2176
|
-
}
|
|
2177
|
-
headers[trimmedName] = val;
|
|
2178
|
-
logger.success(`Added: ${import_picocolors7.default.cyan(trimmedName)}`);
|
|
2179
|
-
}
|
|
2180
|
-
return headers;
|
|
2181
|
-
};
|
|
2182
|
-
var promptEditHeadersConfig = async (currentHeaders = {}) => promptEditKeyValueConfig(currentHeaders, {
|
|
2183
|
-
title: "HTTP Headers",
|
|
2184
|
-
itemNoun: "header",
|
|
2185
|
-
itemsNoun: "HTTP headers",
|
|
2186
|
-
separator: ":",
|
|
2187
|
-
editorMessage: "Edit HTTP headers in editor, then save and exit:",
|
|
2188
|
-
pasteMessage: "Paste HTTP headers content (multiline supported, e.g. Authorization: Bearer ...):",
|
|
2189
|
-
keyPromptMessage: "Header name (e.g. Authorization):",
|
|
2190
|
-
valuePromptMessage: "Header value",
|
|
2191
|
-
isSecretKey: (k) => SECRET_HEADER_PATTERN.test(k),
|
|
2192
|
-
maskValue: maskSecretHeader,
|
|
2193
|
-
formatText: formatHeadersText,
|
|
2194
|
-
parseText: parseHeadersText
|
|
2195
|
-
});
|
|
2196
|
-
|
|
2197
|
-
// src/interactive/wizard-add.ts
|
|
2198
|
-
var wizardAdd = async (initial = {}) => {
|
|
2199
|
-
const cwd = initial.cwd ?? process.cwd();
|
|
2200
|
-
logger.info(import_picocolors8.default.bold("Welcome to the MCP interactive add wizard"));
|
|
2201
|
-
let source = initial.source;
|
|
2202
|
-
if (!source) {
|
|
2203
|
-
const sourceType = await (0, import_prompts8.select)({
|
|
2204
|
-
message: "Select MCP server type:",
|
|
2205
|
-
choices: [
|
|
2206
|
-
{
|
|
2207
|
-
name: "npm package (run via npx)",
|
|
2208
|
-
value: "npm"
|
|
2209
|
-
},
|
|
2210
|
-
{
|
|
2211
|
-
name: "Remote MCP server (via HTTP / SSE URL)",
|
|
2212
|
-
value: "remote"
|
|
2213
|
-
},
|
|
2214
|
-
{
|
|
2215
|
-
name: "Local command / script / Docker (stdio)",
|
|
2216
|
-
value: "command"
|
|
2217
|
-
}
|
|
2218
|
-
]
|
|
2219
|
-
});
|
|
2220
|
-
if (sourceType === "npm") {
|
|
2221
|
-
source = await (0, import_prompts8.input)({
|
|
2222
|
-
message: "Enter npm package name (e.g. @modelcontextprotocol/server-postgres):",
|
|
2223
|
-
validate: (val) => val.trim() ? true : "Package name cannot be empty"
|
|
2224
|
-
});
|
|
2225
|
-
} else if (sourceType === "remote") {
|
|
2226
|
-
source = await (0, import_prompts8.input)({
|
|
2227
|
-
message: "Enter remote server URL (e.g. https://mcp.example.com/sse):",
|
|
2228
|
-
validate: (val) => {
|
|
2229
|
-
const trimmed = val.trim();
|
|
2230
|
-
if (!trimmed) return "URL cannot be empty";
|
|
2231
|
-
if (!/^https?:\/\//i.test(trimmed)) return "Please enter a valid URL starting with http:// or https://";
|
|
2232
|
-
return true;
|
|
2233
|
-
}
|
|
2234
|
-
});
|
|
2235
|
-
} else {
|
|
2236
|
-
source = await (0, import_prompts8.input)({
|
|
2237
|
-
message: "Enter command and arguments (e.g. python -m my_mcp_server or docker run ...):",
|
|
2238
|
-
validate: (val) => val.trim() ? true : "Command cannot be empty"
|
|
2239
|
-
});
|
|
2240
|
-
}
|
|
2241
|
-
}
|
|
2242
|
-
source = source.trim();
|
|
2243
|
-
const parsed = parseMcpSource(source);
|
|
2244
|
-
let serverName = initial.name;
|
|
2245
|
-
if (!serverName) {
|
|
2246
|
-
serverName = await (0, import_prompts8.input)({
|
|
2247
|
-
message: "MCP server name:",
|
|
2248
|
-
default: parsed.inferredName,
|
|
2249
|
-
validate: (val) => val.trim() ? true : "Server name cannot be empty"
|
|
2250
|
-
});
|
|
2251
|
-
}
|
|
2252
|
-
serverName = serverName.trim();
|
|
2253
|
-
let transport = initial.transport;
|
|
2254
|
-
let headers = initial.headers ?? {};
|
|
2255
|
-
if (parsed.type === "remote") {
|
|
2256
|
-
if (!transport) {
|
|
2257
|
-
const isSseUrl = /\/sse\b/i.test(parsed.value);
|
|
2258
|
-
transport = await (0, import_prompts8.select)({
|
|
2259
|
-
message: "Select remote transport protocol:",
|
|
2260
|
-
choices: [
|
|
2261
|
-
{ name: "HTTP", value: "http" },
|
|
2262
|
-
{ name: "SSE (Server-Sent Events)", value: "sse" }
|
|
2263
|
-
],
|
|
2264
|
-
default: isSseUrl ? "sse" : "http"
|
|
2265
|
-
});
|
|
2266
|
-
}
|
|
2267
|
-
if (Object.keys(headers).length === 0) {
|
|
2268
|
-
const needHeader = await (0, import_prompts8.confirm)({
|
|
2269
|
-
message: "Configure HTTP headers (e.g. Authorization Bearer token)?",
|
|
2270
|
-
default: false
|
|
2271
|
-
});
|
|
2272
|
-
if (needHeader) {
|
|
2273
|
-
headers = await promptHeadersConfig();
|
|
2274
|
-
}
|
|
2275
|
-
}
|
|
2276
|
-
}
|
|
2277
|
-
const { global: isGlobal, agents: selectedAgents } = await promptScopeAndAgents({
|
|
2278
|
-
cwd,
|
|
2279
|
-
defaultGlobal: initial.global,
|
|
2280
|
-
defaultAgents: initial.agents
|
|
2281
|
-
});
|
|
2282
|
-
let args = initial.args ?? [];
|
|
2283
|
-
if (parsed.type !== "remote") {
|
|
2284
|
-
args = await promptArgsConfig(args);
|
|
2285
|
-
}
|
|
2286
|
-
let env = initial.env ?? {};
|
|
2287
|
-
if (parsed.type !== "remote") {
|
|
2288
|
-
env = await promptEnvConfig(env);
|
|
2289
|
-
}
|
|
2290
|
-
console.log("\n" + import_picocolors8.default.cyan(import_picocolors8.default.bold("Configuration Preview:")));
|
|
2291
|
-
console.log(` ${import_picocolors8.default.bold("Server Name:")} ${import_picocolors8.default.green(serverName)}`);
|
|
2292
|
-
console.log(` ${import_picocolors8.default.bold("Server Type:")} ${import_picocolors8.default.magenta(parsed.type)}`);
|
|
2293
|
-
console.log(` ${import_picocolors8.default.bold("Source/Command:")} ${import_picocolors8.default.dim(source)}`);
|
|
2294
|
-
console.log(` ${import_picocolors8.default.bold("Scope:")} ${isGlobal ? import_picocolors8.default.yellow("Global") : import_picocolors8.default.blue("Project")}`);
|
|
2295
|
-
console.log(` ${import_picocolors8.default.bold("Target Agents:")} ${import_picocolors8.default.cyan(selectedAgents.join(", "))}`);
|
|
2296
|
-
if (args.length > 0) {
|
|
2297
|
-
console.log(` ${import_picocolors8.default.bold("Arguments:")} ${import_picocolors8.default.dim(args.join(" "))}`);
|
|
2298
|
-
}
|
|
2299
|
-
if (transport) {
|
|
2300
|
-
console.log(` ${import_picocolors8.default.bold("Transport:")} ${import_picocolors8.default.magenta(transport)}`);
|
|
2301
|
-
}
|
|
2302
|
-
const envKeys = Object.keys(env);
|
|
2303
|
-
if (envKeys.length > 0) {
|
|
2304
|
-
console.log(` ${import_picocolors8.default.bold("Environment Variables:")} ${import_picocolors8.default.dim(envKeys.join(", "))} (${envKeys.length})`);
|
|
2305
|
-
}
|
|
2306
|
-
const headerKeys = Object.keys(headers);
|
|
2307
|
-
if (headerKeys.length > 0) {
|
|
2308
|
-
console.log(` ${import_picocolors8.default.bold("Headers:")} ${import_picocolors8.default.dim(headerKeys.join(", "))} (${headerKeys.length})`);
|
|
2309
|
-
}
|
|
2310
|
-
console.log();
|
|
2311
|
-
const proceed = await (0, import_prompts8.confirm)({
|
|
2312
|
-
message: "Confirm installation with this configuration?",
|
|
2313
|
-
default: true
|
|
2314
|
-
});
|
|
2315
|
-
if (!proceed) {
|
|
2316
|
-
logger.warn("Operation cancelled");
|
|
2317
|
-
return false;
|
|
2318
|
-
}
|
|
2319
|
-
const result = installMcpServer({
|
|
2320
|
-
source,
|
|
2321
|
-
name: serverName,
|
|
2322
|
-
agents: selectedAgents,
|
|
2323
|
-
args,
|
|
2324
|
-
global: isGlobal,
|
|
2325
|
-
cwd,
|
|
2326
|
-
transport,
|
|
2327
|
-
headers,
|
|
2328
|
-
env
|
|
2329
|
-
});
|
|
2330
|
-
logger.info(
|
|
2331
|
-
`Writing ${import_picocolors8.default.bold(result.serverName)} to ${import_picocolors8.default.cyan(String(result.results.length))} agent config files...`
|
|
2332
|
-
);
|
|
2333
|
-
let allSuccess = true;
|
|
2334
|
-
for (const record of result.results) {
|
|
2335
|
-
if (record.success) {
|
|
2336
|
-
logger.success(`${import_picocolors8.default.cyan(record.agent)}: Successfully written to ${import_picocolors8.default.dim(record.path)}`);
|
|
2337
|
-
} else {
|
|
2338
|
-
allSuccess = false;
|
|
2339
|
-
logger.error(`${import_picocolors8.default.cyan(record.agent)}: Failed to write - ${record.error}`);
|
|
2340
|
-
}
|
|
2341
|
-
}
|
|
2342
|
-
if (allSuccess) {
|
|
2343
|
-
logger.success(import_picocolors8.default.bold(`MCP server "${serverName}" configured successfully!`));
|
|
2344
|
-
}
|
|
2345
|
-
return allSuccess;
|
|
2346
|
-
};
|
|
2347
|
-
|
|
2348
|
-
// src/interactive/wizard-manage.ts
|
|
2349
|
-
var import_prompts9 = require("@inquirer/prompts");
|
|
2350
|
-
var import_picocolors9 = __toESM(require("picocolors"), 1);
|
|
2351
|
-
|
|
2352
|
-
// src/interactive/utils/group-installed-servers.ts
|
|
2353
|
-
var normalizeServerConfig = parseServerConfig;
|
|
2354
1823
|
var groupInstalledServersByName = (installed) => {
|
|
2355
1824
|
const grouped = /* @__PURE__ */ new Map();
|
|
2356
1825
|
for (const item of installed) {
|
|
1826
|
+
const itemConfig = item.serverConfig ?? parseServerConfig(item.config);
|
|
2357
1827
|
let entry = grouped.get(item.serverName);
|
|
2358
1828
|
if (!entry) {
|
|
2359
1829
|
entry = {
|
|
2360
1830
|
serverName: item.serverName,
|
|
2361
1831
|
agents: [],
|
|
2362
1832
|
paths: [],
|
|
2363
|
-
config:
|
|
1833
|
+
config: itemConfig,
|
|
1834
|
+
hasDivergence: false
|
|
2364
1835
|
};
|
|
2365
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
|
+
}
|
|
2366
1841
|
}
|
|
2367
1842
|
if (!entry.agents.includes(item.agent)) {
|
|
2368
1843
|
entry.agents.push(item.agent);
|
|
@@ -2373,679 +1848,127 @@ var groupInstalledServersByName = (installed) => {
|
|
|
2373
1848
|
}
|
|
2374
1849
|
return grouped;
|
|
2375
1850
|
};
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
serverName,
|
|
2380
|
-
config,
|
|
2381
|
-
agents,
|
|
2382
|
-
isGlobal,
|
|
2383
|
-
titlePrefix = "MCP Server Details"
|
|
2384
|
-
}) => {
|
|
2385
|
-
console.log("\n" + import_picocolors9.default.cyan(import_picocolors9.default.bold(`${titlePrefix}: [${serverName}]`)));
|
|
2386
|
-
if (isGlobal !== void 0) {
|
|
2387
|
-
console.log(` ${import_picocolors9.default.bold("Scope:")} ${isGlobal ? "Global" : "Project"}`);
|
|
2388
|
-
}
|
|
2389
|
-
if (agents && agents.length > 0) {
|
|
2390
|
-
console.log(
|
|
2391
|
-
` ${import_picocolors9.default.bold("Configured Agents:")} ${import_picocolors9.default.green(agents.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
|
|
2392
|
-
);
|
|
2393
|
-
}
|
|
2394
|
-
const isRemote = Boolean(config.url && config.url.length > 0);
|
|
2395
|
-
if (isRemote) {
|
|
2396
|
-
console.log(` ${import_picocolors9.default.bold("Transport:")} ${import_picocolors9.default.magenta(config.type ?? "http")}`);
|
|
2397
|
-
console.log(` ${import_picocolors9.default.bold("URL:")} ${import_picocolors9.default.dim(config.url ?? "")}`);
|
|
2398
|
-
const headerKeys = Object.keys(config.headers ?? {});
|
|
2399
|
-
if (headerKeys.length > 0) {
|
|
2400
|
-
console.log(` ${import_picocolors9.default.bold("Headers:")} ${import_picocolors9.default.cyan(String(headerKeys.length))}`);
|
|
2401
|
-
for (const [k, v] of Object.entries(config.headers ?? {})) {
|
|
2402
|
-
console.log(` ${import_picocolors9.default.bold(k)}: ${import_picocolors9.default.dim(maskSecretHeader(k, v))}`);
|
|
2403
|
-
}
|
|
2404
|
-
} else {
|
|
2405
|
-
console.log(` ${import_picocolors9.default.bold("Headers:")} ${import_picocolors9.default.dim("(none)")}`);
|
|
2406
|
-
}
|
|
2407
|
-
} else {
|
|
2408
|
-
console.log(` ${import_picocolors9.default.bold("Command:")} ${import_picocolors9.default.magenta(config.command ?? "")}`);
|
|
2409
|
-
const argsStr = config.args && config.args.length > 0 ? config.args.join(" ") : "(none)";
|
|
2410
|
-
console.log(` ${import_picocolors9.default.bold("Arguments:")} ${import_picocolors9.default.dim(argsStr)}`);
|
|
2411
|
-
const envKeys = Object.keys(config.env ?? {});
|
|
2412
|
-
if (envKeys.length > 0) {
|
|
2413
|
-
console.log(` ${import_picocolors9.default.bold("Environment Variables:")} ${import_picocolors9.default.cyan(String(envKeys.length))}`);
|
|
2414
|
-
for (const [k, v] of Object.entries(config.env ?? {})) {
|
|
2415
|
-
console.log(` ${import_picocolors9.default.bold(k)}=${import_picocolors9.default.dim(maskSecretValue(k, v))}`);
|
|
2416
|
-
}
|
|
2417
|
-
} else {
|
|
2418
|
-
console.log(` ${import_picocolors9.default.bold("Environment Variables:")} ${import_picocolors9.default.dim("(none)")}`);
|
|
2419
|
-
}
|
|
2420
|
-
}
|
|
2421
|
-
console.log();
|
|
2422
|
-
};
|
|
2423
|
-
var handleEditServerConfig = async ({
|
|
2424
|
-
targetGroup,
|
|
2425
|
-
isGlobal,
|
|
2426
|
-
cwd
|
|
2427
|
-
}) => {
|
|
2428
|
-
const serverName = targetGroup.serverName;
|
|
2429
|
-
let workingConfig = {
|
|
2430
|
-
...targetGroup.config,
|
|
2431
|
-
args: targetGroup.config.args ? [...targetGroup.config.args] : void 0,
|
|
2432
|
-
env: targetGroup.config.env ? { ...targetGroup.config.env } : void 0,
|
|
2433
|
-
headers: targetGroup.config.headers ? { ...targetGroup.config.headers } : void 0
|
|
2434
|
-
};
|
|
2435
|
-
while (true) {
|
|
2436
|
-
const isRemote = Boolean(workingConfig.url && workingConfig.url.length > 0);
|
|
2437
|
-
displayServerDetails({
|
|
2438
|
-
serverName,
|
|
2439
|
-
config: workingConfig,
|
|
2440
|
-
titlePrefix: "Edit Server Configuration"
|
|
2441
|
-
});
|
|
2442
|
-
const editChoices = isRemote ? [
|
|
2443
|
-
{ name: "Edit HTTP Headers (headers)", value: "headers" },
|
|
2444
|
-
{ name: "Edit Remote URL (url)", value: "url" },
|
|
2445
|
-
{ name: "Edit Transport Protocol (type)", value: "transport" },
|
|
2446
|
-
{ name: "Reset changes to original", value: "reset" },
|
|
2447
|
-
{ name: "Save and apply changes", value: "save" },
|
|
2448
|
-
{ name: "Cancel (discard changes)", value: "cancel" }
|
|
2449
|
-
] : [
|
|
2450
|
-
{ name: "Edit Environment Variables (env)", value: "env" },
|
|
2451
|
-
{ name: "Edit Command Arguments (args)", value: "args" },
|
|
2452
|
-
{ name: "Edit Executable Command (command)", value: "command" },
|
|
2453
|
-
{ name: "Reset changes to original", value: "reset" },
|
|
2454
|
-
{ name: "Save and apply changes", value: "save" },
|
|
2455
|
-
{ name: "Cancel (discard changes)", value: "cancel" }
|
|
2456
|
-
];
|
|
2457
|
-
const editAction = await (0, import_prompts9.select)({
|
|
2458
|
-
message: `What would you like to modify in [${serverName}]?`,
|
|
2459
|
-
choices: editChoices
|
|
2460
|
-
});
|
|
2461
|
-
if (editAction === "cancel") {
|
|
2462
|
-
logger.info("Modification cancelled; changes discarded");
|
|
2463
|
-
return;
|
|
2464
|
-
}
|
|
2465
|
-
if (editAction === "reset") {
|
|
2466
|
-
workingConfig = {
|
|
2467
|
-
...targetGroup.config,
|
|
2468
|
-
args: targetGroup.config.args ? [...targetGroup.config.args] : void 0,
|
|
2469
|
-
env: targetGroup.config.env ? { ...targetGroup.config.env } : void 0,
|
|
2470
|
-
headers: targetGroup.config.headers ? { ...targetGroup.config.headers } : void 0
|
|
2471
|
-
};
|
|
2472
|
-
logger.info("Configuration reset to original");
|
|
2473
|
-
continue;
|
|
2474
|
-
}
|
|
2475
|
-
if (editAction === "env") {
|
|
2476
|
-
workingConfig.env = await promptEditEnvConfig(workingConfig.env ?? {});
|
|
2477
|
-
} else if (editAction === "args") {
|
|
2478
|
-
workingConfig.args = await promptEditArgs(workingConfig.args ?? []);
|
|
2479
|
-
} else if (editAction === "command") {
|
|
2480
|
-
const newCmd = await (0, import_prompts9.input)({
|
|
2481
|
-
message: "Executable command:",
|
|
2482
|
-
default: workingConfig.command,
|
|
2483
|
-
validate: (val) => val.trim() ? true : "Command cannot be empty"
|
|
2484
|
-
});
|
|
2485
|
-
workingConfig.command = newCmd.trim();
|
|
2486
|
-
} else if (editAction === "headers") {
|
|
2487
|
-
workingConfig.headers = await promptEditHeadersConfig(workingConfig.headers ?? {});
|
|
2488
|
-
} else if (editAction === "url") {
|
|
2489
|
-
const newUrl = await (0, import_prompts9.input)({
|
|
2490
|
-
message: "Remote server URL:",
|
|
2491
|
-
default: workingConfig.url,
|
|
2492
|
-
validate: (val) => {
|
|
2493
|
-
const trimmed = val.trim();
|
|
2494
|
-
if (!trimmed) return "URL cannot be empty";
|
|
2495
|
-
if (!/^https?:\/\//i.test(trimmed)) {
|
|
2496
|
-
return "Please enter a valid URL starting with http:// or https://";
|
|
2497
|
-
}
|
|
2498
|
-
return true;
|
|
2499
|
-
}
|
|
2500
|
-
});
|
|
2501
|
-
workingConfig.url = newUrl.trim();
|
|
2502
|
-
} else if (editAction === "transport") {
|
|
2503
|
-
workingConfig.type = await (0, import_prompts9.select)({
|
|
2504
|
-
message: "Select remote transport protocol:",
|
|
2505
|
-
choices: [
|
|
2506
|
-
{ name: "HTTP", value: "http" },
|
|
2507
|
-
{ name: "SSE (Server-Sent Events)", value: "sse" }
|
|
2508
|
-
],
|
|
2509
|
-
default: workingConfig.type === "sse" ? "sse" : "http"
|
|
2510
|
-
});
|
|
2511
|
-
} else if (editAction === "save") {
|
|
2512
|
-
let targetAgents = targetGroup.agents;
|
|
2513
|
-
if (targetGroup.agents.length > 1) {
|
|
2514
|
-
targetAgents = await (0, import_prompts9.checkbox)({
|
|
2515
|
-
message: "Select agents to update configuration (Space to toggle):",
|
|
2516
|
-
choices: targetGroup.agents.map((a) => ({
|
|
2517
|
-
name: `${getMcpAgentConfig(a).displayName} (${a})`,
|
|
2518
|
-
value: a,
|
|
2519
|
-
checked: true
|
|
2520
|
-
})),
|
|
2521
|
-
loop: false,
|
|
2522
|
-
validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
|
|
2523
|
-
});
|
|
2524
|
-
}
|
|
2525
|
-
const requestedTransport = workingConfig.url ? workingConfig.type ?? "http" : "stdio";
|
|
2526
|
-
const compatibleAgents = [];
|
|
2527
|
-
const incompatibleAgents = [];
|
|
2528
|
-
for (const agent of targetAgents) {
|
|
2529
|
-
const agentConfig = getMcpAgentConfig(agent);
|
|
2530
|
-
if (isMcpTransportSupported(agentConfig, requestedTransport)) {
|
|
2531
|
-
compatibleAgents.push(agent);
|
|
2532
|
-
} else {
|
|
2533
|
-
const reason = agentConfig.unsupportedTransportMessage ?? `Agent does not support ${requestedTransport} transport`;
|
|
2534
|
-
incompatibleAgents.push({ agent, reason });
|
|
2535
|
-
}
|
|
2536
|
-
}
|
|
2537
|
-
if (incompatibleAgents.length > 0) {
|
|
2538
|
-
for (const item of incompatibleAgents) {
|
|
2539
|
-
logger.warn(`Skipping ${import_picocolors9.default.cyan(item.agent)}: ${item.reason}`);
|
|
2540
|
-
}
|
|
2541
|
-
}
|
|
2542
|
-
if (compatibleAgents.length === 0) {
|
|
2543
|
-
logger.error(
|
|
2544
|
-
`None of the selected agents support ${requestedTransport} transport. Cannot update.`
|
|
2545
|
-
);
|
|
2546
|
-
continue;
|
|
2547
|
-
}
|
|
2548
|
-
const agentNames = compatibleAgents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
|
|
2549
|
-
const confirmed = await (0, import_prompts9.confirm)({
|
|
2550
|
-
message: `Confirm updating configuration for [${serverName}] across: ${agentNames}?`,
|
|
2551
|
-
default: true
|
|
2552
|
-
});
|
|
2553
|
-
if (!confirmed) {
|
|
2554
|
-
logger.warn("Update cancelled");
|
|
2555
|
-
continue;
|
|
2556
|
-
}
|
|
2557
|
-
for (const targetAgent of compatibleAgents) {
|
|
2558
|
-
const res = installMcpServerForAgent(serverName, workingConfig, targetAgent, {
|
|
2559
|
-
global: isGlobal,
|
|
2560
|
-
cwd
|
|
2561
|
-
});
|
|
2562
|
-
if (res.success) {
|
|
2563
|
-
logger.success(
|
|
2564
|
-
`${import_picocolors9.default.cyan(targetAgent)}: Successfully updated configuration in ${import_picocolors9.default.dim(res.path)}`
|
|
2565
|
-
);
|
|
2566
|
-
} else {
|
|
2567
|
-
logger.error(`${import_picocolors9.default.cyan(targetAgent)}: Update failed - ${res.error}`);
|
|
2568
|
-
}
|
|
2569
|
-
}
|
|
2570
|
-
targetGroup.config = workingConfig;
|
|
2571
|
-
logger.success(`Configuration for [${serverName}] updated successfully!`);
|
|
2572
|
-
return;
|
|
2573
|
-
}
|
|
2574
|
-
}
|
|
2575
|
-
};
|
|
2576
|
-
var wizardManage = async (options = {}) => {
|
|
2577
|
-
const cwd = options.cwd ?? process.cwd();
|
|
2578
|
-
const isGlobal = await promptScope({
|
|
2579
|
-
cwd,
|
|
2580
|
-
defaultGlobal: options.global,
|
|
2581
|
-
message: "Select MCP scope to inspect and manage:"
|
|
2582
|
-
});
|
|
2583
|
-
const installed = listInstalledMcpServers({ global: isGlobal, cwd });
|
|
2584
|
-
if (installed.length === 0) {
|
|
2585
|
-
logger.warn(`No configured MCP servers found in ${isGlobal ? "global" : "project"} scope`);
|
|
2586
|
-
return;
|
|
2587
|
-
}
|
|
2588
|
-
const grouped = groupInstalledServersByName(installed);
|
|
2589
|
-
let pendingServerName = options.serverName;
|
|
2590
|
-
while (true) {
|
|
2591
|
-
let chosenServerName;
|
|
2592
|
-
if (pendingServerName && grouped.has(pendingServerName)) {
|
|
2593
|
-
chosenServerName = pendingServerName;
|
|
2594
|
-
pendingServerName = void 0;
|
|
2595
|
-
} else {
|
|
2596
|
-
pendingServerName = void 0;
|
|
2597
|
-
const choices = Array.from(grouped.values()).map((g) => {
|
|
2598
|
-
const agentNames = g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
|
|
2599
|
-
return {
|
|
2600
|
-
name: `${import_picocolors9.default.bold(g.serverName)} ${import_picocolors9.default.dim(`(configured in: ${agentNames})`)}`,
|
|
2601
|
-
value: g.serverName
|
|
2602
|
-
};
|
|
2603
|
-
});
|
|
2604
|
-
choices.push({
|
|
2605
|
-
name: `Back`,
|
|
2606
|
-
value: "__back__"
|
|
2607
|
-
});
|
|
2608
|
-
chosenServerName = await (0, import_prompts9.select)({
|
|
2609
|
-
message: "Select MCP server to manage or sync:",
|
|
2610
|
-
choices
|
|
2611
|
-
});
|
|
2612
|
-
if (chosenServerName === "__back__") {
|
|
2613
|
-
return;
|
|
2614
|
-
}
|
|
2615
|
-
}
|
|
2616
|
-
const targetGroup = grouped.get(chosenServerName);
|
|
2617
|
-
if (!targetGroup) continue;
|
|
2618
|
-
displayServerDetails({
|
|
2619
|
-
serverName: chosenServerName,
|
|
2620
|
-
config: targetGroup.config,
|
|
2621
|
-
agents: targetGroup.agents,
|
|
2622
|
-
isGlobal
|
|
2623
|
-
});
|
|
2624
|
-
const action = await (0, import_prompts9.select)({
|
|
2625
|
-
message: `What would you like to do with [${chosenServerName}]?`,
|
|
2626
|
-
choices: [
|
|
2627
|
-
{
|
|
2628
|
-
name: "Edit server configuration",
|
|
2629
|
-
value: "edit"
|
|
2630
|
-
},
|
|
2631
|
-
{
|
|
2632
|
-
name: "Sync / clone to other agents",
|
|
2633
|
-
value: "sync"
|
|
2634
|
-
},
|
|
2635
|
-
{
|
|
2636
|
-
name: "Back to list",
|
|
2637
|
-
value: "back"
|
|
2638
|
-
}
|
|
2639
|
-
]
|
|
2640
|
-
});
|
|
2641
|
-
if (action === "back") continue;
|
|
2642
|
-
if (action === "edit") {
|
|
2643
|
-
await handleEditServerConfig({
|
|
2644
|
-
targetGroup,
|
|
2645
|
-
isGlobal,
|
|
2646
|
-
cwd
|
|
2647
|
-
});
|
|
2648
|
-
continue;
|
|
2649
|
-
}
|
|
2650
|
-
if (action === "sync") {
|
|
2651
|
-
const allAllowedAgents = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
|
|
2652
|
-
const candidateAgents = allAllowedAgents.filter((a) => !targetGroup.agents.includes(a));
|
|
2653
|
-
if (candidateAgents.length === 0) {
|
|
2654
|
-
logger.info(
|
|
2655
|
-
"All supported agents in this scope already have this MCP server configured; no sync needed"
|
|
2656
|
-
);
|
|
2657
|
-
continue;
|
|
2658
|
-
}
|
|
2659
|
-
const selectedToSync = await (0, import_prompts9.checkbox)({
|
|
2660
|
-
message: "Select target agents to sync to (Space to select):",
|
|
2661
|
-
choices: candidateAgents.map((a) => ({
|
|
2662
|
-
name: `${getMcpAgentConfig(a).displayName} (${a})`,
|
|
2663
|
-
value: a,
|
|
2664
|
-
checked: false
|
|
2665
|
-
})),
|
|
2666
|
-
loop: false,
|
|
2667
|
-
validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
|
|
2668
|
-
});
|
|
2669
|
-
const confirmed = await (0, import_prompts9.confirm)({
|
|
2670
|
-
message: `Confirm syncing configuration of [${chosenServerName}] to: ${selectedToSync.join(", ")}?`,
|
|
2671
|
-
default: true
|
|
2672
|
-
});
|
|
2673
|
-
if (!confirmed) {
|
|
2674
|
-
logger.warn("Sync cancelled");
|
|
2675
|
-
continue;
|
|
2676
|
-
}
|
|
2677
|
-
for (const targetAgent of selectedToSync) {
|
|
2678
|
-
const res = installMcpServerForAgent(chosenServerName, targetGroup.config, targetAgent, {
|
|
2679
|
-
global: isGlobal,
|
|
2680
|
-
cwd
|
|
2681
|
-
});
|
|
2682
|
-
if (res.success) {
|
|
2683
|
-
logger.success(`${import_picocolors9.default.cyan(targetAgent)}: Successfully synced to ${import_picocolors9.default.dim(res.path)}`);
|
|
2684
|
-
targetGroup.agents.push(targetAgent);
|
|
2685
|
-
} else {
|
|
2686
|
-
logger.error(`${import_picocolors9.default.cyan(targetAgent)}: Sync failed - ${res.error}`);
|
|
2687
|
-
}
|
|
2688
|
-
}
|
|
2689
|
-
}
|
|
2690
|
-
}
|
|
1851
|
+
var queryGroupedInstalledServers = (options = {}) => {
|
|
1852
|
+
const installed = listInstalledMcpServers(options);
|
|
1853
|
+
return groupInstalledServersByName(installed);
|
|
2691
1854
|
};
|
|
2692
1855
|
|
|
2693
|
-
// src/
|
|
2694
|
-
var
|
|
2695
|
-
|
|
2696
|
-
var wizardRemove = async (options = {}) => {
|
|
1856
|
+
// src/update-mcp-server.ts
|
|
1857
|
+
var updateMcpServer = (options) => {
|
|
1858
|
+
const isGlobal = options.global ?? false;
|
|
2697
1859
|
const cwd = options.cwd ?? process.cwd();
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
if (installed.length === 0) {
|
|
2705
|
-
logger.warn(`No installed MCP servers found in ${isGlobal ? "global" : "project"} scope`);
|
|
2706
|
-
return false;
|
|
2707
|
-
}
|
|
2708
|
-
const serverMap = groupInstalledServersByName(installed);
|
|
2709
|
-
let serverName = options.name;
|
|
2710
|
-
if (!serverName) {
|
|
2711
|
-
const choices = Array.from(serverMap.values()).map((g) => ({
|
|
2712
|
-
name: `${import_picocolors10.default.bold(g.serverName)} ${import_picocolors10.default.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
|
|
2713
|
-
value: g.serverName
|
|
2714
|
-
}));
|
|
2715
|
-
serverName = await (0, import_prompts10.select)({
|
|
2716
|
-
message: "Select MCP server to remove:",
|
|
2717
|
-
choices
|
|
1860
|
+
let previousConfig = options.previousConfig;
|
|
1861
|
+
if (!previousConfig) {
|
|
1862
|
+
const existing = listInstalledMcpServers({
|
|
1863
|
+
global: isGlobal,
|
|
1864
|
+
cwd,
|
|
1865
|
+
agents: options.agents
|
|
2718
1866
|
});
|
|
1867
|
+
const found = existing.find((s) => s.serverName === options.serverName && s.serverConfig);
|
|
1868
|
+
if (found) {
|
|
1869
|
+
previousConfig = found.serverConfig;
|
|
1870
|
+
}
|
|
2719
1871
|
}
|
|
2720
|
-
const
|
|
2721
|
-
if (installedAgents.length === 0) {
|
|
2722
|
-
logger.warn(`No agents found with [${serverName}] installed`);
|
|
2723
|
-
return false;
|
|
2724
|
-
}
|
|
1872
|
+
const serverConfig = sanitizeUpdatedServerConfig(options.config, previousConfig);
|
|
2725
1873
|
let targetAgents = options.agents;
|
|
2726
1874
|
if (!targetAgents || targetAgents.length === 0) {
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
choices: installedAgents.map((agent) => ({
|
|
2730
|
-
name: `${getMcpAgentConfig(agent)?.displayName ?? agent} (${agent})`,
|
|
2731
|
-
value: agent,
|
|
2732
|
-
checked: true
|
|
2733
|
-
})),
|
|
2734
|
-
loop: false,
|
|
2735
|
-
validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
|
|
2736
|
-
});
|
|
2737
|
-
} else {
|
|
2738
|
-
const validAgents = targetAgents.filter((agent) => installedAgents.includes(agent));
|
|
2739
|
-
if (validAgents.length === 0) {
|
|
2740
|
-
logger.warn(`None of the specified agents (${targetAgents.join(", ")}) have [${serverName}] installed`);
|
|
2741
|
-
return false;
|
|
2742
|
-
}
|
|
2743
|
-
targetAgents = validAgents;
|
|
1875
|
+
const existing = listInstalledMcpServers({ global: isGlobal, cwd });
|
|
1876
|
+
targetAgents = existing.filter((s) => s.serverName === options.serverName).map((s) => s.agent);
|
|
2744
1877
|
}
|
|
2745
|
-
const
|
|
2746
|
-
|
|
2747
|
-
|
|
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
|
|
2748
1884
|
});
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
}
|
|
2753
|
-
const results = removeMcpServer({
|
|
2754
|
-
name: serverName,
|
|
2755
|
-
agents: targetAgents,
|
|
1885
|
+
const results = installToCompatibleAgents(options.serverName, serverConfig, {
|
|
1886
|
+
allAgents,
|
|
1887
|
+
incompatible,
|
|
2756
1888
|
global: isGlobal,
|
|
2757
1889
|
cwd
|
|
2758
1890
|
});
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
logger.error(`${import_picocolors10.default.cyan(res.agent)}: Failed to remove - ${res.error}`);
|
|
2766
|
-
}
|
|
2767
|
-
}
|
|
2768
|
-
if (removedCount > 0) {
|
|
2769
|
-
logger.success(`Successfully removed [${serverName}] from ${removedCount} agent(s)`);
|
|
2770
|
-
return true;
|
|
2771
|
-
}
|
|
2772
|
-
logger.warn(`Failed to remove [${serverName}] from specified agents`);
|
|
2773
|
-
return false;
|
|
1891
|
+
return {
|
|
1892
|
+
serverName: options.serverName,
|
|
1893
|
+
config: serverConfig,
|
|
1894
|
+
results,
|
|
1895
|
+
incompatible
|
|
1896
|
+
};
|
|
2774
1897
|
};
|
|
2775
1898
|
|
|
2776
|
-
// src/
|
|
2777
|
-
var
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
value: "add"
|
|
2790
|
-
},
|
|
2791
|
-
{
|
|
2792
|
-
name: "Manage & Sync Installed MCP Servers",
|
|
2793
|
-
value: "manage"
|
|
2794
|
-
},
|
|
2795
|
-
{
|
|
2796
|
-
name: "Remove MCP Server",
|
|
2797
|
-
value: "remove"
|
|
2798
|
-
},
|
|
2799
|
-
{
|
|
2800
|
-
name: "Exit",
|
|
2801
|
-
value: "exit"
|
|
2802
|
-
}
|
|
2803
|
-
]
|
|
2804
|
-
});
|
|
2805
|
-
if (action === "exit") {
|
|
2806
|
-
console.log(import_picocolors11.default.dim("Goodbye!"));
|
|
2807
|
-
break;
|
|
2808
|
-
}
|
|
2809
|
-
if (action === "add") {
|
|
2810
|
-
await wizardAdd();
|
|
2811
|
-
} else if (action === "manage") {
|
|
2812
|
-
await wizardManage();
|
|
2813
|
-
} else if (action === "remove") {
|
|
2814
|
-
await wizardRemove();
|
|
2815
|
-
}
|
|
2816
|
-
console.log();
|
|
2817
|
-
} catch (error) {
|
|
2818
|
-
if (error?.name === "ExitPromptError") {
|
|
2819
|
-
console.log("\n" + import_picocolors11.default.dim("Exited."));
|
|
2820
|
-
break;
|
|
2821
|
-
}
|
|
2822
|
-
throw error;
|
|
2823
|
-
}
|
|
2824
|
-
}
|
|
1899
|
+
// src/remove.ts
|
|
1900
|
+
var removeMcpServer = (options) => {
|
|
1901
|
+
const { allAgents } = resolveTargetAgents({
|
|
1902
|
+
requested: options.agents,
|
|
1903
|
+
all: !options.agents,
|
|
1904
|
+
global: options.global,
|
|
1905
|
+
cwd: options.cwd
|
|
1906
|
+
});
|
|
1907
|
+
const storeResults = agentConfigStore.removeServers(allAgents, options.name, {
|
|
1908
|
+
global: options.global,
|
|
1909
|
+
cwd: options.cwd
|
|
1910
|
+
});
|
|
1911
|
+
return storeResults.filter((r) => r.removed || Boolean(r.error));
|
|
2825
1912
|
};
|
|
2826
1913
|
|
|
2827
|
-
// src/
|
|
2828
|
-
var
|
|
2829
|
-
var
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
var parseKeyValueList = (entries, separator) => {
|
|
2833
|
-
if (!entries || entries.length === 0) return {};
|
|
2834
|
-
const result = {};
|
|
2835
|
-
for (const entry of entries) {
|
|
2836
|
-
const splitIndex = entry.indexOf(separator);
|
|
2837
|
-
if (splitIndex === -1) {
|
|
2838
|
-
throw new Error(`Invalid entry "${entry}": expected "${separator}" separator`);
|
|
2839
|
-
}
|
|
2840
|
-
const key = entry.slice(0, splitIndex).trim();
|
|
2841
|
-
const value = entry.slice(splitIndex + separator.length).trim();
|
|
2842
|
-
if (!key) throw new Error(`Invalid entry "${entry}": empty key`);
|
|
2843
|
-
result[key] = value;
|
|
1914
|
+
// src/utils/mask-secret.ts
|
|
1915
|
+
var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
|
|
1916
|
+
var maskSecretValue = (key, value) => {
|
|
1917
|
+
if (!SECRET_KEY_PATTERN.test(key) || value.length <= 4) {
|
|
1918
|
+
return value;
|
|
2844
1919
|
}
|
|
2845
|
-
return
|
|
2846
|
-
};
|
|
2847
|
-
|
|
2848
|
-
// src/cli/manage.ts
|
|
2849
|
-
var resolveTransport = (input7) => {
|
|
2850
|
-
if (!input7) return void 0;
|
|
2851
|
-
if (input7 === "http" || input7 === "sse") return input7;
|
|
2852
|
-
throw new Error(`Unsupported transport "${input7}" (expected: http, sse)`);
|
|
1920
|
+
return `${value.slice(0, 2)}***${value.slice(-2)}`;
|
|
2853
1921
|
};
|
|
2854
|
-
var
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
const hasModifications = options.command !== void 0 || options.args !== void 0 || options.env !== void 0 || options.header !== void 0 || options.url !== void 0 || options.transport !== void 0;
|
|
2859
|
-
const isInteractive = Boolean(process.stdin.isTTY && !options.yes);
|
|
2860
|
-
if (hasModifications) {
|
|
2861
|
-
if (!serverName) {
|
|
2862
|
-
logger.error('Missing required argument: "server-name" when passing modification flags.');
|
|
2863
|
-
process.exitCode = 1;
|
|
2864
|
-
return;
|
|
2865
|
-
}
|
|
2866
|
-
const installed = listInstalledMcpServers({ global: isGlobal, cwd });
|
|
2867
|
-
const grouped = groupInstalledServersByName(installed);
|
|
2868
|
-
const targetGroup = grouped.get(serverName);
|
|
2869
|
-
if (!targetGroup) {
|
|
2870
|
-
logger.error(
|
|
2871
|
-
`MCP server "${serverName}" is not configured in ${isGlobal ? "global" : "project"} scope.`
|
|
2872
|
-
);
|
|
2873
|
-
process.exitCode = 1;
|
|
2874
|
-
return;
|
|
2875
|
-
}
|
|
2876
|
-
const updatedConfig = {
|
|
2877
|
-
...targetGroup.config,
|
|
2878
|
-
args: targetGroup.config.args ? [...targetGroup.config.args] : void 0,
|
|
2879
|
-
env: targetGroup.config.env ? { ...targetGroup.config.env } : void 0,
|
|
2880
|
-
headers: targetGroup.config.headers ? { ...targetGroup.config.headers } : void 0
|
|
2881
|
-
};
|
|
2882
|
-
if (options.command !== void 0) {
|
|
2883
|
-
updatedConfig.command = options.command;
|
|
2884
|
-
}
|
|
2885
|
-
if (options.args !== void 0) {
|
|
2886
|
-
updatedConfig.args = options.args;
|
|
2887
|
-
}
|
|
2888
|
-
if (options.url !== void 0) {
|
|
2889
|
-
updatedConfig.url = options.url;
|
|
2890
|
-
}
|
|
2891
|
-
if (options.transport !== void 0) {
|
|
2892
|
-
updatedConfig.type = resolveTransport(options.transport);
|
|
2893
|
-
}
|
|
2894
|
-
if (options.env !== void 0) {
|
|
2895
|
-
const parsedEnv = parseKeyValueList(options.env, "=");
|
|
2896
|
-
updatedConfig.env = { ...updatedConfig.env ?? {}, ...parsedEnv };
|
|
2897
|
-
}
|
|
2898
|
-
if (options.header !== void 0) {
|
|
2899
|
-
const parsedHeaders = parseKeyValueList(options.header, ":");
|
|
2900
|
-
updatedConfig.headers = { ...updatedConfig.headers ?? {}, ...parsedHeaders };
|
|
2901
|
-
}
|
|
2902
|
-
const targetAgents = options.agent ? parseMcpAgentList(options.agent) ?? targetGroup.agents : targetGroup.agents;
|
|
2903
|
-
const requestedTransport = updatedConfig.url ? updatedConfig.type ?? "http" : "stdio";
|
|
2904
|
-
const compatibleAgents = [];
|
|
2905
|
-
for (const agent of targetAgents) {
|
|
2906
|
-
const agentConfig = getMcpAgentConfig(agent);
|
|
2907
|
-
if (isMcpTransportSupported(agentConfig, requestedTransport)) {
|
|
2908
|
-
compatibleAgents.push(agent);
|
|
2909
|
-
} else {
|
|
2910
|
-
const reason = agentConfig.unsupportedTransportMessage ?? `Agent does not support ${requestedTransport} transport`;
|
|
2911
|
-
logger.warn(`Skipping ${import_picocolors12.default.cyan(agent)}: ${reason}`);
|
|
2912
|
-
}
|
|
2913
|
-
}
|
|
2914
|
-
if (compatibleAgents.length === 0) {
|
|
2915
|
-
logger.error(
|
|
2916
|
-
`None of the target agents support ${requestedTransport} transport. Update aborted.`
|
|
2917
|
-
);
|
|
2918
|
-
process.exitCode = 1;
|
|
2919
|
-
return;
|
|
2920
|
-
}
|
|
2921
|
-
logger.info(
|
|
2922
|
-
`Updating ${import_picocolors12.default.bold(serverName)} across ${import_picocolors12.default.cyan(String(compatibleAgents.length))} agent(s)...`
|
|
2923
|
-
);
|
|
2924
|
-
let allSuccess = true;
|
|
2925
|
-
for (const agent of compatibleAgents) {
|
|
2926
|
-
const res = installMcpServerForAgent(serverName, updatedConfig, agent, {
|
|
2927
|
-
global: isGlobal,
|
|
2928
|
-
cwd
|
|
2929
|
-
});
|
|
2930
|
-
if (res.success) {
|
|
2931
|
-
logger.success(`${import_picocolors12.default.cyan(agent)}: Successfully updated in ${import_picocolors12.default.dim(res.path)}`);
|
|
2932
|
-
} else {
|
|
2933
|
-
allSuccess = false;
|
|
2934
|
-
logger.error(`${import_picocolors12.default.cyan(agent)}: Update failed - ${res.error}`);
|
|
2935
|
-
}
|
|
2936
|
-
}
|
|
2937
|
-
if (!allSuccess) {
|
|
2938
|
-
process.exitCode = 1;
|
|
2939
|
-
}
|
|
2940
|
-
return;
|
|
2941
|
-
}
|
|
2942
|
-
if (!isInteractive) {
|
|
2943
|
-
if (!serverName) {
|
|
2944
|
-
logger.error(
|
|
2945
|
-
'Missing required argument: "server-name" for non-interactive manage command. Specify a server name or use interactive terminal.'
|
|
2946
|
-
);
|
|
2947
|
-
process.exitCode = 1;
|
|
2948
|
-
return;
|
|
2949
|
-
}
|
|
2950
|
-
const installed = listInstalledMcpServers({ global: isGlobal, cwd });
|
|
2951
|
-
const grouped = groupInstalledServersByName(installed);
|
|
2952
|
-
const targetGroup = grouped.get(serverName);
|
|
2953
|
-
if (!targetGroup) {
|
|
2954
|
-
logger.error(
|
|
2955
|
-
`MCP server "${serverName}" is not configured in ${isGlobal ? "global" : "project"} scope.`
|
|
2956
|
-
);
|
|
2957
|
-
process.exitCode = 1;
|
|
2958
|
-
return;
|
|
2959
|
-
}
|
|
2960
|
-
displayServerDetails({
|
|
2961
|
-
serverName,
|
|
2962
|
-
config: targetGroup.config,
|
|
2963
|
-
agents: targetGroup.agents,
|
|
2964
|
-
isGlobal
|
|
2965
|
-
});
|
|
2966
|
-
return;
|
|
2967
|
-
}
|
|
2968
|
-
await wizardManage({
|
|
2969
|
-
global: options.global,
|
|
2970
|
-
serverName
|
|
2971
|
-
});
|
|
2972
|
-
} catch (error) {
|
|
2973
|
-
if (error && typeof error === "object" && "name" in error && error.name === "ExitPromptError") {
|
|
2974
|
-
process.exit(0);
|
|
2975
|
-
}
|
|
2976
|
-
logger.error(toErrorMessage(error));
|
|
2977
|
-
process.exitCode = 1;
|
|
1922
|
+
var SECRET_HEADER_PATTERN = /(authorization|token|key|secret|auth)/i;
|
|
1923
|
+
var maskSecretHeader = (key, value) => {
|
|
1924
|
+
if (!SECRET_HEADER_PATTERN.test(key) || value.length <= 8) {
|
|
1925
|
+
return value;
|
|
2978
1926
|
}
|
|
2979
|
-
})
|
|
1927
|
+
return `${value.slice(0, 4)}***${value.slice(-3)}`;
|
|
1928
|
+
};
|
|
2980
1929
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2981
1930
|
0 && (module.exports = {
|
|
2982
1931
|
AgentConfigStore,
|
|
2983
1932
|
DEFAULT_REMOTE_TRANSPORT,
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
add,
|
|
1933
|
+
SECRET_HEADER_PATTERN,
|
|
1934
|
+
SECRET_KEY_PATTERN,
|
|
2987
1935
|
agentConfigStore,
|
|
1936
|
+
applyServerConfigDelta,
|
|
2988
1937
|
buildMcpServerConfig,
|
|
2989
1938
|
createAgentTransform,
|
|
2990
1939
|
detectGloballyInstalledMcpAgents,
|
|
2991
1940
|
detectProjectInstalledMcpAgents,
|
|
2992
|
-
|
|
1941
|
+
detectUpdateTransition,
|
|
2993
1942
|
extractPackageName,
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
formatHeadersText,
|
|
1943
|
+
getCandidateAgentsForScope,
|
|
1944
|
+
getCoHostedAgents,
|
|
2997
1945
|
getMcpAgentConfig,
|
|
2998
1946
|
getMcpAgentTypes,
|
|
2999
1947
|
getMcpAgentsSupportingProjectScope,
|
|
3000
|
-
groupInstalledServersByName,
|
|
3001
|
-
install,
|
|
3002
1948
|
installMcpServer,
|
|
3003
1949
|
installMcpServerForAgent,
|
|
3004
1950
|
installMcpServerForAgents,
|
|
1951
|
+
installToCompatibleAgents,
|
|
3005
1952
|
isMcpAgentType,
|
|
3006
1953
|
isMcpTransportSupported,
|
|
3007
1954
|
isRemoteMcpSource,
|
|
3008
1955
|
isRemoteServerConfig,
|
|
3009
1956
|
isStdioServerConfig,
|
|
3010
|
-
list,
|
|
3011
1957
|
listInstalledMcpServers,
|
|
3012
|
-
listServersInConfigFile,
|
|
3013
|
-
mainMenu,
|
|
3014
1958
|
maskSecretHeader,
|
|
3015
1959
|
maskSecretValue,
|
|
3016
|
-
mcpAgentAliases,
|
|
3017
|
-
mcpAgents,
|
|
3018
|
-
mcpManageCommand,
|
|
3019
|
-
normalizeServerConfig,
|
|
3020
|
-
parseArgsString,
|
|
3021
|
-
parseEnvText,
|
|
3022
|
-
parseHeadersText,
|
|
3023
1960
|
parseMcpSource,
|
|
3024
1961
|
parseServerConfig,
|
|
3025
|
-
|
|
3026
|
-
promptArgsConfig,
|
|
3027
|
-
promptEditArgs,
|
|
3028
|
-
promptEditEnvConfig,
|
|
3029
|
-
promptEditHeadersConfig,
|
|
3030
|
-
promptEditKeyValueConfig,
|
|
3031
|
-
promptEnvConfig,
|
|
3032
|
-
promptHeadersConfig,
|
|
3033
|
-
promptScope,
|
|
3034
|
-
promptScopeAndAgents,
|
|
3035
|
-
readConfigFile,
|
|
3036
|
-
remove,
|
|
1962
|
+
queryGroupedInstalledServers,
|
|
3037
1963
|
removeMcpServer,
|
|
3038
|
-
|
|
3039
|
-
removeServerFromConfigFile,
|
|
1964
|
+
resolveConfigClusters,
|
|
3040
1965
|
resolveMcpAgentAlias,
|
|
3041
1966
|
resolveMcpConfigTarget,
|
|
3042
1967
|
resolveTargetAgents,
|
|
3043
|
-
|
|
1968
|
+
sanitizeUpdatedServerConfig,
|
|
1969
|
+
sortAgentsByClusters,
|
|
1970
|
+
toRemoteServerConfig,
|
|
1971
|
+
toStdioServerConfig,
|
|
3044
1972
|
transformServerConfigForAgent,
|
|
3045
|
-
|
|
3046
|
-
updateMcpServerForAgents,
|
|
3047
|
-
wizardAdd,
|
|
3048
|
-
wizardManage,
|
|
3049
|
-
wizardRemove,
|
|
3050
|
-
writeServerToConfigFile
|
|
1973
|
+
updateMcpServer
|
|
3051
1974
|
});
|