@mcp-abap-adt/configurator 0.0.5 → 0.0.6
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 +10 -2
- package/bin/mcp-conf-tui.js +183 -0
- package/bin/mcp-conf.js +129 -45
- package/docs/CLIENT_INSTALLERS.md +23 -10
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -11,17 +11,25 @@ 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
|
|
14
|
+
mcp-conf --client cline --env-path /path/to/.env --name abap
|
|
15
15
|
mcp-conf --client cline --mcp TRIAL --name abap
|
|
16
16
|
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=...
|
|
17
17
|
mcp-conf --client cline --name local-mcp-sse --transport sse --url http://localhost:3001/sse
|
|
18
18
|
mcp-conf --client codex --name abap-http --transport http --url http://localhost:3000/mcp/stream/http
|
|
19
19
|
mcp-conf --client codex --name abap-http --transport http --url http://localhost:3000/mcp/stream/http --header x-mcp-destination=trial
|
|
20
20
|
mcp-conf --client opencode --name abap --transport http --url http://localhost:3000/mcp/stream/http
|
|
21
|
+
mcp-conf --client kilo --name abap --transport http --url http://localhost:3000/mcp/stream/http
|
|
21
22
|
mcp-conf --client copilot --name abap --transport http --url http://localhost:3000/mcp/stream/http --header x-mcp-destination=trial
|
|
23
|
+
mcp-conf tui
|
|
22
24
|
```
|
|
23
25
|
|
|
26
|
+
## TUI
|
|
27
|
+
|
|
28
|
+
`mcp-conf tui` starts an interactive wizard.
|
|
29
|
+
- Step order: `operation` -> `client` -> `scope` (auto-skipped if only one scope is supported).
|
|
30
|
+
- For `add` + `sse/http`: prompts for URL, timeout, and repeatable headers.
|
|
31
|
+
- Keyboard: arrow keys + Enter, Ctrl+C to cancel.
|
|
32
|
+
|
|
24
33
|
## Docs
|
|
25
34
|
|
|
26
35
|
- See `docs/CLIENT_INSTALLERS.md` for client-specific behavior, defaults, and config paths.
|
|
27
|
-
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { Select, Input, Confirm } = require("enquirer");
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
|
|
6
|
+
const CLIENTS = [
|
|
7
|
+
{ name: "cline", message: "Cline" },
|
|
8
|
+
{ name: "codex", message: "Codex" },
|
|
9
|
+
{ name: "claude", message: "Claude" },
|
|
10
|
+
{ name: "goose", message: "Goose" },
|
|
11
|
+
{ name: "cursor", message: "Cursor" },
|
|
12
|
+
{ name: "windsurf", message: "Windsurf" },
|
|
13
|
+
{ name: "opencode", message: "OpenCode (kilo)" },
|
|
14
|
+
{ name: "copilot", message: "GitHub Copilot" },
|
|
15
|
+
{ name: "antigravity", message: "Antigravity" },
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const HEADER_KEYS = [
|
|
19
|
+
"x-mcp-destination",
|
|
20
|
+
"x-sap-url",
|
|
21
|
+
"x-sap-client",
|
|
22
|
+
"x-sap-auth-type",
|
|
23
|
+
"x-sap-jwt-token",
|
|
24
|
+
"x-sap-user",
|
|
25
|
+
"x-sap-password",
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
async function main() {
|
|
29
|
+
const result = {
|
|
30
|
+
headers: {},
|
|
31
|
+
timeout: 60,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
result.tuiAction = await askSelect("Operation", ["ls", "add", "rm", "enable", "disable"]);
|
|
35
|
+
const client = await askSelect(
|
|
36
|
+
"Client",
|
|
37
|
+
CLIENTS.map((item) => item.name),
|
|
38
|
+
CLIENTS.map((item) => item.message),
|
|
39
|
+
);
|
|
40
|
+
result.clients = [client];
|
|
41
|
+
|
|
42
|
+
const scopes = getSupportedScopes(client);
|
|
43
|
+
result.scope = scopes.length === 1 ? scopes[0] : await askSelect("Scope", ["global", "local"]);
|
|
44
|
+
|
|
45
|
+
if (result.tuiAction !== "ls") {
|
|
46
|
+
result.name = await askInput("Server name", "abap");
|
|
47
|
+
} else {
|
|
48
|
+
result.name = null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (result.tuiAction !== "add") {
|
|
52
|
+
emitResult(result);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const transports = getSupportedTransports(client);
|
|
57
|
+
result.transport =
|
|
58
|
+
transports.length === 1 ? transports[0] : await askSelect("Transport", transports);
|
|
59
|
+
|
|
60
|
+
if (result.transport === "stdio") {
|
|
61
|
+
const authSource = await askSelect("Auth source for stdio", [
|
|
62
|
+
"service key destination (--mcp)",
|
|
63
|
+
"session environment (--env)",
|
|
64
|
+
"specific env file (--env-path)",
|
|
65
|
+
]);
|
|
66
|
+
if (authSource.startsWith("service key")) {
|
|
67
|
+
result.mcpDestination = await askInput("Destination name", "TRIAL");
|
|
68
|
+
result.useSessionEnv = false;
|
|
69
|
+
result.envPath = null;
|
|
70
|
+
result.url = null;
|
|
71
|
+
emitResult(result);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (authSource.startsWith("specific env file")) {
|
|
75
|
+
result.envPath = await askInput("Path to .env file");
|
|
76
|
+
result.useSessionEnv = false;
|
|
77
|
+
result.mcpDestination = null;
|
|
78
|
+
result.url = null;
|
|
79
|
+
emitResult(result);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
result.useSessionEnv = true;
|
|
83
|
+
result.envPath = null;
|
|
84
|
+
result.mcpDestination = null;
|
|
85
|
+
result.url = null;
|
|
86
|
+
emitResult(result);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
result.url = await askInput("Server URL (http/https)");
|
|
91
|
+
result.timeout = await askPositiveNumber("Timeout seconds", 60);
|
|
92
|
+
result.headers = await askHeaders();
|
|
93
|
+
result.useSessionEnv = false;
|
|
94
|
+
result.envPath = null;
|
|
95
|
+
result.mcpDestination = null;
|
|
96
|
+
|
|
97
|
+
emitResult(result);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function emitResult(result) {
|
|
101
|
+
fs.writeFileSync(3, JSON.stringify(result), "utf8");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function askSelect(message, choices, choiceLabels) {
|
|
105
|
+
const promptChoices = choices.map((value, index) => ({
|
|
106
|
+
name: value,
|
|
107
|
+
message: choiceLabels?.[index] || value,
|
|
108
|
+
}));
|
|
109
|
+
const select = new Select({
|
|
110
|
+
name: "value",
|
|
111
|
+
message,
|
|
112
|
+
choices: promptChoices,
|
|
113
|
+
footer: "Use arrow keys + Enter. Ctrl+C to cancel.",
|
|
114
|
+
});
|
|
115
|
+
return select.run();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function askInput(message, initial) {
|
|
119
|
+
const input = new Input({
|
|
120
|
+
name: "value",
|
|
121
|
+
message,
|
|
122
|
+
initial,
|
|
123
|
+
});
|
|
124
|
+
const value = await input.run();
|
|
125
|
+
if (!String(value || "").trim()) {
|
|
126
|
+
return askInput(message, initial);
|
|
127
|
+
}
|
|
128
|
+
return String(value).trim();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function askPositiveNumber(message, initialValue) {
|
|
132
|
+
while (true) {
|
|
133
|
+
const raw = await askInput(message, String(initialValue));
|
|
134
|
+
const parsed = Number(raw);
|
|
135
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
136
|
+
return parsed;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function askHeaders() {
|
|
142
|
+
const headers = {};
|
|
143
|
+
while (true) {
|
|
144
|
+
const key = await askSelect("Header key", [...HEADER_KEYS, "done"]);
|
|
145
|
+
if (key === "done") {
|
|
146
|
+
return headers;
|
|
147
|
+
}
|
|
148
|
+
headers[key] = await askInput(`Value for ${key}`);
|
|
149
|
+
const addMore = await new Confirm({
|
|
150
|
+
name: "value",
|
|
151
|
+
message: "Add another header?",
|
|
152
|
+
initial: true,
|
|
153
|
+
}).run();
|
|
154
|
+
if (!addMore) {
|
|
155
|
+
return headers;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function getSupportedScopes(clientName) {
|
|
161
|
+
if (clientName === "copilot") {
|
|
162
|
+
return ["local"];
|
|
163
|
+
}
|
|
164
|
+
if (["cline", "goose", "windsurf", "antigravity"].includes(clientName)) {
|
|
165
|
+
return ["global"];
|
|
166
|
+
}
|
|
167
|
+
return ["global", "local"];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function getSupportedTransports(clientName) {
|
|
171
|
+
if (clientName === "codex") {
|
|
172
|
+
return ["stdio", "http"];
|
|
173
|
+
}
|
|
174
|
+
return ["stdio", "sse", "http"];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
main().catch((error) => {
|
|
178
|
+
if (error === "") {
|
|
179
|
+
process.exit(0);
|
|
180
|
+
}
|
|
181
|
+
process.stderr.write(`${error?.message || String(error)}\n`);
|
|
182
|
+
process.exit(1);
|
|
183
|
+
});
|
package/bin/mcp-conf.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const fs = require("node:fs");
|
|
4
4
|
const path = require("node:path");
|
|
5
5
|
const os = require("node:os");
|
|
6
|
+
const { spawnSync } = require("node:child_process");
|
|
6
7
|
|
|
7
8
|
let yaml;
|
|
8
9
|
try {
|
|
@@ -23,12 +24,13 @@ try {
|
|
|
23
24
|
|
|
24
25
|
const args = process.argv.slice(2);
|
|
25
26
|
const action = args[0] && !args[0].startsWith("-") ? args[0] : null;
|
|
26
|
-
if (action && ["add", "rm", "ls", "enable", "disable", "where", "help"].includes(action)) {
|
|
27
|
+
if (action && ["add", "rm", "ls", "enable", "disable", "where", "tui", "help"].includes(action)) {
|
|
27
28
|
args.shift();
|
|
28
29
|
}
|
|
29
30
|
const options = {
|
|
30
31
|
clients: [],
|
|
31
32
|
envPath: null,
|
|
33
|
+
useSessionEnv: false,
|
|
32
34
|
mcpDestination: null,
|
|
33
35
|
name: null,
|
|
34
36
|
transport: "stdio",
|
|
@@ -52,7 +54,7 @@ if (args.includes("--help") || args.includes("-h") || action === "help") {
|
|
|
52
54
|
const helpAction =
|
|
53
55
|
action === "help"
|
|
54
56
|
? args[0]
|
|
55
|
-
: action && ["add", "rm", "ls", "enable", "disable", "where"].includes(action)
|
|
57
|
+
: action && ["add", "rm", "ls", "enable", "disable", "where", "tui"].includes(action)
|
|
56
58
|
? action
|
|
57
59
|
: null;
|
|
58
60
|
printHelp(helpAction);
|
|
@@ -62,13 +64,34 @@ if (args.includes("--help") || args.includes("-h") || action === "help") {
|
|
|
62
64
|
for (let i = 0; i < args.length; i += 1) {
|
|
63
65
|
const arg = args[i];
|
|
64
66
|
if (arg === "--client") {
|
|
65
|
-
options.clients.push(args[i + 1]);
|
|
67
|
+
options.clients.push(normalizeClientName(args[i + 1]));
|
|
66
68
|
i += 1;
|
|
67
69
|
} else if (arg === "--env") {
|
|
70
|
+
const maybePath = args[i + 1];
|
|
71
|
+
if (maybePath && !maybePath.startsWith("-")) {
|
|
72
|
+
// Backward-compatible form: --env /path/to/.env
|
|
73
|
+
options.envPath = maybePath;
|
|
74
|
+
options.useSessionEnv = false;
|
|
75
|
+
options.mcpDestination = null;
|
|
76
|
+
i += 1;
|
|
77
|
+
} else {
|
|
78
|
+
options.useSessionEnv = true;
|
|
79
|
+
options.envPath = null;
|
|
80
|
+
options.mcpDestination = null;
|
|
81
|
+
}
|
|
82
|
+
} else if (arg === "--env-path") {
|
|
68
83
|
options.envPath = args[i + 1];
|
|
84
|
+
options.useSessionEnv = false;
|
|
85
|
+
options.mcpDestination = null;
|
|
69
86
|
i += 1;
|
|
87
|
+
} else if (arg === "--session-env") {
|
|
88
|
+
options.useSessionEnv = true;
|
|
89
|
+
options.envPath = null;
|
|
90
|
+
options.mcpDestination = null;
|
|
70
91
|
} else if (arg === "--mcp") {
|
|
71
92
|
options.mcpDestination = args[i + 1];
|
|
93
|
+
options.useSessionEnv = false;
|
|
94
|
+
options.envPath = null;
|
|
72
95
|
i += 1;
|
|
73
96
|
} else if (arg === "--name") {
|
|
74
97
|
options.name = args[i + 1];
|
|
@@ -122,40 +145,46 @@ for (let i = 0; i < args.length; i += 1) {
|
|
|
122
145
|
}
|
|
123
146
|
}
|
|
124
147
|
|
|
125
|
-
if (!action || !["add", "rm", "ls", "enable", "disable", "where"].includes(action)) {
|
|
126
|
-
fail("Provide a command: add | rm | ls | enable | disable | where.");
|
|
148
|
+
if (!action || !["add", "rm", "ls", "enable", "disable", "where", "tui"].includes(action)) {
|
|
149
|
+
fail("Provide a command: add | rm | ls | enable | disable | where | tui.");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let effectiveAction = action;
|
|
153
|
+
if (action === "tui") {
|
|
154
|
+
runTuiWizard(options);
|
|
155
|
+
effectiveAction = options.tuiAction || "add";
|
|
127
156
|
}
|
|
128
157
|
|
|
129
158
|
if (options.clients.length === 0) {
|
|
130
159
|
fail("Provide at least one --client.");
|
|
131
160
|
}
|
|
132
161
|
|
|
133
|
-
if (!["ls"].includes(
|
|
162
|
+
if (!["ls"].includes(effectiveAction) && !options.name) {
|
|
134
163
|
fail("Provide --name <serverName> (required).");
|
|
135
164
|
}
|
|
136
165
|
|
|
137
166
|
const transportNormalized = options.transport === "http" ? "streamableHttp" : options.transport;
|
|
138
167
|
options.transport = transportNormalized;
|
|
139
168
|
|
|
140
|
-
if (
|
|
169
|
+
if (effectiveAction === "rm") {
|
|
141
170
|
options.remove = true;
|
|
142
171
|
}
|
|
143
|
-
if (
|
|
172
|
+
if (effectiveAction === "ls") {
|
|
144
173
|
options.list = true;
|
|
145
174
|
}
|
|
146
|
-
if (
|
|
175
|
+
if (effectiveAction === "enable") {
|
|
147
176
|
options.toggle = true;
|
|
148
177
|
options.disabled = false;
|
|
149
178
|
}
|
|
150
|
-
if (
|
|
179
|
+
if (effectiveAction === "disable") {
|
|
151
180
|
options.toggle = true;
|
|
152
181
|
options.disabled = true;
|
|
153
182
|
}
|
|
154
|
-
if (
|
|
183
|
+
if (effectiveAction === "where") {
|
|
155
184
|
options.where = true;
|
|
156
185
|
}
|
|
157
186
|
|
|
158
|
-
if (options.remove &&
|
|
187
|
+
if (options.remove && effectiveAction !== "rm") {
|
|
159
188
|
fail("Use the rm command instead of --remove.");
|
|
160
189
|
}
|
|
161
190
|
if (options.list && options.toggle) {
|
|
@@ -173,15 +202,16 @@ if (options.projectPath && options.allProjects) {
|
|
|
173
202
|
if (options.where && (options.list || options.remove || options.toggle)) {
|
|
174
203
|
fail("The where command does not support ls/rm/enable/disable flags.");
|
|
175
204
|
}
|
|
176
|
-
if (options.projectPath &&
|
|
205
|
+
if (options.projectPath && effectiveAction === "add" && options.scope !== "global") {
|
|
177
206
|
fail("--project is only supported for Claude global config.");
|
|
178
207
|
}
|
|
179
208
|
|
|
180
|
-
const requiresConnectionParams =
|
|
209
|
+
const requiresConnectionParams =
|
|
210
|
+
!options.remove && !options.toggle && !options.list && !options.where;
|
|
181
211
|
|
|
182
212
|
if (requiresConnectionParams && options.transport === "stdio") {
|
|
183
|
-
if (!options.envPath && !options.mcpDestination) {
|
|
184
|
-
fail("Provide
|
|
213
|
+
if (!options.envPath && !options.mcpDestination && !options.useSessionEnv) {
|
|
214
|
+
fail("Provide --env, --env-path <path>, or --mcp <destination>.");
|
|
185
215
|
}
|
|
186
216
|
}
|
|
187
217
|
|
|
@@ -189,8 +219,8 @@ if (requiresConnectionParams && options.transport !== "stdio") {
|
|
|
189
219
|
if (!options.url) {
|
|
190
220
|
fail("Provide --url <http(s)://...> for sse/http transports.");
|
|
191
221
|
}
|
|
192
|
-
if (options.envPath || options.mcpDestination) {
|
|
193
|
-
fail("--env/--mcp are only valid for stdio transport.");
|
|
222
|
+
if (options.envPath || options.mcpDestination || options.useSessionEnv) {
|
|
223
|
+
fail("--env/--env-path/--mcp are only valid for stdio transport.");
|
|
194
224
|
}
|
|
195
225
|
}
|
|
196
226
|
|
|
@@ -201,20 +231,22 @@ const userProfile = process.env.USERPROFILE || home;
|
|
|
201
231
|
|
|
202
232
|
const serverArgsRaw = [
|
|
203
233
|
`--transport=${options.transport}`,
|
|
204
|
-
options.
|
|
205
|
-
?
|
|
206
|
-
: options.
|
|
207
|
-
? `--
|
|
208
|
-
:
|
|
234
|
+
options.useSessionEnv
|
|
235
|
+
? "--env"
|
|
236
|
+
: options.envPath
|
|
237
|
+
? `--env-path=${options.envPath}`
|
|
238
|
+
: options.mcpDestination
|
|
239
|
+
? `--mcp=${options.mcpDestination.toLowerCase()}`
|
|
240
|
+
: undefined,
|
|
209
241
|
];
|
|
210
242
|
const serverArgs = serverArgsRaw.filter(Boolean);
|
|
211
243
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
244
|
+
for (const client of options.clients) {
|
|
245
|
+
const scope = options.scope || getDefaultScope(client);
|
|
246
|
+
if (options.projectPath && client !== "claude") {
|
|
247
|
+
fail("--project is only supported for Claude.");
|
|
248
|
+
}
|
|
249
|
+
switch (client) {
|
|
218
250
|
case "cline":
|
|
219
251
|
requireScope("Cline", ["global"], scope);
|
|
220
252
|
if (options.list) {
|
|
@@ -235,10 +267,14 @@ const serverArgs = serverArgsRaw.filter(Boolean);
|
|
|
235
267
|
} else if (options.where) {
|
|
236
268
|
whereCodexConfig(getCodexPath(platform, home, userProfile, scope), options.name);
|
|
237
269
|
} else {
|
|
238
|
-
writeCodexConfig(
|
|
270
|
+
writeCodexConfig(
|
|
271
|
+
getCodexPath(platform, home, userProfile, scope),
|
|
272
|
+
options.name,
|
|
273
|
+
serverArgs,
|
|
274
|
+
);
|
|
239
275
|
}
|
|
240
276
|
break;
|
|
241
|
-
case "claude":
|
|
277
|
+
case "claude": {
|
|
242
278
|
requireScope("Claude", ["global", "local"], scope);
|
|
243
279
|
const claudeToggleScope = options.toggle ? "global" : scope;
|
|
244
280
|
if (options.allProjects && claudeToggleScope !== "global") {
|
|
@@ -274,6 +310,7 @@ const serverArgs = serverArgsRaw.filter(Boolean);
|
|
|
274
310
|
);
|
|
275
311
|
}
|
|
276
312
|
break;
|
|
313
|
+
}
|
|
277
314
|
case "goose":
|
|
278
315
|
requireScope("Goose", ["global"], scope);
|
|
279
316
|
if (options.list) {
|
|
@@ -310,12 +347,7 @@ const serverArgs = serverArgsRaw.filter(Boolean);
|
|
|
310
347
|
} else if (options.where) {
|
|
311
348
|
whereJsonConfig(getAntigravityPath(home, scope), "antigravity", options.name);
|
|
312
349
|
} else {
|
|
313
|
-
writeJsonConfig(
|
|
314
|
-
getAntigravityPath(home, scope),
|
|
315
|
-
options.name,
|
|
316
|
-
serverArgs,
|
|
317
|
-
"antigravity",
|
|
318
|
-
);
|
|
350
|
+
writeJsonConfig(getAntigravityPath(home, scope), options.name, serverArgs, "antigravity");
|
|
319
351
|
}
|
|
320
352
|
break;
|
|
321
353
|
case "copilot":
|
|
@@ -363,6 +395,43 @@ const serverArgs = serverArgsRaw.filter(Boolean);
|
|
|
363
395
|
}
|
|
364
396
|
}
|
|
365
397
|
|
|
398
|
+
function normalizeClientName(clientName) {
|
|
399
|
+
if (!clientName) {
|
|
400
|
+
return clientName;
|
|
401
|
+
}
|
|
402
|
+
const normalized = clientName.toLowerCase();
|
|
403
|
+
return normalized === "kilo" ? "opencode" : normalized;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function runTuiWizard(opts) {
|
|
407
|
+
if (!process.stdin.isTTY) {
|
|
408
|
+
fail("TUI mode requires an interactive terminal.");
|
|
409
|
+
}
|
|
410
|
+
const helperPath = path.join(__dirname, "mcp-conf-tui.js");
|
|
411
|
+
const run = spawnSync(process.execPath, [helperPath], {
|
|
412
|
+
stdio: ["inherit", "inherit", "inherit", "pipe"],
|
|
413
|
+
encoding: "utf8",
|
|
414
|
+
});
|
|
415
|
+
if (run.error) {
|
|
416
|
+
fail(`Failed to start TUI helper: ${run.error.message}`);
|
|
417
|
+
}
|
|
418
|
+
if (run.status !== 0) {
|
|
419
|
+
process.exit(run.status || 1);
|
|
420
|
+
}
|
|
421
|
+
const rawPayload = run.output?.[3] || "";
|
|
422
|
+
const payload = String(rawPayload).trim();
|
|
423
|
+
if (!payload) {
|
|
424
|
+
fail("TUI did not return configuration.");
|
|
425
|
+
}
|
|
426
|
+
let selected;
|
|
427
|
+
try {
|
|
428
|
+
selected = JSON.parse(payload);
|
|
429
|
+
} catch {
|
|
430
|
+
fail("Invalid TUI output.");
|
|
431
|
+
}
|
|
432
|
+
Object.assign(opts, selected);
|
|
433
|
+
}
|
|
434
|
+
|
|
366
435
|
function getClinePath(platformValue, homeDir, appDataDir) {
|
|
367
436
|
if (platformValue === "win32") {
|
|
368
437
|
return path.join(
|
|
@@ -1215,6 +1284,7 @@ function printHelp(command) {
|
|
|
1215
1284
|
|
|
1216
1285
|
Usage:
|
|
1217
1286
|
mcp-conf <add|rm|ls|enable|disable|where> --client <name> [options]
|
|
1287
|
+
mcp-conf tui
|
|
1218
1288
|
mcp-conf help <command>
|
|
1219
1289
|
|
|
1220
1290
|
Commands:
|
|
@@ -1224,6 +1294,7 @@ Commands:
|
|
|
1224
1294
|
enable enable an existing entry
|
|
1225
1295
|
disable disable an existing entry
|
|
1226
1296
|
where show where a server name is defined
|
|
1297
|
+
tui interactive setup wizard
|
|
1227
1298
|
|
|
1228
1299
|
Run:
|
|
1229
1300
|
mcp-conf <command> --help
|
|
@@ -1241,12 +1312,13 @@ Notes:
|
|
|
1241
1312
|
process.stdout.write(`${header} add
|
|
1242
1313
|
|
|
1243
1314
|
Usage:
|
|
1244
|
-
mcp-conf add --client <name> --name <serverName> [--env <path> | --mcp <dest>] [options]
|
|
1315
|
+
mcp-conf add --client <name> --name <serverName> [--env | --env-path <path> | --mcp <dest>] [options]
|
|
1245
1316
|
|
|
1246
1317
|
Options:
|
|
1247
|
-
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot | antigravity (repeatable)
|
|
1318
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | kilo | copilot | antigravity (repeatable)
|
|
1248
1319
|
--name <serverName> required MCP server name key
|
|
1249
|
-
--env
|
|
1320
|
+
--env use current shell/session env vars (stdio only)
|
|
1321
|
+
--env-path <path> .env path (stdio only)
|
|
1250
1322
|
--mcp <dest> destination name (stdio only)
|
|
1251
1323
|
--transport <type> stdio | sse | http (http => streamableHttp)
|
|
1252
1324
|
--command <bin> command to run (default: mcp-abap-adt)
|
|
@@ -1270,7 +1342,7 @@ Usage:
|
|
|
1270
1342
|
mcp-conf rm --client <name> --name <serverName> [options]
|
|
1271
1343
|
|
|
1272
1344
|
Options:
|
|
1273
|
-
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot | antigravity (repeatable)
|
|
1345
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | kilo | copilot | antigravity (repeatable)
|
|
1274
1346
|
--name <serverName> required MCP server name key
|
|
1275
1347
|
--global write to global user config (default)
|
|
1276
1348
|
--local write to project config (where supported)
|
|
@@ -1289,7 +1361,7 @@ Usage:
|
|
|
1289
1361
|
mcp-conf ls --client <name> [options]
|
|
1290
1362
|
|
|
1291
1363
|
Options:
|
|
1292
|
-
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot | antigravity (repeatable)
|
|
1364
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | kilo | copilot | antigravity (repeatable)
|
|
1293
1365
|
--global write to global user config (default)
|
|
1294
1366
|
--local write to project config (where supported)
|
|
1295
1367
|
--all-projects Claude global: list across all projects
|
|
@@ -1306,7 +1378,7 @@ Usage:
|
|
|
1306
1378
|
mcp-conf enable --client <name> --name <serverName> [options]
|
|
1307
1379
|
|
|
1308
1380
|
Options:
|
|
1309
|
-
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot | antigravity (repeatable)
|
|
1381
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | kilo | copilot | antigravity (repeatable)
|
|
1310
1382
|
--name <serverName> required MCP server name key
|
|
1311
1383
|
--global write to global user config (default)
|
|
1312
1384
|
--local write to project config (where supported)
|
|
@@ -1325,7 +1397,7 @@ Usage:
|
|
|
1325
1397
|
mcp-conf disable --client <name> --name <serverName> [options]
|
|
1326
1398
|
|
|
1327
1399
|
Options:
|
|
1328
|
-
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot | antigravity (repeatable)
|
|
1400
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | kilo | copilot | antigravity (repeatable)
|
|
1329
1401
|
--name <serverName> required MCP server name key
|
|
1330
1402
|
--global write to global user config (default)
|
|
1331
1403
|
--local write to project config (where supported)
|
|
@@ -1344,7 +1416,7 @@ Usage:
|
|
|
1344
1416
|
mcp-conf where --client <name> --name <serverName> [options]
|
|
1345
1417
|
|
|
1346
1418
|
Options:
|
|
1347
|
-
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | copilot | antigravity (repeatable)
|
|
1419
|
+
--client <name> cline | codex | claude | goose | cursor | windsurf | opencode | kilo | copilot | antigravity (repeatable)
|
|
1348
1420
|
--name <serverName> required MCP server name key
|
|
1349
1421
|
--global write to global user config (default)
|
|
1350
1422
|
--local write to project config (where supported)
|
|
@@ -1353,6 +1425,18 @@ Options:
|
|
|
1353
1425
|
|
|
1354
1426
|
Notes:
|
|
1355
1427
|
Antigravity local scope is not supported yet; use --global.
|
|
1428
|
+
`);
|
|
1429
|
+
break;
|
|
1430
|
+
case "tui":
|
|
1431
|
+
process.stdout.write(`${header} tui
|
|
1432
|
+
|
|
1433
|
+
Usage:
|
|
1434
|
+
mcp-conf tui
|
|
1435
|
+
|
|
1436
|
+
Description:
|
|
1437
|
+
Start interactive setup wizard for add/ls/rm/enable/disable.
|
|
1438
|
+
Flow: operation -> client -> scope (skips scope when only one is supported).
|
|
1439
|
+
For add + sse/http, wizard also asks timeout and repeatable headers.
|
|
1356
1440
|
`);
|
|
1357
1441
|
break;
|
|
1358
1442
|
default:
|
|
@@ -11,9 +11,9 @@ npm install -g @mcp-abap-adt/configurator
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
mcp-conf add --client cline --env /path/to/.env --name abap
|
|
14
|
+
mcp-conf add --client cline --env-path /path/to/.env --name abap
|
|
15
15
|
mcp-conf add --client cline --mcp TRIAL --name abap
|
|
16
|
-
mcp-conf add --client cline --env /path/to/.env --name abap --transport stdio
|
|
16
|
+
mcp-conf add --client cline --env-path /path/to/.env --name abap --transport stdio
|
|
17
17
|
mcp-conf add --client claude --mcp TRIAL --name abap
|
|
18
18
|
mcp-conf rm --client codex --name abap
|
|
19
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=...
|
|
@@ -21,8 +21,10 @@ mcp-conf add --client cline --name local-mcp-sse --transport sse --url http://lo
|
|
|
21
21
|
mcp-conf add --client codex --name abap-http --transport http --url http://localhost:3000/mcp/stream/http
|
|
22
22
|
mcp-conf add --client codex --name abap-http --transport http --url http://localhost:3000/mcp/stream/http --header x-mcp-destination=trial
|
|
23
23
|
mcp-conf add --client opencode --name abap --transport http --url http://localhost:3000/mcp/stream/http
|
|
24
|
+
mcp-conf add --client kilo --name abap --transport http --url http://localhost:3000/mcp/stream/http
|
|
24
25
|
mcp-conf add --client copilot --name abap --transport http --url http://localhost:3000/mcp/stream/http --header x-mcp-destination=trial
|
|
25
26
|
mcp-conf add --client antigravity --name abap --transport http --url http://localhost:3000/mcp/stream/http
|
|
27
|
+
mcp-conf tui
|
|
26
28
|
```
|
|
27
29
|
|
|
28
30
|
## Common Tasks
|
|
@@ -30,7 +32,7 @@ mcp-conf add --client antigravity --name abap --transport http --url http://loca
|
|
|
30
32
|
Add MCP:
|
|
31
33
|
```bash
|
|
32
34
|
mcp-conf add --client codex --mcp TRIAL --name abap
|
|
33
|
-
mcp-conf add --client cline --env /path/to/.env --name abap
|
|
35
|
+
mcp-conf add --client cline --env-path /path/to/.env --name abap
|
|
34
36
|
mcp-conf add --client claude --mcp TRIAL --name abap
|
|
35
37
|
mcp-conf add --client claude --name abap-http --transport http --url http://localhost:3000/mcp/stream/http --header x-mcp-destination=trial
|
|
36
38
|
mcp-conf add --client claude --name abap --project /path/to/project --mcp TRIAL
|
|
@@ -73,16 +75,26 @@ mcp-conf where --client claude --name goose --project /path/to/project
|
|
|
73
75
|
mcp-conf where --client claude --name goose --all-projects
|
|
74
76
|
```
|
|
75
77
|
|
|
78
|
+
TUI wizard:
|
|
79
|
+
```bash
|
|
80
|
+
mcp-conf tui
|
|
81
|
+
```
|
|
82
|
+
- Flow order: `operation` -> `client` -> `scope`.
|
|
83
|
+
- Scope step is skipped automatically for single-scope clients.
|
|
84
|
+
- For `add` with `sse/http`, the wizard asks URL, timeout, and repeatable headers.
|
|
85
|
+
- Controls: arrow keys + Enter, Ctrl+C to cancel.
|
|
86
|
+
|
|
76
87
|
Options:
|
|
77
|
-
- Commands: `add`, `rm`, `ls`, `enable`, `disable`, `where` (first argument)
|
|
78
|
-
- `--client <name>` (repeatable): `cline`, `codex`, `claude`, `goose`, `cursor`, `windsurf`, `opencode
|
|
79
|
-
- `--env
|
|
88
|
+
- Commands: `add`, `rm`, `ls`, `enable`, `disable`, `where`, `tui` (first argument)
|
|
89
|
+
- `--client <name>` (repeatable): `cline`, `codex`, `claude`, `goose`, `cursor`, `windsurf`, `opencode` (`kilo` alias), `copilot`, `antigravity`
|
|
90
|
+
- `--env`: use shell/session environment variables (stdio only)
|
|
91
|
+
- `--env-path <path>`: use a specific `.env` file (stdio only)
|
|
80
92
|
- `--mcp <destination>`: use service key destination
|
|
81
93
|
- `--name <serverName>`: MCP server name (required)
|
|
82
94
|
- `--transport <type>`: `stdio`, `sse`, or `http` (`http` maps to `streamableHttp`)
|
|
83
95
|
- `--command <bin>`: command to run (default: `mcp-abap-adt`)
|
|
84
96
|
- `--global`: write to the global user config (default)
|
|
85
|
-
- `--local`: write to the project config (supported by `cursor`, `opencode`, `copilot`, `claude`, `codex`)
|
|
97
|
+
- `--local`: write to the project config (supported by `cursor`, `opencode`/`kilo`, `copilot`, `claude`, `codex`)
|
|
86
98
|
- `--all-projects`: for Claude (global scope), apply `rm/enable/disable/ls/where` across all projects
|
|
87
99
|
- `--project <path>`: for Claude (global scope), target a specific project path
|
|
88
100
|
- `--url <http(s)://...>`: required for `sse` and `http`
|
|
@@ -90,8 +102,9 @@ Options:
|
|
|
90
102
|
- `--timeout <seconds>`: timeout value for client entries (default: 60)
|
|
91
103
|
|
|
92
104
|
Notes:
|
|
93
|
-
- `disable` and `rm` do not require `--env
|
|
94
|
-
- `--env`/`--mcp` are only valid for `stdio` transport. For `sse/http`, use `--url` and optional `--header`.
|
|
105
|
+
- `disable` and `rm` do not require `--env`, `--env-path`, or `--mcp`.
|
|
106
|
+
- `--env`/`--env-path`/`--mcp` are only valid for `stdio` transport. For `sse/http`, use `--url` and optional `--header`.
|
|
107
|
+
- `mcp-conf tui` starts an interactive wizard and writes the same config as `add`.
|
|
95
108
|
- Cursor/Copilot enable/disable are not implemented yet.
|
|
96
109
|
- Antigravity enable/disable uses `disabled: true|false` on the entry.
|
|
97
110
|
- Antigravity local scope is not supported yet; use `--global`.
|
|
@@ -100,7 +113,7 @@ Notes:
|
|
|
100
113
|
- Antigravity HTTP entries use `serverUrl` instead of `url`.
|
|
101
114
|
- New entries for Cline, Codex, Windsurf, Goose, Claude, and OpenCode are added **disabled by default**. Use `enable` to turn them on.
|
|
102
115
|
- Windsurf follows `disabled` like Cline. The configurator sets `disabled = true` for default-disabled entries.
|
|
103
|
-
- `enable`/`disable` only work if the server entry already exists. Use add commands with `--env
|
|
116
|
+
- `enable`/`disable` only work if the server entry already exists. Use add commands with `--env`, `--env-path`, or `--mcp` first.
|
|
104
117
|
- Non-stdio transports are supported for Cline/Cursor/Windsurf/Claude/Goose. Codex supports `http` (streamable HTTP) but not `sse`.
|
|
105
118
|
- Codex writes custom headers under `http_headers` in `~/.codex/config.toml` (or `./.codex/config.toml` for `--local`).
|
|
106
119
|
- Codex HTTP entries include `startup_timeout_sec` (default: 60).
|
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.6",
|
|
4
4
|
"description": "MCP client configurator for mcp-abap-adt and mcp-abap-adt-proxy",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -28,9 +28,10 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@iarna/toml": "^3.0.0",
|
|
31
|
+
"enquirer": "^2.4.1",
|
|
31
32
|
"yaml": "^2.8.1"
|
|
32
33
|
},
|
|
33
34
|
"devDependencies": {
|
|
34
|
-
"@biomejs/biome": "^2.3.
|
|
35
|
+
"@biomejs/biome": "^2.3.15"
|
|
35
36
|
}
|
|
36
37
|
}
|