@mcp-abap-adt/configurator 0.0.4 → 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 +137 -49
- package/docs/CLIENT_INSTALLERS.md +25 -11
- 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) {
|
|
@@ -229,16 +261,20 @@ const serverArgs = serverArgsRaw.filter(Boolean);
|
|
|
229
261
|
if (options.transport === "sse") {
|
|
230
262
|
fail("Codex does not support SSE transport.");
|
|
231
263
|
}
|
|
232
|
-
requireScope("Codex", ["global"], scope);
|
|
264
|
+
requireScope("Codex", ["global", "local"], scope);
|
|
233
265
|
if (options.list) {
|
|
234
|
-
listCodexConfig(getCodexPath(platform, home, userProfile));
|
|
266
|
+
listCodexConfig(getCodexPath(platform, home, userProfile, scope));
|
|
235
267
|
} else if (options.where) {
|
|
236
|
-
whereCodexConfig(getCodexPath(platform, home, userProfile), options.name);
|
|
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(
|
|
@@ -387,7 +456,10 @@ function getClinePath(platformValue, homeDir, appDataDir) {
|
|
|
387
456
|
);
|
|
388
457
|
}
|
|
389
458
|
|
|
390
|
-
function getCodexPath(platformValue, homeDir, userProfileDir) {
|
|
459
|
+
function getCodexPath(platformValue, homeDir, userProfileDir, scopeValue) {
|
|
460
|
+
if (scopeValue === "local") {
|
|
461
|
+
return path.join(process.cwd(), ".codex", "config.toml");
|
|
462
|
+
}
|
|
391
463
|
if (platformValue === "win32") {
|
|
392
464
|
return path.join(userProfileDir, ".codex", "config.toml");
|
|
393
465
|
}
|
|
@@ -1212,6 +1284,7 @@ function printHelp(command) {
|
|
|
1212
1284
|
|
|
1213
1285
|
Usage:
|
|
1214
1286
|
mcp-conf <add|rm|ls|enable|disable|where> --client <name> [options]
|
|
1287
|
+
mcp-conf tui
|
|
1215
1288
|
mcp-conf help <command>
|
|
1216
1289
|
|
|
1217
1290
|
Commands:
|
|
@@ -1221,6 +1294,7 @@ Commands:
|
|
|
1221
1294
|
enable enable an existing entry
|
|
1222
1295
|
disable disable an existing entry
|
|
1223
1296
|
where show where a server name is defined
|
|
1297
|
+
tui interactive setup wizard
|
|
1224
1298
|
|
|
1225
1299
|
Run:
|
|
1226
1300
|
mcp-conf <command> --help
|
|
@@ -1229,6 +1303,7 @@ Run:
|
|
|
1229
1303
|
Notes:
|
|
1230
1304
|
Scope defaults to --global (Copilot uses --local only).
|
|
1231
1305
|
For Claude, --local maps to the project scope file ./.mcp.json.
|
|
1306
|
+
For Codex, --local writes to ./.codex/config.toml.
|
|
1232
1307
|
`);
|
|
1233
1308
|
return;
|
|
1234
1309
|
}
|
|
@@ -1237,12 +1312,13 @@ Notes:
|
|
|
1237
1312
|
process.stdout.write(`${header} add
|
|
1238
1313
|
|
|
1239
1314
|
Usage:
|
|
1240
|
-
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]
|
|
1241
1316
|
|
|
1242
1317
|
Options:
|
|
1243
|
-
--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)
|
|
1244
1319
|
--name <serverName> required MCP server name key
|
|
1245
|
-
--env
|
|
1320
|
+
--env use current shell/session env vars (stdio only)
|
|
1321
|
+
--env-path <path> .env path (stdio only)
|
|
1246
1322
|
--mcp <dest> destination name (stdio only)
|
|
1247
1323
|
--transport <type> stdio | sse | http (http => streamableHttp)
|
|
1248
1324
|
--command <bin> command to run (default: mcp-abap-adt)
|
|
@@ -1266,7 +1342,7 @@ Usage:
|
|
|
1266
1342
|
mcp-conf rm --client <name> --name <serverName> [options]
|
|
1267
1343
|
|
|
1268
1344
|
Options:
|
|
1269
|
-
--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)
|
|
1270
1346
|
--name <serverName> required MCP server name key
|
|
1271
1347
|
--global write to global user config (default)
|
|
1272
1348
|
--local write to project config (where supported)
|
|
@@ -1285,7 +1361,7 @@ Usage:
|
|
|
1285
1361
|
mcp-conf ls --client <name> [options]
|
|
1286
1362
|
|
|
1287
1363
|
Options:
|
|
1288
|
-
--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)
|
|
1289
1365
|
--global write to global user config (default)
|
|
1290
1366
|
--local write to project config (where supported)
|
|
1291
1367
|
--all-projects Claude global: list across all projects
|
|
@@ -1302,7 +1378,7 @@ Usage:
|
|
|
1302
1378
|
mcp-conf enable --client <name> --name <serverName> [options]
|
|
1303
1379
|
|
|
1304
1380
|
Options:
|
|
1305
|
-
--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)
|
|
1306
1382
|
--name <serverName> required MCP server name key
|
|
1307
1383
|
--global write to global user config (default)
|
|
1308
1384
|
--local write to project config (where supported)
|
|
@@ -1321,7 +1397,7 @@ Usage:
|
|
|
1321
1397
|
mcp-conf disable --client <name> --name <serverName> [options]
|
|
1322
1398
|
|
|
1323
1399
|
Options:
|
|
1324
|
-
--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)
|
|
1325
1401
|
--name <serverName> required MCP server name key
|
|
1326
1402
|
--global write to global user config (default)
|
|
1327
1403
|
--local write to project config (where supported)
|
|
@@ -1340,7 +1416,7 @@ Usage:
|
|
|
1340
1416
|
mcp-conf where --client <name> --name <serverName> [options]
|
|
1341
1417
|
|
|
1342
1418
|
Options:
|
|
1343
|
-
--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)
|
|
1344
1420
|
--name <serverName> required MCP server name key
|
|
1345
1421
|
--global write to global user config (default)
|
|
1346
1422
|
--local write to project config (where supported)
|
|
@@ -1349,6 +1425,18 @@ Options:
|
|
|
1349
1425
|
|
|
1350
1426
|
Notes:
|
|
1351
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.
|
|
1352
1440
|
`);
|
|
1353
1441
|
break;
|
|
1354
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`)
|
|
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,9 +113,9 @@ 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
|
-
- Codex writes custom headers under `http_headers` in `~/.codex/config.toml
|
|
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).
|
|
107
120
|
- `--dry-run`: print changes without writing files
|
|
108
121
|
- `--force`: overwrite existing server entry if it exists
|
|
@@ -120,6 +133,7 @@ Global (default) locations:
|
|
|
120
133
|
- **Codex**:
|
|
121
134
|
- Linux/macOS: `~/.codex/config.toml`
|
|
122
135
|
- Windows: `%USERPROFILE%\.codex\config.toml`
|
|
136
|
+
- Local (project): `./.codex/config.toml`
|
|
123
137
|
- **Claude Code (CLI)**:
|
|
124
138
|
- Linux default: `~/.claude.json` (per-project entries under `projects.<cwd>.mcpServers`)
|
|
125
139
|
- **Claude Desktop**:
|
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
|
}
|