@ai-ecoverse/mcpcat 0.31.17 → 0.31.18
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/host/mcpcat.mjs +225 -55
- package/dist/kernel/mcpcat.mjs +225 -55
- package/package.json +4 -4
package/dist/host/mcpcat.mjs
CHANGED
|
@@ -6558,6 +6558,12 @@ function agentIgnoresConfig(platform2, path) {
|
|
|
6558
6558
|
function projectConfigPath(platform2) {
|
|
6559
6559
|
return `${platform2.cwd}/.pi/mcp.json`;
|
|
6560
6560
|
}
|
|
6561
|
+
function cacheDir(platform2) {
|
|
6562
|
+
if (platform2.env.XDG_CACHE_HOME) return `${platform2.env.XDG_CACHE_HOME}/mcpcat`;
|
|
6563
|
+
const home = platform2.env.HOME ?? platform2.env.USERPROFILE ?? "/";
|
|
6564
|
+
if (platform2.env.LOCALAPPDATA) return `${platform2.env.LOCALAPPDATA}\\mcpcat\\cache`;
|
|
6565
|
+
return `${home}/Library/Caches/mcpcat`;
|
|
6566
|
+
}
|
|
6561
6567
|
function stateDir(platform2) {
|
|
6562
6568
|
if (platform2.env.XDG_STATE_HOME) return `${platform2.env.XDG_STATE_HOME}/mcpcat`;
|
|
6563
6569
|
const home = platform2.env.HOME ?? platform2.env.USERPROFILE ?? "/";
|
|
@@ -17441,6 +17447,142 @@ function parseLauncher(text) {
|
|
|
17441
17447
|
return m ? { node: m[1], entry: m[2] } : void 0;
|
|
17442
17448
|
}
|
|
17443
17449
|
|
|
17450
|
+
// src/auth/callback-port.ts
|
|
17451
|
+
function hasFixedCallback(oauth) {
|
|
17452
|
+
if (oauth?.callbackPort !== void 0 && oauth.callbackPort > 0) return true;
|
|
17453
|
+
if (!oauth?.callbackUrl) return false;
|
|
17454
|
+
try {
|
|
17455
|
+
const port = Number(new URL(oauth.callbackUrl).port);
|
|
17456
|
+
return port > 0;
|
|
17457
|
+
} catch {
|
|
17458
|
+
return false;
|
|
17459
|
+
}
|
|
17460
|
+
}
|
|
17461
|
+
function needsInjectedCallbackPort(options) {
|
|
17462
|
+
return options.namedEntry && !hasFixedCallback(options.oauth);
|
|
17463
|
+
}
|
|
17464
|
+
async function withInjectedCallbackPortIfNeeded(platform2, name, options, fn) {
|
|
17465
|
+
if (!needsInjectedCallbackPort(options)) return fn(void 0);
|
|
17466
|
+
const port = await allocateCallbackPort();
|
|
17467
|
+
return withTempCallbackPortConfig(platform2, name, port, fn);
|
|
17468
|
+
}
|
|
17469
|
+
async function allocateCallbackPort() {
|
|
17470
|
+
const callback = await OAuthCallbackServer.listen({
|
|
17471
|
+
host: "127.0.0.1",
|
|
17472
|
+
port: 0,
|
|
17473
|
+
path: "/callback"
|
|
17474
|
+
});
|
|
17475
|
+
try {
|
|
17476
|
+
return Number(new URL(callback.redirectUrl).port);
|
|
17477
|
+
} finally {
|
|
17478
|
+
await callback.close();
|
|
17479
|
+
}
|
|
17480
|
+
}
|
|
17481
|
+
function isRecord7(value) {
|
|
17482
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17483
|
+
}
|
|
17484
|
+
function hostEnv(platform2) {
|
|
17485
|
+
const out = {};
|
|
17486
|
+
for (const [key, value] of Object.entries(platform2.env)) {
|
|
17487
|
+
if (value !== void 0) out[key] = value;
|
|
17488
|
+
}
|
|
17489
|
+
return out;
|
|
17490
|
+
}
|
|
17491
|
+
async function makeTempDir(platform2) {
|
|
17492
|
+
const base = `${cacheDir(platform2)}/mcp-cb`;
|
|
17493
|
+
await platform2.fs.mkdir(base, { mode: 448 });
|
|
17494
|
+
for (let i = 0; i < 32; i++) {
|
|
17495
|
+
const dir = `${base}/${Date.now().toString(36)}-${i.toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
17496
|
+
try {
|
|
17497
|
+
await platform2.fs.mkdirExclusive(dir);
|
|
17498
|
+
return dir;
|
|
17499
|
+
} catch {
|
|
17500
|
+
}
|
|
17501
|
+
}
|
|
17502
|
+
throw new Error("unable to create temporary mcp config directory");
|
|
17503
|
+
}
|
|
17504
|
+
async function removeTempDir(platform2, dir) {
|
|
17505
|
+
try {
|
|
17506
|
+
if (platform2.fs.unlink) await platform2.fs.unlink(`${dir}/mcp.json`);
|
|
17507
|
+
} catch {
|
|
17508
|
+
}
|
|
17509
|
+
try {
|
|
17510
|
+
await platform2.fs.rmdir(dir);
|
|
17511
|
+
} catch {
|
|
17512
|
+
}
|
|
17513
|
+
}
|
|
17514
|
+
async function withTempCallbackPortConfig(platform2, name, port, fn) {
|
|
17515
|
+
const path = userConfigPath(platform2);
|
|
17516
|
+
let raw;
|
|
17517
|
+
try {
|
|
17518
|
+
raw = new TextDecoder().decode(await platform2.fs.readFile(path));
|
|
17519
|
+
} catch {
|
|
17520
|
+
return fn(void 0);
|
|
17521
|
+
}
|
|
17522
|
+
let parsed;
|
|
17523
|
+
try {
|
|
17524
|
+
parsed = JSON.parse(raw);
|
|
17525
|
+
} catch {
|
|
17526
|
+
return fn(void 0);
|
|
17527
|
+
}
|
|
17528
|
+
if (!isRecord7(parsed) || !isRecord7(parsed.mcpServers) || !isRecord7(parsed.mcpServers[name])) {
|
|
17529
|
+
return fn(void 0);
|
|
17530
|
+
}
|
|
17531
|
+
const entry = { ...parsed.mcpServers[name] };
|
|
17532
|
+
const prevOauth = isRecord7(entry.oauth) ? { ...entry.oauth } : {};
|
|
17533
|
+
const oauth = { ...prevOauth, callbackPort: port };
|
|
17534
|
+
if (typeof oauth.callbackUrl === "string") {
|
|
17535
|
+
try {
|
|
17536
|
+
const url = new URL(oauth.callbackUrl);
|
|
17537
|
+
if (!(Number(url.port) > 0)) {
|
|
17538
|
+
url.port = String(port);
|
|
17539
|
+
oauth.callbackUrl = url.href;
|
|
17540
|
+
}
|
|
17541
|
+
} catch {
|
|
17542
|
+
}
|
|
17543
|
+
}
|
|
17544
|
+
entry.oauth = oauth;
|
|
17545
|
+
const tempServers = { ...parsed.mcpServers, [name]: entry };
|
|
17546
|
+
const merged = { ...parsed, mcpServers: tempServers };
|
|
17547
|
+
const tempDir = await makeTempDir(platform2);
|
|
17548
|
+
const tempPath = `${tempDir}/mcp.json`;
|
|
17549
|
+
await platform2.fs.writeFile(tempPath, `${JSON.stringify(merged, null, 2)}
|
|
17550
|
+
`, { mode: 384 });
|
|
17551
|
+
const env = { ...hostEnv(platform2), PI_MCP_CONFIG: tempPath };
|
|
17552
|
+
let cleaned = false;
|
|
17553
|
+
const cleanup = async () => {
|
|
17554
|
+
if (cleaned) return;
|
|
17555
|
+
cleaned = true;
|
|
17556
|
+
await removeTempDir(platform2, tempDir);
|
|
17557
|
+
};
|
|
17558
|
+
const exitFor = (signal) => signal === "SIGINT" ? 130 : signal === "SIGTERM" ? 143 : 129;
|
|
17559
|
+
let signalCode;
|
|
17560
|
+
let wake;
|
|
17561
|
+
const stopped = new Promise((resolve) => {
|
|
17562
|
+
wake = resolve;
|
|
17563
|
+
});
|
|
17564
|
+
if (platform2.onSignal) {
|
|
17565
|
+
for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
|
|
17566
|
+
await platform2.onSignal(signal, () => {
|
|
17567
|
+
void cleanup().then(() => {
|
|
17568
|
+
signalCode = exitFor(signal);
|
|
17569
|
+
wake?.();
|
|
17570
|
+
});
|
|
17571
|
+
});
|
|
17572
|
+
}
|
|
17573
|
+
}
|
|
17574
|
+
try {
|
|
17575
|
+
const result = await Promise.race([
|
|
17576
|
+
fn(env).then((value) => ({ ok: true, value })),
|
|
17577
|
+
stopped.then(() => ({ ok: false }))
|
|
17578
|
+
]);
|
|
17579
|
+
if (!result.ok) platform2.exit(signalCode ?? 130);
|
|
17580
|
+
return result.value;
|
|
17581
|
+
} finally {
|
|
17582
|
+
await cleanup();
|
|
17583
|
+
}
|
|
17584
|
+
}
|
|
17585
|
+
|
|
17444
17586
|
// src/auth/oauth.ts
|
|
17445
17587
|
var CALLBACK_HOST2 = "127.0.0.1";
|
|
17446
17588
|
var CALLBACK_PATH2 = "/callback";
|
|
@@ -17456,14 +17598,23 @@ function timedFetch2(fetchImpl) {
|
|
|
17456
17598
|
});
|
|
17457
17599
|
};
|
|
17458
17600
|
}
|
|
17601
|
+
function nonzeroPort(value) {
|
|
17602
|
+
return value !== void 0 && value > 0 ? value : void 0;
|
|
17603
|
+
}
|
|
17604
|
+
function preferredPortFromRegistration(configured, registered) {
|
|
17605
|
+
if (configured !== void 0) return configured;
|
|
17606
|
+
if (!registered[0]) return void 0;
|
|
17607
|
+
return nonzeroPort(Number(new URL(registered[0]).port));
|
|
17608
|
+
}
|
|
17459
17609
|
function callbackSettings(oauth) {
|
|
17460
17610
|
const raw = oauth?.callbackUrl ?? `http://${CALLBACK_HOST2}${CALLBACK_PATH2}`;
|
|
17461
17611
|
const url = new URL(raw);
|
|
17462
17612
|
const address = url.hostname.replace(/^\[|\]$/g, "");
|
|
17463
|
-
const port = url.port ? Number(url.port) : oauth?.callbackPort;
|
|
17613
|
+
const port = nonzeroPort(url.port ? Number(url.port) : oauth?.callbackPort);
|
|
17464
17614
|
let fixedRedirectUrl;
|
|
17465
|
-
if (url.port)
|
|
17466
|
-
|
|
17615
|
+
if (nonzeroPort(url.port ? Number(url.port) : void 0) !== void 0 && oauth?.callbackUrl) {
|
|
17616
|
+
fixedRedirectUrl = oauth.callbackUrl;
|
|
17617
|
+
} else if (port !== void 0) {
|
|
17467
17618
|
url.port = String(port);
|
|
17468
17619
|
fixedRedirectUrl = url.href;
|
|
17469
17620
|
}
|
|
@@ -17475,6 +17626,24 @@ function callbackSettings(oauth) {
|
|
|
17475
17626
|
fixedRedirectUrl
|
|
17476
17627
|
};
|
|
17477
17628
|
}
|
|
17629
|
+
async function listenCallback(cbSettings, preferredPort) {
|
|
17630
|
+
try {
|
|
17631
|
+
return await OAuthCallbackServer.listen({
|
|
17632
|
+
host: cbSettings.host,
|
|
17633
|
+
redirectHost: cbSettings.redirectHost,
|
|
17634
|
+
port: preferredPort ?? 0,
|
|
17635
|
+
path: cbSettings.path
|
|
17636
|
+
});
|
|
17637
|
+
} catch (err) {
|
|
17638
|
+
if (preferredPort === void 0 || cbSettings.fixedRedirectUrl) throw err;
|
|
17639
|
+
return OAuthCallbackServer.listen({
|
|
17640
|
+
host: cbSettings.host,
|
|
17641
|
+
redirectHost: cbSettings.redirectHost,
|
|
17642
|
+
port: 0,
|
|
17643
|
+
path: cbSettings.path
|
|
17644
|
+
});
|
|
17645
|
+
}
|
|
17646
|
+
}
|
|
17478
17647
|
function cimdForServer(metadata, redirectUrl) {
|
|
17479
17648
|
if (!metadata?.client_id_metadata_document_supported) return void 0;
|
|
17480
17649
|
if (!metadata.token_endpoint_auth_methods_supported?.includes("none")) return void 0;
|
|
@@ -17579,24 +17748,17 @@ async function signIn(options) {
|
|
|
17579
17748
|
const stored = await store.load();
|
|
17580
17749
|
const cbSettings = callbackSettings(oauth);
|
|
17581
17750
|
const registered = stored?.clientInformation && "redirect_uris" in stored.clientInformation ? stored.clientInformation.redirect_uris : [];
|
|
17582
|
-
const preferredPort = cbSettings.port
|
|
17583
|
-
const callback = await
|
|
17584
|
-
host: cbSettings.host,
|
|
17585
|
-
redirectHost: cbSettings.redirectHost,
|
|
17586
|
-
port: preferredPort ?? 0,
|
|
17587
|
-
path: cbSettings.path
|
|
17588
|
-
});
|
|
17751
|
+
const preferredPort = preferredPortFromRegistration(cbSettings.port, registered);
|
|
17752
|
+
const callback = await listenCallback(cbSettings, preferredPort);
|
|
17589
17753
|
const redirectUrl = cbSettings.fixedRedirectUrl ?? callback.redirectUrl;
|
|
17590
17754
|
try {
|
|
17591
17755
|
if (stored) {
|
|
17592
17756
|
const next = { ...stored };
|
|
17593
17757
|
delete next.oauthState;
|
|
17594
|
-
|
|
17595
|
-
|
|
17596
|
-
if (!
|
|
17758
|
+
delete next.tokens;
|
|
17759
|
+
delete next.tokensExpireAt;
|
|
17760
|
+
if (!oauth?.clientId) {
|
|
17597
17761
|
delete next.clientInformation;
|
|
17598
|
-
delete next.tokens;
|
|
17599
|
-
delete next.tokensExpireAt;
|
|
17600
17762
|
}
|
|
17601
17763
|
await store.save(next);
|
|
17602
17764
|
}
|
|
@@ -17679,13 +17841,14 @@ async function resolveLoginTarget(platform2, target) {
|
|
|
17679
17841
|
return {
|
|
17680
17842
|
name: target,
|
|
17681
17843
|
serverUrl: httpConfig.url,
|
|
17682
|
-
oauth: httpConfig.oauth
|
|
17844
|
+
oauth: httpConfig.oauth,
|
|
17845
|
+
namedEntry: true
|
|
17683
17846
|
};
|
|
17684
17847
|
}
|
|
17685
17848
|
const resolved = resolveServerName(target);
|
|
17686
17849
|
if (resolved.isUrl) {
|
|
17687
17850
|
const url = withScheme(target);
|
|
17688
|
-
return { name: resolved.name, serverUrl: url, oauth: void 0 };
|
|
17851
|
+
return { name: resolved.name, serverUrl: url, oauth: void 0, namedEntry: false };
|
|
17689
17852
|
}
|
|
17690
17853
|
throw new Error(`unknown target '${target}': not a URL and not found in mcp.json`);
|
|
17691
17854
|
}
|
|
@@ -17716,24 +17879,31 @@ async function jerkLogin(platform2, target, resolved, args2) {
|
|
|
17716
17879
|
if (args2.includes("--no-browser")) {
|
|
17717
17880
|
argv.push("--no-browser");
|
|
17718
17881
|
}
|
|
17719
|
-
|
|
17720
|
-
|
|
17721
|
-
|
|
17722
|
-
|
|
17723
|
-
|
|
17724
|
-
|
|
17725
|
-
|
|
17726
|
-
|
|
17727
|
-
|
|
17728
|
-
|
|
17882
|
+
return withInjectedCallbackPortIfNeeded(
|
|
17883
|
+
platform2,
|
|
17884
|
+
resolved.name,
|
|
17885
|
+
{ namedEntry: resolved.namedEntry, oauth: resolved.oauth },
|
|
17886
|
+
async (env) => {
|
|
17887
|
+
const proc = await platform2.spawn({ argv, env });
|
|
17888
|
+
proc.stdin.close().catch(() => {
|
|
17889
|
+
});
|
|
17890
|
+
const [, errText, result] = await Promise.all([
|
|
17891
|
+
readStream2(proc.stdout),
|
|
17892
|
+
readStream2(proc.stderr),
|
|
17893
|
+
proc.wait()
|
|
17894
|
+
]);
|
|
17895
|
+
if (result.status === 0) {
|
|
17896
|
+
await platform2.write(1, `Signed in to ${target}
|
|
17729
17897
|
`);
|
|
17730
|
-
|
|
17731
|
-
|
|
17732
|
-
|
|
17733
|
-
|
|
17734
|
-
|
|
17735
|
-
|
|
17736
|
-
|
|
17898
|
+
return 0;
|
|
17899
|
+
}
|
|
17900
|
+
if (errText.trim()) {
|
|
17901
|
+
await platform2.write(2, sanitizeTerminal(errText));
|
|
17902
|
+
}
|
|
17903
|
+
if (result.status === JERK_EXIT_SIGN_IN) return 4;
|
|
17904
|
+
return result.status;
|
|
17905
|
+
}
|
|
17906
|
+
);
|
|
17737
17907
|
}
|
|
17738
17908
|
async function jerkLogout(platform2, target, resolved, source) {
|
|
17739
17909
|
const id = jerkId(resolved.name, resolved.serverUrl);
|
|
@@ -17910,11 +18080,11 @@ function concatUint8Arrays(arrays) {
|
|
|
17910
18080
|
}
|
|
17911
18081
|
|
|
17912
18082
|
// src/config/import.ts
|
|
17913
|
-
function
|
|
18083
|
+
function isRecord8(value) {
|
|
17914
18084
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17915
18085
|
}
|
|
17916
18086
|
function isStringRecord2(value) {
|
|
17917
|
-
return
|
|
18087
|
+
return isRecord8(value) && Object.values(value).every((v) => typeof v === "string");
|
|
17918
18088
|
}
|
|
17919
18089
|
function tryParse(text) {
|
|
17920
18090
|
try {
|
|
@@ -17944,17 +18114,17 @@ function importClaude(text, names) {
|
|
|
17944
18114
|
result.errors.push(error);
|
|
17945
18115
|
return result;
|
|
17946
18116
|
}
|
|
17947
|
-
if (!
|
|
18117
|
+
if (!isRecord8(parsed)) {
|
|
17948
18118
|
result.errors.push("expected an object");
|
|
17949
18119
|
return result;
|
|
17950
18120
|
}
|
|
17951
18121
|
const mcpServers = parsed.mcpServers;
|
|
17952
|
-
if (!
|
|
18122
|
+
if (!isRecord8(mcpServers)) {
|
|
17953
18123
|
result.errors.push('no "mcpServers" object');
|
|
17954
18124
|
return result;
|
|
17955
18125
|
}
|
|
17956
18126
|
for (const [name, entry] of filterNames(Object.entries(mcpServers), names)) {
|
|
17957
|
-
if (!
|
|
18127
|
+
if (!isRecord8(entry)) {
|
|
17958
18128
|
result.errors.push(`${name}: not an object`);
|
|
17959
18129
|
continue;
|
|
17960
18130
|
}
|
|
@@ -17969,17 +18139,17 @@ function importVSCode(text, names) {
|
|
|
17969
18139
|
result.errors.push(error);
|
|
17970
18140
|
return result;
|
|
17971
18141
|
}
|
|
17972
|
-
if (!
|
|
18142
|
+
if (!isRecord8(parsed)) {
|
|
17973
18143
|
result.errors.push("expected an object");
|
|
17974
18144
|
return result;
|
|
17975
18145
|
}
|
|
17976
18146
|
const servers = parsed.servers ?? parsed.mcpServers;
|
|
17977
|
-
if (!
|
|
18147
|
+
if (!isRecord8(servers)) {
|
|
17978
18148
|
result.errors.push('no "servers" or "mcpServers" object');
|
|
17979
18149
|
return result;
|
|
17980
18150
|
}
|
|
17981
18151
|
for (const [name, entry] of filterNames(Object.entries(servers), names)) {
|
|
17982
|
-
if (!
|
|
18152
|
+
if (!isRecord8(entry)) {
|
|
17983
18153
|
result.errors.push(`${name}: not an object`);
|
|
17984
18154
|
continue;
|
|
17985
18155
|
}
|
|
@@ -18013,17 +18183,17 @@ function importSixServers(text, names) {
|
|
|
18013
18183
|
result.errors.push(error);
|
|
18014
18184
|
return result;
|
|
18015
18185
|
}
|
|
18016
|
-
if (!
|
|
18186
|
+
if (!isRecord8(parsed)) {
|
|
18017
18187
|
result.errors.push("expected an object");
|
|
18018
18188
|
return result;
|
|
18019
18189
|
}
|
|
18020
18190
|
const servers = parsed.servers;
|
|
18021
|
-
if (!
|
|
18191
|
+
if (!isRecord8(servers)) {
|
|
18022
18192
|
result.errors.push('no "servers" object');
|
|
18023
18193
|
return result;
|
|
18024
18194
|
}
|
|
18025
18195
|
for (const [name, entry] of filterNames(Object.entries(servers), names)) {
|
|
18026
|
-
if (!
|
|
18196
|
+
if (!isRecord8(entry)) {
|
|
18027
18197
|
result.errors.push(`${name}: not an object`);
|
|
18028
18198
|
continue;
|
|
18029
18199
|
}
|
|
@@ -18031,7 +18201,7 @@ function importSixServers(text, names) {
|
|
|
18031
18201
|
if (typeof entry.url === "string") config.url = entry.url;
|
|
18032
18202
|
if (isStringRecord2(entry.headers)) config.headers = entry.headers;
|
|
18033
18203
|
if (typeof entry.exposure === "string") config.exposure = entry.exposure;
|
|
18034
|
-
if (
|
|
18204
|
+
if (isRecord8(entry.toolExposure)) config.toolExposure = entry.toolExposure;
|
|
18035
18205
|
result.servers.push({ name, config });
|
|
18036
18206
|
}
|
|
18037
18207
|
return result;
|
|
@@ -18048,7 +18218,7 @@ function importCodexToml(text, names) {
|
|
|
18048
18218
|
if (fields.command) config.command = fields.command;
|
|
18049
18219
|
if (fields.args) config.args = fields.args;
|
|
18050
18220
|
if (fields.url) config.url = fields.url;
|
|
18051
|
-
if (fields.env &&
|
|
18221
|
+
if (fields.env && isRecord8(fields.env)) config.env = fields.env;
|
|
18052
18222
|
result.servers.push({ name, config });
|
|
18053
18223
|
}
|
|
18054
18224
|
return result;
|
|
@@ -18100,7 +18270,7 @@ function convertOpenCodeLocal(entry) {
|
|
|
18100
18270
|
} else if (typeof entry.command === "string") {
|
|
18101
18271
|
config.command = entry.command;
|
|
18102
18272
|
}
|
|
18103
|
-
if (
|
|
18273
|
+
if (isRecord8(entry.environment)) {
|
|
18104
18274
|
const env = {};
|
|
18105
18275
|
for (const [k, v] of Object.entries(entry.environment)) {
|
|
18106
18276
|
if (typeof v === "string")
|
|
@@ -18123,17 +18293,17 @@ function importOpenCode(text, names) {
|
|
|
18123
18293
|
result.errors.push(error);
|
|
18124
18294
|
return result;
|
|
18125
18295
|
}
|
|
18126
|
-
if (!
|
|
18296
|
+
if (!isRecord8(parsed)) {
|
|
18127
18297
|
result.errors.push("expected an object");
|
|
18128
18298
|
return result;
|
|
18129
18299
|
}
|
|
18130
18300
|
const mcpServers = parsed.mcpServers ?? parsed.mcp;
|
|
18131
|
-
if (!
|
|
18301
|
+
if (!isRecord8(mcpServers)) {
|
|
18132
18302
|
result.errors.push("no mcp servers found");
|
|
18133
18303
|
return result;
|
|
18134
18304
|
}
|
|
18135
18305
|
for (const [name, entry] of filterNames(Object.entries(mcpServers), names)) {
|
|
18136
|
-
if (!
|
|
18306
|
+
if (!isRecord8(entry)) {
|
|
18137
18307
|
result.errors.push(`${name}: not an object`);
|
|
18138
18308
|
continue;
|
|
18139
18309
|
}
|
|
@@ -18149,9 +18319,9 @@ function detectFormat(text, filename) {
|
|
|
18149
18319
|
if (filename.includes(".vscode")) return "vscode";
|
|
18150
18320
|
try {
|
|
18151
18321
|
const parsed = JSON.parse(text);
|
|
18152
|
-
if (
|
|
18153
|
-
if (parsed.servers &&
|
|
18154
|
-
if (parsed.servers &&
|
|
18322
|
+
if (isRecord8(parsed)) {
|
|
18323
|
+
if (parsed.servers && isRecord8(parsed.servers) && parsed.version !== void 0) return "six";
|
|
18324
|
+
if (parsed.servers && isRecord8(parsed.servers)) return "vscode";
|
|
18155
18325
|
if (parsed.mcpServers) return "claude";
|
|
18156
18326
|
if (parsed.mcp) return "opencode";
|
|
18157
18327
|
}
|
|
@@ -22315,5 +22485,5 @@ try {
|
|
|
22315
22485
|
});
|
|
22316
22486
|
} catch {
|
|
22317
22487
|
}
|
|
22318
|
-
var code = await run(platform, "0.31.
|
|
22488
|
+
var code = await run(platform, "0.31.18", args);
|
|
22319
22489
|
process.exit(code);
|
package/dist/kernel/mcpcat.mjs
CHANGED
|
@@ -6179,6 +6179,12 @@ function agentIgnoresConfig(platform2, path) {
|
|
|
6179
6179
|
function projectConfigPath(platform2) {
|
|
6180
6180
|
return `${platform2.cwd}/.pi/mcp.json`;
|
|
6181
6181
|
}
|
|
6182
|
+
function cacheDir(platform2) {
|
|
6183
|
+
if (platform2.env.XDG_CACHE_HOME) return `${platform2.env.XDG_CACHE_HOME}/mcpcat`;
|
|
6184
|
+
const home = platform2.env.HOME ?? platform2.env.USERPROFILE ?? "/";
|
|
6185
|
+
if (platform2.env.LOCALAPPDATA) return `${platform2.env.LOCALAPPDATA}\\mcpcat\\cache`;
|
|
6186
|
+
return `${home}/Library/Caches/mcpcat`;
|
|
6187
|
+
}
|
|
6182
6188
|
function stateDir(platform2) {
|
|
6183
6189
|
if (platform2.env.XDG_STATE_HOME) return `${platform2.env.XDG_STATE_HOME}/mcpcat`;
|
|
6184
6190
|
const home = platform2.env.HOME ?? platform2.env.USERPROFILE ?? "/";
|
|
@@ -16968,6 +16974,142 @@ function parseUpgradeArgs(args) {
|
|
|
16968
16974
|
return { kind: "run", check, force };
|
|
16969
16975
|
}
|
|
16970
16976
|
|
|
16977
|
+
// src/auth/callback-port.ts
|
|
16978
|
+
function hasFixedCallback(oauth) {
|
|
16979
|
+
if (oauth?.callbackPort !== void 0 && oauth.callbackPort > 0) return true;
|
|
16980
|
+
if (!oauth?.callbackUrl) return false;
|
|
16981
|
+
try {
|
|
16982
|
+
const port = Number(new URL(oauth.callbackUrl).port);
|
|
16983
|
+
return port > 0;
|
|
16984
|
+
} catch {
|
|
16985
|
+
return false;
|
|
16986
|
+
}
|
|
16987
|
+
}
|
|
16988
|
+
function needsInjectedCallbackPort(options) {
|
|
16989
|
+
return options.namedEntry && !hasFixedCallback(options.oauth);
|
|
16990
|
+
}
|
|
16991
|
+
async function withInjectedCallbackPortIfNeeded(platform2, name, options, fn) {
|
|
16992
|
+
if (!needsInjectedCallbackPort(options)) return fn(void 0);
|
|
16993
|
+
const port = await allocateCallbackPort();
|
|
16994
|
+
return withTempCallbackPortConfig(platform2, name, port, fn);
|
|
16995
|
+
}
|
|
16996
|
+
async function allocateCallbackPort() {
|
|
16997
|
+
const callback = await OAuthCallbackServer.listen({
|
|
16998
|
+
host: "127.0.0.1",
|
|
16999
|
+
port: 0,
|
|
17000
|
+
path: "/callback"
|
|
17001
|
+
});
|
|
17002
|
+
try {
|
|
17003
|
+
return Number(new URL(callback.redirectUrl).port);
|
|
17004
|
+
} finally {
|
|
17005
|
+
await callback.close();
|
|
17006
|
+
}
|
|
17007
|
+
}
|
|
17008
|
+
function isRecord7(value) {
|
|
17009
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17010
|
+
}
|
|
17011
|
+
function hostEnv(platform2) {
|
|
17012
|
+
const out = {};
|
|
17013
|
+
for (const [key, value] of Object.entries(platform2.env)) {
|
|
17014
|
+
if (value !== void 0) out[key] = value;
|
|
17015
|
+
}
|
|
17016
|
+
return out;
|
|
17017
|
+
}
|
|
17018
|
+
async function makeTempDir(platform2) {
|
|
17019
|
+
const base = `${cacheDir(platform2)}/mcp-cb`;
|
|
17020
|
+
await platform2.fs.mkdir(base, { mode: 448 });
|
|
17021
|
+
for (let i = 0; i < 32; i++) {
|
|
17022
|
+
const dir = `${base}/${Date.now().toString(36)}-${i.toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
17023
|
+
try {
|
|
17024
|
+
await platform2.fs.mkdirExclusive(dir);
|
|
17025
|
+
return dir;
|
|
17026
|
+
} catch {
|
|
17027
|
+
}
|
|
17028
|
+
}
|
|
17029
|
+
throw new Error("unable to create temporary mcp config directory");
|
|
17030
|
+
}
|
|
17031
|
+
async function removeTempDir(platform2, dir) {
|
|
17032
|
+
try {
|
|
17033
|
+
if (platform2.fs.unlink) await platform2.fs.unlink(`${dir}/mcp.json`);
|
|
17034
|
+
} catch {
|
|
17035
|
+
}
|
|
17036
|
+
try {
|
|
17037
|
+
await platform2.fs.rmdir(dir);
|
|
17038
|
+
} catch {
|
|
17039
|
+
}
|
|
17040
|
+
}
|
|
17041
|
+
async function withTempCallbackPortConfig(platform2, name, port, fn) {
|
|
17042
|
+
const path = userConfigPath(platform2);
|
|
17043
|
+
let raw;
|
|
17044
|
+
try {
|
|
17045
|
+
raw = new TextDecoder().decode(await platform2.fs.readFile(path));
|
|
17046
|
+
} catch {
|
|
17047
|
+
return fn(void 0);
|
|
17048
|
+
}
|
|
17049
|
+
let parsed;
|
|
17050
|
+
try {
|
|
17051
|
+
parsed = JSON.parse(raw);
|
|
17052
|
+
} catch {
|
|
17053
|
+
return fn(void 0);
|
|
17054
|
+
}
|
|
17055
|
+
if (!isRecord7(parsed) || !isRecord7(parsed.mcpServers) || !isRecord7(parsed.mcpServers[name])) {
|
|
17056
|
+
return fn(void 0);
|
|
17057
|
+
}
|
|
17058
|
+
const entry = { ...parsed.mcpServers[name] };
|
|
17059
|
+
const prevOauth = isRecord7(entry.oauth) ? { ...entry.oauth } : {};
|
|
17060
|
+
const oauth = { ...prevOauth, callbackPort: port };
|
|
17061
|
+
if (typeof oauth.callbackUrl === "string") {
|
|
17062
|
+
try {
|
|
17063
|
+
const url = new URL(oauth.callbackUrl);
|
|
17064
|
+
if (!(Number(url.port) > 0)) {
|
|
17065
|
+
url.port = String(port);
|
|
17066
|
+
oauth.callbackUrl = url.href;
|
|
17067
|
+
}
|
|
17068
|
+
} catch {
|
|
17069
|
+
}
|
|
17070
|
+
}
|
|
17071
|
+
entry.oauth = oauth;
|
|
17072
|
+
const tempServers = { ...parsed.mcpServers, [name]: entry };
|
|
17073
|
+
const merged = { ...parsed, mcpServers: tempServers };
|
|
17074
|
+
const tempDir = await makeTempDir(platform2);
|
|
17075
|
+
const tempPath = `${tempDir}/mcp.json`;
|
|
17076
|
+
await platform2.fs.writeFile(tempPath, `${JSON.stringify(merged, null, 2)}
|
|
17077
|
+
`, { mode: 384 });
|
|
17078
|
+
const env2 = { ...hostEnv(platform2), PI_MCP_CONFIG: tempPath };
|
|
17079
|
+
let cleaned = false;
|
|
17080
|
+
const cleanup = async () => {
|
|
17081
|
+
if (cleaned) return;
|
|
17082
|
+
cleaned = true;
|
|
17083
|
+
await removeTempDir(platform2, tempDir);
|
|
17084
|
+
};
|
|
17085
|
+
const exitFor = (signal) => signal === "SIGINT" ? 130 : signal === "SIGTERM" ? 143 : 129;
|
|
17086
|
+
let signalCode;
|
|
17087
|
+
let wake;
|
|
17088
|
+
const stopped = new Promise((resolve2) => {
|
|
17089
|
+
wake = resolve2;
|
|
17090
|
+
});
|
|
17091
|
+
if (platform2.onSignal) {
|
|
17092
|
+
for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
|
|
17093
|
+
await platform2.onSignal(signal, () => {
|
|
17094
|
+
void cleanup().then(() => {
|
|
17095
|
+
signalCode = exitFor(signal);
|
|
17096
|
+
wake?.();
|
|
17097
|
+
});
|
|
17098
|
+
});
|
|
17099
|
+
}
|
|
17100
|
+
}
|
|
17101
|
+
try {
|
|
17102
|
+
const result = await Promise.race([
|
|
17103
|
+
fn(env2).then((value) => ({ ok: true, value })),
|
|
17104
|
+
stopped.then(() => ({ ok: false }))
|
|
17105
|
+
]);
|
|
17106
|
+
if (!result.ok) platform2.exit(signalCode ?? 130);
|
|
17107
|
+
return result.value;
|
|
17108
|
+
} finally {
|
|
17109
|
+
await cleanup();
|
|
17110
|
+
}
|
|
17111
|
+
}
|
|
17112
|
+
|
|
16971
17113
|
// src/auth/oauth.ts
|
|
16972
17114
|
var CALLBACK_HOST2 = "127.0.0.1";
|
|
16973
17115
|
var CALLBACK_PATH2 = "/callback";
|
|
@@ -16983,14 +17125,23 @@ function timedFetch2(fetchImpl) {
|
|
|
16983
17125
|
});
|
|
16984
17126
|
};
|
|
16985
17127
|
}
|
|
17128
|
+
function nonzeroPort(value) {
|
|
17129
|
+
return value !== void 0 && value > 0 ? value : void 0;
|
|
17130
|
+
}
|
|
17131
|
+
function preferredPortFromRegistration(configured, registered) {
|
|
17132
|
+
if (configured !== void 0) return configured;
|
|
17133
|
+
if (!registered[0]) return void 0;
|
|
17134
|
+
return nonzeroPort(Number(new URL(registered[0]).port));
|
|
17135
|
+
}
|
|
16986
17136
|
function callbackSettings(oauth) {
|
|
16987
17137
|
const raw = oauth?.callbackUrl ?? `http://${CALLBACK_HOST2}${CALLBACK_PATH2}`;
|
|
16988
17138
|
const url = new URL(raw);
|
|
16989
17139
|
const address = url.hostname.replace(/^\[|\]$/g, "");
|
|
16990
|
-
const port = url.port ? Number(url.port) : oauth?.callbackPort;
|
|
17140
|
+
const port = nonzeroPort(url.port ? Number(url.port) : oauth?.callbackPort);
|
|
16991
17141
|
let fixedRedirectUrl;
|
|
16992
|
-
if (url.port)
|
|
16993
|
-
|
|
17142
|
+
if (nonzeroPort(url.port ? Number(url.port) : void 0) !== void 0 && oauth?.callbackUrl) {
|
|
17143
|
+
fixedRedirectUrl = oauth.callbackUrl;
|
|
17144
|
+
} else if (port !== void 0) {
|
|
16994
17145
|
url.port = String(port);
|
|
16995
17146
|
fixedRedirectUrl = url.href;
|
|
16996
17147
|
}
|
|
@@ -17002,6 +17153,24 @@ function callbackSettings(oauth) {
|
|
|
17002
17153
|
fixedRedirectUrl
|
|
17003
17154
|
};
|
|
17004
17155
|
}
|
|
17156
|
+
async function listenCallback(cbSettings, preferredPort) {
|
|
17157
|
+
try {
|
|
17158
|
+
return await OAuthCallbackServer.listen({
|
|
17159
|
+
host: cbSettings.host,
|
|
17160
|
+
redirectHost: cbSettings.redirectHost,
|
|
17161
|
+
port: preferredPort ?? 0,
|
|
17162
|
+
path: cbSettings.path
|
|
17163
|
+
});
|
|
17164
|
+
} catch (err) {
|
|
17165
|
+
if (preferredPort === void 0 || cbSettings.fixedRedirectUrl) throw err;
|
|
17166
|
+
return OAuthCallbackServer.listen({
|
|
17167
|
+
host: cbSettings.host,
|
|
17168
|
+
redirectHost: cbSettings.redirectHost,
|
|
17169
|
+
port: 0,
|
|
17170
|
+
path: cbSettings.path
|
|
17171
|
+
});
|
|
17172
|
+
}
|
|
17173
|
+
}
|
|
17005
17174
|
function cimdForServer(metadata, redirectUrl) {
|
|
17006
17175
|
if (!metadata?.client_id_metadata_document_supported) return void 0;
|
|
17007
17176
|
if (!metadata.token_endpoint_auth_methods_supported?.includes("none")) return void 0;
|
|
@@ -17106,24 +17275,17 @@ async function signIn(options) {
|
|
|
17106
17275
|
const stored = await store.load();
|
|
17107
17276
|
const cbSettings = callbackSettings(oauth);
|
|
17108
17277
|
const registered = stored?.clientInformation && "redirect_uris" in stored.clientInformation ? stored.clientInformation.redirect_uris : [];
|
|
17109
|
-
const preferredPort = cbSettings.port
|
|
17110
|
-
const callback = await
|
|
17111
|
-
host: cbSettings.host,
|
|
17112
|
-
redirectHost: cbSettings.redirectHost,
|
|
17113
|
-
port: preferredPort ?? 0,
|
|
17114
|
-
path: cbSettings.path
|
|
17115
|
-
});
|
|
17278
|
+
const preferredPort = preferredPortFromRegistration(cbSettings.port, registered);
|
|
17279
|
+
const callback = await listenCallback(cbSettings, preferredPort);
|
|
17116
17280
|
const redirectUrl = cbSettings.fixedRedirectUrl ?? callback.redirectUrl;
|
|
17117
17281
|
try {
|
|
17118
17282
|
if (stored) {
|
|
17119
17283
|
const next = { ...stored };
|
|
17120
17284
|
delete next.oauthState;
|
|
17121
|
-
|
|
17122
|
-
|
|
17123
|
-
if (!
|
|
17285
|
+
delete next.tokens;
|
|
17286
|
+
delete next.tokensExpireAt;
|
|
17287
|
+
if (!oauth?.clientId) {
|
|
17124
17288
|
delete next.clientInformation;
|
|
17125
|
-
delete next.tokens;
|
|
17126
|
-
delete next.tokensExpireAt;
|
|
17127
17289
|
}
|
|
17128
17290
|
await store.save(next);
|
|
17129
17291
|
}
|
|
@@ -17206,13 +17368,14 @@ async function resolveLoginTarget(platform2, target) {
|
|
|
17206
17368
|
return {
|
|
17207
17369
|
name: target,
|
|
17208
17370
|
serverUrl: httpConfig.url,
|
|
17209
|
-
oauth: httpConfig.oauth
|
|
17371
|
+
oauth: httpConfig.oauth,
|
|
17372
|
+
namedEntry: true
|
|
17210
17373
|
};
|
|
17211
17374
|
}
|
|
17212
17375
|
const resolved = resolveServerName(target);
|
|
17213
17376
|
if (resolved.isUrl) {
|
|
17214
17377
|
const url = withScheme(target);
|
|
17215
|
-
return { name: resolved.name, serverUrl: url, oauth: void 0 };
|
|
17378
|
+
return { name: resolved.name, serverUrl: url, oauth: void 0, namedEntry: false };
|
|
17216
17379
|
}
|
|
17217
17380
|
throw new Error(`unknown target '${target}': not a URL and not found in mcp.json`);
|
|
17218
17381
|
}
|
|
@@ -17243,24 +17406,31 @@ async function jerkLogin(platform2, target, resolved, args) {
|
|
|
17243
17406
|
if (args.includes("--no-browser")) {
|
|
17244
17407
|
argv.push("--no-browser");
|
|
17245
17408
|
}
|
|
17246
|
-
|
|
17247
|
-
|
|
17248
|
-
|
|
17249
|
-
|
|
17250
|
-
|
|
17251
|
-
|
|
17252
|
-
|
|
17253
|
-
|
|
17254
|
-
|
|
17255
|
-
|
|
17409
|
+
return withInjectedCallbackPortIfNeeded(
|
|
17410
|
+
platform2,
|
|
17411
|
+
resolved.name,
|
|
17412
|
+
{ namedEntry: resolved.namedEntry, oauth: resolved.oauth },
|
|
17413
|
+
async (env2) => {
|
|
17414
|
+
const proc = await platform2.spawn({ argv, env: env2 });
|
|
17415
|
+
proc.stdin.close().catch(() => {
|
|
17416
|
+
});
|
|
17417
|
+
const [, errText, result] = await Promise.all([
|
|
17418
|
+
readStream2(proc.stdout),
|
|
17419
|
+
readStream2(proc.stderr),
|
|
17420
|
+
proc.wait()
|
|
17421
|
+
]);
|
|
17422
|
+
if (result.status === 0) {
|
|
17423
|
+
await platform2.write(1, `Signed in to ${target}
|
|
17256
17424
|
`);
|
|
17257
|
-
|
|
17258
|
-
|
|
17259
|
-
|
|
17260
|
-
|
|
17261
|
-
|
|
17262
|
-
|
|
17263
|
-
|
|
17425
|
+
return 0;
|
|
17426
|
+
}
|
|
17427
|
+
if (errText.trim()) {
|
|
17428
|
+
await platform2.write(2, sanitizeTerminal(errText));
|
|
17429
|
+
}
|
|
17430
|
+
if (result.status === JERK_EXIT_SIGN_IN) return 4;
|
|
17431
|
+
return result.status;
|
|
17432
|
+
}
|
|
17433
|
+
);
|
|
17264
17434
|
}
|
|
17265
17435
|
async function jerkLogout(platform2, target, resolved, source) {
|
|
17266
17436
|
const id = jerkId(resolved.name, resolved.serverUrl);
|
|
@@ -17437,11 +17607,11 @@ function concatUint8Arrays(arrays) {
|
|
|
17437
17607
|
}
|
|
17438
17608
|
|
|
17439
17609
|
// src/config/import.ts
|
|
17440
|
-
function
|
|
17610
|
+
function isRecord8(value) {
|
|
17441
17611
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17442
17612
|
}
|
|
17443
17613
|
function isStringRecord2(value) {
|
|
17444
|
-
return
|
|
17614
|
+
return isRecord8(value) && Object.values(value).every((v) => typeof v === "string");
|
|
17445
17615
|
}
|
|
17446
17616
|
function tryParse(text) {
|
|
17447
17617
|
try {
|
|
@@ -17471,17 +17641,17 @@ function importClaude(text, names) {
|
|
|
17471
17641
|
result.errors.push(error);
|
|
17472
17642
|
return result;
|
|
17473
17643
|
}
|
|
17474
|
-
if (!
|
|
17644
|
+
if (!isRecord8(parsed)) {
|
|
17475
17645
|
result.errors.push("expected an object");
|
|
17476
17646
|
return result;
|
|
17477
17647
|
}
|
|
17478
17648
|
const mcpServers = parsed.mcpServers;
|
|
17479
|
-
if (!
|
|
17649
|
+
if (!isRecord8(mcpServers)) {
|
|
17480
17650
|
result.errors.push('no "mcpServers" object');
|
|
17481
17651
|
return result;
|
|
17482
17652
|
}
|
|
17483
17653
|
for (const [name, entry] of filterNames(Object.entries(mcpServers), names)) {
|
|
17484
|
-
if (!
|
|
17654
|
+
if (!isRecord8(entry)) {
|
|
17485
17655
|
result.errors.push(`${name}: not an object`);
|
|
17486
17656
|
continue;
|
|
17487
17657
|
}
|
|
@@ -17496,17 +17666,17 @@ function importVSCode(text, names) {
|
|
|
17496
17666
|
result.errors.push(error);
|
|
17497
17667
|
return result;
|
|
17498
17668
|
}
|
|
17499
|
-
if (!
|
|
17669
|
+
if (!isRecord8(parsed)) {
|
|
17500
17670
|
result.errors.push("expected an object");
|
|
17501
17671
|
return result;
|
|
17502
17672
|
}
|
|
17503
17673
|
const servers = parsed.servers ?? parsed.mcpServers;
|
|
17504
|
-
if (!
|
|
17674
|
+
if (!isRecord8(servers)) {
|
|
17505
17675
|
result.errors.push('no "servers" or "mcpServers" object');
|
|
17506
17676
|
return result;
|
|
17507
17677
|
}
|
|
17508
17678
|
for (const [name, entry] of filterNames(Object.entries(servers), names)) {
|
|
17509
|
-
if (!
|
|
17679
|
+
if (!isRecord8(entry)) {
|
|
17510
17680
|
result.errors.push(`${name}: not an object`);
|
|
17511
17681
|
continue;
|
|
17512
17682
|
}
|
|
@@ -17540,17 +17710,17 @@ function importSixServers(text, names) {
|
|
|
17540
17710
|
result.errors.push(error);
|
|
17541
17711
|
return result;
|
|
17542
17712
|
}
|
|
17543
|
-
if (!
|
|
17713
|
+
if (!isRecord8(parsed)) {
|
|
17544
17714
|
result.errors.push("expected an object");
|
|
17545
17715
|
return result;
|
|
17546
17716
|
}
|
|
17547
17717
|
const servers = parsed.servers;
|
|
17548
|
-
if (!
|
|
17718
|
+
if (!isRecord8(servers)) {
|
|
17549
17719
|
result.errors.push('no "servers" object');
|
|
17550
17720
|
return result;
|
|
17551
17721
|
}
|
|
17552
17722
|
for (const [name, entry] of filterNames(Object.entries(servers), names)) {
|
|
17553
|
-
if (!
|
|
17723
|
+
if (!isRecord8(entry)) {
|
|
17554
17724
|
result.errors.push(`${name}: not an object`);
|
|
17555
17725
|
continue;
|
|
17556
17726
|
}
|
|
@@ -17558,7 +17728,7 @@ function importSixServers(text, names) {
|
|
|
17558
17728
|
if (typeof entry.url === "string") config.url = entry.url;
|
|
17559
17729
|
if (isStringRecord2(entry.headers)) config.headers = entry.headers;
|
|
17560
17730
|
if (typeof entry.exposure === "string") config.exposure = entry.exposure;
|
|
17561
|
-
if (
|
|
17731
|
+
if (isRecord8(entry.toolExposure)) config.toolExposure = entry.toolExposure;
|
|
17562
17732
|
result.servers.push({ name, config });
|
|
17563
17733
|
}
|
|
17564
17734
|
return result;
|
|
@@ -17575,7 +17745,7 @@ function importCodexToml(text, names) {
|
|
|
17575
17745
|
if (fields.command) config.command = fields.command;
|
|
17576
17746
|
if (fields.args) config.args = fields.args;
|
|
17577
17747
|
if (fields.url) config.url = fields.url;
|
|
17578
|
-
if (fields.env &&
|
|
17748
|
+
if (fields.env && isRecord8(fields.env)) config.env = fields.env;
|
|
17579
17749
|
result.servers.push({ name, config });
|
|
17580
17750
|
}
|
|
17581
17751
|
return result;
|
|
@@ -17627,7 +17797,7 @@ function convertOpenCodeLocal(entry) {
|
|
|
17627
17797
|
} else if (typeof entry.command === "string") {
|
|
17628
17798
|
config.command = entry.command;
|
|
17629
17799
|
}
|
|
17630
|
-
if (
|
|
17800
|
+
if (isRecord8(entry.environment)) {
|
|
17631
17801
|
const env2 = {};
|
|
17632
17802
|
for (const [k, v] of Object.entries(entry.environment)) {
|
|
17633
17803
|
if (typeof v === "string")
|
|
@@ -17650,17 +17820,17 @@ function importOpenCode(text, names) {
|
|
|
17650
17820
|
result.errors.push(error);
|
|
17651
17821
|
return result;
|
|
17652
17822
|
}
|
|
17653
|
-
if (!
|
|
17823
|
+
if (!isRecord8(parsed)) {
|
|
17654
17824
|
result.errors.push("expected an object");
|
|
17655
17825
|
return result;
|
|
17656
17826
|
}
|
|
17657
17827
|
const mcpServers = parsed.mcpServers ?? parsed.mcp;
|
|
17658
|
-
if (!
|
|
17828
|
+
if (!isRecord8(mcpServers)) {
|
|
17659
17829
|
result.errors.push("no mcp servers found");
|
|
17660
17830
|
return result;
|
|
17661
17831
|
}
|
|
17662
17832
|
for (const [name, entry] of filterNames(Object.entries(mcpServers), names)) {
|
|
17663
|
-
if (!
|
|
17833
|
+
if (!isRecord8(entry)) {
|
|
17664
17834
|
result.errors.push(`${name}: not an object`);
|
|
17665
17835
|
continue;
|
|
17666
17836
|
}
|
|
@@ -17676,9 +17846,9 @@ function detectFormat(text, filename) {
|
|
|
17676
17846
|
if (filename.includes(".vscode")) return "vscode";
|
|
17677
17847
|
try {
|
|
17678
17848
|
const parsed = JSON.parse(text);
|
|
17679
|
-
if (
|
|
17680
|
-
if (parsed.servers &&
|
|
17681
|
-
if (parsed.servers &&
|
|
17849
|
+
if (isRecord8(parsed)) {
|
|
17850
|
+
if (parsed.servers && isRecord8(parsed.servers) && parsed.version !== void 0) return "six";
|
|
17851
|
+
if (parsed.servers && isRecord8(parsed.servers)) return "vscode";
|
|
17682
17852
|
if (parsed.mcpServers) return "claude";
|
|
17683
17853
|
if (parsed.mcp) return "opencode";
|
|
17684
17854
|
}
|
|
@@ -21684,7 +21854,7 @@ async function main(ctx) {
|
|
|
21684
21854
|
packageDir: "/node_modules/@ai-ecoverse/mcpcat"
|
|
21685
21855
|
});
|
|
21686
21856
|
const args = ctx.argv.slice(1);
|
|
21687
|
-
return run(platform2, "0.31.
|
|
21857
|
+
return run(platform2, "0.31.18", args);
|
|
21688
21858
|
}
|
|
21689
21859
|
export {
|
|
21690
21860
|
main as default
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/mcpcat",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.18",
|
|
4
4
|
"description": "A curl for the Model Context Protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -58,16 +58,16 @@
|
|
|
58
58
|
"trust:dry": "npx fledgling sync --dry-run -y --skip-publish"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@ai-ecoverse/slicc-kernel": "1.
|
|
61
|
+
"@ai-ecoverse/slicc-kernel": "1.174.0",
|
|
62
62
|
"@ai-ecoverse/slicc-shared-web": "2.13.10",
|
|
63
|
-
"@ai-ecoverse/slicc-vault": "1.
|
|
63
|
+
"@ai-ecoverse/slicc-vault": "1.22.0",
|
|
64
64
|
"@biomejs/biome": "2.6.3",
|
|
65
65
|
"@earendil-works/pi-codemode": "1.4.0",
|
|
66
66
|
"@earendil-works/pi-mcp": "1.4.0",
|
|
67
67
|
"@types/node": "26.6.5",
|
|
68
68
|
"esbuild": "0.28.2",
|
|
69
69
|
"lefthook": "2.2.2",
|
|
70
|
-
"monocart-coverage-reports": "3.
|
|
70
|
+
"monocart-coverage-reports": "3.2.0",
|
|
71
71
|
"proper-lockfile": "4.1.2",
|
|
72
72
|
"quickjs-wasi": "3.6.3",
|
|
73
73
|
"semantic-release": "25.0.9",
|