@mcp-abap-adt/configurator 0.0.2 → 0.0.4
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/bin/mcp-conf.js +686 -82
- package/docs/CLIENT_INSTALLERS.md +71 -29
- package/package.json +2 -2
package/bin/mcp-conf.js
CHANGED
|
@@ -22,6 +22,10 @@ try {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
const args = process.argv.slice(2);
|
|
25
|
+
const action = args[0] && !args[0].startsWith("-") ? args[0] : null;
|
|
26
|
+
if (action && ["add", "rm", "ls", "enable", "disable", "where", "help"].includes(action)) {
|
|
27
|
+
args.shift();
|
|
28
|
+
}
|
|
25
29
|
const options = {
|
|
26
30
|
clients: [],
|
|
27
31
|
envPath: null,
|
|
@@ -29,18 +33,29 @@ const options = {
|
|
|
29
33
|
name: null,
|
|
30
34
|
transport: "stdio",
|
|
31
35
|
command: "mcp-abap-adt",
|
|
36
|
+
scope: null,
|
|
32
37
|
dryRun: false,
|
|
33
38
|
force: false,
|
|
34
39
|
disabled: false,
|
|
35
40
|
toggle: false,
|
|
36
41
|
remove: false,
|
|
42
|
+
list: false,
|
|
43
|
+
allProjects: false,
|
|
44
|
+
projectPath: null,
|
|
45
|
+
where: false,
|
|
37
46
|
url: null,
|
|
38
47
|
headers: {},
|
|
39
48
|
timeout: 60,
|
|
40
49
|
};
|
|
41
50
|
|
|
42
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
43
|
-
|
|
51
|
+
if (args.includes("--help") || args.includes("-h") || action === "help") {
|
|
52
|
+
const helpAction =
|
|
53
|
+
action === "help"
|
|
54
|
+
? args[0]
|
|
55
|
+
: action && ["add", "rm", "ls", "enable", "disable", "where"].includes(action)
|
|
56
|
+
? action
|
|
57
|
+
: null;
|
|
58
|
+
printHelp(helpAction);
|
|
44
59
|
process.exit(0);
|
|
45
60
|
}
|
|
46
61
|
|
|
@@ -64,6 +79,21 @@ for (let i = 0; i < args.length; i += 1) {
|
|
|
64
79
|
} else if (arg === "--command") {
|
|
65
80
|
options.command = args[i + 1];
|
|
66
81
|
i += 1;
|
|
82
|
+
} else if (arg === "--global") {
|
|
83
|
+
if (options.scope && options.scope !== "global") {
|
|
84
|
+
fail("Choose either --global or --local (not both).");
|
|
85
|
+
}
|
|
86
|
+
options.scope = "global";
|
|
87
|
+
} else if (arg === "--local") {
|
|
88
|
+
if (options.scope && options.scope !== "local") {
|
|
89
|
+
fail("Choose either --global or --local (not both).");
|
|
90
|
+
}
|
|
91
|
+
options.scope = "local";
|
|
92
|
+
} else if (arg === "--all-projects") {
|
|
93
|
+
options.allProjects = true;
|
|
94
|
+
} else if (arg === "--project") {
|
|
95
|
+
options.projectPath = args[i + 1];
|
|
96
|
+
i += 1;
|
|
67
97
|
} else if (arg === "--url") {
|
|
68
98
|
options.url = args[i + 1];
|
|
69
99
|
i += 1;
|
|
@@ -92,18 +122,62 @@ for (let i = 0; i < args.length; i += 1) {
|
|
|
92
122
|
}
|
|
93
123
|
}
|
|
94
124
|
|
|
125
|
+
if (!action || !["add", "rm", "ls", "enable", "disable", "where"].includes(action)) {
|
|
126
|
+
fail("Provide a command: add | rm | ls | enable | disable | where.");
|
|
127
|
+
}
|
|
128
|
+
|
|
95
129
|
if (options.clients.length === 0) {
|
|
96
130
|
fail("Provide at least one --client.");
|
|
97
131
|
}
|
|
98
132
|
|
|
99
|
-
if (!options.name) {
|
|
133
|
+
if (!["ls"].includes(action) && !options.name) {
|
|
100
134
|
fail("Provide --name <serverName> (required).");
|
|
101
135
|
}
|
|
102
136
|
|
|
103
137
|
const transportNormalized = options.transport === "http" ? "streamableHttp" : options.transport;
|
|
104
138
|
options.transport = transportNormalized;
|
|
105
139
|
|
|
106
|
-
|
|
140
|
+
if (action === "rm") {
|
|
141
|
+
options.remove = true;
|
|
142
|
+
}
|
|
143
|
+
if (action === "ls") {
|
|
144
|
+
options.list = true;
|
|
145
|
+
}
|
|
146
|
+
if (action === "enable") {
|
|
147
|
+
options.toggle = true;
|
|
148
|
+
options.disabled = false;
|
|
149
|
+
}
|
|
150
|
+
if (action === "disable") {
|
|
151
|
+
options.toggle = true;
|
|
152
|
+
options.disabled = true;
|
|
153
|
+
}
|
|
154
|
+
if (action === "where") {
|
|
155
|
+
options.where = true;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (options.remove && action !== "rm") {
|
|
159
|
+
fail("Use the rm command instead of --remove.");
|
|
160
|
+
}
|
|
161
|
+
if (options.list && options.toggle) {
|
|
162
|
+
fail("The ls command does not support --enable/--disable.");
|
|
163
|
+
}
|
|
164
|
+
if (options.remove && options.toggle) {
|
|
165
|
+
fail("The rm command does not support --enable/--disable.");
|
|
166
|
+
}
|
|
167
|
+
if (options.allProjects && !options.list && !options.toggle && !options.remove && !options.where) {
|
|
168
|
+
fail("--all-projects is only supported for rm/enable/disable/ls/where.");
|
|
169
|
+
}
|
|
170
|
+
if (options.projectPath && options.allProjects) {
|
|
171
|
+
fail("Use either --project or --all-projects (not both).");
|
|
172
|
+
}
|
|
173
|
+
if (options.where && (options.list || options.remove || options.toggle)) {
|
|
174
|
+
fail("The where command does not support ls/rm/enable/disable flags.");
|
|
175
|
+
}
|
|
176
|
+
if (options.projectPath && action === "add" && options.scope !== "global") {
|
|
177
|
+
fail("--project is only supported for Claude global config.");
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const requiresConnectionParams = !options.remove && !options.toggle && !options.list && !options.where;
|
|
107
181
|
|
|
108
182
|
if (requiresConnectionParams && options.transport === "stdio") {
|
|
109
183
|
if (!options.envPath && !options.mcpDestination) {
|
|
@@ -135,44 +209,154 @@ const serverArgsRaw = [
|
|
|
135
209
|
];
|
|
136
210
|
const serverArgs = serverArgsRaw.filter(Boolean);
|
|
137
211
|
|
|
138
|
-
for (const client of options.clients) {
|
|
139
|
-
|
|
212
|
+
for (const client of options.clients) {
|
|
213
|
+
const scope = options.scope || getDefaultScope(client);
|
|
214
|
+
if (options.projectPath && client !== "claude") {
|
|
215
|
+
fail("--project is only supported for Claude.");
|
|
216
|
+
}
|
|
217
|
+
switch (client) {
|
|
140
218
|
case "cline":
|
|
141
|
-
|
|
219
|
+
requireScope("Cline", ["global"], scope);
|
|
220
|
+
if (options.list) {
|
|
221
|
+
listJsonConfig(getClinePath(platform, home, appData), "cline");
|
|
222
|
+
} else if (options.where) {
|
|
223
|
+
whereJsonConfig(getClinePath(platform, home, appData), "cline", options.name);
|
|
224
|
+
} else {
|
|
225
|
+
writeJsonConfig(getClinePath(platform, home, appData), options.name, serverArgs, "cline");
|
|
226
|
+
}
|
|
142
227
|
break;
|
|
143
228
|
case "codex":
|
|
144
229
|
if (options.transport === "sse") {
|
|
145
230
|
fail("Codex does not support SSE transport.");
|
|
146
231
|
}
|
|
147
|
-
|
|
232
|
+
requireScope("Codex", ["global"], scope);
|
|
233
|
+
if (options.list) {
|
|
234
|
+
listCodexConfig(getCodexPath(platform, home, userProfile));
|
|
235
|
+
} else if (options.where) {
|
|
236
|
+
whereCodexConfig(getCodexPath(platform, home, userProfile), options.name);
|
|
237
|
+
} else {
|
|
238
|
+
writeCodexConfig(getCodexPath(platform, home, userProfile), options.name, serverArgs);
|
|
239
|
+
}
|
|
148
240
|
break;
|
|
149
241
|
case "claude":
|
|
150
|
-
|
|
242
|
+
requireScope("Claude", ["global", "local"], scope);
|
|
243
|
+
const claudeToggleScope = options.toggle ? "global" : scope;
|
|
244
|
+
if (options.allProjects && claudeToggleScope !== "global") {
|
|
245
|
+
fail("--all-projects is only supported for Claude global config.");
|
|
246
|
+
}
|
|
247
|
+
if (options.projectPath && claudeToggleScope !== "global") {
|
|
248
|
+
fail("--project is only supported for Claude global config.");
|
|
249
|
+
}
|
|
250
|
+
if (options.toggle && scope === "local") {
|
|
251
|
+
const localPath = getClaudePath(platform, home, appData, "local");
|
|
252
|
+
if (!claudeLocalHasServer(localPath, options.name)) {
|
|
253
|
+
fail(`Server "${options.name}" not found in ${localPath}.`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (options.list) {
|
|
257
|
+
listClaudeConfig(
|
|
258
|
+
getClaudePath(platform, home, appData, claudeToggleScope),
|
|
259
|
+
options.allProjects,
|
|
260
|
+
options.projectPath,
|
|
261
|
+
);
|
|
262
|
+
} else if (options.where) {
|
|
263
|
+
whereClaudeConfig(
|
|
264
|
+
getClaudePath(platform, home, appData, claudeToggleScope),
|
|
265
|
+
options.name,
|
|
266
|
+
options.allProjects,
|
|
267
|
+
options.projectPath,
|
|
268
|
+
);
|
|
269
|
+
} else {
|
|
270
|
+
writeClaudeConfig(
|
|
271
|
+
getClaudePath(platform, home, appData, claudeToggleScope),
|
|
272
|
+
options.name,
|
|
273
|
+
serverArgs,
|
|
274
|
+
);
|
|
275
|
+
}
|
|
151
276
|
break;
|
|
152
277
|
case "goose":
|
|
153
|
-
|
|
278
|
+
requireScope("Goose", ["global"], scope);
|
|
279
|
+
if (options.list) {
|
|
280
|
+
listGooseConfig(getGoosePath(platform, home, appData));
|
|
281
|
+
} else if (options.where) {
|
|
282
|
+
whereGooseConfig(getGoosePath(platform, home, appData), options.name);
|
|
283
|
+
} else {
|
|
284
|
+
writeGooseConfig(getGoosePath(platform, home, appData), options.name, serverArgs);
|
|
285
|
+
}
|
|
154
286
|
break;
|
|
155
287
|
case "opencode":
|
|
156
|
-
|
|
288
|
+
requireScope("OpenCode", ["global", "local"], scope);
|
|
289
|
+
if (options.list) {
|
|
290
|
+
listJsonConfig(getOpenCodePath(platform, home, appData, scope), "opencode");
|
|
291
|
+
} else if (options.where) {
|
|
292
|
+
whereJsonConfig(getOpenCodePath(platform, home, appData, scope), "opencode", options.name);
|
|
293
|
+
} else {
|
|
294
|
+
writeJsonConfig(
|
|
295
|
+
getOpenCodePath(platform, home, appData, scope),
|
|
296
|
+
options.name,
|
|
297
|
+
serverArgs,
|
|
298
|
+
"opencode",
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
break;
|
|
302
|
+
case "antigravity":
|
|
303
|
+
requireScope("Antigravity", ["global", "local"], scope);
|
|
304
|
+
if (scope === "local") {
|
|
305
|
+
process.stdout.write("Antigravity local scope is not supported yet.\n");
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
if (options.list) {
|
|
309
|
+
listJsonConfig(getAntigravityPath(home, scope), "antigravity");
|
|
310
|
+
} else if (options.where) {
|
|
311
|
+
whereJsonConfig(getAntigravityPath(home, scope), "antigravity", options.name);
|
|
312
|
+
} else {
|
|
313
|
+
writeJsonConfig(
|
|
314
|
+
getAntigravityPath(home, scope),
|
|
315
|
+
options.name,
|
|
316
|
+
serverArgs,
|
|
317
|
+
"antigravity",
|
|
318
|
+
);
|
|
319
|
+
}
|
|
157
320
|
break;
|
|
158
321
|
case "copilot":
|
|
159
|
-
|
|
322
|
+
requireScope("GitHub Copilot", ["local"], scope);
|
|
323
|
+
if (options.list) {
|
|
324
|
+
listJsonConfig(getCopilotPath(), "copilot");
|
|
325
|
+
} else if (options.where) {
|
|
326
|
+
whereJsonConfig(getCopilotPath(), "copilot", options.name);
|
|
327
|
+
} else {
|
|
328
|
+
writeJsonConfig(getCopilotPath(), options.name, serverArgs, "copilot");
|
|
329
|
+
}
|
|
160
330
|
break;
|
|
161
331
|
case "cursor":
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
"cursor",
|
|
167
|
-
|
|
332
|
+
requireScope("Cursor", ["global", "local"], scope);
|
|
333
|
+
if (options.list) {
|
|
334
|
+
listJsonConfig(getCursorPath(platform, home, userProfile, scope), "cursor");
|
|
335
|
+
} else if (options.where) {
|
|
336
|
+
whereJsonConfig(getCursorPath(platform, home, userProfile, scope), "cursor", options.name);
|
|
337
|
+
} else {
|
|
338
|
+
writeJsonConfig(
|
|
339
|
+
getCursorPath(platform, home, userProfile, scope),
|
|
340
|
+
options.name,
|
|
341
|
+
serverArgs,
|
|
342
|
+
"cursor",
|
|
343
|
+
);
|
|
344
|
+
}
|
|
168
345
|
break;
|
|
169
346
|
case "windsurf":
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
"windsurf",
|
|
175
|
-
|
|
347
|
+
requireScope("Windsurf", ["global"], scope);
|
|
348
|
+
if (options.list) {
|
|
349
|
+
listJsonConfig(getWindsurfPath(platform, home, userProfile), "windsurf");
|
|
350
|
+
} else if (options.where) {
|
|
351
|
+
whereJsonConfig(getWindsurfPath(platform, home, userProfile), "windsurf", options.name);
|
|
352
|
+
} else {
|
|
353
|
+
writeJsonConfig(
|
|
354
|
+
getWindsurfPath(platform, home, userProfile),
|
|
355
|
+
options.name,
|
|
356
|
+
serverArgs,
|
|
357
|
+
"windsurf",
|
|
358
|
+
);
|
|
359
|
+
}
|
|
176
360
|
break;
|
|
177
361
|
default:
|
|
178
362
|
fail(`Unknown client: ${client}`);
|
|
@@ -210,7 +394,10 @@ function getCodexPath(platformValue, homeDir, userProfileDir) {
|
|
|
210
394
|
return path.join(homeDir, ".codex", "config.toml");
|
|
211
395
|
}
|
|
212
396
|
|
|
213
|
-
function getClaudePath(platformValue, homeDir, appDataDir) {
|
|
397
|
+
function getClaudePath(platformValue, homeDir, appDataDir, scopeValue) {
|
|
398
|
+
if (scopeValue === "local") {
|
|
399
|
+
return path.join(process.cwd(), ".mcp.json");
|
|
400
|
+
}
|
|
214
401
|
if (platformValue === "darwin") {
|
|
215
402
|
return path.join(
|
|
216
403
|
homeDir,
|
|
@@ -233,7 +420,10 @@ function getGoosePath(platformValue, homeDir, appDataDir) {
|
|
|
233
420
|
return path.join(homeDir, ".config", "goose", "config.yaml");
|
|
234
421
|
}
|
|
235
422
|
|
|
236
|
-
function getCursorPath(platformValue, homeDir, userProfileDir) {
|
|
423
|
+
function getCursorPath(platformValue, homeDir, userProfileDir, scopeValue) {
|
|
424
|
+
if (scopeValue === "local") {
|
|
425
|
+
return path.join(process.cwd(), ".cursor", "mcp.json");
|
|
426
|
+
}
|
|
237
427
|
const base = platformValue === "win32" ? userProfileDir : homeDir;
|
|
238
428
|
return path.join(base, ".cursor", "mcp.json");
|
|
239
429
|
}
|
|
@@ -242,8 +432,21 @@ function getCopilotPath() {
|
|
|
242
432
|
return path.join(process.cwd(), ".vscode", "mcp.json");
|
|
243
433
|
}
|
|
244
434
|
|
|
245
|
-
function getOpenCodePath() {
|
|
246
|
-
|
|
435
|
+
function getOpenCodePath(platformValue, homeDir, appDataDir, scopeValue) {
|
|
436
|
+
if (scopeValue === "local") {
|
|
437
|
+
return path.join(process.cwd(), "opencode.json");
|
|
438
|
+
}
|
|
439
|
+
if (platformValue === "win32") {
|
|
440
|
+
return path.join(appDataDir, "opencode", "opencode.json");
|
|
441
|
+
}
|
|
442
|
+
return path.join(homeDir, ".config", "opencode", "opencode.json");
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function getAntigravityPath(homeDir, scopeValue) {
|
|
446
|
+
if (scopeValue === "local") {
|
|
447
|
+
return path.join(process.cwd(), ".antigravity", "mcp.json");
|
|
448
|
+
}
|
|
449
|
+
return path.join(homeDir, ".gemini", "antigravity", "mcp_config.json");
|
|
247
450
|
}
|
|
248
451
|
|
|
249
452
|
function getWindsurfPath(platformValue, homeDir, userProfileDir) {
|
|
@@ -253,6 +456,50 @@ function getWindsurfPath(platformValue, homeDir, userProfileDir) {
|
|
|
253
456
|
return path.join(homeDir, ".codeium", "windsurf", "mcp_config.json");
|
|
254
457
|
}
|
|
255
458
|
|
|
459
|
+
function requireScope(clientLabel, allowedScopes, requestedScope) {
|
|
460
|
+
if (!allowedScopes.includes(requestedScope)) {
|
|
461
|
+
fail(
|
|
462
|
+
`${clientLabel} supports ${allowedScopes.join("/")} configuration only. ` +
|
|
463
|
+
`Use --${allowedScopes[0]}.`,
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function getDefaultScope(clientType) {
|
|
469
|
+
if (clientType === "copilot") {
|
|
470
|
+
return "local";
|
|
471
|
+
}
|
|
472
|
+
return "global";
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function resolveProjectSelector(data, projectPath) {
|
|
476
|
+
if (!projectPath) {
|
|
477
|
+
return resolveClaudeProjectKey(data);
|
|
478
|
+
}
|
|
479
|
+
if (!data.projects) {
|
|
480
|
+
return projectPath;
|
|
481
|
+
}
|
|
482
|
+
if (data.projects[projectPath]) {
|
|
483
|
+
return projectPath;
|
|
484
|
+
}
|
|
485
|
+
let desiredReal;
|
|
486
|
+
try {
|
|
487
|
+
desiredReal = fs.realpathSync(projectPath);
|
|
488
|
+
} catch {
|
|
489
|
+
return projectPath;
|
|
490
|
+
}
|
|
491
|
+
for (const key of Object.keys(data.projects)) {
|
|
492
|
+
try {
|
|
493
|
+
if (fs.realpathSync(key) === desiredReal) {
|
|
494
|
+
return key;
|
|
495
|
+
}
|
|
496
|
+
} catch {
|
|
497
|
+
// ignore invalid paths
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return projectPath;
|
|
501
|
+
}
|
|
502
|
+
|
|
256
503
|
function getDefaultDisabled(clientType) {
|
|
257
504
|
return ["cline", "codex", "windsurf", "goose", "claude", "opencode"].includes(clientType);
|
|
258
505
|
}
|
|
@@ -262,6 +509,8 @@ function writeJsonConfig(filePath, serverName, argsArray, clientType) {
|
|
|
262
509
|
const data = readJson(filePath);
|
|
263
510
|
if (clientType === "opencode") {
|
|
264
511
|
data.mcp = data.mcp || {};
|
|
512
|
+
} else if (clientType === "antigravity") {
|
|
513
|
+
data.mcpServers = data.mcpServers || {};
|
|
265
514
|
} else if (clientType === "copilot") {
|
|
266
515
|
data.servers = data.servers || {};
|
|
267
516
|
data.inputs = data.inputs || [];
|
|
@@ -288,6 +537,8 @@ function writeJsonConfig(filePath, serverName, argsArray, clientType) {
|
|
|
288
537
|
};
|
|
289
538
|
if (clientType === "opencode") {
|
|
290
539
|
store[serverName].enabled = !options.disabled;
|
|
540
|
+
} else if (clientType === "antigravity") {
|
|
541
|
+
store[serverName].disabled = !!options.disabled;
|
|
291
542
|
} else {
|
|
292
543
|
store[serverName].disabled = !!options.disabled;
|
|
293
544
|
}
|
|
@@ -356,6 +607,29 @@ function writeJsonConfig(filePath, serverName, argsArray, clientType) {
|
|
|
356
607
|
writeFile(filePath, JSON.stringify(data, null, 2));
|
|
357
608
|
return;
|
|
358
609
|
}
|
|
610
|
+
if (clientType === "antigravity") {
|
|
611
|
+
if (options.transport === "stdio") {
|
|
612
|
+
store[serverName] = {
|
|
613
|
+
command: options.command,
|
|
614
|
+
args: argsArray,
|
|
615
|
+
timeout: options.timeout,
|
|
616
|
+
disabled: !!options.disabled,
|
|
617
|
+
};
|
|
618
|
+
} else {
|
|
619
|
+
const entry = {
|
|
620
|
+
type: "http",
|
|
621
|
+
serverUrl: options.url,
|
|
622
|
+
timeout: options.timeout,
|
|
623
|
+
disabled: !!options.disabled,
|
|
624
|
+
};
|
|
625
|
+
if (Object.keys(options.headers).length > 0) {
|
|
626
|
+
entry.headers = options.headers;
|
|
627
|
+
}
|
|
628
|
+
store[serverName] = entry;
|
|
629
|
+
}
|
|
630
|
+
writeFile(filePath, JSON.stringify(data, null, 2));
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
359
633
|
if (options.transport === "stdio") {
|
|
360
634
|
data.mcpServers[serverName] = {
|
|
361
635
|
command: options.command,
|
|
@@ -384,30 +658,7 @@ function writeClaudeConfig(filePath, serverName, argsArray) {
|
|
|
384
658
|
const data = readJson(filePath);
|
|
385
659
|
const isDesktopConfig =
|
|
386
660
|
filePath.endsWith(".claude.json") || filePath.endsWith("claude_desktop_config.json");
|
|
387
|
-
const
|
|
388
|
-
const resolveProjectKey = () => {
|
|
389
|
-
const desired = projectPath;
|
|
390
|
-
if (!data.projects || data.projects[desired]) {
|
|
391
|
-
return desired;
|
|
392
|
-
}
|
|
393
|
-
let desiredReal;
|
|
394
|
-
try {
|
|
395
|
-
desiredReal = fs.realpathSync(desired);
|
|
396
|
-
} catch {
|
|
397
|
-
return desired;
|
|
398
|
-
}
|
|
399
|
-
const keys = Object.keys(data.projects || {});
|
|
400
|
-
for (const key of keys) {
|
|
401
|
-
try {
|
|
402
|
-
if (fs.realpathSync(key) === desiredReal) {
|
|
403
|
-
return key;
|
|
404
|
-
}
|
|
405
|
-
} catch {
|
|
406
|
-
// ignore invalid paths
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
return desired;
|
|
410
|
-
};
|
|
661
|
+
const resolveProjectKey = () => resolveProjectSelector(data, options.projectPath);
|
|
411
662
|
const updateClaudeMcpLists = (projectNode) => {
|
|
412
663
|
projectNode.enabledMcpServers = projectNode.enabledMcpServers || [];
|
|
413
664
|
projectNode.disabledMcpServers = projectNode.disabledMcpServers || [];
|
|
@@ -450,15 +701,35 @@ function writeClaudeConfig(filePath, serverName, argsArray) {
|
|
|
450
701
|
};
|
|
451
702
|
if (options.remove) {
|
|
452
703
|
if (isDesktopConfig) {
|
|
453
|
-
if (
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
704
|
+
if (options.allProjects) {
|
|
705
|
+
const projects = Object.keys(data.projects || {});
|
|
706
|
+
let removed = false;
|
|
707
|
+
for (const key of projects) {
|
|
708
|
+
if (data.projects?.[key]?.mcpServers?.[serverName]) {
|
|
709
|
+
delete data.projects[key].mcpServers[serverName];
|
|
710
|
+
const projectNode = data.projects[key];
|
|
711
|
+
projectNode.enabledMcpServers =
|
|
712
|
+
projectNode.enabledMcpServers?.filter((name) => name !== serverName) || [];
|
|
713
|
+
projectNode.disabledMcpServers =
|
|
714
|
+
projectNode.disabledMcpServers?.filter((name) => name !== serverName) || [];
|
|
715
|
+
removed = true;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
if (!removed) {
|
|
719
|
+
fail(`Server "${serverName}" not found in any Claude projects.`);
|
|
720
|
+
}
|
|
721
|
+
} else {
|
|
722
|
+
const projectKey = resolveProjectKey();
|
|
723
|
+
if (!data.projects?.[projectKey]?.mcpServers?.[serverName]) {
|
|
724
|
+
fail(`Server "${serverName}" not found for ${projectKey}.`);
|
|
725
|
+
}
|
|
726
|
+
delete data.projects[projectKey].mcpServers[serverName];
|
|
727
|
+
const projectNode = data.projects[projectKey];
|
|
728
|
+
projectNode.enabledMcpServers =
|
|
729
|
+
projectNode.enabledMcpServers?.filter((name) => name !== serverName) || [];
|
|
730
|
+
projectNode.disabledMcpServers =
|
|
731
|
+
projectNode.disabledMcpServers?.filter((name) => name !== serverName) || [];
|
|
732
|
+
}
|
|
462
733
|
} else {
|
|
463
734
|
data.mcpServers = data.mcpServers || {};
|
|
464
735
|
if (!data.mcpServers[serverName]) {
|
|
@@ -474,6 +745,42 @@ function writeClaudeConfig(filePath, serverName, argsArray) {
|
|
|
474
745
|
}
|
|
475
746
|
if (isDesktopConfig) {
|
|
476
747
|
data.projects = data.projects || {};
|
|
748
|
+
if (options.toggle) {
|
|
749
|
+
if (options.allProjects) {
|
|
750
|
+
const projects = Object.keys(data.projects || {});
|
|
751
|
+
let toggled = false;
|
|
752
|
+
for (const key of projects) {
|
|
753
|
+
if (!data.projects[key]) {
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
data.projects[key].mcpServers = data.projects[key].mcpServers || {};
|
|
757
|
+
if (!data.projects[key].mcpServers[serverName]) {
|
|
758
|
+
continue;
|
|
759
|
+
}
|
|
760
|
+
updateClaudeMcpLists(data.projects[key]);
|
|
761
|
+
toggled = true;
|
|
762
|
+
}
|
|
763
|
+
if (!toggled) {
|
|
764
|
+
fail(`Server "${serverName}" not found in any Claude projects.`);
|
|
765
|
+
}
|
|
766
|
+
writeFile(filePath, JSON.stringify(data, null, 2));
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
const projectKey = resolveProjectKey();
|
|
770
|
+
if (!data.projects[projectKey]) {
|
|
771
|
+
data.projects[projectKey] = {
|
|
772
|
+
allowedTools: [],
|
|
773
|
+
mcpContextUris: [],
|
|
774
|
+
mcpServers: {},
|
|
775
|
+
enabledMcpServers: [],
|
|
776
|
+
disabledMcpServers: [],
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
data.projects[projectKey].mcpServers = data.projects[projectKey].mcpServers || {};
|
|
780
|
+
updateClaudeMcpLists(data.projects[projectKey]);
|
|
781
|
+
writeFile(filePath, JSON.stringify(data, null, 2));
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
477
784
|
const projectKey = resolveProjectKey();
|
|
478
785
|
if (!data.projects[projectKey]) {
|
|
479
786
|
data.projects[projectKey] = {
|
|
@@ -488,14 +795,6 @@ function writeClaudeConfig(filePath, serverName, argsArray) {
|
|
|
488
795
|
data.projects[projectKey].disabledMcpServers =
|
|
489
796
|
data.projects[projectKey].disabledMcpServers || [];
|
|
490
797
|
data.projects[projectKey].mcpServers = data.projects[projectKey].mcpServers || {};
|
|
491
|
-
if (options.toggle) {
|
|
492
|
-
if (!data.projects[projectKey].mcpServers[serverName]) {
|
|
493
|
-
fail(`Server "${serverName}" not found for ${projectKey}.`);
|
|
494
|
-
}
|
|
495
|
-
updateClaudeMcpLists(data.projects[projectKey]);
|
|
496
|
-
writeFile(filePath, JSON.stringify(data, null, 2));
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
798
|
if (data.projects[projectKey].mcpServers[serverName] && !options.force) {
|
|
500
799
|
fail(`Server "${serverName}" already exists for ${projectKey}. Use --force to overwrite.`);
|
|
501
800
|
}
|
|
@@ -532,7 +831,7 @@ function writeClaudeConfig(filePath, serverName, argsArray) {
|
|
|
532
831
|
};
|
|
533
832
|
} else {
|
|
534
833
|
const entry = {
|
|
535
|
-
type: options.transport,
|
|
834
|
+
type: options.transport === "streamableHttp" ? "http" : options.transport,
|
|
536
835
|
url: options.url,
|
|
537
836
|
timeout: options.timeout,
|
|
538
837
|
};
|
|
@@ -545,6 +844,30 @@ function writeClaudeConfig(filePath, serverName, argsArray) {
|
|
|
545
844
|
writeFile(filePath, JSON.stringify(data, null, 2));
|
|
546
845
|
}
|
|
547
846
|
|
|
847
|
+
function resolveClaudeProjectKey(data, projectPath = process.cwd()) {
|
|
848
|
+
const desired = projectPath;
|
|
849
|
+
if (!data.projects || data.projects[desired]) {
|
|
850
|
+
return desired;
|
|
851
|
+
}
|
|
852
|
+
let desiredReal;
|
|
853
|
+
try {
|
|
854
|
+
desiredReal = fs.realpathSync(desired);
|
|
855
|
+
} catch {
|
|
856
|
+
return desired;
|
|
857
|
+
}
|
|
858
|
+
const keys = Object.keys(data.projects || {});
|
|
859
|
+
for (const key of keys) {
|
|
860
|
+
try {
|
|
861
|
+
if (fs.realpathSync(key) === desiredReal) {
|
|
862
|
+
return key;
|
|
863
|
+
}
|
|
864
|
+
} catch {
|
|
865
|
+
// ignore invalid paths
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
return desired;
|
|
869
|
+
}
|
|
870
|
+
|
|
548
871
|
function writeCodexConfig(filePath, serverName, argsArray) {
|
|
549
872
|
ensureDir(filePath);
|
|
550
873
|
if (!toml) {
|
|
@@ -663,6 +986,141 @@ function writeGooseConfig(filePath, serverName, argsArray) {
|
|
|
663
986
|
writeFile(filePath, yaml.stringify(data));
|
|
664
987
|
}
|
|
665
988
|
|
|
989
|
+
function listJsonConfig(filePath, clientType) {
|
|
990
|
+
const data = readJson(filePath);
|
|
991
|
+
let store;
|
|
992
|
+
if (clientType === "opencode") {
|
|
993
|
+
store = data.mcp || {};
|
|
994
|
+
} else if (clientType === "antigravity") {
|
|
995
|
+
store = data.mcpServers || {};
|
|
996
|
+
} else if (clientType === "copilot") {
|
|
997
|
+
store = data.servers || {};
|
|
998
|
+
} else {
|
|
999
|
+
store = data.mcpServers || {};
|
|
1000
|
+
}
|
|
1001
|
+
outputList(filePath, Object.keys(store));
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
function listCodexConfig(filePath) {
|
|
1005
|
+
if (!toml) {
|
|
1006
|
+
fail("TOML dependency not available. Install dependencies and retry.");
|
|
1007
|
+
}
|
|
1008
|
+
const data = readToml(filePath);
|
|
1009
|
+
const store = data.mcp_servers || {};
|
|
1010
|
+
outputList(filePath, Object.keys(store));
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
function listGooseConfig(filePath) {
|
|
1014
|
+
if (!yaml) {
|
|
1015
|
+
fail("YAML dependency not available. Install dependencies and retry.");
|
|
1016
|
+
}
|
|
1017
|
+
const data = readYaml(filePath);
|
|
1018
|
+
const store = data.extensions || {};
|
|
1019
|
+
outputList(filePath, Object.keys(store));
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
function listClaudeConfig(filePath, allProjects, projectPath) {
|
|
1023
|
+
const data = readJson(filePath);
|
|
1024
|
+
const isDesktopConfig =
|
|
1025
|
+
filePath.endsWith(".claude.json") || filePath.endsWith("claude_desktop_config.json");
|
|
1026
|
+
if (isDesktopConfig) {
|
|
1027
|
+
const projects = Object.keys(data.projects || {});
|
|
1028
|
+
if (allProjects) {
|
|
1029
|
+
if (!projects.length) {
|
|
1030
|
+
outputList(filePath, [], "no-projects");
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
for (const key of projects.sort()) {
|
|
1034
|
+
const projectNode = data.projects?.[key];
|
|
1035
|
+
const store = projectNode?.mcpServers || {};
|
|
1036
|
+
outputList(filePath, Object.keys(store), key);
|
|
1037
|
+
}
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
const projectKey = resolveProjectSelector(data, projectPath);
|
|
1041
|
+
const projectNode = data.projects?.[projectKey];
|
|
1042
|
+
const store = projectNode?.mcpServers || {};
|
|
1043
|
+
outputList(filePath, Object.keys(store), projectKey);
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
const store = data.mcpServers || {};
|
|
1047
|
+
outputList(filePath, Object.keys(store));
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
function claudeLocalHasServer(filePath, serverName) {
|
|
1051
|
+
const data = readJson(filePath);
|
|
1052
|
+
const store = data.mcpServers || {};
|
|
1053
|
+
return Boolean(store[serverName]);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
function whereJsonConfig(filePath, clientType, serverName) {
|
|
1057
|
+
const data = readJson(filePath);
|
|
1058
|
+
let store;
|
|
1059
|
+
if (clientType === "opencode") {
|
|
1060
|
+
store = data.mcp || {};
|
|
1061
|
+
} else if (clientType === "antigravity") {
|
|
1062
|
+
store = data.mcpServers || {};
|
|
1063
|
+
} else if (clientType === "copilot") {
|
|
1064
|
+
store = data.servers || {};
|
|
1065
|
+
} else {
|
|
1066
|
+
store = data.mcpServers || {};
|
|
1067
|
+
}
|
|
1068
|
+
outputWhere(filePath, serverName, Boolean(store[serverName]));
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
function whereCodexConfig(filePath, serverName) {
|
|
1072
|
+
if (!toml) {
|
|
1073
|
+
fail("TOML dependency not available. Install dependencies and retry.");
|
|
1074
|
+
}
|
|
1075
|
+
const data = readToml(filePath);
|
|
1076
|
+
const store = data.mcp_servers || {};
|
|
1077
|
+
outputWhere(filePath, serverName, Boolean(store[serverName]));
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
function whereGooseConfig(filePath, serverName) {
|
|
1081
|
+
if (!yaml) {
|
|
1082
|
+
fail("YAML dependency not available. Install dependencies and retry.");
|
|
1083
|
+
}
|
|
1084
|
+
const data = readYaml(filePath);
|
|
1085
|
+
const store = data.extensions || {};
|
|
1086
|
+
outputWhere(filePath, serverName, Boolean(store[serverName]));
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
function whereClaudeConfig(filePath, serverName, allProjects, projectPath) {
|
|
1090
|
+
const data = readJson(filePath);
|
|
1091
|
+
const isDesktopConfig =
|
|
1092
|
+
filePath.endsWith(".claude.json") || filePath.endsWith("claude_desktop_config.json");
|
|
1093
|
+
if (isDesktopConfig) {
|
|
1094
|
+
const projects = Object.keys(data.projects || {});
|
|
1095
|
+
if (allProjects) {
|
|
1096
|
+
if (!projects.length) {
|
|
1097
|
+
outputWhere(filePath, serverName, false, "no-projects");
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
let found = false;
|
|
1101
|
+
for (const key of projects.sort()) {
|
|
1102
|
+
const projectNode = data.projects?.[key];
|
|
1103
|
+
const store = projectNode?.mcpServers || {};
|
|
1104
|
+
if (store[serverName]) {
|
|
1105
|
+
outputWhere(filePath, serverName, true, key);
|
|
1106
|
+
found = true;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
if (!found) {
|
|
1110
|
+
outputWhere(filePath, serverName, false, "all-projects");
|
|
1111
|
+
}
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
const projectKey = resolveProjectSelector(data, projectPath);
|
|
1115
|
+
const projectNode = data.projects?.[projectKey];
|
|
1116
|
+
const store = projectNode?.mcpServers || {};
|
|
1117
|
+
outputWhere(filePath, serverName, Boolean(store[serverName]), projectKey);
|
|
1118
|
+
return;
|
|
1119
|
+
}
|
|
1120
|
+
const store = data.mcpServers || {};
|
|
1121
|
+
outputWhere(filePath, serverName, Boolean(store[serverName]));
|
|
1122
|
+
}
|
|
1123
|
+
|
|
666
1124
|
function readJson(filePath) {
|
|
667
1125
|
if (!fs.existsSync(filePath)) {
|
|
668
1126
|
return {};
|
|
@@ -708,6 +1166,24 @@ function readToml(filePath) {
|
|
|
708
1166
|
}
|
|
709
1167
|
}
|
|
710
1168
|
|
|
1169
|
+
function outputList(filePath, keys, projectKey) {
|
|
1170
|
+
const header = projectKey ? `# ${filePath} (${projectKey})` : `# ${filePath}`;
|
|
1171
|
+
process.stdout.write(`${header}\n`);
|
|
1172
|
+
if (!keys.length) {
|
|
1173
|
+
process.stdout.write("- (none)\n");
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
for (const name of keys.sort()) {
|
|
1177
|
+
process.stdout.write(`- ${name}\n`);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
function outputWhere(filePath, serverName, found, projectKey) {
|
|
1182
|
+
const header = projectKey ? `# ${filePath} (${projectKey})` : `# ${filePath}`;
|
|
1183
|
+
process.stdout.write(`${header}\n`);
|
|
1184
|
+
process.stdout.write(`- ${serverName}: ${found ? "found" : "not found"}\n`);
|
|
1185
|
+
}
|
|
1186
|
+
|
|
711
1187
|
function ensureDir(filePath) {
|
|
712
1188
|
const dir = path.dirname(filePath);
|
|
713
1189
|
if (!fs.existsSync(dir)) {
|
|
@@ -729,30 +1205,158 @@ function fail(message) {
|
|
|
729
1205
|
process.exit(1);
|
|
730
1206
|
}
|
|
731
1207
|
|
|
732
|
-
function printHelp() {
|
|
733
|
-
|
|
1208
|
+
function printHelp(command) {
|
|
1209
|
+
const header = "mcp-conf";
|
|
1210
|
+
if (!command) {
|
|
1211
|
+
process.stdout.write(`${header}
|
|
734
1212
|
|
|
735
1213
|
Usage:
|
|
736
|
-
mcp-conf
|
|
1214
|
+
mcp-conf <add|rm|ls|enable|disable|where> --client <name> [options]
|
|
1215
|
+
mcp-conf help <command>
|
|
1216
|
+
|
|
1217
|
+
Commands:
|
|
1218
|
+
add add or update an MCP server entry
|
|
1219
|
+
rm remove an MCP server entry
|
|
1220
|
+
ls list MCP server entries
|
|
1221
|
+
enable enable an existing entry
|
|
1222
|
+
disable disable an existing entry
|
|
1223
|
+
where show where a server name is defined
|
|
1224
|
+
|
|
1225
|
+
Run:
|
|
1226
|
+
mcp-conf <command> --help
|
|
1227
|
+
mcp-conf help <command>
|
|
1228
|
+
|
|
1229
|
+
Notes:
|
|
1230
|
+
Scope defaults to --global (Copilot uses --local only).
|
|
1231
|
+
For Claude, --local maps to the project scope file ./.mcp.json.
|
|
1232
|
+
`);
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
switch (command) {
|
|
1236
|
+
case "add":
|
|
1237
|
+
process.stdout.write(`${header} add
|
|
1238
|
+
|
|
1239
|
+
Usage:
|
|
1240
|
+
mcp-conf add --client <name> --name <serverName> [--env <path> | --mcp <dest>] [options]
|
|
737
1241
|
|
|
738
1242
|
Options:
|
|
739
|
-
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot (repeatable)
|
|
1243
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot | antigravity (repeatable)
|
|
740
1244
|
--name <serverName> required MCP server name key
|
|
741
|
-
--env <path> .env path (
|
|
742
|
-
--mcp <dest> destination name (
|
|
1245
|
+
--env <path> .env path (stdio only)
|
|
1246
|
+
--mcp <dest> destination name (stdio only)
|
|
743
1247
|
--transport <type> stdio | sse | http (http => streamableHttp)
|
|
744
1248
|
--command <bin> command to run (default: mcp-abap-adt)
|
|
1249
|
+
--global write to global user config (default)
|
|
1250
|
+
--local write to project config (where supported)
|
|
1251
|
+
--project <path> Claude global: target a specific project path
|
|
745
1252
|
--url <http(s)://...> required for sse/http
|
|
746
1253
|
--header key=value add request header (repeatable)
|
|
747
1254
|
--timeout <seconds> entry timeout (default: 60)
|
|
748
|
-
--
|
|
749
|
-
--
|
|
750
|
-
|
|
751
|
-
|
|
1255
|
+
--force overwrite existing entry
|
|
1256
|
+
--dry-run print changes without writing files
|
|
1257
|
+
|
|
1258
|
+
Notes:
|
|
1259
|
+
Antigravity local scope is not supported yet; use --global.
|
|
1260
|
+
`);
|
|
1261
|
+
break;
|
|
1262
|
+
case "rm":
|
|
1263
|
+
process.stdout.write(`${header} rm
|
|
1264
|
+
|
|
1265
|
+
Usage:
|
|
1266
|
+
mcp-conf rm --client <name> --name <serverName> [options]
|
|
1267
|
+
|
|
1268
|
+
Options:
|
|
1269
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot | antigravity (repeatable)
|
|
1270
|
+
--name <serverName> required MCP server name key
|
|
1271
|
+
--global write to global user config (default)
|
|
1272
|
+
--local write to project config (where supported)
|
|
1273
|
+
--all-projects Claude global: remove across all projects
|
|
1274
|
+
--project <path> Claude global: target a specific project path
|
|
1275
|
+
--dry-run print changes without writing files
|
|
1276
|
+
|
|
1277
|
+
Notes:
|
|
1278
|
+
Antigravity local scope is not supported yet; use --global.
|
|
1279
|
+
`);
|
|
1280
|
+
break;
|
|
1281
|
+
case "ls":
|
|
1282
|
+
process.stdout.write(`${header} ls
|
|
1283
|
+
|
|
1284
|
+
Usage:
|
|
1285
|
+
mcp-conf ls --client <name> [options]
|
|
1286
|
+
|
|
1287
|
+
Options:
|
|
1288
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot | antigravity (repeatable)
|
|
1289
|
+
--global write to global user config (default)
|
|
1290
|
+
--local write to project config (where supported)
|
|
1291
|
+
--all-projects Claude global: list across all projects
|
|
1292
|
+
--project <path> Claude global: target a specific project path
|
|
1293
|
+
|
|
1294
|
+
Notes:
|
|
1295
|
+
Antigravity local scope is not supported yet; use --global.
|
|
1296
|
+
`);
|
|
1297
|
+
break;
|
|
1298
|
+
case "enable":
|
|
1299
|
+
process.stdout.write(`${header} enable
|
|
1300
|
+
|
|
1301
|
+
Usage:
|
|
1302
|
+
mcp-conf enable --client <name> --name <serverName> [options]
|
|
1303
|
+
|
|
1304
|
+
Options:
|
|
1305
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot | antigravity (repeatable)
|
|
1306
|
+
--name <serverName> required MCP server name key
|
|
1307
|
+
--global write to global user config (default)
|
|
1308
|
+
--local write to project config (where supported)
|
|
1309
|
+
--all-projects Claude global: enable across all projects
|
|
1310
|
+
--project <path> Claude global: target a specific project path
|
|
752
1311
|
--dry-run print changes without writing files
|
|
753
|
-
-h, --help show this help
|
|
754
1312
|
|
|
755
1313
|
Notes:
|
|
756
|
-
|
|
1314
|
+
Antigravity local scope is not supported yet; use --global.
|
|
757
1315
|
`);
|
|
1316
|
+
break;
|
|
1317
|
+
case "disable":
|
|
1318
|
+
process.stdout.write(`${header} disable
|
|
1319
|
+
|
|
1320
|
+
Usage:
|
|
1321
|
+
mcp-conf disable --client <name> --name <serverName> [options]
|
|
1322
|
+
|
|
1323
|
+
Options:
|
|
1324
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot | antigravity (repeatable)
|
|
1325
|
+
--name <serverName> required MCP server name key
|
|
1326
|
+
--global write to global user config (default)
|
|
1327
|
+
--local write to project config (where supported)
|
|
1328
|
+
--all-projects Claude global: disable across all projects
|
|
1329
|
+
--project <path> Claude global: target a specific project path
|
|
1330
|
+
--dry-run print changes without writing files
|
|
1331
|
+
|
|
1332
|
+
Notes:
|
|
1333
|
+
Antigravity local scope is not supported yet; use --global.
|
|
1334
|
+
`);
|
|
1335
|
+
break;
|
|
1336
|
+
case "where":
|
|
1337
|
+
process.stdout.write(`${header} where
|
|
1338
|
+
|
|
1339
|
+
Usage:
|
|
1340
|
+
mcp-conf where --client <name> --name <serverName> [options]
|
|
1341
|
+
|
|
1342
|
+
Options:
|
|
1343
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot | antigravity (repeatable)
|
|
1344
|
+
--name <serverName> required MCP server name key
|
|
1345
|
+
--global write to global user config (default)
|
|
1346
|
+
--local write to project config (where supported)
|
|
1347
|
+
--all-projects Claude global: search across all projects
|
|
1348
|
+
--project <path> Claude global: target a specific project path
|
|
1349
|
+
|
|
1350
|
+
Notes:
|
|
1351
|
+
Antigravity local scope is not supported yet; use --global.
|
|
1352
|
+
`);
|
|
1353
|
+
break;
|
|
1354
|
+
default:
|
|
1355
|
+
process.stdout.write(`${header}
|
|
1356
|
+
|
|
1357
|
+
Unknown command "${command}".
|
|
1358
|
+
Run:
|
|
1359
|
+
mcp-conf help
|
|
1360
|
+
`);
|
|
1361
|
+
}
|
|
758
1362
|
}
|
|
@@ -11,79 +11,109 @@ npm install -g @mcp-abap-adt/configurator
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
mcp-conf --client cline --env /path/to/.env --name abap
|
|
15
|
-
mcp-conf --client cline --mcp TRIAL --name abap
|
|
16
|
-
mcp-conf --client cline --env /path/to/.env --name abap --transport stdio
|
|
17
|
-
mcp-conf --client claude --mcp TRIAL --name abap
|
|
18
|
-
mcp-conf --client codex --name abap
|
|
19
|
-
mcp-conf --client cline --name direct-jwt-test-001 --transport http --url http://localhost:4004/mcp/stream/http --header x-sap-url=https://... --header x-sap-client=210 --header x-sap-auth-type=jwt --header x-sap-jwt-token=...
|
|
20
|
-
mcp-conf --client cline --name local-mcp-sse --transport sse --url http://localhost:3001/sse
|
|
21
|
-
mcp-conf --client codex --name abap-http --transport http --url http://localhost:3000/mcp/stream/http
|
|
22
|
-
mcp-conf --client codex --name abap-http --transport http --url http://localhost:3000/mcp/stream/http --header x-mcp-destination=trial
|
|
23
|
-
mcp-conf --client opencode --name abap --transport http --url http://localhost:3000/mcp/stream/http
|
|
24
|
-
mcp-conf --client copilot --name abap --transport http --url http://localhost:3000/mcp/stream/http --header x-mcp-destination=trial
|
|
14
|
+
mcp-conf add --client cline --env /path/to/.env --name abap
|
|
15
|
+
mcp-conf add --client cline --mcp TRIAL --name abap
|
|
16
|
+
mcp-conf add --client cline --env /path/to/.env --name abap --transport stdio
|
|
17
|
+
mcp-conf add --client claude --mcp TRIAL --name abap
|
|
18
|
+
mcp-conf rm --client codex --name abap
|
|
19
|
+
mcp-conf add --client cline --name direct-jwt-test-001 --transport http --url http://localhost:4004/mcp/stream/http --header x-sap-url=https://... --header x-sap-client=210 --header x-sap-auth-type=jwt --header x-sap-jwt-token=...
|
|
20
|
+
mcp-conf add --client cline --name local-mcp-sse --transport sse --url http://localhost:3001/sse
|
|
21
|
+
mcp-conf add --client codex --name abap-http --transport http --url http://localhost:3000/mcp/stream/http
|
|
22
|
+
mcp-conf add --client codex --name abap-http --transport http --url http://localhost:3000/mcp/stream/http --header x-mcp-destination=trial
|
|
23
|
+
mcp-conf add --client opencode --name abap --transport http --url http://localhost:3000/mcp/stream/http
|
|
24
|
+
mcp-conf add --client copilot --name abap --transport http --url http://localhost:3000/mcp/stream/http --header x-mcp-destination=trial
|
|
25
|
+
mcp-conf add --client antigravity --name abap --transport http --url http://localhost:3000/mcp/stream/http
|
|
25
26
|
```
|
|
26
27
|
|
|
27
28
|
## Common Tasks
|
|
28
29
|
|
|
29
30
|
Add MCP:
|
|
30
31
|
```bash
|
|
31
|
-
mcp-conf --client codex --mcp TRIAL --name abap
|
|
32
|
-
mcp-conf --client cline --env /path/to/.env --name abap
|
|
33
|
-
mcp-conf --client claude --mcp TRIAL --name abap
|
|
32
|
+
mcp-conf add --client codex --mcp TRIAL --name abap
|
|
33
|
+
mcp-conf add --client cline --env /path/to/.env --name abap
|
|
34
|
+
mcp-conf add --client claude --mcp TRIAL --name abap
|
|
35
|
+
mcp-conf add --client claude --name abap-http --transport http --url http://localhost:3000/mcp/stream/http --header x-mcp-destination=trial
|
|
36
|
+
mcp-conf add --client claude --name abap --project /path/to/project --mcp TRIAL
|
|
34
37
|
```
|
|
35
38
|
|
|
36
39
|
Disable MCP:
|
|
37
40
|
```bash
|
|
38
|
-
mcp-conf --client codex --name abap
|
|
39
|
-
mcp-conf --client cline --name abap
|
|
41
|
+
mcp-conf disable --client codex --name abap
|
|
42
|
+
mcp-conf disable --client cline --name abap
|
|
40
43
|
```
|
|
41
44
|
|
|
42
45
|
Enable MCP:
|
|
43
46
|
```bash
|
|
44
|
-
mcp-conf --client codex --name abap
|
|
45
|
-
mcp-conf --client cline --name abap
|
|
47
|
+
mcp-conf enable --client codex --name abap
|
|
48
|
+
mcp-conf enable --client cline --name abap
|
|
49
|
+
mcp-conf enable --client antigravity --name abap
|
|
46
50
|
```
|
|
47
51
|
|
|
48
52
|
Remove MCP:
|
|
49
53
|
```bash
|
|
50
|
-
mcp-conf --client codex --name abap
|
|
51
|
-
mcp-conf --client cline --name abap
|
|
52
|
-
mcp-conf --client claude --name abap
|
|
54
|
+
mcp-conf rm --client codex --name abap
|
|
55
|
+
mcp-conf rm --client cline --name abap
|
|
56
|
+
mcp-conf rm --client claude --name abap
|
|
57
|
+
mcp-conf rm --client antigravity --name abap
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
List MCP servers:
|
|
61
|
+
```bash
|
|
62
|
+
mcp-conf ls --client codex
|
|
63
|
+
mcp-conf ls --client cline
|
|
64
|
+
mcp-conf ls --client claude --local
|
|
65
|
+
mcp-conf ls --client claude --all-projects
|
|
66
|
+
mcp-conf ls --client antigravity --global
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Find where a server is defined:
|
|
70
|
+
```bash
|
|
71
|
+
mcp-conf where --client codex --name abap
|
|
72
|
+
mcp-conf where --client claude --name goose --project /path/to/project
|
|
73
|
+
mcp-conf where --client claude --name goose --all-projects
|
|
53
74
|
```
|
|
54
75
|
|
|
55
76
|
Options:
|
|
56
|
-
-
|
|
77
|
+
- Commands: `add`, `rm`, `ls`, `enable`, `disable`, `where` (first argument)
|
|
78
|
+
- `--client <name>` (repeatable): `cline`, `codex`, `claude`, `goose`, `cursor`, `windsurf`, `opencode`, `copilot`, `antigravity`
|
|
57
79
|
- `--env <path>`: use a specific `.env` file
|
|
58
80
|
- `--mcp <destination>`: use service key destination
|
|
59
81
|
- `--name <serverName>`: MCP server name (required)
|
|
60
82
|
- `--transport <type>`: `stdio`, `sse`, or `http` (`http` maps to `streamableHttp`)
|
|
61
83
|
- `--command <bin>`: command to run (default: `mcp-abap-adt`)
|
|
84
|
+
- `--global`: write to the global user config (default)
|
|
85
|
+
- `--local`: write to the project config (supported by `cursor`, `opencode`, `copilot`, `claude`)
|
|
86
|
+
- `--all-projects`: for Claude (global scope), apply `rm/enable/disable/ls/where` across all projects
|
|
87
|
+
- `--project <path>`: for Claude (global scope), target a specific project path
|
|
62
88
|
- `--url <http(s)://...>`: required for `sse` and `http`
|
|
63
89
|
- `--header key=value`: add request header (repeatable)
|
|
64
90
|
- `--timeout <seconds>`: timeout value for client entries (default: 60)
|
|
65
|
-
- `--disable`: disable server entry (Codex/OpenCode: `enabled = false`, Cline/Windsurf: `disabled = true`, Claude: moves name to `disabledMcpServers`; not Cursor/Copilot)
|
|
66
|
-
- `--enable`: enable server entry (Codex/OpenCode: `enabled = true`, Cline/Windsurf: `disabled = false`, Claude: moves name to `enabledMcpServers`; not Cursor/Copilot)
|
|
67
|
-
- `--remove`: remove server entry from client config
|
|
68
91
|
|
|
69
92
|
Notes:
|
|
70
|
-
-
|
|
93
|
+
- `disable` and `rm` do not require `--env` or `--mcp`.
|
|
71
94
|
- `--env`/`--mcp` are only valid for `stdio` transport. For `sse/http`, use `--url` and optional `--header`.
|
|
72
95
|
- Cursor/Copilot enable/disable are not implemented yet.
|
|
96
|
+
- Antigravity enable/disable uses `disabled: true|false` on the entry.
|
|
97
|
+
- Antigravity local scope is not supported yet; use `--global`.
|
|
73
98
|
- Claude stores enable/disable state under `enabledMcpServers` and `disabledMcpServers` for each project.
|
|
74
|
-
-
|
|
99
|
+
- Claude enable/disable always updates `~/.claude.json` (global scope), even if you pass `--local`.
|
|
100
|
+
- Antigravity HTTP entries use `serverUrl` instead of `url`.
|
|
101
|
+
- New entries for Cline, Codex, Windsurf, Goose, Claude, and OpenCode are added **disabled by default**. Use `enable` to turn them on.
|
|
75
102
|
- Windsurf follows `disabled` like Cline. The configurator sets `disabled = true` for default-disabled entries.
|
|
76
|
-
-
|
|
103
|
+
- `enable`/`disable` only work if the server entry already exists. Use add commands with `--env` or `--mcp` first.
|
|
77
104
|
- Non-stdio transports are supported for Cline/Cursor/Windsurf/Claude/Goose. Codex supports `http` (streamable HTTP) but not `sse`.
|
|
78
105
|
- Codex writes custom headers under `http_headers` in `~/.codex/config.toml`.
|
|
79
106
|
- Codex HTTP entries include `startup_timeout_sec` (default: 60).
|
|
80
107
|
- `--dry-run`: print changes without writing files
|
|
81
108
|
- `--force`: overwrite existing server entry if it exists
|
|
109
|
+
- Scope defaults to `--global` (GitHub Copilot is `--local` only).
|
|
110
|
+
- For Claude, `--local` maps to the documented project scope file `./.mcp.json`.
|
|
82
111
|
|
|
83
112
|
## Config Locations
|
|
84
113
|
|
|
85
114
|
Paths are client-specific and OS-dependent. The installer writes config files in:
|
|
86
115
|
|
|
116
|
+
Global (default) locations:
|
|
87
117
|
- **Cline**:
|
|
88
118
|
- Linux/macOS: `~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`
|
|
89
119
|
- Windows: `%APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json`
|
|
@@ -104,8 +134,20 @@ Paths are client-specific and OS-dependent. The installer writes config files in
|
|
|
104
134
|
- **Windsurf**:
|
|
105
135
|
- Linux/macOS: `~/.codeium/windsurf/mcp_config.json`
|
|
106
136
|
- Windows: `%USERPROFILE%\.codeium\windsurf\mcp_config.json`
|
|
137
|
+
- **OpenCode**:
|
|
138
|
+
- Linux/macOS: `~/.config/opencode/opencode.json`
|
|
139
|
+
- Windows: `%APPDATA%\opencode\opencode.json`
|
|
140
|
+
- **Antigravity**:
|
|
141
|
+
- Linux/macOS: `~/.gemini/antigravity/mcp_config.json`
|
|
142
|
+
|
|
143
|
+
Local (project) locations:
|
|
144
|
+
- **Claude Code**:
|
|
145
|
+
- Project: `./.mcp.json`
|
|
146
|
+
- **Cursor**:
|
|
147
|
+
- Project: `./.cursor/mcp.json`
|
|
107
148
|
- **OpenCode**:
|
|
108
149
|
- Project: `./opencode.json` (uses `mcp.<name>` entries with `enabled: true|false`)
|
|
109
150
|
- **GitHub Copilot**:
|
|
110
151
|
- Project: `./.vscode/mcp.json` (uses `servers.<name>` entries)
|
|
111
|
-
|
|
152
|
+
- **Antigravity**:
|
|
153
|
+
- Project: `./.antigravity/mcp.json` (community-reported; not supported yet)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-abap-adt/configurator",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "MCP client configurator for mcp-abap-adt and mcp-abap-adt-proxy",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"npm": ">=9.0.0"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@iarna/toml": "^
|
|
30
|
+
"@iarna/toml": "^3.0.0",
|
|
31
31
|
"yaml": "^2.8.1"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|