@mcp-abap-adt/core 2.1.8 → 2.2.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/CHANGELOG.md +5 -3
- package/README.md +2 -42
- package/bin/mcp-abap-adt-configure.js +514 -0
- package/docs/README.md +2 -0
- package/docs/deployment/MCP_REGISTRY.md +34 -0
- package/docs/deployment/README.md +5 -0
- package/docs/installation/CLIENT_INSTALLERS.md +91 -0
- package/package.json +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
-
## [2.
|
|
5
|
+
## [2.2.0] - 2026-02-09
|
|
6
6
|
### Added
|
|
7
7
|
- **MCP Registry metadata**: Added `server.json` and `mcpName` for registry publishing.
|
|
8
|
-
- **
|
|
8
|
+
- **Client configurator**: Added `mcp-abap-adt-configure` to add/enable/disable/remove MCP entries across clients.
|
|
9
|
+
- **Auto-config docs**: Added `docs/installation/CLIENT_INSTALLERS.md` with usage and common tasks.
|
|
9
10
|
|
|
10
11
|
### Changed
|
|
11
12
|
- **Default logger loading**: Lazy-load logger to avoid bundler issues with optional transports.
|
|
12
|
-
- **
|
|
13
|
+
- **Claude config**: Write MCP settings under `projects.<full_path>.mcpServers` for Claude CLI on Linux.
|
|
14
|
+
- **Config defaults**: New entries for Cline/Codex/Windsurf/Goose are disabled by default; enable explicitly.
|
|
13
15
|
|
|
14
16
|
## [2.1.7] - 2026-01-29
|
|
15
17
|
### Fixed
|
package/README.md
CHANGED
|
@@ -39,49 +39,9 @@ await server.connect(transport);
|
|
|
39
39
|
2. **Configure**: See [Client Configuration](docs/user-guide/CLIENT_CONFIGURATION.md)
|
|
40
40
|
3. **Use**: See [Available Tools](docs/user-guide/AVAILABLE_TOOLS.md)
|
|
41
41
|
|
|
42
|
-
##
|
|
42
|
+
## MCP Registry
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
Smithery requires exactly one of these config fields:
|
|
47
|
-
- `envPath` → maps to `--env=<path>` (use a specific `.env` file)
|
|
48
|
-
- `mcpDestination` → maps to `--mcp=<destination>` (use service keys/auth-broker)
|
|
49
|
-
|
|
50
|
-
Minimal parameter docs:
|
|
51
|
-
- `--env` is documented in [CLI Options](docs/user-guide/CLI_OPTIONS.md#environment-file-configuration)
|
|
52
|
-
- `--mcp` (auth-broker destination) is documented in [Client Configuration](docs/user-guide/CLIENT_CONFIGURATION.md#destination-based-authentication)
|
|
53
|
-
|
|
54
|
-
### Smithery CLI examples
|
|
55
|
-
|
|
56
|
-
**Codex:**
|
|
57
|
-
```bash
|
|
58
|
-
npx -y @smithery/cli install mcp-abap-adt --client codex
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
**Cline:**
|
|
62
|
-
```bash
|
|
63
|
-
npx -y @smithery/cli install mcp-abap-adt --client cline
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
**Claude:**
|
|
67
|
-
```bash
|
|
68
|
-
npx -y @smithery/cli install mcp-abap-adt --client claude
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
**Crush:**
|
|
72
|
-
```bash
|
|
73
|
-
npx -y @smithery/cli install mcp-abap-adt --client crush
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
**Goose:**
|
|
77
|
-
```bash
|
|
78
|
-
npx -y @smithery/cli install mcp-abap-adt --client goose
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
If a client name is not accepted by your CLI version, run:
|
|
82
|
-
```bash
|
|
83
|
-
npx -y @smithery/cli install --help
|
|
84
|
-
```
|
|
44
|
+
Published in the official MCP Registry. See `docs/deployment/MCP_REGISTRY.md` for full details.
|
|
85
45
|
|
|
86
46
|
## Features
|
|
87
47
|
|
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const os = require("os");
|
|
6
|
+
|
|
7
|
+
let yaml;
|
|
8
|
+
try {
|
|
9
|
+
// Optional dependency already in package.json
|
|
10
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
11
|
+
yaml = require("yaml");
|
|
12
|
+
} catch {
|
|
13
|
+
yaml = null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let toml;
|
|
17
|
+
try {
|
|
18
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
19
|
+
toml = require("@iarna/toml");
|
|
20
|
+
} catch {
|
|
21
|
+
toml = null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const args = process.argv.slice(2);
|
|
25
|
+
const options = {
|
|
26
|
+
clients: [],
|
|
27
|
+
envPath: null,
|
|
28
|
+
mcpDestination: null,
|
|
29
|
+
name: null,
|
|
30
|
+
transport: "stdio",
|
|
31
|
+
command: "mcp-abap-adt",
|
|
32
|
+
dryRun: false,
|
|
33
|
+
force: false,
|
|
34
|
+
project: null,
|
|
35
|
+
disabled: false,
|
|
36
|
+
toggle: false,
|
|
37
|
+
remove: false,
|
|
38
|
+
configPath: null,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
42
|
+
printHelp();
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
47
|
+
const arg = args[i];
|
|
48
|
+
if (arg === "--client") {
|
|
49
|
+
options.clients.push(args[i + 1]);
|
|
50
|
+
i += 1;
|
|
51
|
+
} else if (arg === "--env") {
|
|
52
|
+
options.envPath = args[i + 1];
|
|
53
|
+
i += 1;
|
|
54
|
+
} else if (arg === "--mcp") {
|
|
55
|
+
options.mcpDestination = args[i + 1];
|
|
56
|
+
i += 1;
|
|
57
|
+
} else if (arg === "--name") {
|
|
58
|
+
options.name = args[i + 1];
|
|
59
|
+
i += 1;
|
|
60
|
+
} else if (arg === "--transport") {
|
|
61
|
+
options.transport = args[i + 1];
|
|
62
|
+
i += 1;
|
|
63
|
+
} else if (arg === "--command") {
|
|
64
|
+
options.command = args[i + 1];
|
|
65
|
+
i += 1;
|
|
66
|
+
} else if (arg === "--project") {
|
|
67
|
+
options.project = args[i + 1];
|
|
68
|
+
i += 1;
|
|
69
|
+
} else if (arg === "--config") {
|
|
70
|
+
options.configPath = args[i + 1];
|
|
71
|
+
i += 1;
|
|
72
|
+
} else if (arg === "--disable") {
|
|
73
|
+
options.disabled = true;
|
|
74
|
+
options.toggle = true;
|
|
75
|
+
} else if (arg === "--enable") {
|
|
76
|
+
options.disabled = false;
|
|
77
|
+
options.toggle = true;
|
|
78
|
+
} else if (arg === "--remove") {
|
|
79
|
+
options.remove = true;
|
|
80
|
+
} else if (arg === "--dry-run") {
|
|
81
|
+
options.dryRun = true;
|
|
82
|
+
} else if (arg === "--force") {
|
|
83
|
+
options.force = true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (options.clients.length === 0) {
|
|
88
|
+
fail("Provide at least one --client.");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!options.name) {
|
|
92
|
+
fail("Provide --name <serverName> (required).");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (options.transport !== "stdio") {
|
|
96
|
+
fail("Only --transport stdio is supported by this installer.");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const requiresConnectionParams = !options.remove && !options.toggle;
|
|
100
|
+
|
|
101
|
+
if (requiresConnectionParams) {
|
|
102
|
+
if (!options.envPath && !options.mcpDestination) {
|
|
103
|
+
fail("Provide either --env <path> or --mcp <destination>.");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (options.envPath && options.mcpDestination) {
|
|
107
|
+
fail("Use only one of --env or --mcp.");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const platform = process.platform;
|
|
112
|
+
const home = os.homedir();
|
|
113
|
+
const appData =
|
|
114
|
+
process.env.APPDATA || path.join(home, "AppData", "Roaming");
|
|
115
|
+
const userProfile = process.env.USERPROFILE || home;
|
|
116
|
+
|
|
117
|
+
const serverArgsRaw = options.remove || options.toggle
|
|
118
|
+
? []
|
|
119
|
+
: [
|
|
120
|
+
`--transport=${options.transport}`,
|
|
121
|
+
options.envPath
|
|
122
|
+
? `--env=${options.envPath}`
|
|
123
|
+
: options.mcpDestination
|
|
124
|
+
? `--mcp=${options.mcpDestination.toLowerCase()}`
|
|
125
|
+
: undefined,
|
|
126
|
+
];
|
|
127
|
+
const serverArgs = serverArgsRaw.filter(Boolean);
|
|
128
|
+
|
|
129
|
+
for (const client of options.clients) {
|
|
130
|
+
switch (client) {
|
|
131
|
+
case "cline":
|
|
132
|
+
writeJsonConfig(
|
|
133
|
+
getClinePath(platform, home, appData),
|
|
134
|
+
options.name,
|
|
135
|
+
serverArgs,
|
|
136
|
+
"cline"
|
|
137
|
+
);
|
|
138
|
+
break;
|
|
139
|
+
case "codex":
|
|
140
|
+
writeCodexConfig(getCodexPath(platform, home, userProfile), options.name, serverArgs);
|
|
141
|
+
break;
|
|
142
|
+
case "claude":
|
|
143
|
+
writeClaudeConfig(
|
|
144
|
+
getClaudePath(platform, home, appData, options.configPath),
|
|
145
|
+
options.name,
|
|
146
|
+
serverArgs
|
|
147
|
+
);
|
|
148
|
+
break;
|
|
149
|
+
case "goose":
|
|
150
|
+
writeGooseConfig(
|
|
151
|
+
getGoosePath(platform, home, appData),
|
|
152
|
+
options.name,
|
|
153
|
+
serverArgs
|
|
154
|
+
);
|
|
155
|
+
break;
|
|
156
|
+
case "cursor":
|
|
157
|
+
writeJsonConfig(
|
|
158
|
+
getCursorPath(platform, home, userProfile),
|
|
159
|
+
options.name,
|
|
160
|
+
serverArgs,
|
|
161
|
+
"cursor"
|
|
162
|
+
);
|
|
163
|
+
break;
|
|
164
|
+
case "windsurf":
|
|
165
|
+
writeJsonConfig(
|
|
166
|
+
getWindsurfPath(platform, home, userProfile),
|
|
167
|
+
options.name,
|
|
168
|
+
serverArgs,
|
|
169
|
+
"windsurf"
|
|
170
|
+
);
|
|
171
|
+
break;
|
|
172
|
+
default:
|
|
173
|
+
fail(`Unknown client: ${client}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function getClinePath(platformValue, homeDir, appDataDir) {
|
|
178
|
+
if (platformValue === "win32") {
|
|
179
|
+
return path.join(
|
|
180
|
+
appDataDir,
|
|
181
|
+
"Code",
|
|
182
|
+
"User",
|
|
183
|
+
"globalStorage",
|
|
184
|
+
"saoudrizwan.claude-dev",
|
|
185
|
+
"settings",
|
|
186
|
+
"cline_mcp_settings.json"
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
return path.join(
|
|
190
|
+
homeDir,
|
|
191
|
+
".config",
|
|
192
|
+
"Code",
|
|
193
|
+
"User",
|
|
194
|
+
"globalStorage",
|
|
195
|
+
"saoudrizwan.claude-dev",
|
|
196
|
+
"settings",
|
|
197
|
+
"cline_mcp_settings.json"
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function getCodexPath(platformValue, homeDir, userProfileDir) {
|
|
202
|
+
if (platformValue === "win32") {
|
|
203
|
+
return path.join(userProfileDir, ".codex", "config.toml");
|
|
204
|
+
}
|
|
205
|
+
return path.join(homeDir, ".codex", "config.toml");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function getClaudePath(platformValue, homeDir, appDataDir, overridePath) {
|
|
209
|
+
if (overridePath) {
|
|
210
|
+
return overridePath;
|
|
211
|
+
}
|
|
212
|
+
if (platformValue === "darwin") {
|
|
213
|
+
return path.join(
|
|
214
|
+
homeDir,
|
|
215
|
+
"Library",
|
|
216
|
+
"Application Support",
|
|
217
|
+
"Claude",
|
|
218
|
+
"claude_desktop_config.json"
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
if (platformValue === "win32") {
|
|
222
|
+
return path.join(appDataDir, "Claude", "claude_desktop_config.json");
|
|
223
|
+
}
|
|
224
|
+
return path.join(homeDir, ".claude.json");
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function getGoosePath(platformValue, homeDir, appDataDir) {
|
|
228
|
+
if (platformValue === "win32") {
|
|
229
|
+
return path.join(appDataDir, "Block", "goose", "config", "config.yaml");
|
|
230
|
+
}
|
|
231
|
+
return path.join(homeDir, ".config", "goose", "config.yaml");
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function getCursorPath(_platformValue, homeDir, userProfileDir) {
|
|
235
|
+
const base = _platformValue === "win32" ? userProfileDir : homeDir;
|
|
236
|
+
return path.join(base, ".cursor", "mcp.json");
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function getWindsurfPath(platformValue, homeDir, userProfileDir) {
|
|
240
|
+
if (platformValue === "win32") {
|
|
241
|
+
return path.join(userProfileDir, ".codeium", "windsurf", "mcp_config.json");
|
|
242
|
+
}
|
|
243
|
+
return path.join(homeDir, ".codeium", "windsurf", "mcp_config.json");
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function getDefaultDisabled(clientType) {
|
|
247
|
+
return ["cline", "codex", "windsurf", "goose"].includes(clientType);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function writeJsonConfig(filePath, serverName, argsArray, clientType) {
|
|
251
|
+
ensureDir(filePath);
|
|
252
|
+
const data = readJson(filePath);
|
|
253
|
+
data.mcpServers = data.mcpServers || {};
|
|
254
|
+
if (options.toggle && clientType === "cursor") {
|
|
255
|
+
fail("Cursor does not support enable/disable. Use --remove instead.");
|
|
256
|
+
}
|
|
257
|
+
if (options.toggle) {
|
|
258
|
+
if (!data.mcpServers[serverName]) {
|
|
259
|
+
fail(`Server "${serverName}" not found in ${filePath}.`);
|
|
260
|
+
}
|
|
261
|
+
data.mcpServers[serverName] = {
|
|
262
|
+
...data.mcpServers[serverName],
|
|
263
|
+
disabled: options.disabled || undefined,
|
|
264
|
+
};
|
|
265
|
+
writeFile(filePath, JSON.stringify(data, null, 2));
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (options.remove) {
|
|
269
|
+
if (!data.mcpServers[serverName]) {
|
|
270
|
+
fail(`Server "${serverName}" not found in ${filePath}.`);
|
|
271
|
+
}
|
|
272
|
+
delete data.mcpServers[serverName];
|
|
273
|
+
writeFile(filePath, JSON.stringify(data, null, 2));
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (data.mcpServers[serverName] && !options.force) {
|
|
277
|
+
fail(
|
|
278
|
+
`Server "${serverName}" already exists in ${filePath}. Use --force to overwrite.`
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
data.mcpServers[serverName] = {
|
|
282
|
+
command: options.command,
|
|
283
|
+
args: argsArray,
|
|
284
|
+
disabled:
|
|
285
|
+
options.disabled || (getDefaultDisabled(clientType) ? true : undefined),
|
|
286
|
+
};
|
|
287
|
+
writeFile(filePath, JSON.stringify(data, null, 2));
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function writeClaudeConfig(filePath, serverName, argsArray) {
|
|
291
|
+
ensureDir(filePath);
|
|
292
|
+
const data = readJson(filePath);
|
|
293
|
+
if (!options.project) {
|
|
294
|
+
options.project = process.cwd();
|
|
295
|
+
}
|
|
296
|
+
data.projects = data.projects || {};
|
|
297
|
+
if (!data.projects[options.project]) {
|
|
298
|
+
data.projects[options.project] = {
|
|
299
|
+
allowedTools: [],
|
|
300
|
+
mcpContextUris: [],
|
|
301
|
+
mcpServers: {},
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
data.projects[options.project].mcpServers =
|
|
305
|
+
data.projects[options.project].mcpServers || {};
|
|
306
|
+
if (options.toggle) {
|
|
307
|
+
fail("Claude does not support enable/disable. Use --remove instead.");
|
|
308
|
+
}
|
|
309
|
+
if (options.remove) {
|
|
310
|
+
if (!data.projects[options.project].mcpServers[serverName]) {
|
|
311
|
+
fail(`Server "${serverName}" not found for ${options.project}.`);
|
|
312
|
+
}
|
|
313
|
+
delete data.projects[options.project].mcpServers[serverName];
|
|
314
|
+
writeFile(filePath, JSON.stringify(data, null, 2));
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (data.projects[options.project].mcpServers[serverName] && !options.force) {
|
|
318
|
+
fail(
|
|
319
|
+
`Server "${serverName}" already exists for ${options.project}. Use --force to overwrite.`
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
data.projects[options.project].mcpServers[serverName] = {
|
|
323
|
+
type: "stdio",
|
|
324
|
+
command: options.command,
|
|
325
|
+
args: argsArray,
|
|
326
|
+
env: {},
|
|
327
|
+
};
|
|
328
|
+
writeFile(filePath, JSON.stringify(data, null, 2));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function writeCodexConfig(filePath, serverName, argsArray) {
|
|
332
|
+
ensureDir(filePath);
|
|
333
|
+
if (!toml) {
|
|
334
|
+
fail("TOML dependency not available. Install dependencies and retry.");
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const data = readToml(filePath);
|
|
338
|
+
data.mcp_servers = data.mcp_servers || {};
|
|
339
|
+
const defaultEnabled = !getDefaultDisabled("codex");
|
|
340
|
+
|
|
341
|
+
if (options.remove) {
|
|
342
|
+
if (!data.mcp_servers[serverName]) {
|
|
343
|
+
fail(`Server "${serverName}" not found in ${filePath}.`);
|
|
344
|
+
}
|
|
345
|
+
delete data.mcp_servers[serverName];
|
|
346
|
+
writeFile(filePath, toml.stringify(data));
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (options.toggle) {
|
|
351
|
+
if (!data.mcp_servers[serverName]) {
|
|
352
|
+
fail(`Server "${serverName}" not found in ${filePath}.`);
|
|
353
|
+
}
|
|
354
|
+
data.mcp_servers[serverName] = {
|
|
355
|
+
...data.mcp_servers[serverName],
|
|
356
|
+
enabled: !options.disabled,
|
|
357
|
+
};
|
|
358
|
+
writeFile(filePath, toml.stringify(data));
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (data.mcp_servers[serverName] && !options.force) {
|
|
363
|
+
fail(
|
|
364
|
+
`Server "${serverName}" already exists in ${filePath}. Use --force to overwrite.`
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
data.mcp_servers[serverName] = {
|
|
369
|
+
command: options.command,
|
|
370
|
+
args: argsArray,
|
|
371
|
+
enabled: options.disabled ? false : defaultEnabled,
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
writeFile(filePath, toml.stringify(data));
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function writeGooseConfig(filePath, serverName, argsArray) {
|
|
378
|
+
if (!yaml) {
|
|
379
|
+
fail("YAML dependency not available. Install dependencies and retry.");
|
|
380
|
+
}
|
|
381
|
+
ensureDir(filePath);
|
|
382
|
+
const data = readYaml(filePath);
|
|
383
|
+
data.extensions = data.extensions || {};
|
|
384
|
+
if (options.toggle) {
|
|
385
|
+
if (!data.extensions[serverName]) {
|
|
386
|
+
fail(`Server "${serverName}" not found in ${filePath}.`);
|
|
387
|
+
}
|
|
388
|
+
data.extensions[serverName] = {
|
|
389
|
+
...data.extensions[serverName],
|
|
390
|
+
enabled: !options.disabled,
|
|
391
|
+
};
|
|
392
|
+
writeFile(filePath, yaml.stringify(data));
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
if (options.remove) {
|
|
396
|
+
if (!data.extensions[serverName]) {
|
|
397
|
+
fail(`Server "${serverName}" not found in ${filePath}.`);
|
|
398
|
+
}
|
|
399
|
+
delete data.extensions[serverName];
|
|
400
|
+
writeFile(filePath, yaml.stringify(data));
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
if (data.extensions[serverName] && !options.force) {
|
|
404
|
+
fail(
|
|
405
|
+
`Server "${serverName}" already exists in ${filePath}. Use --force to overwrite.`
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
data.extensions[serverName] = {
|
|
409
|
+
name: "MCP ABAP ADT",
|
|
410
|
+
cmd: options.command,
|
|
411
|
+
args: argsArray,
|
|
412
|
+
type: "stdio",
|
|
413
|
+
enabled: options.disabled ? false : !getDefaultDisabled("goose"),
|
|
414
|
+
timeout: 300,
|
|
415
|
+
};
|
|
416
|
+
writeFile(filePath, yaml.stringify(data));
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function readJson(filePath) {
|
|
420
|
+
if (!fs.existsSync(filePath)) {
|
|
421
|
+
return {};
|
|
422
|
+
}
|
|
423
|
+
const raw = fs.readFileSync(filePath, "utf8").trim();
|
|
424
|
+
if (!raw) {
|
|
425
|
+
return {};
|
|
426
|
+
}
|
|
427
|
+
try {
|
|
428
|
+
return JSON.parse(raw);
|
|
429
|
+
} catch {
|
|
430
|
+
fail(`Invalid JSON: ${filePath}`);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function readYaml(filePath) {
|
|
435
|
+
if (!fs.existsSync(filePath)) {
|
|
436
|
+
return {};
|
|
437
|
+
}
|
|
438
|
+
const raw = fs.readFileSync(filePath, "utf8").trim();
|
|
439
|
+
if (!raw) {
|
|
440
|
+
return {};
|
|
441
|
+
}
|
|
442
|
+
try {
|
|
443
|
+
return yaml.parse(raw) || {};
|
|
444
|
+
} catch {
|
|
445
|
+
fail(`Invalid YAML: ${filePath}`);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function readToml(filePath) {
|
|
450
|
+
if (!fs.existsSync(filePath)) {
|
|
451
|
+
return {};
|
|
452
|
+
}
|
|
453
|
+
const raw = fs.readFileSync(filePath, "utf8").trim();
|
|
454
|
+
if (!raw) {
|
|
455
|
+
return {};
|
|
456
|
+
}
|
|
457
|
+
try {
|
|
458
|
+
return toml.parse(raw) || {};
|
|
459
|
+
} catch {
|
|
460
|
+
fail(`Invalid TOML: ${filePath}`);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function ensureDir(filePath) {
|
|
465
|
+
const dir = path.dirname(filePath);
|
|
466
|
+
if (!fs.existsSync(dir)) {
|
|
467
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function writeFile(filePath, content) {
|
|
472
|
+
if (options.dryRun) {
|
|
473
|
+
process.stdout.write(`\n# ${filePath}\n${content}\n`);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
fs.writeFileSync(filePath, content, "utf8");
|
|
477
|
+
process.stdout.write(`Updated ${filePath}\n`);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function escapeRegex(value) {
|
|
481
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function fail(message) {
|
|
485
|
+
process.stderr.write(`${message}\n`);
|
|
486
|
+
process.exit(1);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
function printHelp() {
|
|
490
|
+
process.stdout.write(`mcp-abap-adt-configure
|
|
491
|
+
|
|
492
|
+
Usage:
|
|
493
|
+
mcp-abap-adt-configure --client <name> --name <serverName> [--env <path> | --mcp <dest>] [options]
|
|
494
|
+
|
|
495
|
+
Options:
|
|
496
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf (repeatable)
|
|
497
|
+
--name <serverName> required MCP server name key
|
|
498
|
+
--env <path> .env path (add/update only)
|
|
499
|
+
--mcp <dest> destination name (add/update only)
|
|
500
|
+
--transport <type> only stdio supported
|
|
501
|
+
--command <bin> command to run (default: mcp-abap-adt)
|
|
502
|
+
--project <path> Claude project path (defaults to cwd)
|
|
503
|
+
--config <path> override client config path (Claude Linux)
|
|
504
|
+
--disable disable entry (Codex/Cline/Windsurf/Goose only)
|
|
505
|
+
--enable enable entry (Codex/Cline/Windsurf/Goose only)
|
|
506
|
+
--remove remove entry
|
|
507
|
+
--force overwrite existing entry (add/update)
|
|
508
|
+
--dry-run print changes without writing files
|
|
509
|
+
-h, --help show this help
|
|
510
|
+
|
|
511
|
+
Notes:
|
|
512
|
+
New entries for Cline/Codex/Windsurf/Goose are added disabled by default.
|
|
513
|
+
`);
|
|
514
|
+
}
|
package/docs/README.md
CHANGED
|
@@ -48,6 +48,8 @@ Documentation for developers: testing, development guides, and internal document
|
|
|
48
48
|
- **Getting Started**: [Installation Guide](installation/INSTALLATION.md)
|
|
49
49
|
- **User Configuration**: [Client Configuration](user-guide/CLIENT_CONFIGURATION.md)
|
|
50
50
|
- **Server Configuration**: [YAML Config](configuration/YAML_CONFIG.md) | [CLI Options](user-guide/CLI_OPTIONS.md)
|
|
51
|
+
- **Deployment**: [MCP Registry](deployment/MCP_REGISTRY.md) | [Docker](deployment/DOCKER.md)
|
|
52
|
+
- **Client Configuration**: [Auto-Configure](installation/CLIENT_INSTALLERS.md)
|
|
51
53
|
- **Available Tools**: [Tools List](user-guide/AVAILABLE_TOOLS.md)
|
|
52
54
|
- **Architecture**: [Stateful Sessions](architecture/STATEFUL_SESSION_GUIDE.md) | [Architecture Docs](architecture/README.md)
|
|
53
55
|
- **Development**: [Development Documentation](development/)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# MCP Registry Publishing
|
|
2
|
+
|
|
3
|
+
This project is published in the official MCP Registry.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
- Install `mcp-publisher` (see official docs).
|
|
7
|
+
- Ensure the npm package is published and contains `mcpName` in `package.json`.
|
|
8
|
+
|
|
9
|
+
## Required Metadata
|
|
10
|
+
|
|
11
|
+
- `server.json` in the repository root
|
|
12
|
+
- `mcpName` in `package.json`
|
|
13
|
+
|
|
14
|
+
Expected values:
|
|
15
|
+
- Registry name: `io.github.fr0ster/mcp-abap-adt`
|
|
16
|
+
- npm package: `@mcp-abap-adt/core` (stdio)
|
|
17
|
+
|
|
18
|
+
## Publish
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
mcp-publisher login github
|
|
22
|
+
mcp-publisher publish
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Verify
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
curl "https://registry.modelcontextprotocol.io/v0/servers?search=io.github.fr0ster/mcp-abap-adt"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Notes
|
|
32
|
+
|
|
33
|
+
- Keep `server.json` version in sync with the npm package version.
|
|
34
|
+
- If publish fails with “missing mcpName”, publish a new npm version that includes `mcpName`.
|
|
@@ -11,6 +11,11 @@ This directory contains documentation for deploying and releasing MCP ABAP ADT S
|
|
|
11
11
|
- Multi-stage builds
|
|
12
12
|
- Production best practices
|
|
13
13
|
|
|
14
|
+
- **[MCP_REGISTRY.md](./MCP_REGISTRY.md)** - MCP Registry publishing
|
|
15
|
+
- `server.json` and `mcpName` metadata
|
|
16
|
+
- Publish with `mcp-publisher`
|
|
17
|
+
- Verification steps
|
|
18
|
+
|
|
14
19
|
- **[RELEASE.md](./RELEASE.md)** - Release process documentation
|
|
15
20
|
- Automated releases via GitHub Actions
|
|
16
21
|
- Manual release process
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Client Auto-Configure
|
|
2
|
+
|
|
3
|
+
This helper writes MCP configuration entries for popular clients.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @mcp-abap-adt/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
mcp-abap-adt-configure --client cline --env /path/to/.env --name abap
|
|
15
|
+
mcp-abap-adt-configure --client cline --mcp TRIAL --name abap
|
|
16
|
+
mcp-abap-adt-configure --client cline --env /path/to/.env --name abap --transport stdio
|
|
17
|
+
mcp-abap-adt-configure --client claude --mcp TRIAL --name abap --project /home/user/prj/myproj
|
|
18
|
+
mcp-abap-adt-configure --client codex --name abap --remove
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Common Tasks
|
|
22
|
+
|
|
23
|
+
Add MCP:
|
|
24
|
+
```bash
|
|
25
|
+
mcp-abap-adt-configure --client codex --mcp TRIAL --name abap
|
|
26
|
+
mcp-abap-adt-configure --client cline --env /path/to/.env --name abap
|
|
27
|
+
mcp-abap-adt-configure --client claude --mcp TRIAL --name abap --project /home/user/prj/myproj
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Disable MCP:
|
|
31
|
+
```bash
|
|
32
|
+
mcp-abap-adt-configure --client codex --name abap --disable
|
|
33
|
+
mcp-abap-adt-configure --client cline --name abap --disable
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Enable MCP:
|
|
37
|
+
```bash
|
|
38
|
+
mcp-abap-adt-configure --client codex --name abap --enable
|
|
39
|
+
mcp-abap-adt-configure --client cline --name abap --enable
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Remove MCP:
|
|
43
|
+
```bash
|
|
44
|
+
mcp-abap-adt-configure --client codex --name abap --remove
|
|
45
|
+
mcp-abap-adt-configure --client cline --name abap --remove
|
|
46
|
+
mcp-abap-adt-configure --client claude --name abap --project /home/user/prj/myproj --remove
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Options:
|
|
50
|
+
- `--client <name>` (repeatable): `cline`, `codex`, `claude`, `goose`, `cursor`, `windsurf`
|
|
51
|
+
- `--env <path>`: use a specific `.env` file
|
|
52
|
+
- `--mcp <destination>`: use service key destination
|
|
53
|
+
- `--name <serverName>`: MCP server name (required)
|
|
54
|
+
- `--transport <type>`: transport type (only `stdio` supported)
|
|
55
|
+
- `--command <bin>`: command to run (default: `mcp-abap-adt`)
|
|
56
|
+
- `--project <path>`: project path for Claude Desktop (defaults to current directory)
|
|
57
|
+
- `--config <path>`: override client config path (optional for Claude on Linux; default: `~/.claude.json`)
|
|
58
|
+
- `--disable`: disable server entry (Codex: `enabled = false`, Cline: `disabled = true`)
|
|
59
|
+
- `--enable`: enable server entry (Codex: `enabled = true`, Cline: `disabled = false`)
|
|
60
|
+
- `--remove`: remove server entry from client config
|
|
61
|
+
|
|
62
|
+
Notes:
|
|
63
|
+
- `--disable` and `--remove` do not require `--env` or `--mcp`.
|
|
64
|
+
- Cursor ignores enable/disable via `mcp.json`; use `--remove` instead.
|
|
65
|
+
- New entries for Cline, Codex, Windsurf, and Goose are added **disabled by default**. Use `--enable` to turn them on.
|
|
66
|
+
- `--enable`/`--disable` only work if the server entry already exists. Use add commands with `--env` or `--mcp` first.
|
|
67
|
+
- `--dry-run`: print changes without writing files
|
|
68
|
+
- `--force`: overwrite existing server entry if it exists
|
|
69
|
+
|
|
70
|
+
## Config Locations
|
|
71
|
+
|
|
72
|
+
Paths are client-specific and OS-dependent. The installer writes config files in:
|
|
73
|
+
|
|
74
|
+
- **Cline**:
|
|
75
|
+
- Linux/macOS: `~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`
|
|
76
|
+
- Windows: `%APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json`
|
|
77
|
+
- **Codex**:
|
|
78
|
+
- Linux/macOS: `~/.codex/config.toml`
|
|
79
|
+
- Windows: `%USERPROFILE%\.codex\config.toml`
|
|
80
|
+
- **Claude Desktop**:
|
|
81
|
+
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
82
|
+
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
83
|
+
- **Goose**:
|
|
84
|
+
- Linux/macOS: `~/.config/goose/config.yaml`
|
|
85
|
+
- Windows: `%APPDATA%\Block\goose\config\config.yaml`
|
|
86
|
+
- **Cursor**:
|
|
87
|
+
- Linux/macOS: `~/.cursor/mcp.json`
|
|
88
|
+
- Windows: `%USERPROFILE%\.cursor\mcp.json`
|
|
89
|
+
- **Windsurf**:
|
|
90
|
+
- Linux/macOS: `~/.codeium/windsurf/mcp_config.json`
|
|
91
|
+
- Windows: `%USERPROFILE%\.codeium\windsurf\mcp_config.json`
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-abap-adt/core",
|
|
3
3
|
"mcpName": "io.github.fr0ster/mcp-abap-adt",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.2.0",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
@@ -127,6 +127,7 @@
|
|
|
127
127
|
"@mcp-abap-adt/interfaces": "^0.2.15",
|
|
128
128
|
"@mcp-abap-adt/logger": "^0.1.4",
|
|
129
129
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
130
|
+
"@iarna/toml": "^2.2.5",
|
|
130
131
|
"axios": "^1.13.5",
|
|
131
132
|
"fast-xml-parser": "^5.3.5",
|
|
132
133
|
"js-yaml": "^4.1.1",
|
|
@@ -149,7 +150,8 @@
|
|
|
149
150
|
],
|
|
150
151
|
"bin": {
|
|
151
152
|
"mcp-abap-adt": "./bin/mcp-abap-adt.js",
|
|
152
|
-
"mcp-abap-adt-v2": "./bin/mcp-abap-adt-v2.js"
|
|
153
|
+
"mcp-abap-adt-v2": "./bin/mcp-abap-adt-v2.js",
|
|
154
|
+
"mcp-abap-adt-configure": "./bin/mcp-abap-adt-configure.js"
|
|
153
155
|
},
|
|
154
156
|
"jest": {
|
|
155
157
|
"preset": "ts-jest",
|