@mcp-abap-adt/configurator 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/mcp-conf.js +610 -81
- package/docs/CLIENT_INSTALLERS.md +59 -28
- 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,135 @@ 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
|
+
}
|
|
157
301
|
break;
|
|
158
302
|
case "copilot":
|
|
159
|
-
|
|
303
|
+
requireScope("GitHub Copilot", ["local"], scope);
|
|
304
|
+
if (options.list) {
|
|
305
|
+
listJsonConfig(getCopilotPath(), "copilot");
|
|
306
|
+
} else if (options.where) {
|
|
307
|
+
whereJsonConfig(getCopilotPath(), "copilot", options.name);
|
|
308
|
+
} else {
|
|
309
|
+
writeJsonConfig(getCopilotPath(), options.name, serverArgs, "copilot");
|
|
310
|
+
}
|
|
160
311
|
break;
|
|
161
312
|
case "cursor":
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
"cursor",
|
|
167
|
-
|
|
313
|
+
requireScope("Cursor", ["global", "local"], scope);
|
|
314
|
+
if (options.list) {
|
|
315
|
+
listJsonConfig(getCursorPath(platform, home, userProfile, scope), "cursor");
|
|
316
|
+
} else if (options.where) {
|
|
317
|
+
whereJsonConfig(getCursorPath(platform, home, userProfile, scope), "cursor", options.name);
|
|
318
|
+
} else {
|
|
319
|
+
writeJsonConfig(
|
|
320
|
+
getCursorPath(platform, home, userProfile, scope),
|
|
321
|
+
options.name,
|
|
322
|
+
serverArgs,
|
|
323
|
+
"cursor",
|
|
324
|
+
);
|
|
325
|
+
}
|
|
168
326
|
break;
|
|
169
327
|
case "windsurf":
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
"windsurf",
|
|
175
|
-
|
|
328
|
+
requireScope("Windsurf", ["global"], scope);
|
|
329
|
+
if (options.list) {
|
|
330
|
+
listJsonConfig(getWindsurfPath(platform, home, userProfile), "windsurf");
|
|
331
|
+
} else if (options.where) {
|
|
332
|
+
whereJsonConfig(getWindsurfPath(platform, home, userProfile), "windsurf", options.name);
|
|
333
|
+
} else {
|
|
334
|
+
writeJsonConfig(
|
|
335
|
+
getWindsurfPath(platform, home, userProfile),
|
|
336
|
+
options.name,
|
|
337
|
+
serverArgs,
|
|
338
|
+
"windsurf",
|
|
339
|
+
);
|
|
340
|
+
}
|
|
176
341
|
break;
|
|
177
342
|
default:
|
|
178
343
|
fail(`Unknown client: ${client}`);
|
|
@@ -210,7 +375,10 @@ function getCodexPath(platformValue, homeDir, userProfileDir) {
|
|
|
210
375
|
return path.join(homeDir, ".codex", "config.toml");
|
|
211
376
|
}
|
|
212
377
|
|
|
213
|
-
function getClaudePath(platformValue, homeDir, appDataDir) {
|
|
378
|
+
function getClaudePath(platformValue, homeDir, appDataDir, scopeValue) {
|
|
379
|
+
if (scopeValue === "local") {
|
|
380
|
+
return path.join(process.cwd(), ".mcp.json");
|
|
381
|
+
}
|
|
214
382
|
if (platformValue === "darwin") {
|
|
215
383
|
return path.join(
|
|
216
384
|
homeDir,
|
|
@@ -233,7 +401,10 @@ function getGoosePath(platformValue, homeDir, appDataDir) {
|
|
|
233
401
|
return path.join(homeDir, ".config", "goose", "config.yaml");
|
|
234
402
|
}
|
|
235
403
|
|
|
236
|
-
function getCursorPath(platformValue, homeDir, userProfileDir) {
|
|
404
|
+
function getCursorPath(platformValue, homeDir, userProfileDir, scopeValue) {
|
|
405
|
+
if (scopeValue === "local") {
|
|
406
|
+
return path.join(process.cwd(), ".cursor", "mcp.json");
|
|
407
|
+
}
|
|
237
408
|
const base = platformValue === "win32" ? userProfileDir : homeDir;
|
|
238
409
|
return path.join(base, ".cursor", "mcp.json");
|
|
239
410
|
}
|
|
@@ -242,8 +413,14 @@ function getCopilotPath() {
|
|
|
242
413
|
return path.join(process.cwd(), ".vscode", "mcp.json");
|
|
243
414
|
}
|
|
244
415
|
|
|
245
|
-
function getOpenCodePath() {
|
|
246
|
-
|
|
416
|
+
function getOpenCodePath(platformValue, homeDir, appDataDir, scopeValue) {
|
|
417
|
+
if (scopeValue === "local") {
|
|
418
|
+
return path.join(process.cwd(), "opencode.json");
|
|
419
|
+
}
|
|
420
|
+
if (platformValue === "win32") {
|
|
421
|
+
return path.join(appDataDir, "opencode", "opencode.json");
|
|
422
|
+
}
|
|
423
|
+
return path.join(homeDir, ".config", "opencode", "opencode.json");
|
|
247
424
|
}
|
|
248
425
|
|
|
249
426
|
function getWindsurfPath(platformValue, homeDir, userProfileDir) {
|
|
@@ -253,6 +430,50 @@ function getWindsurfPath(platformValue, homeDir, userProfileDir) {
|
|
|
253
430
|
return path.join(homeDir, ".codeium", "windsurf", "mcp_config.json");
|
|
254
431
|
}
|
|
255
432
|
|
|
433
|
+
function requireScope(clientLabel, allowedScopes, requestedScope) {
|
|
434
|
+
if (!allowedScopes.includes(requestedScope)) {
|
|
435
|
+
fail(
|
|
436
|
+
`${clientLabel} supports ${allowedScopes.join("/")} configuration only. ` +
|
|
437
|
+
`Use --${allowedScopes[0]}.`,
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function getDefaultScope(clientType) {
|
|
443
|
+
if (clientType === "copilot") {
|
|
444
|
+
return "local";
|
|
445
|
+
}
|
|
446
|
+
return "global";
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function resolveProjectSelector(data, projectPath) {
|
|
450
|
+
if (!projectPath) {
|
|
451
|
+
return resolveClaudeProjectKey(data);
|
|
452
|
+
}
|
|
453
|
+
if (!data.projects) {
|
|
454
|
+
return projectPath;
|
|
455
|
+
}
|
|
456
|
+
if (data.projects[projectPath]) {
|
|
457
|
+
return projectPath;
|
|
458
|
+
}
|
|
459
|
+
let desiredReal;
|
|
460
|
+
try {
|
|
461
|
+
desiredReal = fs.realpathSync(projectPath);
|
|
462
|
+
} catch {
|
|
463
|
+
return projectPath;
|
|
464
|
+
}
|
|
465
|
+
for (const key of Object.keys(data.projects)) {
|
|
466
|
+
try {
|
|
467
|
+
if (fs.realpathSync(key) === desiredReal) {
|
|
468
|
+
return key;
|
|
469
|
+
}
|
|
470
|
+
} catch {
|
|
471
|
+
// ignore invalid paths
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return projectPath;
|
|
475
|
+
}
|
|
476
|
+
|
|
256
477
|
function getDefaultDisabled(clientType) {
|
|
257
478
|
return ["cline", "codex", "windsurf", "goose", "claude", "opencode"].includes(clientType);
|
|
258
479
|
}
|
|
@@ -384,30 +605,7 @@ function writeClaudeConfig(filePath, serverName, argsArray) {
|
|
|
384
605
|
const data = readJson(filePath);
|
|
385
606
|
const isDesktopConfig =
|
|
386
607
|
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
|
-
};
|
|
608
|
+
const resolveProjectKey = () => resolveProjectSelector(data, options.projectPath);
|
|
411
609
|
const updateClaudeMcpLists = (projectNode) => {
|
|
412
610
|
projectNode.enabledMcpServers = projectNode.enabledMcpServers || [];
|
|
413
611
|
projectNode.disabledMcpServers = projectNode.disabledMcpServers || [];
|
|
@@ -450,15 +648,35 @@ function writeClaudeConfig(filePath, serverName, argsArray) {
|
|
|
450
648
|
};
|
|
451
649
|
if (options.remove) {
|
|
452
650
|
if (isDesktopConfig) {
|
|
453
|
-
if (
|
|
454
|
-
|
|
651
|
+
if (options.allProjects) {
|
|
652
|
+
const projects = Object.keys(data.projects || {});
|
|
653
|
+
let removed = false;
|
|
654
|
+
for (const key of projects) {
|
|
655
|
+
if (data.projects?.[key]?.mcpServers?.[serverName]) {
|
|
656
|
+
delete data.projects[key].mcpServers[serverName];
|
|
657
|
+
const projectNode = data.projects[key];
|
|
658
|
+
projectNode.enabledMcpServers =
|
|
659
|
+
projectNode.enabledMcpServers?.filter((name) => name !== serverName) || [];
|
|
660
|
+
projectNode.disabledMcpServers =
|
|
661
|
+
projectNode.disabledMcpServers?.filter((name) => name !== serverName) || [];
|
|
662
|
+
removed = true;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
if (!removed) {
|
|
666
|
+
fail(`Server "${serverName}" not found in any Claude projects.`);
|
|
667
|
+
}
|
|
668
|
+
} else {
|
|
669
|
+
const projectKey = resolveProjectKey();
|
|
670
|
+
if (!data.projects?.[projectKey]?.mcpServers?.[serverName]) {
|
|
671
|
+
fail(`Server "${serverName}" not found for ${projectKey}.`);
|
|
672
|
+
}
|
|
673
|
+
delete data.projects[projectKey].mcpServers[serverName];
|
|
674
|
+
const projectNode = data.projects[projectKey];
|
|
675
|
+
projectNode.enabledMcpServers =
|
|
676
|
+
projectNode.enabledMcpServers?.filter((name) => name !== serverName) || [];
|
|
677
|
+
projectNode.disabledMcpServers =
|
|
678
|
+
projectNode.disabledMcpServers?.filter((name) => name !== serverName) || [];
|
|
455
679
|
}
|
|
456
|
-
delete data.projects[projectPath].mcpServers[serverName];
|
|
457
|
-
const projectNode = data.projects[projectPath];
|
|
458
|
-
projectNode.enabledMcpServers =
|
|
459
|
-
projectNode.enabledMcpServers?.filter((name) => name !== serverName) || [];
|
|
460
|
-
projectNode.disabledMcpServers =
|
|
461
|
-
projectNode.disabledMcpServers?.filter((name) => name !== serverName) || [];
|
|
462
680
|
} else {
|
|
463
681
|
data.mcpServers = data.mcpServers || {};
|
|
464
682
|
if (!data.mcpServers[serverName]) {
|
|
@@ -474,6 +692,42 @@ function writeClaudeConfig(filePath, serverName, argsArray) {
|
|
|
474
692
|
}
|
|
475
693
|
if (isDesktopConfig) {
|
|
476
694
|
data.projects = data.projects || {};
|
|
695
|
+
if (options.toggle) {
|
|
696
|
+
if (options.allProjects) {
|
|
697
|
+
const projects = Object.keys(data.projects || {});
|
|
698
|
+
let toggled = false;
|
|
699
|
+
for (const key of projects) {
|
|
700
|
+
if (!data.projects[key]) {
|
|
701
|
+
continue;
|
|
702
|
+
}
|
|
703
|
+
data.projects[key].mcpServers = data.projects[key].mcpServers || {};
|
|
704
|
+
if (!data.projects[key].mcpServers[serverName]) {
|
|
705
|
+
continue;
|
|
706
|
+
}
|
|
707
|
+
updateClaudeMcpLists(data.projects[key]);
|
|
708
|
+
toggled = true;
|
|
709
|
+
}
|
|
710
|
+
if (!toggled) {
|
|
711
|
+
fail(`Server "${serverName}" not found in any Claude projects.`);
|
|
712
|
+
}
|
|
713
|
+
writeFile(filePath, JSON.stringify(data, null, 2));
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
const projectKey = resolveProjectKey();
|
|
717
|
+
if (!data.projects[projectKey]) {
|
|
718
|
+
data.projects[projectKey] = {
|
|
719
|
+
allowedTools: [],
|
|
720
|
+
mcpContextUris: [],
|
|
721
|
+
mcpServers: {},
|
|
722
|
+
enabledMcpServers: [],
|
|
723
|
+
disabledMcpServers: [],
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
data.projects[projectKey].mcpServers = data.projects[projectKey].mcpServers || {};
|
|
727
|
+
updateClaudeMcpLists(data.projects[projectKey]);
|
|
728
|
+
writeFile(filePath, JSON.stringify(data, null, 2));
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
477
731
|
const projectKey = resolveProjectKey();
|
|
478
732
|
if (!data.projects[projectKey]) {
|
|
479
733
|
data.projects[projectKey] = {
|
|
@@ -488,14 +742,6 @@ function writeClaudeConfig(filePath, serverName, argsArray) {
|
|
|
488
742
|
data.projects[projectKey].disabledMcpServers =
|
|
489
743
|
data.projects[projectKey].disabledMcpServers || [];
|
|
490
744
|
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
745
|
if (data.projects[projectKey].mcpServers[serverName] && !options.force) {
|
|
500
746
|
fail(`Server "${serverName}" already exists for ${projectKey}. Use --force to overwrite.`);
|
|
501
747
|
}
|
|
@@ -532,7 +778,7 @@ function writeClaudeConfig(filePath, serverName, argsArray) {
|
|
|
532
778
|
};
|
|
533
779
|
} else {
|
|
534
780
|
const entry = {
|
|
535
|
-
type: options.transport,
|
|
781
|
+
type: options.transport === "streamableHttp" ? "http" : options.transport,
|
|
536
782
|
url: options.url,
|
|
537
783
|
timeout: options.timeout,
|
|
538
784
|
};
|
|
@@ -545,6 +791,30 @@ function writeClaudeConfig(filePath, serverName, argsArray) {
|
|
|
545
791
|
writeFile(filePath, JSON.stringify(data, null, 2));
|
|
546
792
|
}
|
|
547
793
|
|
|
794
|
+
function resolveClaudeProjectKey(data, projectPath = process.cwd()) {
|
|
795
|
+
const desired = projectPath;
|
|
796
|
+
if (!data.projects || data.projects[desired]) {
|
|
797
|
+
return desired;
|
|
798
|
+
}
|
|
799
|
+
let desiredReal;
|
|
800
|
+
try {
|
|
801
|
+
desiredReal = fs.realpathSync(desired);
|
|
802
|
+
} catch {
|
|
803
|
+
return desired;
|
|
804
|
+
}
|
|
805
|
+
const keys = Object.keys(data.projects || {});
|
|
806
|
+
for (const key of keys) {
|
|
807
|
+
try {
|
|
808
|
+
if (fs.realpathSync(key) === desiredReal) {
|
|
809
|
+
return key;
|
|
810
|
+
}
|
|
811
|
+
} catch {
|
|
812
|
+
// ignore invalid paths
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
return desired;
|
|
816
|
+
}
|
|
817
|
+
|
|
548
818
|
function writeCodexConfig(filePath, serverName, argsArray) {
|
|
549
819
|
ensureDir(filePath);
|
|
550
820
|
if (!toml) {
|
|
@@ -663,6 +933,137 @@ function writeGooseConfig(filePath, serverName, argsArray) {
|
|
|
663
933
|
writeFile(filePath, yaml.stringify(data));
|
|
664
934
|
}
|
|
665
935
|
|
|
936
|
+
function listJsonConfig(filePath, clientType) {
|
|
937
|
+
const data = readJson(filePath);
|
|
938
|
+
let store;
|
|
939
|
+
if (clientType === "opencode") {
|
|
940
|
+
store = data.mcp || {};
|
|
941
|
+
} else if (clientType === "copilot") {
|
|
942
|
+
store = data.servers || {};
|
|
943
|
+
} else {
|
|
944
|
+
store = data.mcpServers || {};
|
|
945
|
+
}
|
|
946
|
+
outputList(filePath, Object.keys(store));
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
function listCodexConfig(filePath) {
|
|
950
|
+
if (!toml) {
|
|
951
|
+
fail("TOML dependency not available. Install dependencies and retry.");
|
|
952
|
+
}
|
|
953
|
+
const data = readToml(filePath);
|
|
954
|
+
const store = data.mcp_servers || {};
|
|
955
|
+
outputList(filePath, Object.keys(store));
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
function listGooseConfig(filePath) {
|
|
959
|
+
if (!yaml) {
|
|
960
|
+
fail("YAML dependency not available. Install dependencies and retry.");
|
|
961
|
+
}
|
|
962
|
+
const data = readYaml(filePath);
|
|
963
|
+
const store = data.extensions || {};
|
|
964
|
+
outputList(filePath, Object.keys(store));
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
function listClaudeConfig(filePath, allProjects, projectPath) {
|
|
968
|
+
const data = readJson(filePath);
|
|
969
|
+
const isDesktopConfig =
|
|
970
|
+
filePath.endsWith(".claude.json") || filePath.endsWith("claude_desktop_config.json");
|
|
971
|
+
if (isDesktopConfig) {
|
|
972
|
+
const projects = Object.keys(data.projects || {});
|
|
973
|
+
if (allProjects) {
|
|
974
|
+
if (!projects.length) {
|
|
975
|
+
outputList(filePath, [], "no-projects");
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
for (const key of projects.sort()) {
|
|
979
|
+
const projectNode = data.projects?.[key];
|
|
980
|
+
const store = projectNode?.mcpServers || {};
|
|
981
|
+
outputList(filePath, Object.keys(store), key);
|
|
982
|
+
}
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
const projectKey = resolveProjectSelector(data, projectPath);
|
|
986
|
+
const projectNode = data.projects?.[projectKey];
|
|
987
|
+
const store = projectNode?.mcpServers || {};
|
|
988
|
+
outputList(filePath, Object.keys(store), projectKey);
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
const store = data.mcpServers || {};
|
|
992
|
+
outputList(filePath, Object.keys(store));
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
function claudeLocalHasServer(filePath, serverName) {
|
|
996
|
+
const data = readJson(filePath);
|
|
997
|
+
const store = data.mcpServers || {};
|
|
998
|
+
return Boolean(store[serverName]);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
function whereJsonConfig(filePath, clientType, serverName) {
|
|
1002
|
+
const data = readJson(filePath);
|
|
1003
|
+
let store;
|
|
1004
|
+
if (clientType === "opencode") {
|
|
1005
|
+
store = data.mcp || {};
|
|
1006
|
+
} else if (clientType === "copilot") {
|
|
1007
|
+
store = data.servers || {};
|
|
1008
|
+
} else {
|
|
1009
|
+
store = data.mcpServers || {};
|
|
1010
|
+
}
|
|
1011
|
+
outputWhere(filePath, serverName, Boolean(store[serverName]));
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
function whereCodexConfig(filePath, serverName) {
|
|
1015
|
+
if (!toml) {
|
|
1016
|
+
fail("TOML dependency not available. Install dependencies and retry.");
|
|
1017
|
+
}
|
|
1018
|
+
const data = readToml(filePath);
|
|
1019
|
+
const store = data.mcp_servers || {};
|
|
1020
|
+
outputWhere(filePath, serverName, Boolean(store[serverName]));
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
function whereGooseConfig(filePath, serverName) {
|
|
1024
|
+
if (!yaml) {
|
|
1025
|
+
fail("YAML dependency not available. Install dependencies and retry.");
|
|
1026
|
+
}
|
|
1027
|
+
const data = readYaml(filePath);
|
|
1028
|
+
const store = data.extensions || {};
|
|
1029
|
+
outputWhere(filePath, serverName, Boolean(store[serverName]));
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
function whereClaudeConfig(filePath, serverName, allProjects, projectPath) {
|
|
1033
|
+
const data = readJson(filePath);
|
|
1034
|
+
const isDesktopConfig =
|
|
1035
|
+
filePath.endsWith(".claude.json") || filePath.endsWith("claude_desktop_config.json");
|
|
1036
|
+
if (isDesktopConfig) {
|
|
1037
|
+
const projects = Object.keys(data.projects || {});
|
|
1038
|
+
if (allProjects) {
|
|
1039
|
+
if (!projects.length) {
|
|
1040
|
+
outputWhere(filePath, serverName, false, "no-projects");
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
let found = false;
|
|
1044
|
+
for (const key of projects.sort()) {
|
|
1045
|
+
const projectNode = data.projects?.[key];
|
|
1046
|
+
const store = projectNode?.mcpServers || {};
|
|
1047
|
+
if (store[serverName]) {
|
|
1048
|
+
outputWhere(filePath, serverName, true, key);
|
|
1049
|
+
found = true;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
if (!found) {
|
|
1053
|
+
outputWhere(filePath, serverName, false, "all-projects");
|
|
1054
|
+
}
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
const projectKey = resolveProjectSelector(data, projectPath);
|
|
1058
|
+
const projectNode = data.projects?.[projectKey];
|
|
1059
|
+
const store = projectNode?.mcpServers || {};
|
|
1060
|
+
outputWhere(filePath, serverName, Boolean(store[serverName]), projectKey);
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
const store = data.mcpServers || {};
|
|
1064
|
+
outputWhere(filePath, serverName, Boolean(store[serverName]));
|
|
1065
|
+
}
|
|
1066
|
+
|
|
666
1067
|
function readJson(filePath) {
|
|
667
1068
|
if (!fs.existsSync(filePath)) {
|
|
668
1069
|
return {};
|
|
@@ -708,6 +1109,24 @@ function readToml(filePath) {
|
|
|
708
1109
|
}
|
|
709
1110
|
}
|
|
710
1111
|
|
|
1112
|
+
function outputList(filePath, keys, projectKey) {
|
|
1113
|
+
const header = projectKey ? `# ${filePath} (${projectKey})` : `# ${filePath}`;
|
|
1114
|
+
process.stdout.write(`${header}\n`);
|
|
1115
|
+
if (!keys.length) {
|
|
1116
|
+
process.stdout.write("- (none)\n");
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
for (const name of keys.sort()) {
|
|
1120
|
+
process.stdout.write(`- ${name}\n`);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
function outputWhere(filePath, serverName, found, projectKey) {
|
|
1125
|
+
const header = projectKey ? `# ${filePath} (${projectKey})` : `# ${filePath}`;
|
|
1126
|
+
process.stdout.write(`${header}\n`);
|
|
1127
|
+
process.stdout.write(`- ${serverName}: ${found ? "found" : "not found"}\n`);
|
|
1128
|
+
}
|
|
1129
|
+
|
|
711
1130
|
function ensureDir(filePath) {
|
|
712
1131
|
const dir = path.dirname(filePath);
|
|
713
1132
|
if (!fs.existsSync(dir)) {
|
|
@@ -729,30 +1148,140 @@ function fail(message) {
|
|
|
729
1148
|
process.exit(1);
|
|
730
1149
|
}
|
|
731
1150
|
|
|
732
|
-
function printHelp() {
|
|
733
|
-
|
|
1151
|
+
function printHelp(command) {
|
|
1152
|
+
const header = "mcp-conf";
|
|
1153
|
+
if (!command) {
|
|
1154
|
+
process.stdout.write(`${header}
|
|
734
1155
|
|
|
735
1156
|
Usage:
|
|
736
|
-
mcp-conf
|
|
1157
|
+
mcp-conf <add|rm|ls|enable|disable|where> --client <name> [options]
|
|
1158
|
+
mcp-conf help <command>
|
|
1159
|
+
|
|
1160
|
+
Commands:
|
|
1161
|
+
add add or update an MCP server entry
|
|
1162
|
+
rm remove an MCP server entry
|
|
1163
|
+
ls list MCP server entries
|
|
1164
|
+
enable enable an existing entry
|
|
1165
|
+
disable disable an existing entry
|
|
1166
|
+
where show where a server name is defined
|
|
1167
|
+
|
|
1168
|
+
Run:
|
|
1169
|
+
mcp-conf <command> --help
|
|
1170
|
+
mcp-conf help <command>
|
|
1171
|
+
|
|
1172
|
+
Notes:
|
|
1173
|
+
Scope defaults to --global (Copilot uses --local only).
|
|
1174
|
+
For Claude, --local maps to the project scope file ./.mcp.json.
|
|
1175
|
+
`);
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
switch (command) {
|
|
1179
|
+
case "add":
|
|
1180
|
+
process.stdout.write(`${header} add
|
|
1181
|
+
|
|
1182
|
+
Usage:
|
|
1183
|
+
mcp-conf add --client <name> --name <serverName> [--env <path> | --mcp <dest>] [options]
|
|
737
1184
|
|
|
738
1185
|
Options:
|
|
739
1186
|
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot (repeatable)
|
|
740
1187
|
--name <serverName> required MCP server name key
|
|
741
|
-
--env <path> .env path (
|
|
742
|
-
--mcp <dest> destination name (
|
|
1188
|
+
--env <path> .env path (stdio only)
|
|
1189
|
+
--mcp <dest> destination name (stdio only)
|
|
743
1190
|
--transport <type> stdio | sse | http (http => streamableHttp)
|
|
744
1191
|
--command <bin> command to run (default: mcp-abap-adt)
|
|
1192
|
+
--global write to global user config (default)
|
|
1193
|
+
--local write to project config (where supported)
|
|
1194
|
+
--project <path> Claude global: target a specific project path
|
|
745
1195
|
--url <http(s)://...> required for sse/http
|
|
746
1196
|
--header key=value add request header (repeatable)
|
|
747
1197
|
--timeout <seconds> entry timeout (default: 60)
|
|
748
|
-
--
|
|
749
|
-
--enable enable entry (Codex/OpenCode/Cline/Windsurf/Goose/Claude; not Cursor/Copilot)
|
|
750
|
-
--remove remove entry
|
|
751
|
-
--force overwrite existing entry (add/update)
|
|
1198
|
+
--force overwrite existing entry
|
|
752
1199
|
--dry-run print changes without writing files
|
|
753
|
-
|
|
1200
|
+
`);
|
|
1201
|
+
break;
|
|
1202
|
+
case "rm":
|
|
1203
|
+
process.stdout.write(`${header} rm
|
|
754
1204
|
|
|
755
|
-
|
|
756
|
-
|
|
1205
|
+
Usage:
|
|
1206
|
+
mcp-conf rm --client <name> --name <serverName> [options]
|
|
1207
|
+
|
|
1208
|
+
Options:
|
|
1209
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot (repeatable)
|
|
1210
|
+
--name <serverName> required MCP server name key
|
|
1211
|
+
--global write to global user config (default)
|
|
1212
|
+
--local write to project config (where supported)
|
|
1213
|
+
--all-projects Claude global: remove across all projects
|
|
1214
|
+
--project <path> Claude global: target a specific project path
|
|
1215
|
+
--dry-run print changes without writing files
|
|
1216
|
+
`);
|
|
1217
|
+
break;
|
|
1218
|
+
case "ls":
|
|
1219
|
+
process.stdout.write(`${header} ls
|
|
1220
|
+
|
|
1221
|
+
Usage:
|
|
1222
|
+
mcp-conf ls --client <name> [options]
|
|
1223
|
+
|
|
1224
|
+
Options:
|
|
1225
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot (repeatable)
|
|
1226
|
+
--global write to global user config (default)
|
|
1227
|
+
--local write to project config (where supported)
|
|
1228
|
+
--all-projects Claude global: list across all projects
|
|
1229
|
+
--project <path> Claude global: target a specific project path
|
|
1230
|
+
`);
|
|
1231
|
+
break;
|
|
1232
|
+
case "enable":
|
|
1233
|
+
process.stdout.write(`${header} enable
|
|
1234
|
+
|
|
1235
|
+
Usage:
|
|
1236
|
+
mcp-conf enable --client <name> --name <serverName> [options]
|
|
1237
|
+
|
|
1238
|
+
Options:
|
|
1239
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot (repeatable)
|
|
1240
|
+
--name <serverName> required MCP server name key
|
|
1241
|
+
--global write to global user config (default)
|
|
1242
|
+
--local write to project config (where supported)
|
|
1243
|
+
--all-projects Claude global: enable across all projects
|
|
1244
|
+
--project <path> Claude global: target a specific project path
|
|
1245
|
+
--dry-run print changes without writing files
|
|
757
1246
|
`);
|
|
1247
|
+
break;
|
|
1248
|
+
case "disable":
|
|
1249
|
+
process.stdout.write(`${header} disable
|
|
1250
|
+
|
|
1251
|
+
Usage:
|
|
1252
|
+
mcp-conf disable --client <name> --name <serverName> [options]
|
|
1253
|
+
|
|
1254
|
+
Options:
|
|
1255
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot (repeatable)
|
|
1256
|
+
--name <serverName> required MCP server name key
|
|
1257
|
+
--global write to global user config (default)
|
|
1258
|
+
--local write to project config (where supported)
|
|
1259
|
+
--all-projects Claude global: disable across all projects
|
|
1260
|
+
--project <path> Claude global: target a specific project path
|
|
1261
|
+
--dry-run print changes without writing files
|
|
1262
|
+
`);
|
|
1263
|
+
break;
|
|
1264
|
+
case "where":
|
|
1265
|
+
process.stdout.write(`${header} where
|
|
1266
|
+
|
|
1267
|
+
Usage:
|
|
1268
|
+
mcp-conf where --client <name> --name <serverName> [options]
|
|
1269
|
+
|
|
1270
|
+
Options:
|
|
1271
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot (repeatable)
|
|
1272
|
+
--name <serverName> required MCP server name key
|
|
1273
|
+
--global write to global user config (default)
|
|
1274
|
+
--local write to project config (where supported)
|
|
1275
|
+
--all-projects Claude global: search across all projects
|
|
1276
|
+
--project <path> Claude global: target a specific project path
|
|
1277
|
+
`);
|
|
1278
|
+
break;
|
|
1279
|
+
default:
|
|
1280
|
+
process.stdout.write(`${header}
|
|
1281
|
+
|
|
1282
|
+
Unknown command "${command}".
|
|
1283
|
+
Run:
|
|
1284
|
+
mcp-conf help
|
|
1285
|
+
`);
|
|
1286
|
+
}
|
|
758
1287
|
}
|
|
@@ -11,79 +11,102 @@ 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
25
|
```
|
|
26
26
|
|
|
27
27
|
## Common Tasks
|
|
28
28
|
|
|
29
29
|
Add MCP:
|
|
30
30
|
```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
|
|
31
|
+
mcp-conf add --client codex --mcp TRIAL --name abap
|
|
32
|
+
mcp-conf add --client cline --env /path/to/.env --name abap
|
|
33
|
+
mcp-conf add --client claude --mcp TRIAL --name abap
|
|
34
|
+
mcp-conf add --client claude --name abap-http --transport http --url http://localhost:3000/mcp/stream/http --header x-mcp-destination=trial
|
|
35
|
+
mcp-conf add --client claude --name abap --project /path/to/project --mcp TRIAL
|
|
34
36
|
```
|
|
35
37
|
|
|
36
38
|
Disable MCP:
|
|
37
39
|
```bash
|
|
38
|
-
mcp-conf --client codex --name abap
|
|
39
|
-
mcp-conf --client cline --name abap
|
|
40
|
+
mcp-conf disable --client codex --name abap
|
|
41
|
+
mcp-conf disable --client cline --name abap
|
|
40
42
|
```
|
|
41
43
|
|
|
42
44
|
Enable MCP:
|
|
43
45
|
```bash
|
|
44
|
-
mcp-conf --client codex --name abap
|
|
45
|
-
mcp-conf --client cline --name abap
|
|
46
|
+
mcp-conf enable --client codex --name abap
|
|
47
|
+
mcp-conf enable --client cline --name abap
|
|
46
48
|
```
|
|
47
49
|
|
|
48
50
|
Remove MCP:
|
|
49
51
|
```bash
|
|
50
|
-
mcp-conf --client codex --name abap
|
|
51
|
-
mcp-conf --client cline --name abap
|
|
52
|
-
mcp-conf --client claude --name abap
|
|
52
|
+
mcp-conf rm --client codex --name abap
|
|
53
|
+
mcp-conf rm --client cline --name abap
|
|
54
|
+
mcp-conf rm --client claude --name abap
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
List MCP servers:
|
|
58
|
+
```bash
|
|
59
|
+
mcp-conf ls --client codex
|
|
60
|
+
mcp-conf ls --client cline
|
|
61
|
+
mcp-conf ls --client claude --local
|
|
62
|
+
mcp-conf ls --client claude --all-projects
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Find where a server is defined:
|
|
66
|
+
```bash
|
|
67
|
+
mcp-conf where --client codex --name abap
|
|
68
|
+
mcp-conf where --client claude --name goose --project /path/to/project
|
|
69
|
+
mcp-conf where --client claude --name goose --all-projects
|
|
53
70
|
```
|
|
54
71
|
|
|
55
72
|
Options:
|
|
73
|
+
- Commands: `add`, `rm`, `ls`, `enable`, `disable`, `where` (first argument)
|
|
56
74
|
- `--client <name>` (repeatable): `cline`, `codex`, `claude`, `goose`, `cursor`, `windsurf`, `opencode`, `copilot`
|
|
57
75
|
- `--env <path>`: use a specific `.env` file
|
|
58
76
|
- `--mcp <destination>`: use service key destination
|
|
59
77
|
- `--name <serverName>`: MCP server name (required)
|
|
60
78
|
- `--transport <type>`: `stdio`, `sse`, or `http` (`http` maps to `streamableHttp`)
|
|
61
79
|
- `--command <bin>`: command to run (default: `mcp-abap-adt`)
|
|
80
|
+
- `--global`: write to the global user config (default)
|
|
81
|
+
- `--local`: write to the project config (supported by `cursor`, `opencode`, `copilot`, `claude`)
|
|
82
|
+
- `--all-projects`: for Claude (global scope), apply `rm/enable/disable/ls/where` across all projects
|
|
83
|
+
- `--project <path>`: for Claude (global scope), target a specific project path
|
|
62
84
|
- `--url <http(s)://...>`: required for `sse` and `http`
|
|
63
85
|
- `--header key=value`: add request header (repeatable)
|
|
64
86
|
- `--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
87
|
|
|
69
88
|
Notes:
|
|
70
|
-
-
|
|
89
|
+
- `disable` and `rm` do not require `--env` or `--mcp`.
|
|
71
90
|
- `--env`/`--mcp` are only valid for `stdio` transport. For `sse/http`, use `--url` and optional `--header`.
|
|
72
91
|
- Cursor/Copilot enable/disable are not implemented yet.
|
|
73
92
|
- Claude stores enable/disable state under `enabledMcpServers` and `disabledMcpServers` for each project.
|
|
74
|
-
-
|
|
93
|
+
- Claude enable/disable always updates `~/.claude.json` (global scope), even if you pass `--local`.
|
|
94
|
+
- New entries for Cline, Codex, Windsurf, Goose, Claude, and OpenCode are added **disabled by default**. Use `enable` to turn them on.
|
|
75
95
|
- Windsurf follows `disabled` like Cline. The configurator sets `disabled = true` for default-disabled entries.
|
|
76
|
-
-
|
|
96
|
+
- `enable`/`disable` only work if the server entry already exists. Use add commands with `--env` or `--mcp` first.
|
|
77
97
|
- Non-stdio transports are supported for Cline/Cursor/Windsurf/Claude/Goose. Codex supports `http` (streamable HTTP) but not `sse`.
|
|
78
98
|
- Codex writes custom headers under `http_headers` in `~/.codex/config.toml`.
|
|
79
99
|
- Codex HTTP entries include `startup_timeout_sec` (default: 60).
|
|
80
100
|
- `--dry-run`: print changes without writing files
|
|
81
101
|
- `--force`: overwrite existing server entry if it exists
|
|
102
|
+
- Scope defaults to `--global` (GitHub Copilot is `--local` only).
|
|
103
|
+
- For Claude, `--local` maps to the documented project scope file `./.mcp.json`.
|
|
82
104
|
|
|
83
105
|
## Config Locations
|
|
84
106
|
|
|
85
107
|
Paths are client-specific and OS-dependent. The installer writes config files in:
|
|
86
108
|
|
|
109
|
+
Global (default) locations:
|
|
87
110
|
- **Cline**:
|
|
88
111
|
- Linux/macOS: `~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`
|
|
89
112
|
- Windows: `%APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json`
|
|
@@ -104,8 +127,16 @@ Paths are client-specific and OS-dependent. The installer writes config files in
|
|
|
104
127
|
- **Windsurf**:
|
|
105
128
|
- Linux/macOS: `~/.codeium/windsurf/mcp_config.json`
|
|
106
129
|
- Windows: `%USERPROFILE%\.codeium\windsurf\mcp_config.json`
|
|
130
|
+
- **OpenCode**:
|
|
131
|
+
- Linux/macOS: `~/.config/opencode/opencode.json`
|
|
132
|
+
- Windows: `%APPDATA%\opencode\opencode.json`
|
|
133
|
+
|
|
134
|
+
Local (project) locations:
|
|
135
|
+
- **Claude Code**:
|
|
136
|
+
- Project: `./.mcp.json`
|
|
137
|
+
- **Cursor**:
|
|
138
|
+
- Project: `./.cursor/mcp.json`
|
|
107
139
|
- **OpenCode**:
|
|
108
140
|
- Project: `./opencode.json` (uses `mcp.<name>` entries with `enabled: true|false`)
|
|
109
141
|
- **GitHub Copilot**:
|
|
110
142
|
- Project: `./.vscode/mcp.json` (uses `servers.<name>` entries)
|
|
111
|
-
|
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.3",
|
|
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": {
|