@mcp-abap-adt/configurator 0.2.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # MCP ABAP ADT Configurator
2
+ [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua)
2
3
 
3
4
  Auto-configure MCP clients for `mcp-abap-adt` and `mcp-abap-adt-proxy`.
4
5
 
@@ -26,6 +27,14 @@ mcp-conf --client crush --name abap --transport http --url http://localhost:3000
26
27
  mcp-conf tui
27
28
  ```
28
29
 
30
+ ### Claude: CLI vs Desktop vs Connectors
31
+
32
+ Anthropic ships several "Claude" products. `mcp-conf` configures MCP servers for two of them:
33
+
34
+ - `--client claude-cli` (alias: `--client claude`) — **Claude Code CLI**. Writes to `~/.claude.json` (global) or `./.mcp.json` (local). Supports stdio / http / sse. No restart needed.
35
+ - `--client claude-desktop` — **Claude Desktop GUI** (macOS / Windows). Writes to `claude_desktop_config.json`. Supports **stdio only**. You must restart Claude Desktop after changes. Linux is not officially supported by Anthropic.
36
+ - **claude.ai Custom Connectors** (web UI) — cloud-side remote MCP, HTTPS only. **No public API**; add them manually via Settings → Connectors. `mcp-conf` cannot touch these.
37
+
29
38
  ## TUI
30
39
 
31
40
  `mcp-conf tui` starts an interactive wizard (`ls`/`show`/`add`/`update`/`rm`/`enable`/`disable`).
@@ -8,7 +8,8 @@ const { spawnSync } = require("node:child_process");
8
8
  const CLIENTS = [
9
9
  { name: "cline", message: "Cline" },
10
10
  { name: "codex", message: "Codex" },
11
- { name: "claude", message: "Claude" },
11
+ { name: "claude-cli", message: "Claude CLI" },
12
+ { name: "claude-desktop", message: "Claude Desktop" },
12
13
  { name: "goose", message: "Goose" },
13
14
  { name: "cursor", message: "Cursor" },
14
15
  { name: "windsurf", message: "Windsurf" },
@@ -267,7 +268,9 @@ function getSupportedScopes(clientName) {
267
268
  if (clientName === "copilot" || clientName === "gemini") {
268
269
  return ["local"];
269
270
  }
270
- if (["cline", "goose", "windsurf", "antigravity", "qwen"].includes(clientName)) {
271
+ if (
272
+ ["cline", "goose", "windsurf", "antigravity", "qwen", "claude-desktop"].includes(clientName)
273
+ ) {
271
274
  return ["global"];
272
275
  }
273
276
  return ["global", "local"];
@@ -277,7 +280,7 @@ async function configureScope(result, clientName) {
277
280
  result.allProjects = false;
278
281
  result.projectPath = null;
279
282
 
280
- if (clientName === "claude") {
283
+ if (clientName === "claude-cli") {
281
284
  result.scope = await askSelect("Scope", ["global", "local"]);
282
285
  if (result.scope === "local") {
283
286
  return;
@@ -304,6 +307,9 @@ function getSupportedTransports(clientName) {
304
307
  if (clientName === "codex") {
305
308
  return ["stdio", "http"];
306
309
  }
310
+ if (clientName === "claude-desktop") {
311
+ return ["stdio"];
312
+ }
307
313
  return ["stdio", "sse", "http"];
308
314
  }
309
315
 
package/bin/mcp-conf.js CHANGED
@@ -299,7 +299,7 @@ const serverArgs = serverArgsRaw.filter(Boolean);
299
299
 
300
300
  for (const client of options.clients) {
301
301
  const scope = options.scope || getDefaultScope(client);
302
- if (options.projectPath && client !== "claude") {
302
+ if (options.projectPath && client !== "claude-cli") {
303
303
  fail("--project is only supported for Claude.");
304
304
  }
305
305
  switch (client) {
@@ -334,7 +334,7 @@ for (const client of options.clients) {
334
334
  );
335
335
  }
336
336
  break;
337
- case "claude": {
337
+ case "claude-cli": {
338
338
  requireScope("Claude", ["global", "local"], scope);
339
339
  const claudeToggleScope = options.toggle ? "global" : scope;
340
340
  if (options.allProjects && claudeToggleScope !== "global") {
@@ -374,6 +374,35 @@ for (const client of options.clients) {
374
374
  }
375
375
  break;
376
376
  }
377
+ case "claude-desktop": {
378
+ requireScope("ClaudeDesktop", ["global"], scope);
379
+ if (options.transport !== "stdio") {
380
+ fail(
381
+ "claude-desktop only supports stdio transport. For remote MCP, add a Custom Connector in Claude Desktop Settings → Connectors.",
382
+ );
383
+ }
384
+ if (options.allProjects || options.projectPath) {
385
+ fail("--all-projects and --project are not supported for claude-desktop.");
386
+ }
387
+ const cdPath = getClaudeDesktopPath(platform, home, appData);
388
+ if (options.list) {
389
+ listClaudeDesktopConfig(cdPath);
390
+ } else if (options.show) {
391
+ showClaudeDesktopConfig(cdPath, options.name);
392
+ } else if (options.where) {
393
+ whereClaudeDesktopConfig(cdPath, options.name);
394
+ } else if (options.remove) {
395
+ removeClaudeDesktopConfig(cdPath, options.name);
396
+ printClaudeDesktopRestartNotice();
397
+ } else if (options.toggle) {
398
+ toggleClaudeDesktopConfig(cdPath, options.name, options.disabled);
399
+ printClaudeDesktopRestartNotice();
400
+ } else {
401
+ writeClaudeDesktopConfig(cdPath, options.name, serverArgs);
402
+ printClaudeDesktopRestartNotice();
403
+ }
404
+ break;
405
+ }
377
406
  case "goose":
378
407
  requireScope("Goose", ["global"], scope);
379
408
  if (options.list) {
@@ -516,7 +545,13 @@ function normalizeClientName(clientName) {
516
545
  return clientName;
517
546
  }
518
547
  const normalized = clientName.toLowerCase();
519
- return normalized === "kilo" ? "opencode" : normalized;
548
+ if (normalized === "kilo") {
549
+ return "opencode";
550
+ }
551
+ if (normalized === "claude") {
552
+ return "claude-cli";
553
+ }
554
+ return normalized;
520
555
  }
521
556
 
522
557
  function runTuiWizard(opts) {
@@ -603,6 +638,22 @@ function getClaudePath(homeDir, scopeValue) {
603
638
  return path.join(homeDir, ".claude.json");
604
639
  }
605
640
 
641
+ function getClaudeDesktopPath(platformValue, homeDir, appDataDir) {
642
+ if (platformValue === "darwin") {
643
+ return path.join(
644
+ homeDir,
645
+ "Library",
646
+ "Application Support",
647
+ "Claude",
648
+ "claude_desktop_config.json",
649
+ );
650
+ }
651
+ if (platformValue === "win32") {
652
+ return path.join(appDataDir, "Claude", "claude_desktop_config.json");
653
+ }
654
+ fail("Claude Desktop is not officially available on Linux. Use --client claude-cli instead.");
655
+ }
656
+
606
657
  function getGoosePath(platformValue, homeDir, appDataDir) {
607
658
  if (platformValue === "win32") {
608
659
  return path.join(appDataDir, "Block", "goose", "config", "config.yaml");
@@ -713,7 +764,7 @@ function resolveProjectSelector(data, projectPath) {
713
764
  }
714
765
 
715
766
  function getDefaultDisabled(clientType) {
716
- return ["cline", "codex", "windsurf", "goose", "claude", "opencode", "crush"].includes(
767
+ return ["cline", "codex", "windsurf", "goose", "claude-cli", "opencode", "crush"].includes(
717
768
  clientType,
718
769
  );
719
770
  }
@@ -923,8 +974,7 @@ function writeJsonConfig(filePath, serverName, argsArray, clientType) {
923
974
  function writeClaudeConfig(filePath, serverName, argsArray) {
924
975
  ensureDir(filePath);
925
976
  const data = readJson(filePath);
926
- const isDesktopConfig =
927
- filePath.endsWith(".claude.json") || filePath.endsWith("claude_desktop_config.json");
977
+ const isDesktopConfig = filePath.endsWith(".claude.json");
928
978
  const resolveProjectKey = () => resolveProjectSelector(data, options.projectPath);
929
979
  const updateClaudeMcpLists = (projectNode) => {
930
980
  projectNode.enabledMcpServers = projectNode.enabledMcpServers || [];
@@ -947,7 +997,7 @@ function writeClaudeConfig(filePath, serverName, argsArray) {
947
997
  const disabled = projectNode.disabledMcpServers;
948
998
  const shouldDisable = options.toggle
949
999
  ? options.disabled
950
- : options.disabled || getDefaultDisabled("claude");
1000
+ : options.disabled || getDefaultDisabled("claude-cli");
951
1001
  const removeFrom = (list) => {
952
1002
  const idx = list.indexOf(serverName);
953
1003
  if (idx >= 0) {
@@ -1111,6 +1161,116 @@ function writeClaudeConfig(filePath, serverName, argsArray) {
1111
1161
  writeFile(filePath, JSON.stringify(data, null, 2));
1112
1162
  }
1113
1163
 
1164
+ function writeClaudeDesktopConfig(filePath, serverName, argsArray) {
1165
+ ensureDir(filePath);
1166
+ const data = readJson(filePath);
1167
+ data.mcpServers = data.mcpServers || {};
1168
+ data._disabled = data._disabled || {};
1169
+ const exists = data.mcpServers[serverName] || data._disabled[serverName];
1170
+ if (exists && !options.force) {
1171
+ fail(`Server "${serverName}" already exists in ${filePath}. Use --force to overwrite.`);
1172
+ }
1173
+ const entry = {
1174
+ command: options.command,
1175
+ args: argsArray,
1176
+ timeout: options.timeout,
1177
+ env: {},
1178
+ };
1179
+ if (data._disabled[serverName]) {
1180
+ // Preserve disabled state on update.
1181
+ data._disabled[serverName] = entry;
1182
+ } else {
1183
+ data.mcpServers[serverName] = entry;
1184
+ }
1185
+ writeFile(filePath, JSON.stringify(data, null, 2));
1186
+ }
1187
+
1188
+ function removeClaudeDesktopConfig(filePath, serverName) {
1189
+ const data = readJson(filePath);
1190
+ const inEnabled = data.mcpServers?.[serverName];
1191
+ const inDisabled = data._disabled?.[serverName];
1192
+ if (!inEnabled && !inDisabled) {
1193
+ fail(`Server "${serverName}" not found in ${filePath}.`);
1194
+ }
1195
+ if (inEnabled) {
1196
+ delete data.mcpServers[serverName];
1197
+ }
1198
+ if (inDisabled) {
1199
+ delete data._disabled[serverName];
1200
+ }
1201
+ writeFile(filePath, JSON.stringify(data, null, 2));
1202
+ }
1203
+
1204
+ function toggleClaudeDesktopConfig(filePath, serverName, shouldDisable) {
1205
+ const data = readJson(filePath);
1206
+ data.mcpServers = data.mcpServers || {};
1207
+ data._disabled = data._disabled || {};
1208
+ if (shouldDisable) {
1209
+ if (data._disabled[serverName]) {
1210
+ fail(`Server "${serverName}" is already disabled in ${filePath}.`);
1211
+ }
1212
+ if (!data.mcpServers[serverName]) {
1213
+ fail(`Server "${serverName}" not found in ${filePath}.`);
1214
+ }
1215
+ data._disabled[serverName] = data.mcpServers[serverName];
1216
+ delete data.mcpServers[serverName];
1217
+ } else {
1218
+ if (data.mcpServers[serverName]) {
1219
+ fail(`Server "${serverName}" is already enabled in ${filePath}.`);
1220
+ }
1221
+ if (!data._disabled[serverName]) {
1222
+ fail(`Server "${serverName}" not found in ${filePath}.`);
1223
+ }
1224
+ data.mcpServers[serverName] = data._disabled[serverName];
1225
+ delete data._disabled[serverName];
1226
+ }
1227
+ writeFile(filePath, JSON.stringify(data, null, 2));
1228
+ }
1229
+
1230
+ function listClaudeDesktopConfig(filePath) {
1231
+ const data = readJson(filePath);
1232
+ const enabled = Object.keys(data.mcpServers || {});
1233
+ const disabled = Object.keys(data._disabled || {});
1234
+ const header = `# ${filePath}`;
1235
+ process.stdout.write(`${header}\n`);
1236
+ if (enabled.length === 0 && disabled.length === 0) {
1237
+ process.stdout.write("- (none)\n");
1238
+ return;
1239
+ }
1240
+ for (const name of enabled.sort()) {
1241
+ process.stdout.write(`- ${name}\n`);
1242
+ }
1243
+ for (const name of disabled.sort()) {
1244
+ process.stdout.write(`- ${name} (disabled)\n`);
1245
+ }
1246
+ }
1247
+
1248
+ function showClaudeDesktopConfig(filePath, serverName) {
1249
+ const data = readJson(filePath);
1250
+ const entry = data.mcpServers?.[serverName] || data._disabled?.[serverName];
1251
+ if (!entry) {
1252
+ fail(`Server "${serverName}" not found in ${filePath}.`);
1253
+ }
1254
+ const details = normalizeServerDetails("claude-desktop", serverName, entry);
1255
+ if (data._disabled?.[serverName]) {
1256
+ details.disabled = true;
1257
+ }
1258
+ outputShow(filePath, serverName, details);
1259
+ }
1260
+
1261
+ function whereClaudeDesktopConfig(filePath, serverName) {
1262
+ const data = readJson(filePath);
1263
+ const found = Boolean(data.mcpServers?.[serverName] || data._disabled?.[serverName]);
1264
+ if (!found) {
1265
+ fail(`Server "${serverName}" not found in ${filePath}.`);
1266
+ }
1267
+ outputWhere(filePath, serverName, found);
1268
+ }
1269
+
1270
+ function printClaudeDesktopRestartNotice() {
1271
+ process.stdout.write("Note: Restart Claude Desktop for changes to take effect.\n");
1272
+ }
1273
+
1114
1274
  function resolveClaudeProjectKey(data, projectPath = process.cwd()) {
1115
1275
  const desired = projectPath;
1116
1276
  if (!data.projects || data.projects[desired]) {
@@ -1305,8 +1465,7 @@ function listGooseConfig(filePath) {
1305
1465
 
1306
1466
  function listClaudeConfig(filePath, allProjects, projectPath) {
1307
1467
  const data = readJson(filePath);
1308
- const isDesktopConfig =
1309
- filePath.endsWith(".claude.json") || filePath.endsWith("claude_desktop_config.json");
1468
+ const isDesktopConfig = filePath.endsWith(".claude.json");
1310
1469
  if (isDesktopConfig) {
1311
1470
  const projects = Object.keys(data.projects || {});
1312
1471
  if (allProjects) {
@@ -1372,8 +1531,7 @@ function whereGooseConfig(filePath, serverName) {
1372
1531
 
1373
1532
  function whereClaudeConfig(filePath, serverName, allProjects, projectPath) {
1374
1533
  const data = readJson(filePath);
1375
- const isDesktopConfig =
1376
- filePath.endsWith(".claude.json") || filePath.endsWith("claude_desktop_config.json");
1534
+ const isDesktopConfig = filePath.endsWith(".claude.json");
1377
1535
  if (isDesktopConfig) {
1378
1536
  const projects = Object.keys(data.projects || {});
1379
1537
  if (allProjects) {
@@ -1461,8 +1619,7 @@ function showGooseConfig(filePath, serverName) {
1461
1619
 
1462
1620
  function showClaudeConfig(filePath, serverName, allProjects, projectPath) {
1463
1621
  const data = readJson(filePath);
1464
- const isDesktopConfig =
1465
- filePath.endsWith(".claude.json") || filePath.endsWith("claude_desktop_config.json");
1622
+ const isDesktopConfig = filePath.endsWith(".claude.json");
1466
1623
  if (isDesktopConfig) {
1467
1624
  const projects = Object.keys(data.projects || {});
1468
1625
  if (allProjects) {
@@ -1475,7 +1632,7 @@ function showClaudeConfig(filePath, serverName, allProjects, projectPath) {
1475
1632
  options.outputNormalized
1476
1633
  ? {
1477
1634
  project: key,
1478
- ...normalizeServerDetails("claude", serverName, store[serverName]),
1635
+ ...normalizeServerDetails("claude-cli", serverName, store[serverName]),
1479
1636
  }
1480
1637
  : {
1481
1638
  project: key,
@@ -1508,7 +1665,7 @@ function showClaudeConfig(filePath, serverName, allProjects, projectPath) {
1508
1665
  fail(`Server "${serverName}" not found for ${projectKey}.`);
1509
1666
  }
1510
1667
  const details = options.outputNormalized
1511
- ? normalizeServerDetails("claude", serverName, entry, projectKey)
1668
+ ? normalizeServerDetails("claude-cli", serverName, entry, projectKey)
1512
1669
  : cloneJsonLike(entry);
1513
1670
  outputShow(filePath, serverName, details, projectKey);
1514
1671
  return;
@@ -1519,7 +1676,7 @@ function showClaudeConfig(filePath, serverName, allProjects, projectPath) {
1519
1676
  fail(`Server "${serverName}" not found in ${filePath}.`);
1520
1677
  }
1521
1678
  const details = options.outputNormalized
1522
- ? normalizeServerDetails("claude", serverName, entry)
1679
+ ? normalizeServerDetails("claude-cli", serverName, entry)
1523
1680
  : cloneJsonLike(entry);
1524
1681
  outputShow(filePath, serverName, details);
1525
1682
  }
@@ -1866,6 +2023,9 @@ Notes:
1866
2023
  For Claude, --local maps to the project scope file ./.mcp.json.
1867
2024
  For Codex, --local writes to ./.codex/config.toml.
1868
2025
  For Gemini, --local writes to ./.gemini/settings.json.
2026
+
2027
+ Aliases:
2028
+ claude → claude-cli (Claude Code CLI)
1869
2029
  `);
1870
2030
  return;
1871
2031
  }
@@ -1877,7 +2037,7 @@ Usage:
1877
2037
  mcp-conf add --client <name> --name <serverName> [--env <name> | --env-path <path> | --session-env | --mcp <dest>] [options]
1878
2038
 
1879
2039
  Options:
1880
- --client <name> cline | codex | claude | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
2040
+ --client <name> cline | codex | claude-cli | claude-desktop | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
1881
2041
  --name <serverName> required MCP server name key
1882
2042
  --env <name> env profile name (stdio only), writes --env=<name>
1883
2043
  --env-path <path> .env path (stdio only)
@@ -1906,7 +2066,7 @@ Usage:
1906
2066
  mcp-conf rm --client <name> --name <serverName> [options]
1907
2067
 
1908
2068
  Options:
1909
- --client <name> cline | codex | claude | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
2069
+ --client <name> cline | codex | claude-cli | claude-desktop | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
1910
2070
  --name <serverName> required MCP server name key
1911
2071
  --global write to global user config (default)
1912
2072
  --local write to project config (where supported)
@@ -1926,7 +2086,7 @@ Usage:
1926
2086
  mcp-conf ls --client <name> [options]
1927
2087
 
1928
2088
  Options:
1929
- --client <name> cline | codex | claude | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
2089
+ --client <name> cline | codex | claude-cli | claude-desktop | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
1930
2090
  --global write to global user config (default)
1931
2091
  --local write to project config (where supported)
1932
2092
  --all-projects Claude global: list across all projects
@@ -1944,7 +2104,7 @@ Usage:
1944
2104
  mcp-conf enable --client <name> --name <serverName> [options]
1945
2105
 
1946
2106
  Options:
1947
- --client <name> cline | codex | claude | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
2107
+ --client <name> cline | codex | claude-cli | claude-desktop | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
1948
2108
  --name <serverName> required MCP server name key
1949
2109
  --global write to global user config (default)
1950
2110
  --local write to project config (where supported)
@@ -1964,7 +2124,7 @@ Usage:
1964
2124
  mcp-conf disable --client <name> --name <serverName> [options]
1965
2125
 
1966
2126
  Options:
1967
- --client <name> cline | codex | claude | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
2127
+ --client <name> cline | codex | claude-cli | claude-desktop | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
1968
2128
  --name <serverName> required MCP server name key
1969
2129
  --global write to global user config (default)
1970
2130
  --local write to project config (where supported)
@@ -1984,7 +2144,7 @@ Usage:
1984
2144
  mcp-conf where --client <name> --name <serverName> [options]
1985
2145
 
1986
2146
  Options:
1987
- --client <name> cline | codex | claude | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
2147
+ --client <name> cline | codex | claude-cli | claude-desktop | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
1988
2148
  --name <serverName> required MCP server name key
1989
2149
  --global write to global user config (default)
1990
2150
  --local write to project config (where supported)
@@ -2003,7 +2163,7 @@ Usage:
2003
2163
  mcp-conf show --client <name> --name <serverName> [options]
2004
2164
 
2005
2165
  Options:
2006
- --client <name> cline | codex | claude | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
2166
+ --client <name> cline | codex | claude-cli | claude-desktop | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
2007
2167
  --name <serverName> required MCP server name key
2008
2168
  --global read from global user config (default)
2009
2169
  --local read from project config (where supported)
@@ -2024,7 +2184,7 @@ Usage:
2024
2184
  mcp-conf update --client <name> --name <serverName> [--env <name> | --env-path <path> | --session-env | --mcp <dest>] [options]
2025
2185
 
2026
2186
  Options:
2027
- --client <name> cline | codex | claude | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
2187
+ --client <name> cline | codex | claude-cli | claude-desktop | goose | cursor | windsurf | opencode | kilo | copilot | antigravity | qwen | gemini | crush (repeatable)
2028
2188
  --name <serverName> required MCP server name key
2029
2189
  --env <name> env profile name (stdio only), writes --env=<name>
2030
2190
  --env-path <path> .env path (stdio only)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-abap-adt/configurator",
3
- "version": "0.2.2",
3
+ "version": "1.0.0",
4
4
  "description": "MCP client configurator for mcp-abap-adt and mcp-abap-adt-proxy",
5
5
  "license": "MIT",
6
6
  "repository": {