@kwonye/mcpx 0.1.77 → 0.1.80
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/dist/adapters/claude.d.ts.map +1 -1
- package/dist/adapters/cline.d.ts.map +1 -1
- package/dist/{cli-fsf33sgp.js → cli-08mgt3c8.js} +4 -1
- package/dist/cli-0ztrmp65.js +514 -0
- package/dist/{cli-htm5cf82.js → cli-f2a6pkds.js} +492 -126
- package/dist/{cli-s4py8ckf.js → cli-ma89vavk.js} +42 -11
- package/dist/{cli-f16kphtq.js → cli-wcxyqz7g.js} +493 -127
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +34 -10
- package/dist/{config-kayej21q.js → config-p8tjffpa.js} +2 -2
- package/dist/core/add-command.d.ts +7 -0
- package/dist/core/add-command.d.ts.map +1 -0
- package/dist/core/auth-probe.d.ts +1 -0
- package/dist/core/auth-probe.d.ts.map +1 -1
- package/dist/core/config-repair.d.ts +3 -0
- package/dist/core/config-repair.d.ts.map +1 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/daemon.d.ts.map +1 -1
- package/dist/core/index.d.ts +5 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +25 -5
- package/dist/core/oauth.d.ts +12 -0
- package/dist/core/oauth.d.ts.map +1 -0
- package/dist/core/paths.d.ts +1 -0
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/registry.d.ts +1 -0
- package/dist/core/registry.d.ts.map +1 -1
- package/dist/core/spawn-env.d.ts +2 -0
- package/dist/core/spawn-env.d.ts.map +1 -0
- package/dist/core/status.d.ts.map +1 -1
- package/dist/core/sync.d.ts.map +1 -1
- package/dist/core/update.d.ts +1 -0
- package/dist/core/update.d.ts.map +1 -1
- package/dist/gateway/server.d.ts +5 -1
- package/dist/gateway/server.d.ts.map +1 -1
- package/dist/{registry-1s14wd58.js → registry-b3cetq7x.js} +4 -2
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/dist/cli-7bsf6akp.js +0 -202
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/adapters/claude.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA4B1G,qBAAa,aAAc,YAAW,aAAa;IACjD,QAAQ,CAAC,EAAE,EAAG,QAAQ,CAAU;IAEhC,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC,YAAY,IAAI,OAAO;IAIvB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY;IAwE9D,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU;
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/adapters/claude.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA4B1G,qBAAa,aAAc,YAAW,aAAa;IACjD,QAAQ,CAAC,EAAE,EAAG,QAAQ,CAAU;IAEhC,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC,YAAY,IAAI,OAAO;IAIvB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY;IAwE9D,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU;CA6DzE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cline.d.ts","sourceRoot":"","sources":["../../src/adapters/cline.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAiD1G,qBAAa,YAAa,YAAW,aAAa;IAChD,QAAQ,CAAC,EAAE,EAAG,OAAO,CAAU;IAE/B,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAWjC,YAAY,IAAI,OAAO;IAIvB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY;IAgE9D,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU;
|
|
1
|
+
{"version":3,"file":"cline.d.ts","sourceRoot":"","sources":["../../src/adapters/cline.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAiD1G,qBAAa,YAAa,YAAW,aAAa;IAChD,QAAQ,CAAC,EAAE,EAAG,OAAO,CAAU;IAE/B,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAWjC,YAAY,IAAI,OAAO;IAIvB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY;IAgE9D,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU;CA0DzE"}
|
|
@@ -44,6 +44,9 @@ function getPidPath() {
|
|
|
44
44
|
function getLogPath() {
|
|
45
45
|
return path.join(getLogDir(), "daemon.log");
|
|
46
46
|
}
|
|
47
|
+
function getGatewayTokenPath(secretName) {
|
|
48
|
+
return path.join(getConfigRoot(), "mcpx", `${secretName}.token`);
|
|
49
|
+
}
|
|
47
50
|
function getUpdatesDir() {
|
|
48
51
|
return path.join(getDataRoot(), "mcpx", "updates");
|
|
49
52
|
}
|
|
@@ -102,4 +105,4 @@ function sha256(value) {
|
|
|
102
105
|
return crypto.createHash("sha256").update(value).digest("hex");
|
|
103
106
|
}
|
|
104
107
|
|
|
105
|
-
export { homeDir, getConfigPath, getSkillsDir, getManagedIndexPath, getSecretNamesPath, getPidPath, getLogPath, getUpdatesDir, getStagedVersionPath, getUpdateLockPath, ensureDir, ensureParentDir, findProjectConfigPath, readJsonFile, writeJsonAtomic, sha256 };
|
|
108
|
+
export { homeDir, getConfigPath, getSkillsDir, getManagedIndexPath, getSecretNamesPath, getPidPath, getLogPath, getGatewayTokenPath, getUpdatesDir, getStagedVersionPath, getUpdateLockPath, ensureDir, ensureParentDir, findProjectConfigPath, readJsonFile, writeJsonAtomic, sha256 };
|
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findProjectConfigPath,
|
|
3
|
+
getConfigPath,
|
|
4
|
+
readJsonFile,
|
|
5
|
+
writeJsonAtomic
|
|
6
|
+
} from "./cli-08mgt3c8.js";
|
|
7
|
+
import {
|
|
8
|
+
normalizeServerSpecEnabled
|
|
9
|
+
} from "./cli-s4gspqdf.js";
|
|
10
|
+
|
|
11
|
+
// src/core/config.ts
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
import path from "node:path";
|
|
14
|
+
import fs from "node:fs";
|
|
15
|
+
|
|
16
|
+
// src/core/add-command.ts
|
|
17
|
+
function tokenizeCommandLine(command) {
|
|
18
|
+
const tokens = [];
|
|
19
|
+
let current = "";
|
|
20
|
+
let quote = null;
|
|
21
|
+
let escaping = false;
|
|
22
|
+
for (const char of command.trim()) {
|
|
23
|
+
if (escaping) {
|
|
24
|
+
current += char;
|
|
25
|
+
escaping = false;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (char === "\\") {
|
|
29
|
+
escaping = true;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (quote) {
|
|
33
|
+
if (char === quote) {
|
|
34
|
+
quote = null;
|
|
35
|
+
} else {
|
|
36
|
+
current += char;
|
|
37
|
+
}
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (char === "'" || char === '"') {
|
|
41
|
+
quote = char;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (/\s/.test(char)) {
|
|
45
|
+
if (current.length > 0) {
|
|
46
|
+
tokens.push(current);
|
|
47
|
+
current = "";
|
|
48
|
+
}
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
current += char;
|
|
52
|
+
}
|
|
53
|
+
if (escaping) {
|
|
54
|
+
current += "\\";
|
|
55
|
+
}
|
|
56
|
+
if (quote) {
|
|
57
|
+
throw new Error("Unterminated quoted string.");
|
|
58
|
+
}
|
|
59
|
+
if (current.length > 0) {
|
|
60
|
+
tokens.push(current);
|
|
61
|
+
}
|
|
62
|
+
return tokens;
|
|
63
|
+
}
|
|
64
|
+
function isHttpUrl(value) {
|
|
65
|
+
try {
|
|
66
|
+
const parsed = new URL(value);
|
|
67
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
68
|
+
} catch {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function parseKeyValueFlag(value, label) {
|
|
73
|
+
const split = value.indexOf("=");
|
|
74
|
+
if (split <= 0 || split >= value.length - 1) {
|
|
75
|
+
throw new Error(`Invalid ${label} format: ${value}. Use KEY=VALUE.`);
|
|
76
|
+
}
|
|
77
|
+
return [value.slice(0, split), value.slice(split + 1)];
|
|
78
|
+
}
|
|
79
|
+
function parseCliAddCommand(command) {
|
|
80
|
+
let trimmed = command.trim();
|
|
81
|
+
if (trimmed.startsWith("mcpx ")) {
|
|
82
|
+
trimmed = trimmed.slice(5).trim();
|
|
83
|
+
}
|
|
84
|
+
const parts = tokenizeCommandLine(trimmed);
|
|
85
|
+
if (parts[0] === "claude" && parts[1] === "mcp" && parts[2] === "add") {
|
|
86
|
+
return parseClaudeAdd(parts.slice(3));
|
|
87
|
+
}
|
|
88
|
+
if (parts[0] === "codex" && parts[1] === "mcp" && parts[2] === "add") {
|
|
89
|
+
return parseCodexAdd(parts.slice(3));
|
|
90
|
+
}
|
|
91
|
+
if (parts[0] === "qwen" && parts[1] === "mcp" && parts[2] === "add") {
|
|
92
|
+
return parseQwenAdd(parts.slice(3));
|
|
93
|
+
}
|
|
94
|
+
if (parts[0] === "code" && parts[1] === "--add-mcp") {
|
|
95
|
+
return parseVSCodeAdd(parts[2]);
|
|
96
|
+
}
|
|
97
|
+
if (parts[0] === "add") {
|
|
98
|
+
return parseStandardAdd(parts.slice(1));
|
|
99
|
+
}
|
|
100
|
+
return parseStandardAdd(parts);
|
|
101
|
+
}
|
|
102
|
+
function parseStandardAdd(args) {
|
|
103
|
+
const header = [];
|
|
104
|
+
const env = [];
|
|
105
|
+
let cwd;
|
|
106
|
+
const values = [];
|
|
107
|
+
for (let i = 0;i < args.length; i++) {
|
|
108
|
+
const arg = args[i];
|
|
109
|
+
if (arg === "--transport") {
|
|
110
|
+
i++;
|
|
111
|
+
} else if (arg === "--header") {
|
|
112
|
+
header.push(args[++i]);
|
|
113
|
+
} else if (arg === "--env") {
|
|
114
|
+
env.push(args[++i]);
|
|
115
|
+
} else if (arg === "--cwd") {
|
|
116
|
+
cwd = args[++i];
|
|
117
|
+
} else if (arg === "--force") {} else {
|
|
118
|
+
values.push(arg);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return buildServerSpec(values, { header, env, cwd });
|
|
122
|
+
}
|
|
123
|
+
function parseClaudeAdd(args) {
|
|
124
|
+
const header = [];
|
|
125
|
+
const env = [];
|
|
126
|
+
let cwd;
|
|
127
|
+
const values = [];
|
|
128
|
+
for (let i = 0;i < args.length; i++) {
|
|
129
|
+
const arg = args[i];
|
|
130
|
+
if (arg === "--header") {
|
|
131
|
+
header.push(args[++i]);
|
|
132
|
+
} else if (arg === "--env") {
|
|
133
|
+
env.push(args[++i]);
|
|
134
|
+
} else if (arg === "--cwd") {
|
|
135
|
+
cwd = args[++i];
|
|
136
|
+
} else if (arg === "--transport" || arg === "--scope") {
|
|
137
|
+
i++;
|
|
138
|
+
} else {
|
|
139
|
+
values.push(arg);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return buildServerSpec(values, { header, env, cwd });
|
|
143
|
+
}
|
|
144
|
+
function parseCodexAdd(args) {
|
|
145
|
+
const env = [];
|
|
146
|
+
const values = [];
|
|
147
|
+
for (let i = 0;i < args.length; i++) {
|
|
148
|
+
const arg = args[i];
|
|
149
|
+
if (arg === "--env") {
|
|
150
|
+
env.push(args[++i]);
|
|
151
|
+
} else if (arg === "--") {
|
|
152
|
+
values.push(...args.slice(i + 1));
|
|
153
|
+
break;
|
|
154
|
+
} else {
|
|
155
|
+
values.push(arg);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return buildServerSpec(values, { header: [], env });
|
|
159
|
+
}
|
|
160
|
+
function parseQwenAdd(args) {
|
|
161
|
+
const header = [];
|
|
162
|
+
const env = [];
|
|
163
|
+
let cwd;
|
|
164
|
+
const values = [];
|
|
165
|
+
for (let i = 0;i < args.length; i++) {
|
|
166
|
+
const arg = args[i];
|
|
167
|
+
if (arg === "--header") {
|
|
168
|
+
header.push(args[++i]);
|
|
169
|
+
} else if (arg === "--env") {
|
|
170
|
+
env.push(args[++i]);
|
|
171
|
+
} else if (arg === "--cwd") {
|
|
172
|
+
cwd = args[++i];
|
|
173
|
+
} else if (arg === "--transport" || arg === "--scope" || arg === "--trust" || arg === "--include-tools" || arg === "--exclude-tools" || arg === "--timeout") {
|
|
174
|
+
i++;
|
|
175
|
+
} else {
|
|
176
|
+
values.push(arg);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return buildServerSpec(values, { header, env, cwd });
|
|
180
|
+
}
|
|
181
|
+
function parseVSCodeAdd(jsonPayload) {
|
|
182
|
+
if (!jsonPayload) {
|
|
183
|
+
throw new Error("Missing JSON payload for --add-mcp");
|
|
184
|
+
}
|
|
185
|
+
const payload = JSON.parse(jsonPayload);
|
|
186
|
+
const name = payload.name;
|
|
187
|
+
if (!name) {
|
|
188
|
+
throw new Error("Missing 'name' in JSON payload");
|
|
189
|
+
}
|
|
190
|
+
if (payload.url) {
|
|
191
|
+
return {
|
|
192
|
+
name,
|
|
193
|
+
spec: {
|
|
194
|
+
transport: "http",
|
|
195
|
+
url: payload.url,
|
|
196
|
+
headers: payload.headers
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
if (payload.command) {
|
|
201
|
+
return {
|
|
202
|
+
name,
|
|
203
|
+
spec: {
|
|
204
|
+
transport: "stdio",
|
|
205
|
+
command: payload.command,
|
|
206
|
+
args: payload.args,
|
|
207
|
+
env: payload.env,
|
|
208
|
+
cwd: payload.cwd
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
throw new Error("JSON payload must include 'url' or 'command'");
|
|
213
|
+
}
|
|
214
|
+
function buildServerSpec(values, options) {
|
|
215
|
+
if (values.length < 2) {
|
|
216
|
+
throw new Error("Usage: add [--transport auto|http|stdio] <name> <url|command> [args...]");
|
|
217
|
+
}
|
|
218
|
+
const name = values[0] ?? "";
|
|
219
|
+
const target = values[1] ?? "";
|
|
220
|
+
const trailing = values.slice(2);
|
|
221
|
+
const transport = isHttpUrl(target) && trailing.length === 0 ? "http" : "stdio";
|
|
222
|
+
if (transport === "http") {
|
|
223
|
+
if (values.length !== 2) {
|
|
224
|
+
throw new Error("HTTP upstream usage: add <name> --transport http <url>");
|
|
225
|
+
}
|
|
226
|
+
if (!isHttpUrl(target)) {
|
|
227
|
+
throw new Error(`Invalid HTTP URL: ${target}`);
|
|
228
|
+
}
|
|
229
|
+
if (options.env.length > 0 || options.cwd) {
|
|
230
|
+
throw new Error("--env/--cwd are only valid for stdio transport.");
|
|
231
|
+
}
|
|
232
|
+
const headers = {};
|
|
233
|
+
for (const item of options.header) {
|
|
234
|
+
const [key, value] = parseKeyValueFlag(item, "header");
|
|
235
|
+
headers[key] = value;
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
name,
|
|
239
|
+
spec: {
|
|
240
|
+
transport: "http",
|
|
241
|
+
url: target,
|
|
242
|
+
headers: Object.keys(headers).length > 0 ? headers : undefined
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
if (options.header.length > 0) {
|
|
247
|
+
throw new Error("--header is only valid for HTTP transport.");
|
|
248
|
+
}
|
|
249
|
+
const env = {};
|
|
250
|
+
for (const item of options.env) {
|
|
251
|
+
const [key, value] = parseKeyValueFlag(item, "env");
|
|
252
|
+
env[key] = value;
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
name,
|
|
256
|
+
spec: {
|
|
257
|
+
transport: "stdio",
|
|
258
|
+
command: target,
|
|
259
|
+
args: trailing.length > 0 ? trailing : undefined,
|
|
260
|
+
env: Object.keys(env).length > 0 ? env : undefined,
|
|
261
|
+
cwd: options.cwd
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// src/core/config-repair.ts
|
|
267
|
+
function isHttpUrl2(value) {
|
|
268
|
+
try {
|
|
269
|
+
const parsed = new URL(value);
|
|
270
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
271
|
+
} catch {
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
function isClientInternalCommand(command) {
|
|
276
|
+
return /\.app\/Contents\//.test(command);
|
|
277
|
+
}
|
|
278
|
+
function repairServerSpec(spec) {
|
|
279
|
+
if (spec.transport !== "stdio") {
|
|
280
|
+
return spec;
|
|
281
|
+
}
|
|
282
|
+
if (isClientInternalCommand(spec.command)) {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
let commandParts;
|
|
286
|
+
try {
|
|
287
|
+
commandParts = tokenizeCommandLine(spec.command);
|
|
288
|
+
} catch {
|
|
289
|
+
return spec;
|
|
290
|
+
}
|
|
291
|
+
if (commandParts.length === 1) {
|
|
292
|
+
const command2 = commandParts[0] ?? spec.command;
|
|
293
|
+
if (isHttpUrl2(command2) && (!spec.args || spec.args.length === 0)) {
|
|
294
|
+
return {
|
|
295
|
+
transport: "http",
|
|
296
|
+
url: command2,
|
|
297
|
+
enabled: spec.enabled
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
...spec,
|
|
302
|
+
command: command2
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
const [command, ...commandArgs] = commandParts;
|
|
306
|
+
return {
|
|
307
|
+
...spec,
|
|
308
|
+
command,
|
|
309
|
+
args: [...commandArgs, ...spec.args ?? []]
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function repairConfig(config) {
|
|
313
|
+
const servers = {};
|
|
314
|
+
for (const [name, spec] of Object.entries(config.servers)) {
|
|
315
|
+
const repaired = repairServerSpec(spec);
|
|
316
|
+
if (repaired) {
|
|
317
|
+
servers[name] = repaired;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
...config,
|
|
322
|
+
servers
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// src/core/config.ts
|
|
327
|
+
var clientStateSchema = z.object({
|
|
328
|
+
status: z.enum(["SYNCED", "UNSUPPORTED_HTTP", "ERROR", "SKIPPED"]),
|
|
329
|
+
lastSyncAt: z.string().optional(),
|
|
330
|
+
message: z.string().optional(),
|
|
331
|
+
configPath: z.string().optional()
|
|
332
|
+
});
|
|
333
|
+
var httpServerSchema = z.object({
|
|
334
|
+
transport: z.literal("http"),
|
|
335
|
+
url: z.url(),
|
|
336
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
337
|
+
enabled: z.boolean().default(true)
|
|
338
|
+
});
|
|
339
|
+
var stdioServerSchema = z.object({
|
|
340
|
+
transport: z.literal("stdio"),
|
|
341
|
+
command: z.string().min(1),
|
|
342
|
+
args: z.array(z.string()).optional(),
|
|
343
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
344
|
+
cwd: z.string().min(1).optional(),
|
|
345
|
+
enabled: z.boolean().default(true)
|
|
346
|
+
});
|
|
347
|
+
var serverSchema = z.discriminatedUnion("transport", [httpServerSchema, stdioServerSchema]);
|
|
348
|
+
var projectEntrySchema = z.object({
|
|
349
|
+
name: z.string(),
|
|
350
|
+
path: z.string()
|
|
351
|
+
});
|
|
352
|
+
var configSchema = z.object({
|
|
353
|
+
schemaVersion: z.literal(1).default(1),
|
|
354
|
+
gateway: z.object({
|
|
355
|
+
port: z.number().int().min(1).max(65535).default(37373),
|
|
356
|
+
tokenRef: z.string().default("secret://local_gateway_token"),
|
|
357
|
+
autoStart: z.boolean().default(true)
|
|
358
|
+
}).default({
|
|
359
|
+
port: 37373,
|
|
360
|
+
tokenRef: "secret://local_gateway_token",
|
|
361
|
+
autoStart: true
|
|
362
|
+
}),
|
|
363
|
+
servers: z.record(z.string(), serverSchema).default({}),
|
|
364
|
+
clients: z.record(z.string(), clientStateSchema).default({}),
|
|
365
|
+
projects: z.record(z.string(), projectEntrySchema).default({})
|
|
366
|
+
});
|
|
367
|
+
var projectConfigSchema = z.object({
|
|
368
|
+
name: z.string().min(1).optional(),
|
|
369
|
+
servers: z.record(z.string(), serverSchema).default({})
|
|
370
|
+
});
|
|
371
|
+
function defaultConfig() {
|
|
372
|
+
return {
|
|
373
|
+
schemaVersion: 1,
|
|
374
|
+
gateway: {
|
|
375
|
+
port: 37373,
|
|
376
|
+
tokenRef: "secret://local_gateway_token",
|
|
377
|
+
autoStart: true
|
|
378
|
+
},
|
|
379
|
+
servers: {},
|
|
380
|
+
clients: {},
|
|
381
|
+
projects: {}
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function loadConfig(configPath = getConfigPath()) {
|
|
385
|
+
const raw = readJsonFile(configPath, defaultConfig());
|
|
386
|
+
const parsed = configSchema.safeParse(raw);
|
|
387
|
+
if (!parsed.success) {
|
|
388
|
+
return defaultConfig();
|
|
389
|
+
}
|
|
390
|
+
const clientEntries = {};
|
|
391
|
+
for (const [key, value] of Object.entries(parsed.data.clients)) {
|
|
392
|
+
if (["claude", "claude-desktop", "codex", "cursor", "cline", "opencode", "kiro", "vscode", "qwen"].includes(key)) {
|
|
393
|
+
clientEntries[key] = value;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
const servers = Object.fromEntries(Object.entries(parsed.data.servers).map(([name, spec]) => [name, normalizeServerSpecEnabled(spec)]));
|
|
397
|
+
return repairConfig({
|
|
398
|
+
schemaVersion: 1,
|
|
399
|
+
gateway: parsed.data.gateway,
|
|
400
|
+
servers,
|
|
401
|
+
clients: clientEntries,
|
|
402
|
+
projects: parsed.data.projects
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
function saveConfig(config, configPath = getConfigPath()) {
|
|
406
|
+
config.servers = Object.fromEntries(Object.entries(config.servers).map(([name, spec]) => [name, normalizeServerSpecEnabled(spec)]));
|
|
407
|
+
let serversToSave = { ...config.servers };
|
|
408
|
+
if (configPath === getConfigPath() && config.projects) {
|
|
409
|
+
for (const [projectPath, projectEntry] of Object.entries(config.projects)) {
|
|
410
|
+
const localPath = path.join(projectPath, ".mcpx.json");
|
|
411
|
+
if (fs.existsSync(localPath)) {
|
|
412
|
+
try {
|
|
413
|
+
const localConfig = loadProjectConfig(localPath);
|
|
414
|
+
const projectName = localConfig.name || projectEntry.name || path.basename(projectPath);
|
|
415
|
+
for (const serverName of Object.keys(localConfig.servers)) {
|
|
416
|
+
const namespacedName = `${projectName}.${serverName}`;
|
|
417
|
+
delete serversToSave[namespacedName];
|
|
418
|
+
}
|
|
419
|
+
} catch {}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
const cleanedConfig = {
|
|
424
|
+
...config,
|
|
425
|
+
servers: serversToSave
|
|
426
|
+
};
|
|
427
|
+
writeJsonAtomic(configPath, cleanedConfig);
|
|
428
|
+
}
|
|
429
|
+
function loadProjectConfig(projectConfigPath) {
|
|
430
|
+
const raw = readJsonFile(projectConfigPath, { servers: {} });
|
|
431
|
+
const parsed = projectConfigSchema.safeParse(raw);
|
|
432
|
+
if (!parsed.success) {
|
|
433
|
+
return { servers: {} };
|
|
434
|
+
}
|
|
435
|
+
return parsed.data;
|
|
436
|
+
}
|
|
437
|
+
function saveProjectConfig(config, projectConfigPath) {
|
|
438
|
+
config.servers = Object.fromEntries(Object.entries(config.servers).map(([name, spec]) => [name, normalizeServerSpecEnabled(spec)]));
|
|
439
|
+
writeJsonAtomic(projectConfigPath, config);
|
|
440
|
+
}
|
|
441
|
+
function loadMergedConfig(configPath = getConfigPath()) {
|
|
442
|
+
const config = loadConfig(configPath);
|
|
443
|
+
if (!config.projects) {
|
|
444
|
+
config.projects = {};
|
|
445
|
+
}
|
|
446
|
+
for (const [projectPath, projectEntry] of Object.entries(config.projects)) {
|
|
447
|
+
const localPath = path.join(projectPath, ".mcpx.json");
|
|
448
|
+
if (!fs.existsSync(localPath)) {
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
try {
|
|
452
|
+
const localConfig = loadProjectConfig(localPath);
|
|
453
|
+
const projectName = localConfig.name || projectEntry.name || path.basename(projectPath);
|
|
454
|
+
for (const [serverName, spec] of Object.entries(localConfig.servers)) {
|
|
455
|
+
const namespacedName = `${projectName}.${serverName}`;
|
|
456
|
+
const normalized = normalizeServerSpecEnabled(spec);
|
|
457
|
+
if (normalized.transport === "stdio" && !normalized.cwd) {
|
|
458
|
+
normalized.cwd = projectPath;
|
|
459
|
+
}
|
|
460
|
+
config.servers[namespacedName] = normalized;
|
|
461
|
+
}
|
|
462
|
+
} catch {}
|
|
463
|
+
}
|
|
464
|
+
return config;
|
|
465
|
+
}
|
|
466
|
+
function resolveActiveConfig(options = {}) {
|
|
467
|
+
if (options.global) {
|
|
468
|
+
const globalPath2 = getConfigPath();
|
|
469
|
+
const config2 = loadConfig(globalPath2);
|
|
470
|
+
return {
|
|
471
|
+
type: "global",
|
|
472
|
+
configPath: globalPath2,
|
|
473
|
+
config: config2,
|
|
474
|
+
save: () => saveConfig(config2, globalPath2)
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
const projectConfigPath = findProjectConfigPath();
|
|
478
|
+
if (options.local || projectConfigPath) {
|
|
479
|
+
const targetPath = projectConfigPath || path.join(process.cwd(), ".mcpx.json");
|
|
480
|
+
const projectPath = path.dirname(targetPath);
|
|
481
|
+
const projectConfig = loadProjectConfig(targetPath);
|
|
482
|
+
const dummyConfig = {
|
|
483
|
+
schemaVersion: 1,
|
|
484
|
+
name: projectConfig.name,
|
|
485
|
+
gateway: {
|
|
486
|
+
port: 37373,
|
|
487
|
+
tokenRef: "secret://local_gateway_token",
|
|
488
|
+
autoStart: true
|
|
489
|
+
},
|
|
490
|
+
servers: projectConfig.servers,
|
|
491
|
+
clients: {}
|
|
492
|
+
};
|
|
493
|
+
return {
|
|
494
|
+
type: "project",
|
|
495
|
+
configPath: targetPath,
|
|
496
|
+
projectPath,
|
|
497
|
+
config: dummyConfig,
|
|
498
|
+
save: () => {
|
|
499
|
+
projectConfig.servers = dummyConfig.servers;
|
|
500
|
+
saveProjectConfig(projectConfig, targetPath);
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
const globalPath = getConfigPath();
|
|
505
|
+
const config = loadConfig(globalPath);
|
|
506
|
+
return {
|
|
507
|
+
type: "global",
|
|
508
|
+
configPath: globalPath,
|
|
509
|
+
config,
|
|
510
|
+
save: () => saveConfig(config, globalPath)
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export { tokenizeCommandLine, parseCliAddCommand, defaultConfig, loadConfig, saveConfig, loadProjectConfig, saveProjectConfig, loadMergedConfig, resolveActiveConfig };
|