@wuyax/mcps 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +318 -0
- package/bin/mcps.mjs +11 -0
- package/dist/chunk-XW2KL6W3.js +2360 -0
- package/dist/cli.cjs +2534 -0
- package/dist/cli.d.cts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +228 -0
- package/dist/index.cjs +2453 -0
- package/dist/index.d.cts +378 -0
- package/dist/index.d.ts +378 -0
- package/dist/index.js +111 -0
- package/package.json +52 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2453 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
AgentConfigStore: () => AgentConfigStore,
|
|
34
|
+
DEFAULT_REMOTE_TRANSPORT: () => DEFAULT_REMOTE_TRANSPORT,
|
|
35
|
+
NPX_COMMAND: () => NPX_COMMAND,
|
|
36
|
+
NPX_DASH_Y: () => NPX_DASH_Y,
|
|
37
|
+
add: () => installMcpServer,
|
|
38
|
+
agentConfigStore: () => agentConfigStore,
|
|
39
|
+
buildMcpServerConfig: () => buildMcpServerConfig,
|
|
40
|
+
createAgentTransform: () => createAgentTransform,
|
|
41
|
+
detectGloballyInstalledMcpAgents: () => detectGloballyInstalledMcpAgents,
|
|
42
|
+
detectProjectInstalledMcpAgents: () => detectProjectInstalledMcpAgents,
|
|
43
|
+
extractPackageName: () => extractPackageName,
|
|
44
|
+
getMcpAgentConfig: () => getMcpAgentConfig,
|
|
45
|
+
getMcpAgentTypes: () => getMcpAgentTypes,
|
|
46
|
+
getMcpAgentsSupportingProjectScope: () => getMcpAgentsSupportingProjectScope,
|
|
47
|
+
groupInstalledServersByName: () => groupInstalledServersByName,
|
|
48
|
+
install: () => installMcpServer,
|
|
49
|
+
installMcpServer: () => installMcpServer,
|
|
50
|
+
installMcpServerForAgent: () => installMcpServerForAgent,
|
|
51
|
+
installMcpServerForAgents: () => installMcpServerForAgents,
|
|
52
|
+
isMcpAgentType: () => isMcpAgentType,
|
|
53
|
+
isMcpTransportSupported: () => isMcpTransportSupported,
|
|
54
|
+
isRemoteMcpSource: () => isRemoteMcpSource,
|
|
55
|
+
isRemoteServerConfig: () => isRemoteServerConfig,
|
|
56
|
+
isStdioServerConfig: () => isStdioServerConfig,
|
|
57
|
+
list: () => listInstalledMcpServers,
|
|
58
|
+
listInstalledMcpServers: () => listInstalledMcpServers,
|
|
59
|
+
listServersInConfigFile: () => listServersInConfigFile,
|
|
60
|
+
mainMenu: () => mainMenu,
|
|
61
|
+
mcpAgentAliases: () => mcpAgentAliases,
|
|
62
|
+
mcpAgents: () => mcpAgents,
|
|
63
|
+
normalizeServerConfig: () => normalizeServerConfig,
|
|
64
|
+
parseArgsString: () => parseArgsString,
|
|
65
|
+
parseEnvText: () => parseEnvText,
|
|
66
|
+
parseHeadersText: () => parseHeadersText,
|
|
67
|
+
parseMcpSource: () => parseMcpSource,
|
|
68
|
+
parseServerConfig: () => parseServerConfig,
|
|
69
|
+
parseSource: () => parseMcpSource,
|
|
70
|
+
promptArgsConfig: () => promptArgsConfig,
|
|
71
|
+
promptEnvConfig: () => promptEnvConfig,
|
|
72
|
+
promptHeadersConfig: () => promptHeadersConfig,
|
|
73
|
+
promptScope: () => promptScope,
|
|
74
|
+
promptScopeAndAgents: () => promptScopeAndAgents,
|
|
75
|
+
readConfigFile: () => readConfigFile,
|
|
76
|
+
remove: () => removeMcpServer,
|
|
77
|
+
removeMcpServer: () => removeMcpServer,
|
|
78
|
+
removeMcpServerFromAgent: () => removeMcpServerFromAgent,
|
|
79
|
+
removeServerFromConfigFile: () => removeServerFromConfigFile,
|
|
80
|
+
resolveMcpAgentAlias: () => resolveMcpAgentAlias,
|
|
81
|
+
resolveMcpConfigTarget: () => resolveMcpConfigTarget,
|
|
82
|
+
resolveTargetAgents: () => resolveTargetAgents,
|
|
83
|
+
transformServerConfig: () => transformServerConfig,
|
|
84
|
+
transformServerConfigForAgent: () => transformServerConfigForAgent,
|
|
85
|
+
wizardAdd: () => wizardAdd,
|
|
86
|
+
wizardManage: () => wizardManage,
|
|
87
|
+
wizardRemove: () => wizardRemove,
|
|
88
|
+
writeServerToConfigFile: () => writeServerToConfigFile
|
|
89
|
+
});
|
|
90
|
+
module.exports = __toCommonJS(src_exports);
|
|
91
|
+
|
|
92
|
+
// src/agents.ts
|
|
93
|
+
var import_node_fs = require("fs");
|
|
94
|
+
var import_node_os = require("os");
|
|
95
|
+
var import_node_path = require("path");
|
|
96
|
+
var home = (0, import_node_os.homedir)();
|
|
97
|
+
var getPlatformPaths = () => {
|
|
98
|
+
const currentPlatform = (0, import_node_os.platform)();
|
|
99
|
+
if (currentPlatform === "win32") {
|
|
100
|
+
const appData = process.env.APPDATA || (0, import_node_path.join)(home, "AppData", "Roaming");
|
|
101
|
+
return {
|
|
102
|
+
appSupport: appData,
|
|
103
|
+
vscodePath: (0, import_node_path.join)(appData, "Code", "User"),
|
|
104
|
+
traePath: (0, import_node_path.join)(appData, "Trae", "User"),
|
|
105
|
+
gooseConfigPath: (0, import_node_path.join)(appData, "Block", "goose", "config", "config.yaml"),
|
|
106
|
+
zedConfigPath: (0, import_node_path.join)(appData, "Zed", "settings.json")
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (currentPlatform === "darwin") {
|
|
110
|
+
return {
|
|
111
|
+
appSupport: (0, import_node_path.join)(home, "Library", "Application Support"),
|
|
112
|
+
vscodePath: (0, import_node_path.join)(home, "Library", "Application Support", "Code", "User"),
|
|
113
|
+
traePath: (0, import_node_path.join)(home, "Library", "Application Support", "Trae", "User"),
|
|
114
|
+
gooseConfigPath: (0, import_node_path.join)(home, ".config", "goose", "config.yaml"),
|
|
115
|
+
zedConfigPath: (0, import_node_path.join)(home, ".config", "zed", "settings.json")
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const configDir = process.env.XDG_CONFIG_HOME || (0, import_node_path.join)(home, ".config");
|
|
119
|
+
return {
|
|
120
|
+
appSupport: configDir,
|
|
121
|
+
vscodePath: (0, import_node_path.join)(configDir, "Code", "User"),
|
|
122
|
+
traePath: (0, import_node_path.join)(configDir, "Trae", "User"),
|
|
123
|
+
gooseConfigPath: (0, import_node_path.join)(configDir, "goose", "config.yaml"),
|
|
124
|
+
zedConfigPath: (0, import_node_path.join)(configDir, "zed", "settings.json")
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
var { appSupport, vscodePath, traePath, gooseConfigPath, zedConfigPath } = getPlatformPaths();
|
|
128
|
+
var ampConfigDir = process.env.AMP_HOME?.trim() || (0, import_node_path.join)(process.env.XDG_CONFIG_HOME || (0, import_node_path.join)(home, ".config"), "amp");
|
|
129
|
+
var ampGlobalConfigPath = (0, import_node_fs.existsSync)((0, import_node_path.join)(ampConfigDir, "settings.jsonc")) ? (0, import_node_path.join)(ampConfigDir, "settings.jsonc") : (0, import_node_path.join)(ampConfigDir, "settings.json");
|
|
130
|
+
var antigravityMcpConfigPath = (0, import_node_path.join)(home, ".gemini", "config", "mcp_config.json");
|
|
131
|
+
var augmentConfigDir = process.env.AUGMENT_HOME?.trim() || (0, import_node_path.join)(home, ".augment");
|
|
132
|
+
var augmentGlobalConfigPath = (0, import_node_fs.existsSync)((0, import_node_path.join)(augmentConfigDir, "settings.jsonc")) ? (0, import_node_path.join)(augmentConfigDir, "settings.jsonc") : (0, import_node_path.join)(augmentConfigDir, "settings.json");
|
|
133
|
+
var clineDir = process.env.CLINE_DIR || (0, import_node_path.join)(home, ".cline");
|
|
134
|
+
var clineCliConfigPath = (0, import_node_path.join)(clineDir, "mcp.json");
|
|
135
|
+
var clineExtensionConfigPath = (0, import_node_path.join)(
|
|
136
|
+
vscodePath,
|
|
137
|
+
"globalStorage",
|
|
138
|
+
"saoudrizwan.claude-dev",
|
|
139
|
+
"settings",
|
|
140
|
+
"cline_mcp_settings.json"
|
|
141
|
+
);
|
|
142
|
+
var copilotConfigPath = (0, import_node_path.join)(
|
|
143
|
+
process.env.COPILOT_HOME?.trim() || (0, import_node_path.join)(home, ".copilot"),
|
|
144
|
+
"mcp-config.json"
|
|
145
|
+
);
|
|
146
|
+
var grokConfigPath = (0, import_node_path.join)(
|
|
147
|
+
process.env.GROK_HOME?.trim() || (0, import_node_path.join)(home, ".grok"),
|
|
148
|
+
"config.toml"
|
|
149
|
+
);
|
|
150
|
+
var kimiCodeConfigPath = (0, import_node_path.join)(
|
|
151
|
+
process.env.KIMI_CODE_HOME?.trim() || (0, import_node_path.join)(home, ".kimi-code"),
|
|
152
|
+
"mcp.json"
|
|
153
|
+
);
|
|
154
|
+
var kiroConfigPath = (0, import_node_path.join)(
|
|
155
|
+
process.env.KIRO_HOME?.trim() || (0, import_node_path.join)(home, ".kiro"),
|
|
156
|
+
"settings",
|
|
157
|
+
"mcp.json"
|
|
158
|
+
);
|
|
159
|
+
var qoderConfigPath = (0, import_node_path.join)(
|
|
160
|
+
process.env.QODER_HOME?.trim() || (0, import_node_path.join)(home, ".qoder"),
|
|
161
|
+
"settings.json"
|
|
162
|
+
);
|
|
163
|
+
var qwenCodeConfigPath = (0, import_node_path.join)(
|
|
164
|
+
process.env.QWEN_CODE_HOME?.trim() || process.env.QWEN_HOME?.trim() || (0, import_node_path.join)(home, ".qwen"),
|
|
165
|
+
"settings.json"
|
|
166
|
+
);
|
|
167
|
+
var traeConfigPath = (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".trae", "mcp.json")) ? (0, import_node_path.join)(home, ".trae", "mcp.json") : (0, import_node_path.join)(traePath, "mcp.json");
|
|
168
|
+
var ALL_TRANSPORTS = ["stdio", "http", "sse"];
|
|
169
|
+
var mcpAgents = {
|
|
170
|
+
// https://ampcode.com/docs/markdown/customize/mcp
|
|
171
|
+
amp: {
|
|
172
|
+
name: "amp",
|
|
173
|
+
displayName: "Amp",
|
|
174
|
+
globalConfigPath: ampGlobalConfigPath,
|
|
175
|
+
projectConfigPath: ".amp/settings.json",
|
|
176
|
+
configKey: "amp.mcpServers",
|
|
177
|
+
format: "jsonc",
|
|
178
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
179
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)(ampConfigDir) || (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".amp")),
|
|
180
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".amp", "settings.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".amp", "settings.jsonc")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".amp")),
|
|
181
|
+
resolveConfigPath: ({ global: isGlobal, cwd }) => {
|
|
182
|
+
if (isGlobal) {
|
|
183
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(ampConfigDir, "settings.jsonc"))) {
|
|
184
|
+
return (0, import_node_path.join)(ampConfigDir, "settings.jsonc");
|
|
185
|
+
}
|
|
186
|
+
return ampGlobalConfigPath;
|
|
187
|
+
}
|
|
188
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".amp", "settings.jsonc"))) {
|
|
189
|
+
return (0, import_node_path.join)(cwd, ".amp", "settings.jsonc");
|
|
190
|
+
}
|
|
191
|
+
return (0, import_node_path.join)(cwd, ".amp", "settings.json");
|
|
192
|
+
},
|
|
193
|
+
transformDialect: "amp"
|
|
194
|
+
},
|
|
195
|
+
antigravity: {
|
|
196
|
+
name: "antigravity",
|
|
197
|
+
displayName: "Antigravity",
|
|
198
|
+
globalConfigPath: antigravityMcpConfigPath,
|
|
199
|
+
projectConfigPath: ".agents/mcp_config.json",
|
|
200
|
+
configKey: "mcpServers",
|
|
201
|
+
format: "jsonc",
|
|
202
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
203
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".gemini", "antigravity")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".gemini", "config")),
|
|
204
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".agents", "mcp_config.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".agents"))
|
|
205
|
+
},
|
|
206
|
+
// https://antigravity.google/docs/cli/mcp/
|
|
207
|
+
"antigravity-cli": {
|
|
208
|
+
name: "antigravity-cli",
|
|
209
|
+
displayName: "Antigravity CLI",
|
|
210
|
+
globalConfigPath: antigravityMcpConfigPath,
|
|
211
|
+
projectConfigPath: ".agents/mcp_config.json",
|
|
212
|
+
configKey: "mcpServers",
|
|
213
|
+
format: "jsonc",
|
|
214
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
215
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".gemini", "antigravity-cli")),
|
|
216
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".agents", "mcp_config.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".agents"))
|
|
217
|
+
},
|
|
218
|
+
// https://docs.augmentcode.com/cli/integrations.md
|
|
219
|
+
augment: {
|
|
220
|
+
name: "augment",
|
|
221
|
+
displayName: "Augment",
|
|
222
|
+
globalConfigPath: augmentGlobalConfigPath,
|
|
223
|
+
projectConfigPath: ".augment/settings.json",
|
|
224
|
+
configKey: "mcpServers",
|
|
225
|
+
format: "jsonc",
|
|
226
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
227
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)(augmentConfigDir) || (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".augment")),
|
|
228
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".augment", "settings.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".augment", "settings.jsonc")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".augment")),
|
|
229
|
+
resolveConfigPath: ({ global: isGlobal, cwd }) => {
|
|
230
|
+
if (isGlobal) {
|
|
231
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(augmentConfigDir, "settings.jsonc"))) {
|
|
232
|
+
return (0, import_node_path.join)(augmentConfigDir, "settings.jsonc");
|
|
233
|
+
}
|
|
234
|
+
return augmentGlobalConfigPath;
|
|
235
|
+
}
|
|
236
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".augment", "settings.jsonc"))) {
|
|
237
|
+
return (0, import_node_path.join)(cwd, ".augment", "settings.jsonc");
|
|
238
|
+
}
|
|
239
|
+
return (0, import_node_path.join)(cwd, ".augment", "settings.json");
|
|
240
|
+
},
|
|
241
|
+
transformDialect: "augment"
|
|
242
|
+
},
|
|
243
|
+
cline: {
|
|
244
|
+
name: "cline",
|
|
245
|
+
displayName: "Cline (VSCode extension)",
|
|
246
|
+
globalConfigPath: clineExtensionConfigPath,
|
|
247
|
+
projectConfigPath: ".cline/mcp.json",
|
|
248
|
+
configKey: "mcpServers",
|
|
249
|
+
format: "jsonc",
|
|
250
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
251
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)(clineExtensionConfigPath),
|
|
252
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".cline", "mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".cline")),
|
|
253
|
+
resolveConfigPath: ({ global: isGlobal, cwd }) => {
|
|
254
|
+
if (isGlobal) {
|
|
255
|
+
return clineExtensionConfigPath;
|
|
256
|
+
}
|
|
257
|
+
return (0, import_node_path.join)(cwd, ".cline", "mcp.json");
|
|
258
|
+
},
|
|
259
|
+
transformDialect: "cline"
|
|
260
|
+
},
|
|
261
|
+
// https://docs.cline.bot/mcp/mcp-overview.md
|
|
262
|
+
"cline-cli": {
|
|
263
|
+
name: "cline-cli",
|
|
264
|
+
displayName: "Cline CLI",
|
|
265
|
+
globalConfigPath: clineCliConfigPath,
|
|
266
|
+
projectConfigPath: ".cline/mcp.json",
|
|
267
|
+
configKey: "mcpServers",
|
|
268
|
+
format: "jsonc",
|
|
269
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
270
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)(clineDir),
|
|
271
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".cline", "mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".cline")),
|
|
272
|
+
resolveConfigPath: ({ global: isGlobal, cwd }) => {
|
|
273
|
+
if (isGlobal) {
|
|
274
|
+
return clineCliConfigPath;
|
|
275
|
+
}
|
|
276
|
+
return (0, import_node_path.join)(cwd, ".cline", "mcp.json");
|
|
277
|
+
},
|
|
278
|
+
transformDialect: "cline"
|
|
279
|
+
},
|
|
280
|
+
// https://code.claude.com/docs/en/mcp-quickstart#edit-mcp-json-directly
|
|
281
|
+
"claude-code": {
|
|
282
|
+
name: "claude-code",
|
|
283
|
+
displayName: "Claude Code",
|
|
284
|
+
globalConfigPath: (0, import_node_path.join)(home, ".claude.json"),
|
|
285
|
+
projectConfigPath: ".mcp.json",
|
|
286
|
+
configKey: "mcpServers",
|
|
287
|
+
format: "jsonc",
|
|
288
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
289
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".claude.json")),
|
|
290
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".mcp.json"))
|
|
291
|
+
},
|
|
292
|
+
"claude-desktop": {
|
|
293
|
+
name: "claude-desktop",
|
|
294
|
+
displayName: "Claude Desktop",
|
|
295
|
+
globalConfigPath: (0, import_node_path.join)(appSupport, "Claude", "claude_desktop_config.json"),
|
|
296
|
+
configKey: "mcpServers",
|
|
297
|
+
format: "jsonc",
|
|
298
|
+
supportedTransports: ["stdio"],
|
|
299
|
+
unsupportedTransportMessage: "Claude Desktop currently supports only stdio MCP servers. Use a package name or command instead of a URL.",
|
|
300
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(appSupport, "Claude", "claude_desktop_config.json"))
|
|
301
|
+
},
|
|
302
|
+
// https://learn.chatgpt.com/docs/extend/mcp?surface=app
|
|
303
|
+
codex: {
|
|
304
|
+
name: "codex",
|
|
305
|
+
displayName: "Codex",
|
|
306
|
+
globalConfigPath: (0, import_node_path.join)(process.env.CODEX_HOME?.trim() || (0, import_node_path.join)(home, ".codex"), "config.toml"),
|
|
307
|
+
projectConfigPath: ".codex/config.toml",
|
|
308
|
+
configKey: "mcp_servers",
|
|
309
|
+
format: "toml",
|
|
310
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
311
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)(process.env.CODEX_HOME?.trim() || (0, import_node_path.join)(home, ".codex")),
|
|
312
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".codex", "config.toml")),
|
|
313
|
+
transformDialect: "augment"
|
|
314
|
+
},
|
|
315
|
+
// https://cursor.com/help/customization/mcp
|
|
316
|
+
cursor: {
|
|
317
|
+
name: "cursor",
|
|
318
|
+
displayName: "Cursor",
|
|
319
|
+
globalConfigPath: (0, import_node_path.join)(home, ".cursor", "mcp.json"),
|
|
320
|
+
projectConfigPath: ".cursor/mcp.json",
|
|
321
|
+
configKey: "mcpServers",
|
|
322
|
+
format: "jsonc",
|
|
323
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
324
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".cursor")),
|
|
325
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".cursor", "mcp.json"))
|
|
326
|
+
},
|
|
327
|
+
"gemini-cli": {
|
|
328
|
+
name: "gemini-cli",
|
|
329
|
+
displayName: "Gemini CLI",
|
|
330
|
+
globalConfigPath: (0, import_node_path.join)(home, ".gemini", "settings.json"),
|
|
331
|
+
projectConfigPath: ".gemini/settings.json",
|
|
332
|
+
configKey: "mcpServers",
|
|
333
|
+
format: "jsonc",
|
|
334
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
335
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".gemini")),
|
|
336
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".gemini", "settings.json"))
|
|
337
|
+
},
|
|
338
|
+
// https://docs.x.ai/build/features/mcp-servers.md
|
|
339
|
+
grok: {
|
|
340
|
+
name: "grok",
|
|
341
|
+
displayName: "Grok",
|
|
342
|
+
globalConfigPath: grokConfigPath,
|
|
343
|
+
projectConfigPath: ".grok/config.toml",
|
|
344
|
+
configKey: "mcp_servers",
|
|
345
|
+
format: "toml",
|
|
346
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
347
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)(grokConfigPath) || (0, import_node_fs.existsSync)(process.env.GROK_HOME?.trim() || (0, import_node_path.join)(home, ".grok")),
|
|
348
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".grok", "config.toml")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".grok")),
|
|
349
|
+
transformDialect: "grok"
|
|
350
|
+
},
|
|
351
|
+
// https://goose-docs.ai/docs/guides/config-files/
|
|
352
|
+
goose: {
|
|
353
|
+
name: "goose",
|
|
354
|
+
displayName: "Goose",
|
|
355
|
+
globalConfigPath: gooseConfigPath,
|
|
356
|
+
projectConfigPath: ".goose/config.yaml",
|
|
357
|
+
configKey: "extensions",
|
|
358
|
+
format: "yaml",
|
|
359
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
360
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)(gooseConfigPath),
|
|
361
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".goose", "config.yaml")),
|
|
362
|
+
transformDialect: "goose"
|
|
363
|
+
},
|
|
364
|
+
"github-copilot-cli": {
|
|
365
|
+
name: "github-copilot-cli",
|
|
366
|
+
displayName: "GitHub Copilot CLI",
|
|
367
|
+
globalConfigPath: copilotConfigPath,
|
|
368
|
+
projectConfigPath: ".mcp.json",
|
|
369
|
+
configKey: "mcpServers",
|
|
370
|
+
format: "jsonc",
|
|
371
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
372
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)(copilotConfigPath) || (0, import_node_fs.existsSync)(process.env.COPILOT_HOME?.trim() || (0, import_node_path.join)(home, ".copilot")),
|
|
373
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".github", "mcp.json")),
|
|
374
|
+
transformDialect: "vscode"
|
|
375
|
+
},
|
|
376
|
+
// https://www.kimi.com/code/docs/en/kimi-code-cli/customization/mcp.html
|
|
377
|
+
"kimi-code-cli": {
|
|
378
|
+
name: "kimi-code-cli",
|
|
379
|
+
displayName: "Kimi Code CLI",
|
|
380
|
+
globalConfigPath: kimiCodeConfigPath,
|
|
381
|
+
projectConfigPath: ".kimi-code/mcp.json",
|
|
382
|
+
configKey: "mcpServers",
|
|
383
|
+
format: "jsonc",
|
|
384
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
385
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)(kimiCodeConfigPath) || (0, import_node_fs.existsSync)(process.env.KIMI_CODE_HOME?.trim() || (0, import_node_path.join)(home, ".kimi-code")),
|
|
386
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".kimi-code", "mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".kimi-code")),
|
|
387
|
+
transformDialect: "kimi-code"
|
|
388
|
+
},
|
|
389
|
+
// https://kiro.dev/docs/mcp/configuration.md
|
|
390
|
+
kiro: {
|
|
391
|
+
name: "kiro",
|
|
392
|
+
displayName: "Kiro",
|
|
393
|
+
globalConfigPath: kiroConfigPath,
|
|
394
|
+
projectConfigPath: ".kiro/settings/mcp.json",
|
|
395
|
+
configKey: "mcpServers",
|
|
396
|
+
format: "jsonc",
|
|
397
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
398
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)(kiroConfigPath) || (0, import_node_fs.existsSync)(process.env.KIRO_HOME?.trim() || (0, import_node_path.join)(home, ".kiro")),
|
|
399
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".kiro", "settings", "mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".kiro")),
|
|
400
|
+
transformDialect: "kiro"
|
|
401
|
+
},
|
|
402
|
+
// https://opencode.ai/docs/config/
|
|
403
|
+
opencode: {
|
|
404
|
+
name: "opencode",
|
|
405
|
+
displayName: "OpenCode",
|
|
406
|
+
globalConfigPath: (0, import_node_path.join)(
|
|
407
|
+
process.env.XDG_CONFIG_HOME || (0, import_node_path.join)(home, ".config"),
|
|
408
|
+
"opencode",
|
|
409
|
+
"opencode.json"
|
|
410
|
+
),
|
|
411
|
+
projectConfigPath: "opencode.json",
|
|
412
|
+
configKey: "mcp",
|
|
413
|
+
format: "jsonc",
|
|
414
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
415
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(process.env.XDG_CONFIG_HOME || (0, import_node_path.join)(home, ".config"), "opencode")),
|
|
416
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, "opencode.json")),
|
|
417
|
+
transformDialect: "opencode"
|
|
418
|
+
},
|
|
419
|
+
// https://pi.dev/packages/pi-mcp-extension
|
|
420
|
+
pi: {
|
|
421
|
+
name: "pi",
|
|
422
|
+
displayName: "Pi",
|
|
423
|
+
globalConfigPath: (0, import_node_path.join)(home, ".pi", "agent", "mcp.json"),
|
|
424
|
+
projectConfigPath: ".pi/mcp.json",
|
|
425
|
+
configKey: "mcpServers",
|
|
426
|
+
format: "jsonc",
|
|
427
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
428
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".pi")),
|
|
429
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".pi", "mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".pi")),
|
|
430
|
+
transformDialect: "pi"
|
|
431
|
+
},
|
|
432
|
+
// https://docs.qoder.com/zh/cli/mcp-servers.md
|
|
433
|
+
qoder: {
|
|
434
|
+
name: "qoder",
|
|
435
|
+
displayName: "Qoder",
|
|
436
|
+
globalConfigPath: qoderConfigPath,
|
|
437
|
+
projectConfigPath: ".mcp.json",
|
|
438
|
+
configKey: "mcpServers",
|
|
439
|
+
format: "jsonc",
|
|
440
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
441
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)(qoderConfigPath) || (0, import_node_fs.existsSync)(process.env.QODER_HOME?.trim() || (0, import_node_path.join)(home, ".qoder")),
|
|
442
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".qoder", "settings.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".qoder")),
|
|
443
|
+
resolveConfigPath: ({ global: isGlobal, cwd }) => {
|
|
444
|
+
if (isGlobal) return qoderConfigPath;
|
|
445
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".qoder", "settings.json"))) {
|
|
446
|
+
return (0, import_node_path.join)(cwd, ".qoder", "settings.json");
|
|
447
|
+
}
|
|
448
|
+
return (0, import_node_path.join)(cwd, ".mcp.json");
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
// https://qwenlm.github.io/qwen-code-docs/en/users/features/mcp/
|
|
452
|
+
"qwen-code": {
|
|
453
|
+
name: "qwen-code",
|
|
454
|
+
displayName: "Qwen Code",
|
|
455
|
+
globalConfigPath: qwenCodeConfigPath,
|
|
456
|
+
projectConfigPath: ".qwen/settings.json",
|
|
457
|
+
configKey: "mcpServers",
|
|
458
|
+
format: "jsonc",
|
|
459
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
460
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)(qwenCodeConfigPath) || (0, import_node_fs.existsSync)(
|
|
461
|
+
process.env.QWEN_CODE_HOME?.trim() || process.env.QWEN_HOME?.trim() || (0, import_node_path.join)(home, ".qwen")
|
|
462
|
+
),
|
|
463
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".qwen", "settings.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".qwen")),
|
|
464
|
+
transformDialect: "qwen-code"
|
|
465
|
+
},
|
|
466
|
+
// https://docs.trae.ai/ide/add-mcp-servers?_lang=en
|
|
467
|
+
trae: {
|
|
468
|
+
name: "trae",
|
|
469
|
+
displayName: "Trae",
|
|
470
|
+
globalConfigPath: traeConfigPath,
|
|
471
|
+
projectConfigPath: ".trae/mcp.json",
|
|
472
|
+
configKey: "mcpServers",
|
|
473
|
+
format: "jsonc",
|
|
474
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
475
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)(traeConfigPath) || (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".trae", "mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".trae")) || (0, import_node_fs.existsSync)(traePath) || (0, import_node_fs.existsSync)((0, import_node_path.join)(appSupport, "Trae")),
|
|
476
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".trae", "mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".trae")),
|
|
477
|
+
resolveConfigPath: ({ global: isGlobal, cwd }) => {
|
|
478
|
+
if (isGlobal) {
|
|
479
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".trae", "mcp.json"))) {
|
|
480
|
+
return (0, import_node_path.join)(home, ".trae", "mcp.json");
|
|
481
|
+
}
|
|
482
|
+
return traeConfigPath;
|
|
483
|
+
}
|
|
484
|
+
return (0, import_node_path.join)(cwd, ".trae", "mcp.json");
|
|
485
|
+
},
|
|
486
|
+
transformDialect: "trae"
|
|
487
|
+
},
|
|
488
|
+
// https://code.visualstudio.com/raw/docs/agents/reference/mcp-configuration.md
|
|
489
|
+
vscode: {
|
|
490
|
+
name: "vscode",
|
|
491
|
+
displayName: "VS Code",
|
|
492
|
+
globalConfigPath: (0, import_node_path.join)(vscodePath, "mcp.json"),
|
|
493
|
+
projectConfigPath: ".vscode/mcp.json",
|
|
494
|
+
configKey: "servers",
|
|
495
|
+
format: "jsonc",
|
|
496
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
497
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(vscodePath, "mcp.json")) || (0, import_node_fs.existsSync)(vscodePath),
|
|
498
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".vscode", "mcp.json")),
|
|
499
|
+
transformDialect: "vscode"
|
|
500
|
+
},
|
|
501
|
+
// https://zed.dev/docs/ai/mcp.md
|
|
502
|
+
zed: {
|
|
503
|
+
name: "zed",
|
|
504
|
+
displayName: "Zed",
|
|
505
|
+
globalConfigPath: zedConfigPath,
|
|
506
|
+
projectConfigPath: ".zed/settings.json",
|
|
507
|
+
configKey: "context_servers",
|
|
508
|
+
format: "jsonc",
|
|
509
|
+
supportedTransports: ALL_TRANSPORTS,
|
|
510
|
+
detectGlobalInstall: () => (0, import_node_fs.existsSync)(zedConfigPath) || (0, import_node_fs.existsSync)((0, import_node_path.join)(process.env.XDG_CONFIG_HOME || (0, import_node_path.join)(home, ".config"), "zed")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(appSupport, "Zed")),
|
|
511
|
+
detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".zed", "settings.json")),
|
|
512
|
+
transformDialect: "zed"
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
var mcpAgentAliases = {
|
|
516
|
+
agy: "antigravity-cli",
|
|
517
|
+
"amp-cli": "amp",
|
|
518
|
+
"amp-code": "amp",
|
|
519
|
+
ampcode: "amp",
|
|
520
|
+
auggie: "augment",
|
|
521
|
+
"augment-code": "augment",
|
|
522
|
+
augmentcode: "augment",
|
|
523
|
+
"cline-vscode": "cline",
|
|
524
|
+
gemini: "gemini-cli",
|
|
525
|
+
"github-copilot": "vscode",
|
|
526
|
+
"grok-cli": "grok",
|
|
527
|
+
kimi: "kimi-code-cli",
|
|
528
|
+
"kimi-cli": "kimi-code-cli",
|
|
529
|
+
"kimi-code": "kimi-code-cli",
|
|
530
|
+
"kiro-cli": "kiro",
|
|
531
|
+
"kiro-ide": "kiro",
|
|
532
|
+
"pi-agent": "pi",
|
|
533
|
+
"qoder-cli": "qoder",
|
|
534
|
+
qwen: "qwen-code",
|
|
535
|
+
"qwen-cli": "qwen-code",
|
|
536
|
+
qwencode: "qwen-code",
|
|
537
|
+
"trae-code": "trae",
|
|
538
|
+
traecode: "trae",
|
|
539
|
+
"trae-ide": "trae",
|
|
540
|
+
xai: "grok",
|
|
541
|
+
"xai-grok": "grok"
|
|
542
|
+
};
|
|
543
|
+
var getMcpAgentConfig = (agentType) => mcpAgents[agentType];
|
|
544
|
+
var getMcpAgentTypes = () => Object.values(mcpAgents).map((config) => config.name);
|
|
545
|
+
var isMcpAgentType = (value) => value in mcpAgents;
|
|
546
|
+
var resolveMcpAgentAlias = (input5) => {
|
|
547
|
+
if (isMcpAgentType(input5)) return input5;
|
|
548
|
+
return mcpAgentAliases[input5] ?? null;
|
|
549
|
+
};
|
|
550
|
+
var isMcpTransportSupported = (agent, transport) => agent.supportedTransports.includes(transport);
|
|
551
|
+
var detectProjectInstalledMcpAgents = (cwd) => getMcpAgentTypes().filter(
|
|
552
|
+
(type) => mcpAgents[type].detectProjectInstall ? mcpAgents[type].detectProjectInstall(cwd) : false
|
|
553
|
+
);
|
|
554
|
+
var detectGloballyInstalledMcpAgents = () => getMcpAgentTypes().filter((type) => mcpAgents[type].detectGlobalInstall());
|
|
555
|
+
var getMcpAgentsSupportingProjectScope = () => getMcpAgentTypes().filter((type) => Boolean(mcpAgents[type].projectConfigPath));
|
|
556
|
+
|
|
557
|
+
// src/constants.ts
|
|
558
|
+
var DEFAULT_REMOTE_TRANSPORT = "http";
|
|
559
|
+
var NPX_COMMAND = "npx";
|
|
560
|
+
var NPX_DASH_Y = "-y";
|
|
561
|
+
var GOOSE_TIMEOUT_SECONDS = 300;
|
|
562
|
+
var DEFAULT_JSON_INDENT_SPACES = 2;
|
|
563
|
+
var MCP_DEFAULT_SERVER_NAME = "mcp-server";
|
|
564
|
+
var GENERIC_HOST_PREFIXES = /* @__PURE__ */ new Set([
|
|
565
|
+
"mcp",
|
|
566
|
+
"api",
|
|
567
|
+
"app",
|
|
568
|
+
"www",
|
|
569
|
+
"server",
|
|
570
|
+
"servers",
|
|
571
|
+
"remote"
|
|
572
|
+
]);
|
|
573
|
+
var COMMON_TLD_LABELS = /* @__PURE__ */ new Set([
|
|
574
|
+
"com",
|
|
575
|
+
"org",
|
|
576
|
+
"net",
|
|
577
|
+
"io",
|
|
578
|
+
"dev",
|
|
579
|
+
"ai",
|
|
580
|
+
"tech",
|
|
581
|
+
"co",
|
|
582
|
+
"app",
|
|
583
|
+
"cloud",
|
|
584
|
+
"sh",
|
|
585
|
+
"run"
|
|
586
|
+
]);
|
|
587
|
+
var PACKAGE_NAME_PREFIX_STRIP = ["mcp-server-", "server-"];
|
|
588
|
+
var PACKAGE_NAME_SUFFIX_STRIP = ["-mcp-server", "-mcp"];
|
|
589
|
+
var KNOWN_COMMAND_RUNNERS = /* @__PURE__ */ new Set([
|
|
590
|
+
"npx",
|
|
591
|
+
"node",
|
|
592
|
+
"python",
|
|
593
|
+
"python3",
|
|
594
|
+
"uvx",
|
|
595
|
+
"bunx",
|
|
596
|
+
"deno"
|
|
597
|
+
]);
|
|
598
|
+
var SCRIPT_EXTENSION_REGEX = /\.(?:js|ts|mjs|cjs|py|sh|rb|go)$/i;
|
|
599
|
+
|
|
600
|
+
// src/build-server-config.ts
|
|
601
|
+
var buildMcpServerConfig = (parsed, options = {}) => {
|
|
602
|
+
if (parsed.type === "remote") {
|
|
603
|
+
const config2 = {
|
|
604
|
+
type: options.transport ?? DEFAULT_REMOTE_TRANSPORT,
|
|
605
|
+
url: parsed.value
|
|
606
|
+
};
|
|
607
|
+
if (options.headers && Object.keys(options.headers).length > 0) {
|
|
608
|
+
config2.headers = options.headers;
|
|
609
|
+
}
|
|
610
|
+
return config2;
|
|
611
|
+
}
|
|
612
|
+
if (parsed.type === "command") {
|
|
613
|
+
const parts = parsed.value.split(/\s+/);
|
|
614
|
+
const command = parts[0] ?? "";
|
|
615
|
+
const args = parts.slice(1);
|
|
616
|
+
if (options.args && options.args.length > 0) {
|
|
617
|
+
args.push(...options.args);
|
|
618
|
+
}
|
|
619
|
+
const config2 = { command, args };
|
|
620
|
+
if (options.env && Object.keys(options.env).length > 0) {
|
|
621
|
+
config2.env = options.env;
|
|
622
|
+
}
|
|
623
|
+
return config2;
|
|
624
|
+
}
|
|
625
|
+
const packageArgs = [NPX_DASH_Y, parsed.value];
|
|
626
|
+
if (options.args && options.args.length > 0) {
|
|
627
|
+
packageArgs.push(...options.args);
|
|
628
|
+
}
|
|
629
|
+
const config = {
|
|
630
|
+
command: NPX_COMMAND,
|
|
631
|
+
args: packageArgs
|
|
632
|
+
};
|
|
633
|
+
if (options.env && Object.keys(options.env).length > 0) {
|
|
634
|
+
config.env = options.env;
|
|
635
|
+
}
|
|
636
|
+
return config;
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
// src/parse-server-config.ts
|
|
640
|
+
var isRemoteServerConfig = (config) => typeof config.url === "string" && config.url.length > 0;
|
|
641
|
+
var isStdioServerConfig = (config) => typeof config.command === "string" && config.command.length > 0;
|
|
642
|
+
var parseServerConfig = (raw) => {
|
|
643
|
+
if (!raw || typeof raw !== "object") return {};
|
|
644
|
+
const data = raw;
|
|
645
|
+
const rawUrl = typeof data.url === "string" && data.url.trim().length > 0 ? data.url.trim() : void 0;
|
|
646
|
+
const rawHttpUrl = typeof data.httpUrl === "string" && data.httpUrl.trim().length > 0 ? data.httpUrl.trim() : void 0;
|
|
647
|
+
const remoteUrl = rawHttpUrl ?? rawUrl;
|
|
648
|
+
if (remoteUrl) {
|
|
649
|
+
const transport = data.type === "sse" || data.transport === "sse" ? "sse" : "http";
|
|
650
|
+
const headers = data.headers && typeof data.headers === "object" ? data.headers : void 0;
|
|
651
|
+
return {
|
|
652
|
+
type: transport,
|
|
653
|
+
url: remoteUrl,
|
|
654
|
+
headers
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
if (typeof data.command === "string" && data.command.trim().length > 0) {
|
|
658
|
+
const args = Array.isArray(data.args) ? data.args.filter((item) => typeof item === "string") : void 0;
|
|
659
|
+
const env = data.env && typeof data.env === "object" ? data.env : void 0;
|
|
660
|
+
return {
|
|
661
|
+
command: data.command.trim(),
|
|
662
|
+
args,
|
|
663
|
+
env
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
return {};
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
// src/utils/is-plain-object.ts
|
|
670
|
+
var isPlainObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
671
|
+
|
|
672
|
+
// src/utils/get-nested-value.ts
|
|
673
|
+
var getNestedValue = (source, dottedKey) => {
|
|
674
|
+
if (!source) return void 0;
|
|
675
|
+
if (dottedKey in source) return source[dottedKey];
|
|
676
|
+
const segments = dottedKey.split(".");
|
|
677
|
+
let cursor = source;
|
|
678
|
+
for (const segment of segments) {
|
|
679
|
+
if (!isPlainObject(cursor)) return void 0;
|
|
680
|
+
cursor = cursor[segment];
|
|
681
|
+
}
|
|
682
|
+
return cursor;
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
// src/formats/json.ts
|
|
686
|
+
var import_node_fs3 = require("fs");
|
|
687
|
+
var import_jsonc_parser = require("jsonc-parser");
|
|
688
|
+
|
|
689
|
+
// src/utils/ensure-parent-dir.ts
|
|
690
|
+
var import_node_fs2 = require("fs");
|
|
691
|
+
var import_node_path2 = require("path");
|
|
692
|
+
var ensureParentDir = (filePath) => {
|
|
693
|
+
const parentDir = (0, import_node_path2.dirname)(filePath);
|
|
694
|
+
if (!(0, import_node_fs2.existsSync)(parentDir)) (0, import_node_fs2.mkdirSync)(parentDir, { recursive: true });
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
// src/utils/set-nested-value.ts
|
|
698
|
+
var DANGEROUS_KEY_SEGMENTS = /* @__PURE__ */ new Set([
|
|
699
|
+
"__proto__",
|
|
700
|
+
"prototype",
|
|
701
|
+
"constructor"
|
|
702
|
+
]);
|
|
703
|
+
var assertSafeSegment = (segment) => {
|
|
704
|
+
if (DANGEROUS_KEY_SEGMENTS.has(segment)) {
|
|
705
|
+
throw new Error(`Refusing to write to unsafe key segment "${segment}"`);
|
|
706
|
+
}
|
|
707
|
+
};
|
|
708
|
+
var setNestedValue = (target, dottedKey, value) => {
|
|
709
|
+
if (dottedKey in target) {
|
|
710
|
+
assertSafeSegment(dottedKey);
|
|
711
|
+
target[dottedKey] = value;
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
const segments = dottedKey.split(".");
|
|
715
|
+
let cursor = target;
|
|
716
|
+
for (let segmentIndex = 0; segmentIndex < segments.length - 1; segmentIndex += 1) {
|
|
717
|
+
const segment = segments[segmentIndex];
|
|
718
|
+
assertSafeSegment(segment);
|
|
719
|
+
const existing = cursor[segment];
|
|
720
|
+
if (isPlainObject(existing)) {
|
|
721
|
+
cursor = existing;
|
|
722
|
+
continue;
|
|
723
|
+
}
|
|
724
|
+
const next = {};
|
|
725
|
+
cursor[segment] = next;
|
|
726
|
+
cursor = next;
|
|
727
|
+
}
|
|
728
|
+
const finalSegment = segments[segments.length - 1];
|
|
729
|
+
assertSafeSegment(finalSegment);
|
|
730
|
+
cursor[finalSegment] = value;
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
// src/utils/walk-nested-object.ts
|
|
734
|
+
var walkNestedObject = (root, segments) => {
|
|
735
|
+
let cursor = root;
|
|
736
|
+
for (const segment of segments) {
|
|
737
|
+
if (!isPlainObject(cursor)) return void 0;
|
|
738
|
+
cursor = cursor[segment];
|
|
739
|
+
}
|
|
740
|
+
return isPlainObject(cursor) ? cursor : void 0;
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
// src/formats/json.ts
|
|
744
|
+
var JSONC_FORMATTING = {
|
|
745
|
+
insertSpaces: true,
|
|
746
|
+
tabSize: DEFAULT_JSON_INDENT_SPACES,
|
|
747
|
+
eol: "\n"
|
|
748
|
+
};
|
|
749
|
+
var readFileOrEmpty = (filePath) => (0, import_node_fs3.existsSync)(filePath) ? (0, import_node_fs3.readFileSync)(filePath, "utf-8") : "";
|
|
750
|
+
var writeWithTrailingNewline = (filePath, contents) => {
|
|
751
|
+
(0, import_node_fs3.writeFileSync)(filePath, contents.endsWith("\n") ? contents : `${contents}
|
|
752
|
+
`, "utf-8");
|
|
753
|
+
};
|
|
754
|
+
var readJsoncConfig = (filePath) => {
|
|
755
|
+
const raw = readFileOrEmpty(filePath);
|
|
756
|
+
if (!raw.trim()) return {};
|
|
757
|
+
const parsed = (0, import_jsonc_parser.parse)(raw);
|
|
758
|
+
return isPlainObject(parsed) ? parsed : {};
|
|
759
|
+
};
|
|
760
|
+
var resolvePathPrefix = (root, dottedKey) => {
|
|
761
|
+
if (dottedKey in root) return [dottedKey];
|
|
762
|
+
const segments = dottedKey.split(".");
|
|
763
|
+
if (segments.length > 1 && walkNestedObject(root, segments)) {
|
|
764
|
+
return segments;
|
|
765
|
+
}
|
|
766
|
+
return [dottedKey];
|
|
767
|
+
};
|
|
768
|
+
var setJsoncNestedValue = (filePath, dottedKey, serverName, serverConfig) => {
|
|
769
|
+
ensureParentDir(filePath);
|
|
770
|
+
const existingText = readFileOrEmpty(filePath);
|
|
771
|
+
const sourceText = existingText.trim() ? existingText : "{}";
|
|
772
|
+
const existing = readJsoncConfig(filePath);
|
|
773
|
+
const pathPrefix = resolvePathPrefix(existing, dottedKey);
|
|
774
|
+
const path = [...pathPrefix, serverName];
|
|
775
|
+
const edits = (0, import_jsonc_parser.modify)(sourceText, path, serverConfig, {
|
|
776
|
+
formattingOptions: JSONC_FORMATTING
|
|
777
|
+
});
|
|
778
|
+
writeWithTrailingNewline(filePath, (0, import_jsonc_parser.applyEdits)(sourceText, edits));
|
|
779
|
+
};
|
|
780
|
+
var writeJsonConfigAtKey = (filePath, dottedKey, serverName, serverConfig) => {
|
|
781
|
+
ensureParentDir(filePath);
|
|
782
|
+
const existing = readJsoncConfig(filePath);
|
|
783
|
+
const pathPrefix = resolvePathPrefix(existing, dottedKey);
|
|
784
|
+
const existingServers = walkNestedObject(existing, pathPrefix);
|
|
785
|
+
const servers = existingServers ? { ...existingServers } : {};
|
|
786
|
+
servers[serverName] = serverConfig;
|
|
787
|
+
if (pathPrefix.length === 1) {
|
|
788
|
+
existing[pathPrefix[0]] = servers;
|
|
789
|
+
} else {
|
|
790
|
+
setNestedValue(existing, dottedKey, servers);
|
|
791
|
+
}
|
|
792
|
+
(0, import_node_fs3.writeFileSync)(
|
|
793
|
+
filePath,
|
|
794
|
+
`${JSON.stringify(existing, null, DEFAULT_JSON_INDENT_SPACES)}
|
|
795
|
+
`,
|
|
796
|
+
"utf-8"
|
|
797
|
+
);
|
|
798
|
+
};
|
|
799
|
+
var removeJsoncConfigKey = (filePath, dottedKey, serverName) => {
|
|
800
|
+
if (!(0, import_node_fs3.existsSync)(filePath)) return false;
|
|
801
|
+
const sourceText = (0, import_node_fs3.readFileSync)(filePath, "utf-8");
|
|
802
|
+
if (!sourceText.trim()) return false;
|
|
803
|
+
const existing = readJsoncConfig(filePath);
|
|
804
|
+
const pathPrefix = resolvePathPrefix(existing, dottedKey);
|
|
805
|
+
const parentObject = walkNestedObject(existing, pathPrefix);
|
|
806
|
+
if (!parentObject || !(serverName in parentObject)) return false;
|
|
807
|
+
const path = [...pathPrefix, serverName];
|
|
808
|
+
const edits = (0, import_jsonc_parser.modify)(sourceText, path, void 0, {
|
|
809
|
+
formattingOptions: JSONC_FORMATTING
|
|
810
|
+
});
|
|
811
|
+
if (edits.length === 0) return false;
|
|
812
|
+
writeWithTrailingNewline(filePath, (0, import_jsonc_parser.applyEdits)(sourceText, edits));
|
|
813
|
+
return true;
|
|
814
|
+
};
|
|
815
|
+
|
|
816
|
+
// src/formats/toml.ts
|
|
817
|
+
var import_node_fs4 = require("fs");
|
|
818
|
+
var import_toml = __toESM(require("@iarna/toml"), 1);
|
|
819
|
+
|
|
820
|
+
// src/utils/delete-nested-value.ts
|
|
821
|
+
var DANGEROUS_KEY_SEGMENTS2 = /* @__PURE__ */ new Set([
|
|
822
|
+
"__proto__",
|
|
823
|
+
"prototype",
|
|
824
|
+
"constructor"
|
|
825
|
+
]);
|
|
826
|
+
var deleteNestedValue = (target, dottedKey) => {
|
|
827
|
+
if (!target) return false;
|
|
828
|
+
if (dottedKey in target) {
|
|
829
|
+
if (DANGEROUS_KEY_SEGMENTS2.has(dottedKey)) return false;
|
|
830
|
+
delete target[dottedKey];
|
|
831
|
+
return true;
|
|
832
|
+
}
|
|
833
|
+
const segments = dottedKey.split(".");
|
|
834
|
+
if (segments.some((segment) => DANGEROUS_KEY_SEGMENTS2.has(segment))) return false;
|
|
835
|
+
let cursor = target;
|
|
836
|
+
for (let segmentIndex = 0; segmentIndex < segments.length - 1; segmentIndex += 1) {
|
|
837
|
+
const segment = segments[segmentIndex];
|
|
838
|
+
const existing = cursor[segment];
|
|
839
|
+
if (!isPlainObject(existing)) return false;
|
|
840
|
+
cursor = existing;
|
|
841
|
+
}
|
|
842
|
+
const lastSegment = segments[segments.length - 1];
|
|
843
|
+
if (!(lastSegment in cursor)) return false;
|
|
844
|
+
delete cursor[lastSegment];
|
|
845
|
+
return true;
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
// src/formats/toml.ts
|
|
849
|
+
var toTomlJsonMap = (value) => JSON.parse(JSON.stringify(value));
|
|
850
|
+
var readTomlConfig = (filePath) => {
|
|
851
|
+
if (!(0, import_node_fs4.existsSync)(filePath)) return {};
|
|
852
|
+
const raw = (0, import_node_fs4.readFileSync)(filePath, "utf-8");
|
|
853
|
+
if (!raw.trim()) return {};
|
|
854
|
+
const parsed = import_toml.default.parse(raw);
|
|
855
|
+
return isPlainObject(parsed) ? parsed : {};
|
|
856
|
+
};
|
|
857
|
+
var writeTomlConfigAtKey = (filePath, dottedKey, serverName, serverConfig) => {
|
|
858
|
+
ensureParentDir(filePath);
|
|
859
|
+
const existing = readTomlConfig(filePath);
|
|
860
|
+
const existingServers = walkNestedObject(existing, dottedKey.split("."));
|
|
861
|
+
const servers = existingServers ? { ...existingServers } : {};
|
|
862
|
+
servers[serverName] = serverConfig;
|
|
863
|
+
setNestedValue(existing, dottedKey, servers);
|
|
864
|
+
(0, import_node_fs4.writeFileSync)(filePath, import_toml.default.stringify(toTomlJsonMap(existing)), "utf-8");
|
|
865
|
+
};
|
|
866
|
+
var removeTomlConfigKey = (filePath, dottedKey, serverName) => {
|
|
867
|
+
if (!(0, import_node_fs4.existsSync)(filePath)) return false;
|
|
868
|
+
const existing = readTomlConfig(filePath);
|
|
869
|
+
const didRemove = deleteNestedValue(existing, `${dottedKey}.${serverName}`);
|
|
870
|
+
if (didRemove) (0, import_node_fs4.writeFileSync)(filePath, import_toml.default.stringify(toTomlJsonMap(existing)), "utf-8");
|
|
871
|
+
return didRemove;
|
|
872
|
+
};
|
|
873
|
+
|
|
874
|
+
// src/formats/yaml.ts
|
|
875
|
+
var import_node_fs5 = require("fs");
|
|
876
|
+
var import_yaml = require("yaml");
|
|
877
|
+
var readYamlConfig = (filePath) => {
|
|
878
|
+
if (!(0, import_node_fs5.existsSync)(filePath)) return {};
|
|
879
|
+
const raw = (0, import_node_fs5.readFileSync)(filePath, "utf-8");
|
|
880
|
+
if (!raw.trim()) return {};
|
|
881
|
+
const parsed = (0, import_yaml.parse)(raw);
|
|
882
|
+
return isPlainObject(parsed) ? parsed : {};
|
|
883
|
+
};
|
|
884
|
+
var writeYamlConfigAtKey = (filePath, dottedKey, serverName, serverConfig) => {
|
|
885
|
+
ensureParentDir(filePath);
|
|
886
|
+
const existing = readYamlConfig(filePath);
|
|
887
|
+
const existingServers = walkNestedObject(existing, dottedKey.split("."));
|
|
888
|
+
const servers = existingServers ? { ...existingServers } : {};
|
|
889
|
+
servers[serverName] = serverConfig;
|
|
890
|
+
setNestedValue(existing, dottedKey, servers);
|
|
891
|
+
(0, import_node_fs5.writeFileSync)(filePath, (0, import_yaml.stringify)(existing), "utf-8");
|
|
892
|
+
};
|
|
893
|
+
var removeYamlConfigKey = (filePath, dottedKey, serverName) => {
|
|
894
|
+
if (!(0, import_node_fs5.existsSync)(filePath)) return false;
|
|
895
|
+
const existing = readYamlConfig(filePath);
|
|
896
|
+
const didRemove = deleteNestedValue(existing, `${dottedKey}.${serverName}`);
|
|
897
|
+
if (didRemove) (0, import_node_fs5.writeFileSync)(filePath, (0, import_yaml.stringify)(existing), "utf-8");
|
|
898
|
+
return didRemove;
|
|
899
|
+
};
|
|
900
|
+
|
|
901
|
+
// src/formats/index.ts
|
|
902
|
+
var readConfigFile = (filePath, format) => {
|
|
903
|
+
switch (format) {
|
|
904
|
+
case "json":
|
|
905
|
+
case "jsonc":
|
|
906
|
+
return readJsoncConfig(filePath);
|
|
907
|
+
case "yaml":
|
|
908
|
+
return readYamlConfig(filePath);
|
|
909
|
+
case "toml":
|
|
910
|
+
return readTomlConfig(filePath);
|
|
911
|
+
default:
|
|
912
|
+
throw new Error(`Unsupported config format: ${format}`);
|
|
913
|
+
}
|
|
914
|
+
};
|
|
915
|
+
var writeServerToConfigFile = (filePath, format, dottedKey, serverName, serverConfig) => {
|
|
916
|
+
switch (format) {
|
|
917
|
+
case "jsonc":
|
|
918
|
+
setJsoncNestedValue(filePath, dottedKey, serverName, serverConfig);
|
|
919
|
+
return;
|
|
920
|
+
case "json":
|
|
921
|
+
writeJsonConfigAtKey(filePath, dottedKey, serverName, serverConfig);
|
|
922
|
+
return;
|
|
923
|
+
case "yaml":
|
|
924
|
+
writeYamlConfigAtKey(filePath, dottedKey, serverName, serverConfig);
|
|
925
|
+
return;
|
|
926
|
+
case "toml":
|
|
927
|
+
writeTomlConfigAtKey(filePath, dottedKey, serverName, serverConfig);
|
|
928
|
+
return;
|
|
929
|
+
default:
|
|
930
|
+
throw new Error(`Unsupported config format: ${format}`);
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
var removeServerFromConfigFile = (filePath, format, dottedKey, serverName) => {
|
|
934
|
+
switch (format) {
|
|
935
|
+
case "json":
|
|
936
|
+
case "jsonc":
|
|
937
|
+
return removeJsoncConfigKey(filePath, dottedKey, serverName);
|
|
938
|
+
case "yaml":
|
|
939
|
+
return removeYamlConfigKey(filePath, dottedKey, serverName);
|
|
940
|
+
case "toml":
|
|
941
|
+
return removeTomlConfigKey(filePath, dottedKey, serverName);
|
|
942
|
+
default:
|
|
943
|
+
throw new Error(`Unsupported config format: ${format}`);
|
|
944
|
+
}
|
|
945
|
+
};
|
|
946
|
+
var listServersInConfigFile = (filePath, format, dottedKey) => {
|
|
947
|
+
const config = readConfigFile(filePath, format);
|
|
948
|
+
const entries = getNestedValue(config, dottedKey);
|
|
949
|
+
return isPlainObject(entries) ? entries : {};
|
|
950
|
+
};
|
|
951
|
+
|
|
952
|
+
// src/config-store.ts
|
|
953
|
+
var import_node_fs6 = require("fs");
|
|
954
|
+
|
|
955
|
+
// src/resolve-config-target.ts
|
|
956
|
+
var import_node_path3 = require("path");
|
|
957
|
+
var resolveMcpConfigTarget = (agent, options = {}) => {
|
|
958
|
+
const isGlobal = options.global ?? false;
|
|
959
|
+
const cwd = options.cwd ?? process.cwd();
|
|
960
|
+
const configPath = agent.resolveConfigPath ? agent.resolveConfigPath({ global: isGlobal, cwd }) : !isGlobal && agent.projectConfigPath ? (0, import_node_path3.join)(cwd, agent.projectConfigPath) : agent.globalConfigPath;
|
|
961
|
+
const configKey = !isGlobal && agent.projectConfigKey ? agent.projectConfigKey : agent.configKey;
|
|
962
|
+
return { configPath, configKey };
|
|
963
|
+
};
|
|
964
|
+
|
|
965
|
+
// src/config-store.ts
|
|
966
|
+
var FsConfigStoreAdapter = class {
|
|
967
|
+
exists(filePath) {
|
|
968
|
+
return (0, import_node_fs6.existsSync)(filePath);
|
|
969
|
+
}
|
|
970
|
+
read(target) {
|
|
971
|
+
return readConfigFile(target.filePath, target.format);
|
|
972
|
+
}
|
|
973
|
+
writeServer(target, serverName, serverConfig) {
|
|
974
|
+
if (!target.dottedKey) {
|
|
975
|
+
throw new Error(`Cannot write server: missing dottedKey for ${target.filePath}`);
|
|
976
|
+
}
|
|
977
|
+
writeServerToConfigFile(
|
|
978
|
+
target.filePath,
|
|
979
|
+
target.format,
|
|
980
|
+
target.dottedKey,
|
|
981
|
+
serverName,
|
|
982
|
+
serverConfig
|
|
983
|
+
);
|
|
984
|
+
}
|
|
985
|
+
removeServer(target, serverName) {
|
|
986
|
+
if (!target.dottedKey) return false;
|
|
987
|
+
return removeServerFromConfigFile(
|
|
988
|
+
target.filePath,
|
|
989
|
+
target.format,
|
|
990
|
+
target.dottedKey,
|
|
991
|
+
serverName
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
listServers(target) {
|
|
995
|
+
if (!target.dottedKey) return {};
|
|
996
|
+
return listServersInConfigFile(target.filePath, target.format, target.dottedKey);
|
|
997
|
+
}
|
|
998
|
+
};
|
|
999
|
+
var AgentConfigStore = class {
|
|
1000
|
+
constructor(adapter = new FsConfigStoreAdapter()) {
|
|
1001
|
+
this.adapter = adapter;
|
|
1002
|
+
}
|
|
1003
|
+
adapter;
|
|
1004
|
+
getAdapter() {
|
|
1005
|
+
return this.adapter;
|
|
1006
|
+
}
|
|
1007
|
+
resolveTarget(agent, options = {}) {
|
|
1008
|
+
const agentConfig = typeof agent === "string" ? getMcpAgentConfig(agent) : agent;
|
|
1009
|
+
const target = resolveMcpConfigTarget(agentConfig, options);
|
|
1010
|
+
return { agent: agentConfig, target };
|
|
1011
|
+
}
|
|
1012
|
+
resolveDescriptor(agent, options = {}) {
|
|
1013
|
+
const { agent: agentConfig, target } = this.resolveTarget(agent, options);
|
|
1014
|
+
return {
|
|
1015
|
+
filePath: target.configPath,
|
|
1016
|
+
format: agentConfig.format,
|
|
1017
|
+
dottedKey: target.configKey
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
writeServer(agent, serverName, serverConfig, options = {}) {
|
|
1021
|
+
const descriptor = this.resolveDescriptor(agent, options);
|
|
1022
|
+
this.adapter.writeServer(descriptor, serverName, serverConfig);
|
|
1023
|
+
return { path: descriptor.filePath };
|
|
1024
|
+
}
|
|
1025
|
+
removeServer(agent, serverName, options = {}) {
|
|
1026
|
+
const descriptor = this.resolveDescriptor(agent, options);
|
|
1027
|
+
if (!this.adapter.exists(descriptor.filePath)) {
|
|
1028
|
+
return { path: descriptor.filePath, removed: false };
|
|
1029
|
+
}
|
|
1030
|
+
const removed = this.adapter.removeServer(descriptor, serverName);
|
|
1031
|
+
return { path: descriptor.filePath, removed };
|
|
1032
|
+
}
|
|
1033
|
+
listServers(agent, options = {}) {
|
|
1034
|
+
const descriptor = this.resolveDescriptor(agent, options);
|
|
1035
|
+
if (!this.adapter.exists(descriptor.filePath)) {
|
|
1036
|
+
return { path: descriptor.filePath, exists: false, servers: {} };
|
|
1037
|
+
}
|
|
1038
|
+
const servers = this.adapter.listServers(descriptor);
|
|
1039
|
+
return { path: descriptor.filePath, exists: true, servers };
|
|
1040
|
+
}
|
|
1041
|
+
read(agent, options = {}) {
|
|
1042
|
+
const descriptor = this.resolveDescriptor(agent, options);
|
|
1043
|
+
if (!this.adapter.exists(descriptor.filePath)) {
|
|
1044
|
+
return {};
|
|
1045
|
+
}
|
|
1046
|
+
return this.adapter.read(descriptor);
|
|
1047
|
+
}
|
|
1048
|
+
readServer(agent, serverName, options = {}) {
|
|
1049
|
+
const { exists, servers } = this.listServers(agent, options);
|
|
1050
|
+
if (!exists) return void 0;
|
|
1051
|
+
return servers[serverName];
|
|
1052
|
+
}
|
|
1053
|
+
};
|
|
1054
|
+
var agentConfigStore = new AgentConfigStore();
|
|
1055
|
+
|
|
1056
|
+
// src/utils/to-error-message.ts
|
|
1057
|
+
var toErrorMessage = (error, fallback = "Unknown error") => error instanceof Error ? error.message : fallback;
|
|
1058
|
+
|
|
1059
|
+
// src/transforms/index.ts
|
|
1060
|
+
var DIALECT_PRESETS = {
|
|
1061
|
+
vscode: {
|
|
1062
|
+
stdioTransport: "type-stdio",
|
|
1063
|
+
remoteTransport: "type-http-sse"
|
|
1064
|
+
},
|
|
1065
|
+
augment: {
|
|
1066
|
+
stdioTransport: "none",
|
|
1067
|
+
remoteTransport: "type-http-sse"
|
|
1068
|
+
},
|
|
1069
|
+
amp: {
|
|
1070
|
+
stdioTransport: "none",
|
|
1071
|
+
remoteTransport: "none"
|
|
1072
|
+
},
|
|
1073
|
+
trae: {
|
|
1074
|
+
stdioTransport: "none",
|
|
1075
|
+
remoteTransport: "sse-only-type"
|
|
1076
|
+
},
|
|
1077
|
+
grok: {
|
|
1078
|
+
stdioTransport: "none",
|
|
1079
|
+
remoteTransport: "sse-only-type"
|
|
1080
|
+
},
|
|
1081
|
+
cline: {
|
|
1082
|
+
stdioTransport: "none",
|
|
1083
|
+
remoteTransport: "streamableHttp"
|
|
1084
|
+
},
|
|
1085
|
+
goose: {
|
|
1086
|
+
stdioTransport: "type-stdio",
|
|
1087
|
+
remoteTransport: "streamable_http",
|
|
1088
|
+
commandField: "cmd",
|
|
1089
|
+
envField: "envs",
|
|
1090
|
+
urlField: "uri",
|
|
1091
|
+
defaultEnvEmpty: true,
|
|
1092
|
+
defaultHeadersEmpty: true,
|
|
1093
|
+
includeServerName: true,
|
|
1094
|
+
timeoutSeconds: GOOSE_TIMEOUT_SECONDS,
|
|
1095
|
+
extraFields: {
|
|
1096
|
+
description: "",
|
|
1097
|
+
enabled: true
|
|
1098
|
+
}
|
|
1099
|
+
},
|
|
1100
|
+
"kimi-code": {
|
|
1101
|
+
stdioTransport: "none",
|
|
1102
|
+
remoteTransport: "sse-only-transport"
|
|
1103
|
+
},
|
|
1104
|
+
kiro: {
|
|
1105
|
+
stdioTransport: "none",
|
|
1106
|
+
remoteTransport: "none"
|
|
1107
|
+
},
|
|
1108
|
+
opencode: {
|
|
1109
|
+
stdioTransport: "type-local",
|
|
1110
|
+
remoteTransport: "remote-type",
|
|
1111
|
+
commandArray: true,
|
|
1112
|
+
envField: "environment",
|
|
1113
|
+
defaultEnvEmpty: true,
|
|
1114
|
+
extraFields: {
|
|
1115
|
+
enabled: true
|
|
1116
|
+
}
|
|
1117
|
+
},
|
|
1118
|
+
pi: {
|
|
1119
|
+
stdioTransport: "transport-stdio",
|
|
1120
|
+
remoteTransport: "streamable-http"
|
|
1121
|
+
},
|
|
1122
|
+
"qwen-code": {
|
|
1123
|
+
stdioTransport: "none",
|
|
1124
|
+
remoteTransport: "qwen"
|
|
1125
|
+
},
|
|
1126
|
+
zed: {
|
|
1127
|
+
stdioTransport: "none",
|
|
1128
|
+
remoteTransport: "none",
|
|
1129
|
+
defaultEnvEmpty: true
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
var resolveDialectOptions = (dialect) => {
|
|
1133
|
+
if (typeof dialect === "string") {
|
|
1134
|
+
const preset = DIALECT_PRESETS[dialect];
|
|
1135
|
+
if (!preset) {
|
|
1136
|
+
throw new Error(`Unknown server config dialect: "${dialect}"`);
|
|
1137
|
+
}
|
|
1138
|
+
return preset;
|
|
1139
|
+
}
|
|
1140
|
+
return dialect;
|
|
1141
|
+
};
|
|
1142
|
+
var transformRemoteConfig = (serverName, config, options) => {
|
|
1143
|
+
const result = {};
|
|
1144
|
+
if (options.includeServerName) {
|
|
1145
|
+
result.name = serverName;
|
|
1146
|
+
}
|
|
1147
|
+
if (options.extraFields) {
|
|
1148
|
+
Object.assign(result, options.extraFields);
|
|
1149
|
+
}
|
|
1150
|
+
const remoteTransport = options.remoteTransport ?? "type-http-sse";
|
|
1151
|
+
const urlField = options.urlField ?? "url";
|
|
1152
|
+
switch (remoteTransport) {
|
|
1153
|
+
case "type-http-sse":
|
|
1154
|
+
result.type = config.type || "http";
|
|
1155
|
+
result[urlField] = config.url;
|
|
1156
|
+
break;
|
|
1157
|
+
case "sse-only-type":
|
|
1158
|
+
result[urlField] = config.url;
|
|
1159
|
+
if (config.type === "sse") {
|
|
1160
|
+
result.type = "sse";
|
|
1161
|
+
}
|
|
1162
|
+
break;
|
|
1163
|
+
case "sse-only-transport":
|
|
1164
|
+
result[urlField] = config.url;
|
|
1165
|
+
if (config.type === "sse") {
|
|
1166
|
+
result.transport = "sse";
|
|
1167
|
+
}
|
|
1168
|
+
break;
|
|
1169
|
+
case "none":
|
|
1170
|
+
result[urlField] = config.url;
|
|
1171
|
+
break;
|
|
1172
|
+
case "streamableHttp":
|
|
1173
|
+
result.type = config.type === "sse" ? "sse" : "streamableHttp";
|
|
1174
|
+
result[urlField] = config.url;
|
|
1175
|
+
break;
|
|
1176
|
+
case "streamable-http":
|
|
1177
|
+
result.transport = config.type === "sse" ? "sse" : "streamable-http";
|
|
1178
|
+
result[urlField] = config.url;
|
|
1179
|
+
break;
|
|
1180
|
+
case "streamable_http":
|
|
1181
|
+
result.type = config.type === "sse" ? "sse" : "streamable_http";
|
|
1182
|
+
result[urlField] = config.url;
|
|
1183
|
+
break;
|
|
1184
|
+
case "remote-type":
|
|
1185
|
+
result.type = "remote";
|
|
1186
|
+
result[urlField] = config.url;
|
|
1187
|
+
break;
|
|
1188
|
+
case "qwen":
|
|
1189
|
+
if (config.type === "sse") {
|
|
1190
|
+
result.url = config.url;
|
|
1191
|
+
} else {
|
|
1192
|
+
result.httpUrl = config.url;
|
|
1193
|
+
}
|
|
1194
|
+
break;
|
|
1195
|
+
}
|
|
1196
|
+
const hasHeaders = config.headers && Object.keys(config.headers).length > 0;
|
|
1197
|
+
if (hasHeaders) {
|
|
1198
|
+
result.headers = config.headers;
|
|
1199
|
+
} else if (options.defaultHeadersEmpty) {
|
|
1200
|
+
result.headers = {};
|
|
1201
|
+
}
|
|
1202
|
+
if (options.timeoutSeconds !== void 0) {
|
|
1203
|
+
result.timeout = options.timeoutSeconds;
|
|
1204
|
+
}
|
|
1205
|
+
return result;
|
|
1206
|
+
};
|
|
1207
|
+
var transformStdioConfig = (serverName, config, options) => {
|
|
1208
|
+
const result = {};
|
|
1209
|
+
if (options.includeServerName) {
|
|
1210
|
+
result.name = serverName;
|
|
1211
|
+
}
|
|
1212
|
+
if (options.extraFields) {
|
|
1213
|
+
Object.assign(result, options.extraFields);
|
|
1214
|
+
}
|
|
1215
|
+
const stdioTransport = options.stdioTransport ?? "none";
|
|
1216
|
+
const commandField = options.commandField ?? "command";
|
|
1217
|
+
const argsField = options.argsField ?? "args";
|
|
1218
|
+
const envField = options.envField ?? "env";
|
|
1219
|
+
switch (stdioTransport) {
|
|
1220
|
+
case "type-stdio":
|
|
1221
|
+
result.type = "stdio";
|
|
1222
|
+
break;
|
|
1223
|
+
case "transport-stdio":
|
|
1224
|
+
result.transport = "stdio";
|
|
1225
|
+
break;
|
|
1226
|
+
case "type-local":
|
|
1227
|
+
result.type = "local";
|
|
1228
|
+
break;
|
|
1229
|
+
case "none":
|
|
1230
|
+
break;
|
|
1231
|
+
}
|
|
1232
|
+
if (options.commandArray) {
|
|
1233
|
+
result[commandField] = [config.command, ...config.args || []];
|
|
1234
|
+
} else {
|
|
1235
|
+
result[commandField] = config.command;
|
|
1236
|
+
result[argsField] = config.args || [];
|
|
1237
|
+
}
|
|
1238
|
+
const hasEnv = config.env && Object.keys(config.env).length > 0;
|
|
1239
|
+
if (hasEnv) {
|
|
1240
|
+
result[envField] = config.env;
|
|
1241
|
+
} else if (options.defaultEnvEmpty) {
|
|
1242
|
+
result[envField] = {};
|
|
1243
|
+
}
|
|
1244
|
+
if (options.timeoutSeconds !== void 0) {
|
|
1245
|
+
result.timeout = options.timeoutSeconds;
|
|
1246
|
+
}
|
|
1247
|
+
return result;
|
|
1248
|
+
};
|
|
1249
|
+
var transformServerConfig = (serverName, config, dialect, _context) => {
|
|
1250
|
+
const options = resolveDialectOptions(dialect);
|
|
1251
|
+
if (config.url) {
|
|
1252
|
+
return transformRemoteConfig(serverName, config, options);
|
|
1253
|
+
}
|
|
1254
|
+
return transformStdioConfig(serverName, config, options);
|
|
1255
|
+
};
|
|
1256
|
+
var createAgentTransform = (dialect) => {
|
|
1257
|
+
return (serverName, config, context) => transformServerConfig(serverName, config, dialect, context);
|
|
1258
|
+
};
|
|
1259
|
+
var transformServerConfigForAgent = (agent, serverName, config, context = { global: false }) => {
|
|
1260
|
+
if (agent.transformConfig) {
|
|
1261
|
+
return agent.transformConfig(serverName, config, context);
|
|
1262
|
+
}
|
|
1263
|
+
if (agent.transformDialect) {
|
|
1264
|
+
return transformServerConfig(serverName, config, agent.transformDialect, context);
|
|
1265
|
+
}
|
|
1266
|
+
return config;
|
|
1267
|
+
};
|
|
1268
|
+
|
|
1269
|
+
// src/installer.ts
|
|
1270
|
+
var installMcpServerForAgent = (serverName, serverConfig, agentType, options = {}) => {
|
|
1271
|
+
const agent = getMcpAgentConfig(agentType);
|
|
1272
|
+
const isGlobal = options.global ?? false;
|
|
1273
|
+
const { target } = agentConfigStore.resolveTarget(agent, options);
|
|
1274
|
+
try {
|
|
1275
|
+
const transformed = transformServerConfigForAgent(agent, serverName, serverConfig, {
|
|
1276
|
+
global: isGlobal
|
|
1277
|
+
});
|
|
1278
|
+
agentConfigStore.writeServer(agent, serverName, transformed, options);
|
|
1279
|
+
return { agent: agentType, success: true, path: target.configPath };
|
|
1280
|
+
} catch (error) {
|
|
1281
|
+
return {
|
|
1282
|
+
agent: agentType,
|
|
1283
|
+
success: false,
|
|
1284
|
+
path: target.configPath,
|
|
1285
|
+
error: toErrorMessage(error)
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
};
|
|
1289
|
+
var installMcpServerForAgents = (serverName, serverConfig, agentTypes, options = {}) => agentTypes.map(
|
|
1290
|
+
(agentType) => installMcpServerForAgent(serverName, serverConfig, agentType, options)
|
|
1291
|
+
);
|
|
1292
|
+
|
|
1293
|
+
// src/utils/parse-mcp-agent-list.ts
|
|
1294
|
+
var parseMcpAgentList = (input5) => {
|
|
1295
|
+
if (!input5 || input5.length === 0) return void 0;
|
|
1296
|
+
if (input5.includes("*")) return getMcpAgentTypes();
|
|
1297
|
+
const resolved = [];
|
|
1298
|
+
for (const value of input5) {
|
|
1299
|
+
const agentType = resolveMcpAgentAlias(value);
|
|
1300
|
+
if (!agentType) throw new Error(`Unknown MCP agent "${value}"`);
|
|
1301
|
+
resolved.push(agentType);
|
|
1302
|
+
}
|
|
1303
|
+
return resolved;
|
|
1304
|
+
};
|
|
1305
|
+
|
|
1306
|
+
// src/resolve-target-agents.ts
|
|
1307
|
+
var normalizeRequestedAgents = (input5) => {
|
|
1308
|
+
if (!input5 || input5.length === 0) return void 0;
|
|
1309
|
+
const rawList = [...input5];
|
|
1310
|
+
if (rawList.every((item) => isMcpAgentType(item))) {
|
|
1311
|
+
return rawList;
|
|
1312
|
+
}
|
|
1313
|
+
return parseMcpAgentList(rawList);
|
|
1314
|
+
};
|
|
1315
|
+
var resolveTargetAgents = (query = {}) => {
|
|
1316
|
+
const cwd = query.cwd ?? process.cwd();
|
|
1317
|
+
const isGlobal = query.global ?? false;
|
|
1318
|
+
let explicitAgents = normalizeRequestedAgents(query.requested);
|
|
1319
|
+
if (query.all) {
|
|
1320
|
+
explicitAgents = getMcpAgentTypes();
|
|
1321
|
+
}
|
|
1322
|
+
const isDetected = !explicitAgents || explicitAgents.length === 0;
|
|
1323
|
+
const detected = isGlobal ? detectGloballyInstalledMcpAgents() : detectProjectInstalledMcpAgents(cwd);
|
|
1324
|
+
const candidateAgents = isDetected ? detected : explicitAgents ?? [];
|
|
1325
|
+
const allAgents = candidateAgents.filter(
|
|
1326
|
+
(type, index) => candidateAgents.indexOf(type) === index
|
|
1327
|
+
);
|
|
1328
|
+
const incompatible = [];
|
|
1329
|
+
const compatibleAgents = [];
|
|
1330
|
+
for (const agentType of allAgents) {
|
|
1331
|
+
const config = getMcpAgentConfig(agentType);
|
|
1332
|
+
if (query.transport && !isMcpTransportSupported(config, query.transport)) {
|
|
1333
|
+
incompatible.push({
|
|
1334
|
+
agent: agentType,
|
|
1335
|
+
reason: config.unsupportedTransportMessage ?? `agent ${agentType} only supports ${config.supportedTransports.join(", ")} transport (attempted ${query.transport})`
|
|
1336
|
+
});
|
|
1337
|
+
} else {
|
|
1338
|
+
compatibleAgents.push(agentType);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
let diagnostic;
|
|
1342
|
+
if (compatibleAgents.length === 0) {
|
|
1343
|
+
if (isDetected) {
|
|
1344
|
+
diagnostic = `No ${isGlobal ? "global" : "project"}-installed MCP agents detected. Pass -a <agent> (e.g. -a cursor) or --all to install.`;
|
|
1345
|
+
} else if (allAgents.length > 0 && incompatible.length > 0 && query.transport) {
|
|
1346
|
+
const list = incompatible.map((item) => `${item.agent} (${item.reason})`).join(", ");
|
|
1347
|
+
diagnostic = `None of the selected agents support ${query.transport} transport: ${list}`;
|
|
1348
|
+
} else {
|
|
1349
|
+
diagnostic = "No valid target agents specified.";
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
return {
|
|
1353
|
+
agents: compatibleAgents,
|
|
1354
|
+
compatibleAgents,
|
|
1355
|
+
allAgents,
|
|
1356
|
+
candidateAgents: allAgents,
|
|
1357
|
+
detected,
|
|
1358
|
+
isDetected,
|
|
1359
|
+
incompatible,
|
|
1360
|
+
diagnostic
|
|
1361
|
+
};
|
|
1362
|
+
};
|
|
1363
|
+
|
|
1364
|
+
// src/source-parser.ts
|
|
1365
|
+
var REMOTE_URL_REGEX = /^https?:\/\//i;
|
|
1366
|
+
var HAS_WHITESPACE_REGEX = /\s/;
|
|
1367
|
+
var PACKAGE_NAME_REGEX = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(?:@[^\s]+)?$/;
|
|
1368
|
+
var PATH_SEPARATOR_REGEX = /[/\\]/;
|
|
1369
|
+
var stripVersionSuffix = (input5) => {
|
|
1370
|
+
if (input5.startsWith("@")) {
|
|
1371
|
+
const secondAtIndex = input5.indexOf("@", 1);
|
|
1372
|
+
if (secondAtIndex > 0) return input5.slice(0, secondAtIndex);
|
|
1373
|
+
return input5;
|
|
1374
|
+
}
|
|
1375
|
+
const atIndex = input5.lastIndexOf("@");
|
|
1376
|
+
if (atIndex > 0) return input5.slice(0, atIndex);
|
|
1377
|
+
return input5;
|
|
1378
|
+
};
|
|
1379
|
+
var stripScopePrefix = (input5) => {
|
|
1380
|
+
if (!input5.startsWith("@") || !input5.includes("/")) return input5;
|
|
1381
|
+
const parts = input5.split("/");
|
|
1382
|
+
return parts[1] || input5;
|
|
1383
|
+
};
|
|
1384
|
+
var stripPathPrefix = (input5) => {
|
|
1385
|
+
if (!PATH_SEPARATOR_REGEX.test(input5)) return input5;
|
|
1386
|
+
const segments = input5.split(PATH_SEPARATOR_REGEX);
|
|
1387
|
+
const basename = segments[segments.length - 1];
|
|
1388
|
+
return basename || input5;
|
|
1389
|
+
};
|
|
1390
|
+
var extractPackageName = (input5) => {
|
|
1391
|
+
let name = stripVersionSuffix(input5);
|
|
1392
|
+
name = stripScopePrefix(name);
|
|
1393
|
+
name = stripPathPrefix(name);
|
|
1394
|
+
name = name.replace(SCRIPT_EXTENSION_REGEX, "");
|
|
1395
|
+
for (const prefix of PACKAGE_NAME_PREFIX_STRIP) {
|
|
1396
|
+
if (name.startsWith(prefix)) {
|
|
1397
|
+
name = name.slice(prefix.length);
|
|
1398
|
+
break;
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
for (const suffix of PACKAGE_NAME_SUFFIX_STRIP) {
|
|
1402
|
+
if (name.endsWith(suffix)) {
|
|
1403
|
+
name = name.slice(0, -suffix.length);
|
|
1404
|
+
break;
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
return name || MCP_DEFAULT_SERVER_NAME;
|
|
1408
|
+
};
|
|
1409
|
+
var inferNameFromUrl = (input5) => {
|
|
1410
|
+
try {
|
|
1411
|
+
const url = new URL(input5);
|
|
1412
|
+
const host = url.hostname;
|
|
1413
|
+
const labels = host.split(".").filter((segment) => segment.length > 0);
|
|
1414
|
+
if (labels.length === 0) return MCP_DEFAULT_SERVER_NAME;
|
|
1415
|
+
const meaningfulLabels = labels.filter((label) => {
|
|
1416
|
+
const lower = label.toLowerCase();
|
|
1417
|
+
if (COMMON_TLD_LABELS.has(lower)) return false;
|
|
1418
|
+
if (GENERIC_HOST_PREFIXES.has(lower)) return false;
|
|
1419
|
+
return true;
|
|
1420
|
+
});
|
|
1421
|
+
if (meaningfulLabels.length > 0) return meaningfulLabels[0];
|
|
1422
|
+
if (labels.length >= 2) return labels[labels.length - 2];
|
|
1423
|
+
return labels[labels.length - 1] || MCP_DEFAULT_SERVER_NAME;
|
|
1424
|
+
} catch {
|
|
1425
|
+
return MCP_DEFAULT_SERVER_NAME;
|
|
1426
|
+
}
|
|
1427
|
+
};
|
|
1428
|
+
var inferNameFromCommand = (command) => {
|
|
1429
|
+
const tokens = command.trim().split(/\s+/);
|
|
1430
|
+
const runnerBase = tokens[0]?.split(PATH_SEPARATOR_REGEX).pop() ?? "";
|
|
1431
|
+
const startIndex = KNOWN_COMMAND_RUNNERS.has(runnerBase) ? 1 : 0;
|
|
1432
|
+
for (let tokenIndex = startIndex; tokenIndex < tokens.length; tokenIndex += 1) {
|
|
1433
|
+
const token = tokens[tokenIndex];
|
|
1434
|
+
if (!token || token.startsWith("-")) continue;
|
|
1435
|
+
return extractPackageName(token);
|
|
1436
|
+
}
|
|
1437
|
+
const firstNonFlag = tokens.find((token) => !token.startsWith("-"));
|
|
1438
|
+
return firstNonFlag ? extractPackageName(firstNonFlag) : MCP_DEFAULT_SERVER_NAME;
|
|
1439
|
+
};
|
|
1440
|
+
var parseMcpSource = (input5) => {
|
|
1441
|
+
const trimmed = input5.trim();
|
|
1442
|
+
if (trimmed.length === 0) {
|
|
1443
|
+
throw new Error(
|
|
1444
|
+
"Invalid MCP source: input is empty. Expected a remote URL, an npm package, or a command line."
|
|
1445
|
+
);
|
|
1446
|
+
}
|
|
1447
|
+
if (REMOTE_URL_REGEX.test(trimmed)) {
|
|
1448
|
+
return {
|
|
1449
|
+
type: "remote",
|
|
1450
|
+
value: trimmed,
|
|
1451
|
+
inferredName: inferNameFromUrl(trimmed)
|
|
1452
|
+
};
|
|
1453
|
+
}
|
|
1454
|
+
if (HAS_WHITESPACE_REGEX.test(trimmed)) {
|
|
1455
|
+
return {
|
|
1456
|
+
type: "command",
|
|
1457
|
+
value: trimmed,
|
|
1458
|
+
inferredName: inferNameFromCommand(trimmed)
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
if (PACKAGE_NAME_REGEX.test(trimmed)) {
|
|
1462
|
+
return {
|
|
1463
|
+
type: "package",
|
|
1464
|
+
value: trimmed,
|
|
1465
|
+
inferredName: extractPackageName(trimmed)
|
|
1466
|
+
};
|
|
1467
|
+
}
|
|
1468
|
+
return {
|
|
1469
|
+
type: "command",
|
|
1470
|
+
value: trimmed,
|
|
1471
|
+
inferredName: inferNameFromCommand(trimmed)
|
|
1472
|
+
};
|
|
1473
|
+
};
|
|
1474
|
+
var isRemoteMcpSource = (parsed) => parsed.type === "remote";
|
|
1475
|
+
|
|
1476
|
+
// src/install-mcp-server.ts
|
|
1477
|
+
var installMcpServer = (options) => {
|
|
1478
|
+
const parsed = parseMcpSource(options.source);
|
|
1479
|
+
const isGlobal = options.global ?? false;
|
|
1480
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1481
|
+
const serverName = options.name ?? parsed.inferredName;
|
|
1482
|
+
const serverConfig = buildMcpServerConfig(parsed, {
|
|
1483
|
+
transport: options.transport,
|
|
1484
|
+
headers: options.headers,
|
|
1485
|
+
env: options.env,
|
|
1486
|
+
args: options.args
|
|
1487
|
+
});
|
|
1488
|
+
const requestedTransport = parsed.type === "remote" ? serverConfig.type ?? "http" : "stdio";
|
|
1489
|
+
const { allAgents, incompatible } = resolveTargetAgents({
|
|
1490
|
+
requested: options.agents,
|
|
1491
|
+
global: isGlobal,
|
|
1492
|
+
cwd,
|
|
1493
|
+
transport: requestedTransport
|
|
1494
|
+
});
|
|
1495
|
+
const incompatibleMap = new Map(incompatible.map((item) => [item.agent, item.reason]));
|
|
1496
|
+
const results = allAgents.map((agentType) => {
|
|
1497
|
+
const incompatibleReason = incompatibleMap.get(agentType);
|
|
1498
|
+
if (incompatibleReason) {
|
|
1499
|
+
return {
|
|
1500
|
+
agent: agentType,
|
|
1501
|
+
success: false,
|
|
1502
|
+
path: "",
|
|
1503
|
+
error: incompatibleReason
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
return installMcpServerForAgent(serverName, serverConfig, agentType, { global: isGlobal, cwd });
|
|
1507
|
+
});
|
|
1508
|
+
return { serverName, config: serverConfig, results };
|
|
1509
|
+
};
|
|
1510
|
+
|
|
1511
|
+
// src/list.ts
|
|
1512
|
+
var listInstalledMcpServers = (options = {}) => {
|
|
1513
|
+
const agentTypes = options.agents ?? getMcpAgentTypes();
|
|
1514
|
+
const collected = [];
|
|
1515
|
+
for (const agentType of agentTypes) {
|
|
1516
|
+
const agent = getMcpAgentConfig(agentType);
|
|
1517
|
+
const { path, exists, servers } = agentConfigStore.listServers(agent, options);
|
|
1518
|
+
if (!exists) continue;
|
|
1519
|
+
for (const [serverName, rawConfig] of Object.entries(servers)) {
|
|
1520
|
+
collected.push({
|
|
1521
|
+
serverName,
|
|
1522
|
+
agent: agentType,
|
|
1523
|
+
path,
|
|
1524
|
+
config: rawConfig,
|
|
1525
|
+
serverConfig: parseServerConfig(rawConfig)
|
|
1526
|
+
});
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
return collected;
|
|
1530
|
+
};
|
|
1531
|
+
|
|
1532
|
+
// src/remove.ts
|
|
1533
|
+
var removeMcpServerFromAgent = (serverName, agentType, options = {}) => {
|
|
1534
|
+
const agent = getMcpAgentConfig(agentType);
|
|
1535
|
+
const { target } = agentConfigStore.resolveTarget(agent, options);
|
|
1536
|
+
try {
|
|
1537
|
+
const { removed } = agentConfigStore.removeServer(agent, serverName, options);
|
|
1538
|
+
return { agent: agentType, path: target.configPath, removed };
|
|
1539
|
+
} catch (error) {
|
|
1540
|
+
return {
|
|
1541
|
+
agent: agentType,
|
|
1542
|
+
path: target.configPath,
|
|
1543
|
+
removed: false,
|
|
1544
|
+
error: toErrorMessage(error)
|
|
1545
|
+
};
|
|
1546
|
+
}
|
|
1547
|
+
};
|
|
1548
|
+
var removeMcpServer = (options) => {
|
|
1549
|
+
const { allAgents } = resolveTargetAgents({
|
|
1550
|
+
requested: options.agents,
|
|
1551
|
+
all: !options.agents,
|
|
1552
|
+
global: options.global,
|
|
1553
|
+
cwd: options.cwd
|
|
1554
|
+
});
|
|
1555
|
+
const results = [];
|
|
1556
|
+
for (const agentType of allAgents) {
|
|
1557
|
+
const result = removeMcpServerFromAgent(options.name, agentType, {
|
|
1558
|
+
global: options.global,
|
|
1559
|
+
cwd: options.cwd
|
|
1560
|
+
});
|
|
1561
|
+
if (result.removed || result.error) results.push(result);
|
|
1562
|
+
}
|
|
1563
|
+
return results;
|
|
1564
|
+
};
|
|
1565
|
+
|
|
1566
|
+
// src/interactive/main-menu.ts
|
|
1567
|
+
var import_prompts10 = require("@inquirer/prompts");
|
|
1568
|
+
var import_picocolors10 = __toESM(require("picocolors"), 1);
|
|
1569
|
+
|
|
1570
|
+
// src/interactive/wizard-add.ts
|
|
1571
|
+
var import_prompts7 = require("@inquirer/prompts");
|
|
1572
|
+
var import_picocolors7 = __toESM(require("picocolors"), 1);
|
|
1573
|
+
|
|
1574
|
+
// src/utils/logger.ts
|
|
1575
|
+
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
1576
|
+
var logger = {
|
|
1577
|
+
info: (message) => {
|
|
1578
|
+
console.log(import_picocolors.default.cyan("i"), message);
|
|
1579
|
+
},
|
|
1580
|
+
success: (message) => {
|
|
1581
|
+
console.log(import_picocolors.default.green("\u221A"), message);
|
|
1582
|
+
},
|
|
1583
|
+
warn: (message) => {
|
|
1584
|
+
console.log(import_picocolors.default.yellow("!"), message);
|
|
1585
|
+
},
|
|
1586
|
+
error: (message) => {
|
|
1587
|
+
console.error(import_picocolors.default.red("x"), message);
|
|
1588
|
+
}
|
|
1589
|
+
};
|
|
1590
|
+
|
|
1591
|
+
// src/interactive/prompts/agents.ts
|
|
1592
|
+
var import_prompts2 = require("@inquirer/prompts");
|
|
1593
|
+
var import_picocolors3 = __toESM(require("picocolors"), 1);
|
|
1594
|
+
|
|
1595
|
+
// src/interactive/prompts/scope.ts
|
|
1596
|
+
var import_prompts = require("@inquirer/prompts");
|
|
1597
|
+
var import_picocolors2 = __toESM(require("picocolors"), 1);
|
|
1598
|
+
var promptScope = async (options = {}) => {
|
|
1599
|
+
const initialGlobal = options.defaultGlobal ?? options.global;
|
|
1600
|
+
if (initialGlobal !== void 0) {
|
|
1601
|
+
return initialGlobal;
|
|
1602
|
+
}
|
|
1603
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1604
|
+
return (0, import_prompts.select)({
|
|
1605
|
+
message: options.message ?? "Select MCP scope:",
|
|
1606
|
+
choices: [
|
|
1607
|
+
{
|
|
1608
|
+
name: `Current Project - ${import_picocolors2.default.dim(cwd)}`,
|
|
1609
|
+
value: false
|
|
1610
|
+
},
|
|
1611
|
+
{
|
|
1612
|
+
name: `Global User Config - ${import_picocolors2.default.dim("applies across all projects")}`,
|
|
1613
|
+
value: true
|
|
1614
|
+
}
|
|
1615
|
+
]
|
|
1616
|
+
});
|
|
1617
|
+
};
|
|
1618
|
+
|
|
1619
|
+
// src/interactive/prompts/agents.ts
|
|
1620
|
+
var promptScopeAndAgents = async (options = {}) => {
|
|
1621
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1622
|
+
const isGlobal = await promptScope({
|
|
1623
|
+
cwd,
|
|
1624
|
+
defaultGlobal: options.defaultGlobal,
|
|
1625
|
+
message: "Select MCP installation scope:"
|
|
1626
|
+
});
|
|
1627
|
+
const resolution = resolveTargetAgents({
|
|
1628
|
+
global: isGlobal,
|
|
1629
|
+
cwd
|
|
1630
|
+
});
|
|
1631
|
+
const detected = resolution.detected;
|
|
1632
|
+
const availableAgentTypes = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
|
|
1633
|
+
if (detected.length > 0) {
|
|
1634
|
+
logger.info(
|
|
1635
|
+
`Detected configured agents: ${import_picocolors3.default.cyan(detected.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
|
|
1636
|
+
);
|
|
1637
|
+
} else {
|
|
1638
|
+
logger.warn(`No active ${isGlobal ? "global" : "project"} agents detected`);
|
|
1639
|
+
}
|
|
1640
|
+
const defaultChecked = options.defaultAgents && options.defaultAgents.length > 0 ? options.defaultAgents : detected;
|
|
1641
|
+
const choices = availableAgentTypes.map((agentType) => {
|
|
1642
|
+
const config = getMcpAgentConfig(agentType);
|
|
1643
|
+
const isDetected = detected.includes(agentType);
|
|
1644
|
+
const label = `${config.displayName} ${import_picocolors3.default.dim(`(${agentType})`)}${isDetected ? import_picocolors3.default.green(" [detected]") : ""}`;
|
|
1645
|
+
return {
|
|
1646
|
+
name: label,
|
|
1647
|
+
value: agentType,
|
|
1648
|
+
checked: defaultChecked.includes(agentType)
|
|
1649
|
+
};
|
|
1650
|
+
});
|
|
1651
|
+
const selectedAgents = await (0, import_prompts2.checkbox)({
|
|
1652
|
+
message: "Select target agents (Space to select, Enter to confirm):",
|
|
1653
|
+
choices,
|
|
1654
|
+
validate: (chosen) => {
|
|
1655
|
+
if (chosen.length === 0) {
|
|
1656
|
+
return "Please select at least one agent";
|
|
1657
|
+
}
|
|
1658
|
+
return true;
|
|
1659
|
+
}
|
|
1660
|
+
});
|
|
1661
|
+
return {
|
|
1662
|
+
global: isGlobal,
|
|
1663
|
+
agents: selectedAgents
|
|
1664
|
+
};
|
|
1665
|
+
};
|
|
1666
|
+
|
|
1667
|
+
// src/interactive/prompts/args.ts
|
|
1668
|
+
var import_prompts3 = require("@inquirer/prompts");
|
|
1669
|
+
var parseArgsString = (rawText) => {
|
|
1670
|
+
const matches = rawText.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g);
|
|
1671
|
+
if (!matches) return [];
|
|
1672
|
+
return matches.map((arg) => {
|
|
1673
|
+
if (arg.startsWith('"') && arg.endsWith('"') || arg.startsWith("'") && arg.endsWith("'")) {
|
|
1674
|
+
return arg.slice(1, -1);
|
|
1675
|
+
}
|
|
1676
|
+
return arg;
|
|
1677
|
+
});
|
|
1678
|
+
};
|
|
1679
|
+
var promptArgsConfig = async (initialArgs = []) => {
|
|
1680
|
+
if (initialArgs.length > 0) {
|
|
1681
|
+
return initialArgs;
|
|
1682
|
+
}
|
|
1683
|
+
const needArgs = await (0, import_prompts3.confirm)({
|
|
1684
|
+
message: "Configure command arguments (e.g. file paths, connection strings)?",
|
|
1685
|
+
default: false
|
|
1686
|
+
});
|
|
1687
|
+
if (!needArgs) {
|
|
1688
|
+
return [];
|
|
1689
|
+
}
|
|
1690
|
+
const raw = await (0, import_prompts3.input)({
|
|
1691
|
+
message: "Enter command arguments (space-separated, wrap paths with spaces in quotes):",
|
|
1692
|
+
validate: (val) => val.trim() ? true : "Arguments cannot be empty"
|
|
1693
|
+
});
|
|
1694
|
+
return parseArgsString(raw.trim());
|
|
1695
|
+
};
|
|
1696
|
+
|
|
1697
|
+
// src/interactive/prompts/env.ts
|
|
1698
|
+
var import_prompts5 = require("@inquirer/prompts");
|
|
1699
|
+
var import_picocolors5 = __toESM(require("picocolors"), 1);
|
|
1700
|
+
|
|
1701
|
+
// src/interactive/prompts/multiline.ts
|
|
1702
|
+
var import_node_readline = require("readline");
|
|
1703
|
+
var import_prompts4 = require("@inquirer/prompts");
|
|
1704
|
+
var import_picocolors4 = __toESM(require("picocolors"), 1);
|
|
1705
|
+
var readMultilineTextFromTerminal = async (message, endHint = "When done pasting, enter END on a new line or press Enter twice to finish") => {
|
|
1706
|
+
console.log(import_picocolors4.default.cyan(`
|
|
1707
|
+
${message}`));
|
|
1708
|
+
console.log(import_picocolors4.default.dim(` (Hint: ${endHint})
|
|
1709
|
+
`));
|
|
1710
|
+
return new Promise((resolve) => {
|
|
1711
|
+
const rl = (0, import_node_readline.createInterface)({
|
|
1712
|
+
input: process.stdin,
|
|
1713
|
+
output: process.stdout
|
|
1714
|
+
});
|
|
1715
|
+
const lines = [];
|
|
1716
|
+
let consecutiveEmpty = 0;
|
|
1717
|
+
const cleanup = () => {
|
|
1718
|
+
rl.removeAllListeners();
|
|
1719
|
+
rl.close();
|
|
1720
|
+
};
|
|
1721
|
+
rl.on("line", (line) => {
|
|
1722
|
+
const trimmed = line.trim();
|
|
1723
|
+
if (trimmed === "END") {
|
|
1724
|
+
cleanup();
|
|
1725
|
+
resolve(lines.join("\n"));
|
|
1726
|
+
return;
|
|
1727
|
+
}
|
|
1728
|
+
if (line === "") {
|
|
1729
|
+
consecutiveEmpty++;
|
|
1730
|
+
if (lines.length > 0) {
|
|
1731
|
+
cleanup();
|
|
1732
|
+
resolve(lines.join("\n"));
|
|
1733
|
+
return;
|
|
1734
|
+
}
|
|
1735
|
+
if (consecutiveEmpty >= 2) {
|
|
1736
|
+
cleanup();
|
|
1737
|
+
resolve("");
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1740
|
+
} else {
|
|
1741
|
+
consecutiveEmpty = 0;
|
|
1742
|
+
lines.push(line);
|
|
1743
|
+
}
|
|
1744
|
+
});
|
|
1745
|
+
rl.on("close", () => {
|
|
1746
|
+
resolve(lines.join("\n"));
|
|
1747
|
+
});
|
|
1748
|
+
});
|
|
1749
|
+
};
|
|
1750
|
+
var promptEditorText = async (options) => {
|
|
1751
|
+
try {
|
|
1752
|
+
return await (0, import_prompts4.editor)({
|
|
1753
|
+
message: options.message,
|
|
1754
|
+
default: options.defaultText ?? "",
|
|
1755
|
+
postfix: options.postfix
|
|
1756
|
+
});
|
|
1757
|
+
} catch {
|
|
1758
|
+
return readMultilineTextFromTerminal(options.message);
|
|
1759
|
+
}
|
|
1760
|
+
};
|
|
1761
|
+
|
|
1762
|
+
// src/interactive/prompts/env.ts
|
|
1763
|
+
var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
|
|
1764
|
+
var parseEnvText = (rawText) => {
|
|
1765
|
+
const result = {};
|
|
1766
|
+
const lines = rawText.split(/\r?\n/);
|
|
1767
|
+
for (const rawLine of lines) {
|
|
1768
|
+
let line = rawLine.trim();
|
|
1769
|
+
if (!line || line.startsWith("#")) continue;
|
|
1770
|
+
if (line.startsWith("export ")) {
|
|
1771
|
+
line = line.slice(7).trim();
|
|
1772
|
+
}
|
|
1773
|
+
const eqIndex = line.indexOf("=");
|
|
1774
|
+
if (eqIndex === -1) continue;
|
|
1775
|
+
const key = line.slice(0, eqIndex).trim();
|
|
1776
|
+
let value = line.slice(eqIndex + 1).trim();
|
|
1777
|
+
if (!key) continue;
|
|
1778
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
1779
|
+
value = value.slice(1, -1);
|
|
1780
|
+
}
|
|
1781
|
+
result[key] = value;
|
|
1782
|
+
}
|
|
1783
|
+
return result;
|
|
1784
|
+
};
|
|
1785
|
+
var promptEnvConfig = async (initialEnv = {}) => {
|
|
1786
|
+
const env = { ...initialEnv };
|
|
1787
|
+
const initialCount = Object.keys(env).length;
|
|
1788
|
+
if (initialCount > 0) {
|
|
1789
|
+
logger.info(`Includes ${import_picocolors5.default.cyan(String(initialCount))} preset environment variables`);
|
|
1790
|
+
}
|
|
1791
|
+
const mode = await (0, import_prompts5.select)({
|
|
1792
|
+
message: "Configure environment variables?",
|
|
1793
|
+
choices: [
|
|
1794
|
+
{
|
|
1795
|
+
name: "Skip / None",
|
|
1796
|
+
value: "skip"
|
|
1797
|
+
},
|
|
1798
|
+
{
|
|
1799
|
+
name: "Paste multiline .env text into terminal",
|
|
1800
|
+
value: "paste"
|
|
1801
|
+
},
|
|
1802
|
+
{
|
|
1803
|
+
name: "Open in system default editor ($EDITOR)",
|
|
1804
|
+
value: "editor"
|
|
1805
|
+
},
|
|
1806
|
+
{
|
|
1807
|
+
name: "Enter key-value pairs one by one",
|
|
1808
|
+
value: "manual"
|
|
1809
|
+
}
|
|
1810
|
+
]
|
|
1811
|
+
});
|
|
1812
|
+
if (mode === "skip") {
|
|
1813
|
+
return env;
|
|
1814
|
+
}
|
|
1815
|
+
if (mode === "paste" || mode === "editor") {
|
|
1816
|
+
const pasted = mode === "editor" ? await promptEditorText({
|
|
1817
|
+
message: "Paste or edit environment variables in editor, then save and exit:",
|
|
1818
|
+
postfix: ".env"
|
|
1819
|
+
}) : await readMultilineTextFromTerminal("Paste .env formatted content (multiline supported):");
|
|
1820
|
+
const parsed = parseEnvText(pasted);
|
|
1821
|
+
const count = Object.keys(parsed).length;
|
|
1822
|
+
if (count === 0) {
|
|
1823
|
+
logger.warn("No valid KEY=VALUE pairs recognized");
|
|
1824
|
+
} else {
|
|
1825
|
+
Object.assign(env, parsed);
|
|
1826
|
+
logger.success(`Successfully parsed ${import_picocolors5.default.cyan(String(count))} environment variables:`);
|
|
1827
|
+
for (const [k, v] of Object.entries(parsed)) {
|
|
1828
|
+
const masked = SECRET_KEY_PATTERN.test(k) && v.length > 4 ? `${v.slice(0, 2)}***${v.slice(-2)}` : v;
|
|
1829
|
+
console.log(` ${import_picocolors5.default.bold(k)}=${import_picocolors5.default.dim(masked)}`);
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
return env;
|
|
1833
|
+
}
|
|
1834
|
+
logger.info("Entering environment variables (leave key empty and press enter to finish):");
|
|
1835
|
+
while (true) {
|
|
1836
|
+
const key = await (0, import_prompts5.input)({
|
|
1837
|
+
message: "Variable name (Key, leave empty to finish):",
|
|
1838
|
+
validate: (val2) => {
|
|
1839
|
+
const trimmed = val2.trim();
|
|
1840
|
+
if (!trimmed) return true;
|
|
1841
|
+
if (/\s/.test(trimmed)) return "Variable name cannot contain spaces";
|
|
1842
|
+
return true;
|
|
1843
|
+
}
|
|
1844
|
+
});
|
|
1845
|
+
const trimmedKey = key.trim();
|
|
1846
|
+
if (!trimmedKey) break;
|
|
1847
|
+
const isSecret = SECRET_KEY_PATTERN.test(trimmedKey);
|
|
1848
|
+
let val;
|
|
1849
|
+
if (isSecret) {
|
|
1850
|
+
val = await (0, import_prompts5.password)({
|
|
1851
|
+
message: `Value for (${trimmedKey}) [secret masked]:`,
|
|
1852
|
+
mask: "*"
|
|
1853
|
+
});
|
|
1854
|
+
} else {
|
|
1855
|
+
val = await (0, import_prompts5.input)({
|
|
1856
|
+
message: `Value for (${trimmedKey}):`
|
|
1857
|
+
});
|
|
1858
|
+
}
|
|
1859
|
+
env[trimmedKey] = val;
|
|
1860
|
+
logger.success(`Added: ${import_picocolors5.default.cyan(trimmedKey)}`);
|
|
1861
|
+
}
|
|
1862
|
+
return env;
|
|
1863
|
+
};
|
|
1864
|
+
|
|
1865
|
+
// src/interactive/prompts/headers.ts
|
|
1866
|
+
var import_prompts6 = require("@inquirer/prompts");
|
|
1867
|
+
var import_picocolors6 = __toESM(require("picocolors"), 1);
|
|
1868
|
+
var SECRET_HEADER_PATTERN = /(authorization|token|key|secret|auth)/i;
|
|
1869
|
+
var parseHeadersText = (rawText) => {
|
|
1870
|
+
const result = {};
|
|
1871
|
+
const lines = rawText.split(/\r?\n/);
|
|
1872
|
+
for (const rawLine of lines) {
|
|
1873
|
+
const line = rawLine.trim();
|
|
1874
|
+
if (!line || line.startsWith("#")) continue;
|
|
1875
|
+
const colonIndex = line.indexOf(":");
|
|
1876
|
+
const equalIndex = line.indexOf("=");
|
|
1877
|
+
let splitIndex = -1;
|
|
1878
|
+
if (colonIndex !== -1 && equalIndex !== -1) {
|
|
1879
|
+
splitIndex = Math.min(colonIndex, equalIndex);
|
|
1880
|
+
} else if (colonIndex !== -1) {
|
|
1881
|
+
splitIndex = colonIndex;
|
|
1882
|
+
} else {
|
|
1883
|
+
splitIndex = equalIndex;
|
|
1884
|
+
}
|
|
1885
|
+
if (splitIndex === -1) continue;
|
|
1886
|
+
const key = line.slice(0, splitIndex).trim();
|
|
1887
|
+
let value = line.slice(splitIndex + 1).trim();
|
|
1888
|
+
if (!key) continue;
|
|
1889
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
1890
|
+
value = value.slice(1, -1);
|
|
1891
|
+
}
|
|
1892
|
+
result[key] = value;
|
|
1893
|
+
}
|
|
1894
|
+
return result;
|
|
1895
|
+
};
|
|
1896
|
+
var promptHeadersConfig = async (initialHeaders = {}) => {
|
|
1897
|
+
const headers = { ...initialHeaders };
|
|
1898
|
+
const mode = await (0, import_prompts6.select)({
|
|
1899
|
+
message: "Select HTTP headers configuration method:",
|
|
1900
|
+
choices: [
|
|
1901
|
+
{
|
|
1902
|
+
name: "Paste multiline headers into terminal (Key: Value format)",
|
|
1903
|
+
value: "paste"
|
|
1904
|
+
},
|
|
1905
|
+
{
|
|
1906
|
+
name: "Open in system default editor ($EDITOR)",
|
|
1907
|
+
value: "editor"
|
|
1908
|
+
},
|
|
1909
|
+
{
|
|
1910
|
+
name: "Enter headers one by one (e.g. Authorization: Bearer ...)",
|
|
1911
|
+
value: "manual"
|
|
1912
|
+
},
|
|
1913
|
+
{
|
|
1914
|
+
name: "Skip / None",
|
|
1915
|
+
value: "skip"
|
|
1916
|
+
}
|
|
1917
|
+
]
|
|
1918
|
+
});
|
|
1919
|
+
if (mode === "skip") {
|
|
1920
|
+
return headers;
|
|
1921
|
+
}
|
|
1922
|
+
if (mode === "paste" || mode === "editor") {
|
|
1923
|
+
const pasted = mode === "editor" ? await promptEditorText({
|
|
1924
|
+
message: "Paste or edit HTTP headers in editor, then save and exit:"
|
|
1925
|
+
}) : await readMultilineTextFromTerminal(
|
|
1926
|
+
"Paste HTTP headers content (multiline supported, e.g. Authorization: Bearer ...):"
|
|
1927
|
+
);
|
|
1928
|
+
const parsed = parseHeadersText(pasted);
|
|
1929
|
+
const count = Object.keys(parsed).length;
|
|
1930
|
+
if (count === 0) {
|
|
1931
|
+
logger.warn("No valid Key: Value pairs recognized");
|
|
1932
|
+
} else {
|
|
1933
|
+
Object.assign(headers, parsed);
|
|
1934
|
+
logger.success(`Successfully parsed ${import_picocolors6.default.cyan(String(count))} headers:`);
|
|
1935
|
+
for (const [k, v] of Object.entries(parsed)) {
|
|
1936
|
+
const masked = SECRET_HEADER_PATTERN.test(k) && v.length > 8 ? `${v.slice(0, 4)}***${v.slice(-3)}` : v;
|
|
1937
|
+
console.log(` ${import_picocolors6.default.bold(k)}: ${import_picocolors6.default.dim(masked)}`);
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
return headers;
|
|
1941
|
+
}
|
|
1942
|
+
logger.info("Entering HTTP headers (leave header name empty and press enter to finish):");
|
|
1943
|
+
while (true) {
|
|
1944
|
+
const name = await (0, import_prompts6.input)({
|
|
1945
|
+
message: "Header name (e.g. Authorization, leave empty to finish):",
|
|
1946
|
+
validate: (val2) => {
|
|
1947
|
+
const trimmed = val2.trim();
|
|
1948
|
+
if (!trimmed) return true;
|
|
1949
|
+
if (/\s/.test(trimmed)) return "Header name cannot contain spaces";
|
|
1950
|
+
return true;
|
|
1951
|
+
}
|
|
1952
|
+
});
|
|
1953
|
+
const trimmedName = name.trim();
|
|
1954
|
+
if (!trimmedName) break;
|
|
1955
|
+
const isSecret = SECRET_HEADER_PATTERN.test(trimmedName);
|
|
1956
|
+
let val;
|
|
1957
|
+
if (isSecret) {
|
|
1958
|
+
val = await (0, import_prompts6.password)({
|
|
1959
|
+
message: `Header value for (${trimmedName}) [sensitive content masked]:`,
|
|
1960
|
+
mask: "*"
|
|
1961
|
+
});
|
|
1962
|
+
} else {
|
|
1963
|
+
val = await (0, import_prompts6.input)({
|
|
1964
|
+
message: `Header value for (${trimmedName}):`
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1967
|
+
headers[trimmedName] = val;
|
|
1968
|
+
logger.success(`Added: ${import_picocolors6.default.cyan(trimmedName)}`);
|
|
1969
|
+
}
|
|
1970
|
+
return headers;
|
|
1971
|
+
};
|
|
1972
|
+
|
|
1973
|
+
// src/interactive/wizard-add.ts
|
|
1974
|
+
var wizardAdd = async (initial = {}) => {
|
|
1975
|
+
const cwd = initial.cwd ?? process.cwd();
|
|
1976
|
+
logger.info(import_picocolors7.default.bold("Welcome to the MCP interactive add wizard"));
|
|
1977
|
+
let source = initial.source;
|
|
1978
|
+
if (!source) {
|
|
1979
|
+
const sourceType = await (0, import_prompts7.select)({
|
|
1980
|
+
message: "Select MCP server type:",
|
|
1981
|
+
choices: [
|
|
1982
|
+
{
|
|
1983
|
+
name: "npm package (run via npx)",
|
|
1984
|
+
value: "npm"
|
|
1985
|
+
},
|
|
1986
|
+
{
|
|
1987
|
+
name: "Remote MCP server (via HTTP / SSE URL)",
|
|
1988
|
+
value: "remote"
|
|
1989
|
+
},
|
|
1990
|
+
{
|
|
1991
|
+
name: "Local command / script / Docker (stdio)",
|
|
1992
|
+
value: "command"
|
|
1993
|
+
}
|
|
1994
|
+
]
|
|
1995
|
+
});
|
|
1996
|
+
if (sourceType === "npm") {
|
|
1997
|
+
source = await (0, import_prompts7.input)({
|
|
1998
|
+
message: "Enter npm package name (e.g. @modelcontextprotocol/server-postgres or mcp-server-git):",
|
|
1999
|
+
validate: (val) => val.trim() ? true : "Package name cannot be empty"
|
|
2000
|
+
});
|
|
2001
|
+
} else if (sourceType === "remote") {
|
|
2002
|
+
source = await (0, import_prompts7.input)({
|
|
2003
|
+
message: "Enter remote server URL (e.g. https://mcp.example.com/sse):",
|
|
2004
|
+
validate: (val) => {
|
|
2005
|
+
const trimmed = val.trim();
|
|
2006
|
+
if (!trimmed) return "URL cannot be empty";
|
|
2007
|
+
if (!/^https?:\/\//i.test(trimmed)) return "Please enter a valid URL starting with http:// or https://";
|
|
2008
|
+
return true;
|
|
2009
|
+
}
|
|
2010
|
+
});
|
|
2011
|
+
} else {
|
|
2012
|
+
source = await (0, import_prompts7.input)({
|
|
2013
|
+
message: "Enter command and arguments (e.g. python -m my_mcp_server or docker run ...):",
|
|
2014
|
+
validate: (val) => val.trim() ? true : "Command cannot be empty"
|
|
2015
|
+
});
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
source = source.trim();
|
|
2019
|
+
const parsed = parseMcpSource(source);
|
|
2020
|
+
let serverName = initial.name;
|
|
2021
|
+
if (!serverName) {
|
|
2022
|
+
serverName = await (0, import_prompts7.input)({
|
|
2023
|
+
message: "MCP server name:",
|
|
2024
|
+
default: parsed.inferredName,
|
|
2025
|
+
validate: (val) => val.trim() ? true : "Server name cannot be empty"
|
|
2026
|
+
});
|
|
2027
|
+
}
|
|
2028
|
+
serverName = serverName.trim();
|
|
2029
|
+
let transport = initial.transport;
|
|
2030
|
+
let headers = initial.headers ?? {};
|
|
2031
|
+
if (parsed.type === "remote") {
|
|
2032
|
+
if (!transport) {
|
|
2033
|
+
const isSseUrl = /\/sse\b/i.test(parsed.value);
|
|
2034
|
+
transport = await (0, import_prompts7.select)({
|
|
2035
|
+
message: "Select remote transport protocol:",
|
|
2036
|
+
choices: [
|
|
2037
|
+
{ name: "HTTP", value: "http" },
|
|
2038
|
+
{ name: "SSE (Server-Sent Events)", value: "sse" }
|
|
2039
|
+
],
|
|
2040
|
+
default: isSseUrl ? "sse" : "http"
|
|
2041
|
+
});
|
|
2042
|
+
}
|
|
2043
|
+
if (Object.keys(headers).length === 0) {
|
|
2044
|
+
const needHeader = await (0, import_prompts7.confirm)({
|
|
2045
|
+
message: "Configure HTTP headers (e.g. Authorization Bearer token)?",
|
|
2046
|
+
default: false
|
|
2047
|
+
});
|
|
2048
|
+
if (needHeader) {
|
|
2049
|
+
headers = await promptHeadersConfig();
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
const { global: isGlobal, agents: selectedAgents } = await promptScopeAndAgents({
|
|
2054
|
+
cwd,
|
|
2055
|
+
defaultGlobal: initial.global,
|
|
2056
|
+
defaultAgents: initial.agents
|
|
2057
|
+
});
|
|
2058
|
+
let args = initial.args ?? [];
|
|
2059
|
+
if (parsed.type !== "remote") {
|
|
2060
|
+
args = await promptArgsConfig(args);
|
|
2061
|
+
}
|
|
2062
|
+
let env = initial.env ?? {};
|
|
2063
|
+
if (parsed.type !== "remote") {
|
|
2064
|
+
env = await promptEnvConfig(env);
|
|
2065
|
+
}
|
|
2066
|
+
console.log("\n" + import_picocolors7.default.cyan(import_picocolors7.default.bold("Configuration Preview:")));
|
|
2067
|
+
console.log(` ${import_picocolors7.default.bold("Server Name:")} ${import_picocolors7.default.green(serverName)}`);
|
|
2068
|
+
console.log(` ${import_picocolors7.default.bold("Server Type:")} ${import_picocolors7.default.magenta(parsed.type)}`);
|
|
2069
|
+
console.log(` ${import_picocolors7.default.bold("Source/Command:")} ${import_picocolors7.default.dim(source)}`);
|
|
2070
|
+
console.log(` ${import_picocolors7.default.bold("Scope:")} ${isGlobal ? import_picocolors7.default.yellow("Global") : import_picocolors7.default.blue("Project")}`);
|
|
2071
|
+
console.log(` ${import_picocolors7.default.bold("Target Agents:")} ${import_picocolors7.default.cyan(selectedAgents.join(", "))}`);
|
|
2072
|
+
if (args.length > 0) {
|
|
2073
|
+
console.log(` ${import_picocolors7.default.bold("Arguments:")} ${import_picocolors7.default.dim(args.join(" "))}`);
|
|
2074
|
+
}
|
|
2075
|
+
if (transport) {
|
|
2076
|
+
console.log(` ${import_picocolors7.default.bold("Transport:")} ${import_picocolors7.default.magenta(transport)}`);
|
|
2077
|
+
}
|
|
2078
|
+
const envKeys = Object.keys(env);
|
|
2079
|
+
if (envKeys.length > 0) {
|
|
2080
|
+
console.log(` ${import_picocolors7.default.bold("Environment Variables:")} ${import_picocolors7.default.dim(envKeys.join(", "))} (${envKeys.length})`);
|
|
2081
|
+
}
|
|
2082
|
+
const headerKeys = Object.keys(headers);
|
|
2083
|
+
if (headerKeys.length > 0) {
|
|
2084
|
+
console.log(` ${import_picocolors7.default.bold("Headers:")} ${import_picocolors7.default.dim(headerKeys.join(", "))} (${headerKeys.length})`);
|
|
2085
|
+
}
|
|
2086
|
+
console.log();
|
|
2087
|
+
const proceed = await (0, import_prompts7.confirm)({
|
|
2088
|
+
message: "Confirm installation with this configuration?",
|
|
2089
|
+
default: true
|
|
2090
|
+
});
|
|
2091
|
+
if (!proceed) {
|
|
2092
|
+
logger.warn("Operation cancelled");
|
|
2093
|
+
return false;
|
|
2094
|
+
}
|
|
2095
|
+
const result = installMcpServer({
|
|
2096
|
+
source,
|
|
2097
|
+
name: serverName,
|
|
2098
|
+
agents: selectedAgents,
|
|
2099
|
+
args,
|
|
2100
|
+
global: isGlobal,
|
|
2101
|
+
cwd,
|
|
2102
|
+
transport,
|
|
2103
|
+
headers,
|
|
2104
|
+
env
|
|
2105
|
+
});
|
|
2106
|
+
logger.info(
|
|
2107
|
+
`Writing ${import_picocolors7.default.bold(result.serverName)} to ${import_picocolors7.default.cyan(String(result.results.length))} agent config files...`
|
|
2108
|
+
);
|
|
2109
|
+
let allSuccess = true;
|
|
2110
|
+
for (const record of result.results) {
|
|
2111
|
+
if (record.success) {
|
|
2112
|
+
logger.success(`${import_picocolors7.default.cyan(record.agent)}: Successfully written to ${import_picocolors7.default.dim(record.path)}`);
|
|
2113
|
+
} else {
|
|
2114
|
+
allSuccess = false;
|
|
2115
|
+
logger.error(`${import_picocolors7.default.cyan(record.agent)}: Failed to write - ${record.error}`);
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
if (allSuccess) {
|
|
2119
|
+
logger.success(import_picocolors7.default.bold(`MCP server "${serverName}" configured successfully!`));
|
|
2120
|
+
}
|
|
2121
|
+
return allSuccess;
|
|
2122
|
+
};
|
|
2123
|
+
|
|
2124
|
+
// src/interactive/wizard-manage.ts
|
|
2125
|
+
var import_prompts8 = require("@inquirer/prompts");
|
|
2126
|
+
var import_picocolors8 = __toESM(require("picocolors"), 1);
|
|
2127
|
+
|
|
2128
|
+
// src/interactive/utils/group-installed-servers.ts
|
|
2129
|
+
var normalizeServerConfig = parseServerConfig;
|
|
2130
|
+
var groupInstalledServersByName = (installed) => {
|
|
2131
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
2132
|
+
for (const item of installed) {
|
|
2133
|
+
let entry = grouped.get(item.serverName);
|
|
2134
|
+
if (!entry) {
|
|
2135
|
+
entry = {
|
|
2136
|
+
serverName: item.serverName,
|
|
2137
|
+
agents: [],
|
|
2138
|
+
paths: [],
|
|
2139
|
+
config: normalizeServerConfig(item.config)
|
|
2140
|
+
};
|
|
2141
|
+
grouped.set(item.serverName, entry);
|
|
2142
|
+
}
|
|
2143
|
+
if (!entry.agents.includes(item.agent)) {
|
|
2144
|
+
entry.agents.push(item.agent);
|
|
2145
|
+
}
|
|
2146
|
+
if (!entry.paths.includes(item.path)) {
|
|
2147
|
+
entry.paths.push(item.path);
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
return grouped;
|
|
2151
|
+
};
|
|
2152
|
+
|
|
2153
|
+
// src/interactive/wizard-manage.ts
|
|
2154
|
+
var wizardManage = async (options = {}) => {
|
|
2155
|
+
const cwd = options.cwd ?? process.cwd();
|
|
2156
|
+
const isGlobal = await promptScope({
|
|
2157
|
+
cwd,
|
|
2158
|
+
defaultGlobal: options.global,
|
|
2159
|
+
message: "Select MCP scope to inspect and manage:"
|
|
2160
|
+
});
|
|
2161
|
+
const installed = listInstalledMcpServers({ global: isGlobal, cwd });
|
|
2162
|
+
if (installed.length === 0) {
|
|
2163
|
+
logger.warn(`No configured MCP servers found in ${isGlobal ? "global" : "project"} scope`);
|
|
2164
|
+
return;
|
|
2165
|
+
}
|
|
2166
|
+
const grouped = groupInstalledServersByName(installed);
|
|
2167
|
+
while (true) {
|
|
2168
|
+
const choices = Array.from(grouped.values()).map((g) => {
|
|
2169
|
+
const agentNames = g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
|
|
2170
|
+
return {
|
|
2171
|
+
name: `${import_picocolors8.default.bold(g.serverName)} ${import_picocolors8.default.dim(`(configured in: ${agentNames})`)}`,
|
|
2172
|
+
value: g.serverName
|
|
2173
|
+
};
|
|
2174
|
+
});
|
|
2175
|
+
choices.push({
|
|
2176
|
+
name: `Back`,
|
|
2177
|
+
value: "__back__"
|
|
2178
|
+
});
|
|
2179
|
+
const chosenServerName = await (0, import_prompts8.select)({
|
|
2180
|
+
message: "Select MCP server to manage or sync:",
|
|
2181
|
+
choices
|
|
2182
|
+
});
|
|
2183
|
+
if (chosenServerName === "__back__") {
|
|
2184
|
+
return;
|
|
2185
|
+
}
|
|
2186
|
+
const targetGroup = grouped.get(chosenServerName);
|
|
2187
|
+
if (!targetGroup) continue;
|
|
2188
|
+
console.log("\n" + import_picocolors8.default.cyan(import_picocolors8.default.bold(`MCP Server Details: [${chosenServerName}]`)));
|
|
2189
|
+
console.log(` ${import_picocolors8.default.bold("Scope:")} ${isGlobal ? "Global" : "Project"}`);
|
|
2190
|
+
console.log(
|
|
2191
|
+
` ${import_picocolors8.default.bold("Configured Agents:")} ${import_picocolors8.default.green(targetGroup.agents.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
|
|
2192
|
+
);
|
|
2193
|
+
const cfg = targetGroup.config;
|
|
2194
|
+
if (isRemoteServerConfig(cfg)) {
|
|
2195
|
+
console.log(` ${import_picocolors8.default.bold("URL:")} ${import_picocolors8.default.dim(cfg.url)} (${cfg.type})`);
|
|
2196
|
+
if (cfg.headers && Object.keys(cfg.headers).length > 0) {
|
|
2197
|
+
console.log(` ${import_picocolors8.default.bold("Headers:")} ${Object.keys(cfg.headers).join(", ")}`);
|
|
2198
|
+
}
|
|
2199
|
+
} else if (isStdioServerConfig(cfg)) {
|
|
2200
|
+
console.log(` ${import_picocolors8.default.bold("Command:")} ${import_picocolors8.default.magenta(cfg.command)}`);
|
|
2201
|
+
if (cfg.args && cfg.args.length > 0) {
|
|
2202
|
+
console.log(` ${import_picocolors8.default.bold("Arguments:")} ${import_picocolors8.default.dim(cfg.args.join(" "))}`);
|
|
2203
|
+
}
|
|
2204
|
+
if (cfg.env && Object.keys(cfg.env).length > 0) {
|
|
2205
|
+
console.log(` ${import_picocolors8.default.bold("Environment Variables:")} ${import_picocolors8.default.dim(Object.keys(cfg.env).join(", "))}`);
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
console.log();
|
|
2209
|
+
const action = await (0, import_prompts8.select)({
|
|
2210
|
+
message: `What would you like to do with [${chosenServerName}]?`,
|
|
2211
|
+
choices: [
|
|
2212
|
+
{
|
|
2213
|
+
name: "Sync / clone to other agents",
|
|
2214
|
+
value: "sync"
|
|
2215
|
+
},
|
|
2216
|
+
{
|
|
2217
|
+
name: "Back to list",
|
|
2218
|
+
value: "back"
|
|
2219
|
+
}
|
|
2220
|
+
]
|
|
2221
|
+
});
|
|
2222
|
+
if (action === "back") continue;
|
|
2223
|
+
if (action === "sync") {
|
|
2224
|
+
const allAllowedAgents = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
|
|
2225
|
+
const candidateAgents = allAllowedAgents.filter((a) => !targetGroup.agents.includes(a));
|
|
2226
|
+
if (candidateAgents.length === 0) {
|
|
2227
|
+
logger.info("All supported agents in this scope already have this MCP server configured; no sync needed");
|
|
2228
|
+
continue;
|
|
2229
|
+
}
|
|
2230
|
+
const selectedToSync = await (0, import_prompts8.checkbox)({
|
|
2231
|
+
message: "Select target agents to sync to (Space to select):",
|
|
2232
|
+
choices: candidateAgents.map((a) => ({
|
|
2233
|
+
name: `${getMcpAgentConfig(a).displayName} (${a})`,
|
|
2234
|
+
value: a,
|
|
2235
|
+
checked: false
|
|
2236
|
+
})),
|
|
2237
|
+
validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
|
|
2238
|
+
});
|
|
2239
|
+
const confirmed = await (0, import_prompts8.confirm)({
|
|
2240
|
+
message: `Confirm syncing configuration of [${chosenServerName}] to: ${selectedToSync.join(", ")}?`,
|
|
2241
|
+
default: true
|
|
2242
|
+
});
|
|
2243
|
+
if (!confirmed) {
|
|
2244
|
+
logger.warn("Sync cancelled");
|
|
2245
|
+
continue;
|
|
2246
|
+
}
|
|
2247
|
+
for (const targetAgent of selectedToSync) {
|
|
2248
|
+
const res = installMcpServerForAgent(chosenServerName, targetGroup.config, targetAgent, {
|
|
2249
|
+
global: isGlobal,
|
|
2250
|
+
cwd
|
|
2251
|
+
});
|
|
2252
|
+
if (res.success) {
|
|
2253
|
+
logger.success(`${import_picocolors8.default.cyan(targetAgent)}: Successfully synced to ${import_picocolors8.default.dim(res.path)}`);
|
|
2254
|
+
targetGroup.agents.push(targetAgent);
|
|
2255
|
+
} else {
|
|
2256
|
+
logger.error(`${import_picocolors8.default.cyan(targetAgent)}: Sync failed - ${res.error}`);
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
};
|
|
2262
|
+
|
|
2263
|
+
// src/interactive/wizard-remove.ts
|
|
2264
|
+
var import_prompts9 = require("@inquirer/prompts");
|
|
2265
|
+
var import_picocolors9 = __toESM(require("picocolors"), 1);
|
|
2266
|
+
var wizardRemove = async (options = {}) => {
|
|
2267
|
+
const cwd = options.cwd ?? process.cwd();
|
|
2268
|
+
const isGlobal = await promptScope({
|
|
2269
|
+
cwd,
|
|
2270
|
+
defaultGlobal: options.global,
|
|
2271
|
+
message: "Select scope to remove MCP server from:"
|
|
2272
|
+
});
|
|
2273
|
+
const installed = listInstalledMcpServers({ global: isGlobal, cwd });
|
|
2274
|
+
if (installed.length === 0) {
|
|
2275
|
+
logger.warn(`No installed MCP servers found in ${isGlobal ? "global" : "project"} scope`);
|
|
2276
|
+
return false;
|
|
2277
|
+
}
|
|
2278
|
+
const serverMap = groupInstalledServersByName(installed);
|
|
2279
|
+
let serverName = options.name;
|
|
2280
|
+
if (!serverName) {
|
|
2281
|
+
const choices = Array.from(serverMap.values()).map((g) => ({
|
|
2282
|
+
name: `${import_picocolors9.default.bold(g.serverName)} ${import_picocolors9.default.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
|
|
2283
|
+
value: g.serverName
|
|
2284
|
+
}));
|
|
2285
|
+
serverName = await (0, import_prompts9.select)({
|
|
2286
|
+
message: "Select MCP server to remove:",
|
|
2287
|
+
choices
|
|
2288
|
+
});
|
|
2289
|
+
}
|
|
2290
|
+
const installedAgents = serverMap.get(serverName)?.agents || [];
|
|
2291
|
+
if (installedAgents.length === 0) {
|
|
2292
|
+
logger.warn(`No agents found with [${serverName}] installed`);
|
|
2293
|
+
return false;
|
|
2294
|
+
}
|
|
2295
|
+
let targetAgents = options.agents;
|
|
2296
|
+
if (!targetAgents || targetAgents.length === 0) {
|
|
2297
|
+
targetAgents = await (0, import_prompts9.checkbox)({
|
|
2298
|
+
message: `Select agents to remove [${serverName}] from:`,
|
|
2299
|
+
choices: installedAgents.map((agent) => ({
|
|
2300
|
+
name: `${getMcpAgentConfig(agent)?.displayName ?? agent} (${agent})`,
|
|
2301
|
+
value: agent,
|
|
2302
|
+
checked: true
|
|
2303
|
+
})),
|
|
2304
|
+
validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
|
|
2305
|
+
});
|
|
2306
|
+
} else {
|
|
2307
|
+
const validAgents = targetAgents.filter((agent) => installedAgents.includes(agent));
|
|
2308
|
+
if (validAgents.length === 0) {
|
|
2309
|
+
logger.warn(`None of the specified agents (${targetAgents.join(", ")}) have [${serverName}] installed`);
|
|
2310
|
+
return false;
|
|
2311
|
+
}
|
|
2312
|
+
targetAgents = validAgents;
|
|
2313
|
+
}
|
|
2314
|
+
const confirmed = await (0, import_prompts9.confirm)({
|
|
2315
|
+
message: `Confirm removing MCP server [${serverName}] from ${targetAgents.join(", ")}?`,
|
|
2316
|
+
default: true
|
|
2317
|
+
});
|
|
2318
|
+
if (!confirmed) {
|
|
2319
|
+
logger.warn("Operation cancelled");
|
|
2320
|
+
return false;
|
|
2321
|
+
}
|
|
2322
|
+
const results = removeMcpServer({
|
|
2323
|
+
name: serverName,
|
|
2324
|
+
agents: targetAgents,
|
|
2325
|
+
global: isGlobal,
|
|
2326
|
+
cwd
|
|
2327
|
+
});
|
|
2328
|
+
let removedCount = 0;
|
|
2329
|
+
for (const res of results) {
|
|
2330
|
+
if (res.removed) {
|
|
2331
|
+
logger.success(`${import_picocolors9.default.cyan(res.agent)}: Successfully removed from ${import_picocolors9.default.dim(res.path)}`);
|
|
2332
|
+
removedCount++;
|
|
2333
|
+
} else if (res.error) {
|
|
2334
|
+
logger.error(`${import_picocolors9.default.cyan(res.agent)}: Failed to remove - ${res.error}`);
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
if (removedCount > 0) {
|
|
2338
|
+
logger.success(`Successfully removed [${serverName}] from ${removedCount} agent(s)`);
|
|
2339
|
+
return true;
|
|
2340
|
+
}
|
|
2341
|
+
logger.warn(`Failed to remove [${serverName}] from specified agents`);
|
|
2342
|
+
return false;
|
|
2343
|
+
};
|
|
2344
|
+
|
|
2345
|
+
// src/interactive/main-menu.ts
|
|
2346
|
+
var mainMenu = async () => {
|
|
2347
|
+
console.log();
|
|
2348
|
+
console.log(import_picocolors10.default.bold(import_picocolors10.default.cyan("mcps - Cross-Platform MCP Manager for AI Coding Agents")));
|
|
2349
|
+
console.log(import_picocolors10.default.dim("Cross-platform MCP server configuration & synchronization tool"));
|
|
2350
|
+
console.log();
|
|
2351
|
+
while (true) {
|
|
2352
|
+
try {
|
|
2353
|
+
const action = await (0, import_prompts10.select)({
|
|
2354
|
+
message: "Select an action:",
|
|
2355
|
+
choices: [
|
|
2356
|
+
{
|
|
2357
|
+
name: "Add MCP Server",
|
|
2358
|
+
value: "add"
|
|
2359
|
+
},
|
|
2360
|
+
{
|
|
2361
|
+
name: "Manage & Sync Installed MCP Servers",
|
|
2362
|
+
value: "manage"
|
|
2363
|
+
},
|
|
2364
|
+
{
|
|
2365
|
+
name: "Remove MCP Server",
|
|
2366
|
+
value: "remove"
|
|
2367
|
+
},
|
|
2368
|
+
{
|
|
2369
|
+
name: "Exit",
|
|
2370
|
+
value: "exit"
|
|
2371
|
+
}
|
|
2372
|
+
]
|
|
2373
|
+
});
|
|
2374
|
+
if (action === "exit") {
|
|
2375
|
+
console.log(import_picocolors10.default.dim("Goodbye!"));
|
|
2376
|
+
break;
|
|
2377
|
+
}
|
|
2378
|
+
if (action === "add") {
|
|
2379
|
+
await wizardAdd();
|
|
2380
|
+
} else if (action === "manage") {
|
|
2381
|
+
await wizardManage();
|
|
2382
|
+
} else if (action === "remove") {
|
|
2383
|
+
await wizardRemove();
|
|
2384
|
+
}
|
|
2385
|
+
console.log();
|
|
2386
|
+
} catch (error) {
|
|
2387
|
+
if (error?.name === "ExitPromptError") {
|
|
2388
|
+
console.log("\n" + import_picocolors10.default.dim("Exited."));
|
|
2389
|
+
break;
|
|
2390
|
+
}
|
|
2391
|
+
throw error;
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
};
|
|
2395
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2396
|
+
0 && (module.exports = {
|
|
2397
|
+
AgentConfigStore,
|
|
2398
|
+
DEFAULT_REMOTE_TRANSPORT,
|
|
2399
|
+
NPX_COMMAND,
|
|
2400
|
+
NPX_DASH_Y,
|
|
2401
|
+
add,
|
|
2402
|
+
agentConfigStore,
|
|
2403
|
+
buildMcpServerConfig,
|
|
2404
|
+
createAgentTransform,
|
|
2405
|
+
detectGloballyInstalledMcpAgents,
|
|
2406
|
+
detectProjectInstalledMcpAgents,
|
|
2407
|
+
extractPackageName,
|
|
2408
|
+
getMcpAgentConfig,
|
|
2409
|
+
getMcpAgentTypes,
|
|
2410
|
+
getMcpAgentsSupportingProjectScope,
|
|
2411
|
+
groupInstalledServersByName,
|
|
2412
|
+
install,
|
|
2413
|
+
installMcpServer,
|
|
2414
|
+
installMcpServerForAgent,
|
|
2415
|
+
installMcpServerForAgents,
|
|
2416
|
+
isMcpAgentType,
|
|
2417
|
+
isMcpTransportSupported,
|
|
2418
|
+
isRemoteMcpSource,
|
|
2419
|
+
isRemoteServerConfig,
|
|
2420
|
+
isStdioServerConfig,
|
|
2421
|
+
list,
|
|
2422
|
+
listInstalledMcpServers,
|
|
2423
|
+
listServersInConfigFile,
|
|
2424
|
+
mainMenu,
|
|
2425
|
+
mcpAgentAliases,
|
|
2426
|
+
mcpAgents,
|
|
2427
|
+
normalizeServerConfig,
|
|
2428
|
+
parseArgsString,
|
|
2429
|
+
parseEnvText,
|
|
2430
|
+
parseHeadersText,
|
|
2431
|
+
parseMcpSource,
|
|
2432
|
+
parseServerConfig,
|
|
2433
|
+
parseSource,
|
|
2434
|
+
promptArgsConfig,
|
|
2435
|
+
promptEnvConfig,
|
|
2436
|
+
promptHeadersConfig,
|
|
2437
|
+
promptScope,
|
|
2438
|
+
promptScopeAndAgents,
|
|
2439
|
+
readConfigFile,
|
|
2440
|
+
remove,
|
|
2441
|
+
removeMcpServer,
|
|
2442
|
+
removeMcpServerFromAgent,
|
|
2443
|
+
removeServerFromConfigFile,
|
|
2444
|
+
resolveMcpAgentAlias,
|
|
2445
|
+
resolveMcpConfigTarget,
|
|
2446
|
+
resolveTargetAgents,
|
|
2447
|
+
transformServerConfig,
|
|
2448
|
+
transformServerConfigForAgent,
|
|
2449
|
+
wizardAdd,
|
|
2450
|
+
wizardManage,
|
|
2451
|
+
wizardRemove,
|
|
2452
|
+
writeServerToConfigFile
|
|
2453
|
+
});
|