@ai-ecoverse/mcpcat 0.15.2 → 0.15.4
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 +137 -90
- package/dist/kernel/mcpcat.mjs +158 -92
- package/package.json +3 -3
package/dist/host/mcpcat.mjs
CHANGED
|
@@ -6477,7 +6477,26 @@ var McpOAuthProvider = class {
|
|
|
6477
6477
|
// src/auth/jerk-token-source.ts
|
|
6478
6478
|
var MIN_VERSION = [0, 14, 1];
|
|
6479
6479
|
var VERSION_TIMEOUT_MS = 2e3;
|
|
6480
|
+
var JERK_TIMEOUT_MS = 15e3;
|
|
6480
6481
|
var cachedAvailable;
|
|
6482
|
+
var cachedKnown;
|
|
6483
|
+
async function listMcpProviders(platform2) {
|
|
6484
|
+
const known = /* @__PURE__ */ new Set();
|
|
6485
|
+
try {
|
|
6486
|
+
const result = await runJerk(platform2, ["jerk", "list", "--json"], VERSION_TIMEOUT_MS);
|
|
6487
|
+
if (result.status !== 0) return known;
|
|
6488
|
+
const providers = JSON.parse(result.stdout);
|
|
6489
|
+
for (const p of providers) {
|
|
6490
|
+
if (p?.source === "mcp.json" && typeof p.provider === "string") known.add(p.provider);
|
|
6491
|
+
}
|
|
6492
|
+
} catch {
|
|
6493
|
+
}
|
|
6494
|
+
return known;
|
|
6495
|
+
}
|
|
6496
|
+
async function jerkKnows(platform2, id) {
|
|
6497
|
+
cachedKnown ??= listMcpProviders(platform2);
|
|
6498
|
+
return (await cachedKnown).has(id);
|
|
6499
|
+
}
|
|
6481
6500
|
function parseVersion(raw) {
|
|
6482
6501
|
const match = raw.trim().match(/(\d+)\.(\d+)\.(\d+)/);
|
|
6483
6502
|
if (!match) return void 0;
|
|
@@ -6523,23 +6542,39 @@ async function jerkAvailable(platform2) {
|
|
|
6523
6542
|
return false;
|
|
6524
6543
|
}
|
|
6525
6544
|
try {
|
|
6526
|
-
const
|
|
6527
|
-
const
|
|
6528
|
-
|
|
6529
|
-
});
|
|
6530
|
-
const work = Promise.all([readAll(proc.stdout), proc.wait()]).then(([out, result]) => {
|
|
6531
|
-
proc.stderr.cancel().catch(() => {
|
|
6532
|
-
});
|
|
6533
|
-
if (result.status !== 0) return false;
|
|
6534
|
-
const ver = parseVersion(out);
|
|
6535
|
-
return ver !== void 0 && versionSatisfied(ver);
|
|
6536
|
-
});
|
|
6537
|
-
cachedAvailable = await Promise.race([work, timeout]);
|
|
6545
|
+
const result = await runJerk(platform2, ["jerk", "--version"], VERSION_TIMEOUT_MS);
|
|
6546
|
+
const ver = result.status === 0 ? parseVersion(result.stdout) : void 0;
|
|
6547
|
+
cachedAvailable = ver !== void 0 && versionSatisfied(ver);
|
|
6538
6548
|
} catch {
|
|
6539
6549
|
cachedAvailable = false;
|
|
6540
6550
|
}
|
|
6541
6551
|
return cachedAvailable;
|
|
6542
6552
|
}
|
|
6553
|
+
var JerkTimeoutError = class extends Error {
|
|
6554
|
+
command;
|
|
6555
|
+
constructor(argv) {
|
|
6556
|
+
const command = argv.slice(0, 3).join(" ");
|
|
6557
|
+
super(`jerk did not answer; run \`${command}\` yourself`);
|
|
6558
|
+
this.name = "JerkTimeoutError";
|
|
6559
|
+
this.command = command;
|
|
6560
|
+
}
|
|
6561
|
+
};
|
|
6562
|
+
async function runJerk(platform2, argv, timeoutMs) {
|
|
6563
|
+
const proc = await platform2.spawn({ argv, stdin: "ignore" });
|
|
6564
|
+
let timer;
|
|
6565
|
+
const expired = new Promise((resolve) => {
|
|
6566
|
+
timer = setTimeout(() => resolve("timeout"), timeoutMs);
|
|
6567
|
+
});
|
|
6568
|
+
const work = Promise.all([readAll(proc.stdout), readAll(proc.stderr), proc.wait()]);
|
|
6569
|
+
const outcome = await Promise.race([work, expired]);
|
|
6570
|
+
clearTimeout(timer);
|
|
6571
|
+
if (outcome === "timeout") {
|
|
6572
|
+
await proc.kill("SIGKILL");
|
|
6573
|
+
throw new JerkTimeoutError(argv);
|
|
6574
|
+
}
|
|
6575
|
+
const [stdout, stderr, result] = outcome;
|
|
6576
|
+
return { status: result.status, stdout, stderr };
|
|
6577
|
+
}
|
|
6543
6578
|
function jerkId(name) {
|
|
6544
6579
|
if (name.startsWith("mcp:")) return name;
|
|
6545
6580
|
if (name.startsWith("url:")) return `mcp:${name}`;
|
|
@@ -6560,8 +6595,10 @@ var JerkSignInRequiredError = class extends Error {
|
|
|
6560
6595
|
};
|
|
6561
6596
|
var JerkTokenSource = class {
|
|
6562
6597
|
platform;
|
|
6563
|
-
|
|
6598
|
+
timeoutMs;
|
|
6599
|
+
constructor(platform2, timeoutMs = JERK_TIMEOUT_MS) {
|
|
6564
6600
|
this.platform = platform2;
|
|
6601
|
+
this.timeoutMs = timeoutMs;
|
|
6565
6602
|
}
|
|
6566
6603
|
async getToken(name, serverUrl, scope) {
|
|
6567
6604
|
const id = jerkId(name);
|
|
@@ -6569,12 +6606,7 @@ var JerkTokenSource = class {
|
|
|
6569
6606
|
if (scope) {
|
|
6570
6607
|
argv.push("--scope", scope);
|
|
6571
6608
|
}
|
|
6572
|
-
const
|
|
6573
|
-
const [outRaw, , result] = await Promise.all([
|
|
6574
|
-
readAll(proc.stdout),
|
|
6575
|
-
readAll(proc.stderr),
|
|
6576
|
-
proc.wait()
|
|
6577
|
-
]);
|
|
6609
|
+
const result = await runJerk(this.platform, argv, this.timeoutMs);
|
|
6578
6610
|
if (result.status === JERK_EXIT_SIGN_IN) {
|
|
6579
6611
|
throw new JerkSignInRequiredError(id, scope);
|
|
6580
6612
|
}
|
|
@@ -6584,7 +6616,7 @@ var JerkTokenSource = class {
|
|
|
6584
6616
|
if (result.status !== 0) {
|
|
6585
6617
|
return void 0;
|
|
6586
6618
|
}
|
|
6587
|
-
const parsed = JSON.parse(
|
|
6619
|
+
const parsed = JSON.parse(result.stdout.trim());
|
|
6588
6620
|
if (!parsed.token) return void 0;
|
|
6589
6621
|
return {
|
|
6590
6622
|
accessToken: parsed.token,
|
|
@@ -8571,7 +8603,7 @@ async function createStatelessConnection(options) {
|
|
|
8571
8603
|
token
|
|
8572
8604
|
});
|
|
8573
8605
|
} catch (authErr) {
|
|
8574
|
-
if (authErr instanceof AuthStepUpError) throw authErr;
|
|
8606
|
+
if (authErr instanceof AuthStepUpError || authErr instanceof JerkTimeoutError) throw authErr;
|
|
8575
8607
|
throw new McpAuthError(err.response.status, url);
|
|
8576
8608
|
}
|
|
8577
8609
|
}
|
|
@@ -11498,15 +11530,15 @@ function readMcpCommand(value) {
|
|
|
11498
11530
|
}
|
|
11499
11531
|
function readMcpPositionals(value) {
|
|
11500
11532
|
if (!Array.isArray(value)) return [];
|
|
11501
|
-
const
|
|
11533
|
+
const positionals2 = [];
|
|
11502
11534
|
for (const entry of value) {
|
|
11503
11535
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
11504
11536
|
const name = ownString(entry, "name");
|
|
11505
11537
|
if (!name) continue;
|
|
11506
11538
|
const required = Object.getOwnPropertyDescriptor(entry, "required")?.value;
|
|
11507
|
-
|
|
11539
|
+
positionals2.push({ name, required: required !== false, description: "" });
|
|
11508
11540
|
}
|
|
11509
|
-
return
|
|
11541
|
+
return positionals2;
|
|
11510
11542
|
}
|
|
11511
11543
|
function readMcpFlags(value) {
|
|
11512
11544
|
if (!Array.isArray(value)) return [];
|
|
@@ -12940,7 +12972,14 @@ async function runServe(platform2, options, version) {
|
|
|
12940
12972
|
generatedBearer
|
|
12941
12973
|
);
|
|
12942
12974
|
}
|
|
12943
|
-
|
|
12975
|
+
function serveAddress(platform2, host, port) {
|
|
12976
|
+
if (platform2.kind !== "kernel") return { url: `http://${host}:${port}/mcp` };
|
|
12977
|
+
return {
|
|
12978
|
+
url: `http://${port}.kernel.localhost/mcp`,
|
|
12979
|
+
loopbackUrl: `http://127.0.0.1:${port}/mcp`
|
|
12980
|
+
};
|
|
12981
|
+
}
|
|
12982
|
+
async function publishBearer(platform2, token, port, address, json) {
|
|
12944
12983
|
if (!json && platform2.isatty(2)) {
|
|
12945
12984
|
await platform2.write(2, `mcpcat serve: bearer ${token}
|
|
12946
12985
|
`);
|
|
@@ -12957,7 +12996,7 @@ async function publishBearer(platform2, token, port, listenUrl, json) {
|
|
|
12957
12996
|
await platform2.write(2, `mcpcat serve: bearer saved to ${tokenPath}
|
|
12958
12997
|
`);
|
|
12959
12998
|
if (json) {
|
|
12960
|
-
await platform2.write(1, `${JSON.stringify({
|
|
12999
|
+
await platform2.write(1, `${JSON.stringify({ ...address, bearerFile: tokenPath })}
|
|
12961
13000
|
`);
|
|
12962
13001
|
}
|
|
12963
13002
|
return tokenPath;
|
|
@@ -13136,19 +13175,20 @@ async function runWebMcpHttp(platform2, options, getTools, callTool, serverName,
|
|
|
13136
13175
|
const actualPort = listener.port;
|
|
13137
13176
|
const serverOrigins = buildServerOrigins(options.host, actualPort);
|
|
13138
13177
|
const allowedHosts = buildAllowedHosts(options.host, actualPort, options.allowHosts);
|
|
13139
|
-
const
|
|
13178
|
+
const address = serveAddress(platform2, options.host, actualPort);
|
|
13179
|
+
const listenUrl = address.url;
|
|
13140
13180
|
let tokenFilePath;
|
|
13141
13181
|
if (generatedBearer && resolvedBearer) {
|
|
13142
13182
|
tokenFilePath = await publishBearer(
|
|
13143
13183
|
platform2,
|
|
13144
13184
|
resolvedBearer,
|
|
13145
13185
|
actualPort,
|
|
13146
|
-
|
|
13186
|
+
address,
|
|
13147
13187
|
options.json
|
|
13148
13188
|
);
|
|
13149
13189
|
} else {
|
|
13150
13190
|
if (options.json) {
|
|
13151
|
-
await platform2.write(1, `${JSON.stringify(
|
|
13191
|
+
await platform2.write(1, `${JSON.stringify(address)}
|
|
13152
13192
|
`);
|
|
13153
13193
|
}
|
|
13154
13194
|
}
|
|
@@ -13331,19 +13371,20 @@ async function runProxyHttp(platform2, options, proxy, resolvedBearer, generated
|
|
|
13331
13371
|
const actualPort = listener.port;
|
|
13332
13372
|
const serverOrigins = buildServerOrigins(options.host, actualPort);
|
|
13333
13373
|
const allowedHosts = buildAllowedHosts(options.host, actualPort, options.allowHosts);
|
|
13334
|
-
const
|
|
13374
|
+
const address = serveAddress(platform2, options.host, actualPort);
|
|
13375
|
+
const listenUrl = address.url;
|
|
13335
13376
|
let tokenFilePath;
|
|
13336
13377
|
if (generatedBearer && resolvedBearer) {
|
|
13337
13378
|
tokenFilePath = await publishBearer(
|
|
13338
13379
|
platform2,
|
|
13339
13380
|
resolvedBearer,
|
|
13340
13381
|
actualPort,
|
|
13341
|
-
|
|
13382
|
+
address,
|
|
13342
13383
|
options.json
|
|
13343
13384
|
);
|
|
13344
13385
|
} else {
|
|
13345
13386
|
if (options.json) {
|
|
13346
|
-
await platform2.write(1, `${JSON.stringify(
|
|
13387
|
+
await platform2.write(1, `${JSON.stringify(address)}
|
|
13347
13388
|
`);
|
|
13348
13389
|
}
|
|
13349
13390
|
}
|
|
@@ -13507,19 +13548,20 @@ async function runHttpServer(platform2, options, tools, call, serverName, versio
|
|
|
13507
13548
|
const actualPort = listener.port;
|
|
13508
13549
|
const serverOrigins = buildServerOrigins(options.host, actualPort);
|
|
13509
13550
|
const allowedHosts = buildAllowedHosts(options.host, actualPort, options.allowHosts);
|
|
13510
|
-
const
|
|
13551
|
+
const address = serveAddress(platform2, options.host, actualPort);
|
|
13552
|
+
const listenUrl = address.url;
|
|
13511
13553
|
let tokenFilePath;
|
|
13512
13554
|
if (generatedBearer && resolvedBearer) {
|
|
13513
13555
|
tokenFilePath = await publishBearer(
|
|
13514
13556
|
platform2,
|
|
13515
13557
|
resolvedBearer,
|
|
13516
13558
|
actualPort,
|
|
13517
|
-
|
|
13559
|
+
address,
|
|
13518
13560
|
options.json
|
|
13519
13561
|
);
|
|
13520
13562
|
} else {
|
|
13521
13563
|
if (options.json) {
|
|
13522
|
-
await platform2.write(1, `${JSON.stringify(
|
|
13564
|
+
await platform2.write(1, `${JSON.stringify(address)}
|
|
13523
13565
|
`);
|
|
13524
13566
|
}
|
|
13525
13567
|
}
|
|
@@ -13846,16 +13888,20 @@ async function signIn(options) {
|
|
|
13846
13888
|
}
|
|
13847
13889
|
|
|
13848
13890
|
// src/cli/auth-verbs.ts
|
|
13849
|
-
|
|
13850
|
-
|
|
13851
|
-
|
|
13852
|
-
if (resolvedSource) return resolvedSource;
|
|
13853
|
-
if (await jerkAvailable(platform2)) {
|
|
13854
|
-
resolvedSource = new JerkTokenSource(platform2);
|
|
13855
|
-
} else {
|
|
13856
|
-
resolvedSource = new PiFileTokenSource(platform2);
|
|
13891
|
+
async function createTokenSource(platform2, name, timeoutMs = JERK_TIMEOUT_MS) {
|
|
13892
|
+
if (!isKernel(platform2) && !name.startsWith("url:") && await jerkAvailable(platform2) && await jerkKnows(platform2, jerkMcpId(name))) {
|
|
13893
|
+
return new JerkTokenSource(platform2, timeoutMs);
|
|
13857
13894
|
}
|
|
13858
|
-
return
|
|
13895
|
+
return new PiFileTokenSource(platform2);
|
|
13896
|
+
}
|
|
13897
|
+
var VALUE_FLAGS = /* @__PURE__ */ new Set(["--scope", "-m", "--timeout"]);
|
|
13898
|
+
function positionals(args2) {
|
|
13899
|
+
const out = [];
|
|
13900
|
+
for (let i = 0; i < args2.length; i++) {
|
|
13901
|
+
if (VALUE_FLAGS.has(args2[i])) i++;
|
|
13902
|
+
else if (!args2[i].startsWith("-")) out.push(args2[i]);
|
|
13903
|
+
}
|
|
13904
|
+
return out;
|
|
13859
13905
|
}
|
|
13860
13906
|
function resolveServerName(target) {
|
|
13861
13907
|
try {
|
|
@@ -13907,8 +13953,7 @@ async function readStream2(stream) {
|
|
|
13907
13953
|
}
|
|
13908
13954
|
return new TextDecoder().decode(buf);
|
|
13909
13955
|
}
|
|
13910
|
-
async function jerkLogin(platform2, target, args2) {
|
|
13911
|
-
const resolved = await resolveLoginTarget(platform2, target);
|
|
13956
|
+
async function jerkLogin(platform2, target, resolved, args2) {
|
|
13912
13957
|
const id = jerkMcpId(resolved.name);
|
|
13913
13958
|
const argv = ["jerk", id, "create"];
|
|
13914
13959
|
const scopeIdx = args2.indexOf("--scope");
|
|
@@ -13937,18 +13982,9 @@ async function jerkLogin(platform2, target, args2) {
|
|
|
13937
13982
|
if (result.status === JERK_EXIT_SIGN_IN) return 4;
|
|
13938
13983
|
return result.status;
|
|
13939
13984
|
}
|
|
13940
|
-
async function jerkLogout(platform2, target) {
|
|
13941
|
-
const resolved = await resolveLoginTarget(platform2, target);
|
|
13985
|
+
async function jerkLogout(platform2, target, resolved, source) {
|
|
13942
13986
|
const id = jerkMcpId(resolved.name);
|
|
13943
|
-
const
|
|
13944
|
-
const proc = await platform2.spawn({ argv });
|
|
13945
|
-
proc.stdin.close().catch(() => {
|
|
13946
|
-
});
|
|
13947
|
-
const [, , result] = await Promise.all([
|
|
13948
|
-
readStream2(proc.stdout),
|
|
13949
|
-
readStream2(proc.stderr),
|
|
13950
|
-
proc.wait()
|
|
13951
|
-
]);
|
|
13987
|
+
const result = await runJerk(platform2, ["jerk", id, "drop", "--yes"], source.timeoutMs);
|
|
13952
13988
|
if (result.status === 0) {
|
|
13953
13989
|
await platform2.write(1, `Signed out of ${target}
|
|
13954
13990
|
`);
|
|
@@ -13958,7 +13994,7 @@ async function jerkLogout(platform2, target) {
|
|
|
13958
13994
|
}
|
|
13959
13995
|
return 0;
|
|
13960
13996
|
}
|
|
13961
|
-
async function runLogin(platform2, args2,
|
|
13997
|
+
async function runLogin(platform2, args2, timeoutMs) {
|
|
13962
13998
|
if (isKernel(platform2)) {
|
|
13963
13999
|
await platform2.write(
|
|
13964
14000
|
2,
|
|
@@ -13966,15 +14002,24 @@ async function runLogin(platform2, args2, source) {
|
|
|
13966
14002
|
);
|
|
13967
14003
|
return 4;
|
|
13968
14004
|
}
|
|
13969
|
-
const positional = args2
|
|
14005
|
+
const positional = positionals(args2);
|
|
13970
14006
|
if (positional.length === 0) {
|
|
13971
14007
|
await platform2.write(2, "mcpcat: login requires a target\n");
|
|
13972
14008
|
return 2;
|
|
13973
14009
|
}
|
|
13974
14010
|
const target = positional[0];
|
|
14011
|
+
let resolved;
|
|
14012
|
+
try {
|
|
14013
|
+
resolved = await resolveLoginTarget(platform2, target);
|
|
14014
|
+
} catch (err) {
|
|
14015
|
+
await platform2.write(2, `mcpcat: ${err.message}
|
|
14016
|
+
`);
|
|
14017
|
+
return 2;
|
|
14018
|
+
}
|
|
14019
|
+
const source = await createTokenSource(platform2, resolved.name, timeoutMs);
|
|
13975
14020
|
if (source instanceof JerkTokenSource) {
|
|
13976
14021
|
try {
|
|
13977
|
-
return await jerkLogin(platform2, target, args2);
|
|
14022
|
+
return await jerkLogin(platform2, target, resolved, args2);
|
|
13978
14023
|
} catch (err) {
|
|
13979
14024
|
await platform2.write(2, `mcpcat: login failed: ${err.message}
|
|
13980
14025
|
`);
|
|
@@ -13982,14 +14027,6 @@ async function runLogin(platform2, args2, source) {
|
|
|
13982
14027
|
}
|
|
13983
14028
|
}
|
|
13984
14029
|
const noBrowser = args2.includes("--no-browser");
|
|
13985
|
-
let resolved;
|
|
13986
|
-
try {
|
|
13987
|
-
resolved = await resolveLoginTarget(platform2, target);
|
|
13988
|
-
} catch (err) {
|
|
13989
|
-
await platform2.write(2, `mcpcat: ${err.message}
|
|
13990
|
-
`);
|
|
13991
|
-
return 2;
|
|
13992
|
-
}
|
|
13993
14030
|
try {
|
|
13994
14031
|
await signIn({
|
|
13995
14032
|
name: resolved.name,
|
|
@@ -14052,26 +14089,17 @@ ${url.href}
|
|
|
14052
14089
|
return 4;
|
|
14053
14090
|
}
|
|
14054
14091
|
}
|
|
14055
|
-
async function runLogout(platform2, args2,
|
|
14092
|
+
async function runLogout(platform2, args2, timeoutMs) {
|
|
14056
14093
|
if (isKernel(platform2)) {
|
|
14057
14094
|
await platform2.write(2, "mcpcat: logout is not available in seven.\n");
|
|
14058
14095
|
return 4;
|
|
14059
14096
|
}
|
|
14060
|
-
const positional = args2
|
|
14097
|
+
const positional = positionals(args2);
|
|
14061
14098
|
if (positional.length === 0) {
|
|
14062
14099
|
await platform2.write(2, "mcpcat: logout requires a target\n");
|
|
14063
14100
|
return 2;
|
|
14064
14101
|
}
|
|
14065
14102
|
const target = positional[0];
|
|
14066
|
-
if (source instanceof JerkTokenSource) {
|
|
14067
|
-
try {
|
|
14068
|
-
return await jerkLogout(platform2, target);
|
|
14069
|
-
} catch (err) {
|
|
14070
|
-
await platform2.write(2, `mcpcat: logout failed: ${err.message}
|
|
14071
|
-
`);
|
|
14072
|
-
return 1;
|
|
14073
|
-
}
|
|
14074
|
-
}
|
|
14075
14103
|
let resolved;
|
|
14076
14104
|
try {
|
|
14077
14105
|
resolved = await resolveLoginTarget(platform2, target);
|
|
@@ -14080,6 +14108,21 @@ async function runLogout(platform2, args2, source) {
|
|
|
14080
14108
|
`);
|
|
14081
14109
|
return 2;
|
|
14082
14110
|
}
|
|
14111
|
+
const source = await createTokenSource(platform2, resolved.name, timeoutMs);
|
|
14112
|
+
if (source instanceof JerkTokenSource) {
|
|
14113
|
+
try {
|
|
14114
|
+
return await jerkLogout(platform2, target, resolved, source);
|
|
14115
|
+
} catch (err) {
|
|
14116
|
+
if (err instanceof JerkTimeoutError) {
|
|
14117
|
+
await platform2.write(2, `mcpcat: ${err.message}
|
|
14118
|
+
`);
|
|
14119
|
+
return 4;
|
|
14120
|
+
}
|
|
14121
|
+
await platform2.write(2, `mcpcat: logout failed: ${err.message}
|
|
14122
|
+
`);
|
|
14123
|
+
return 1;
|
|
14124
|
+
}
|
|
14125
|
+
}
|
|
14083
14126
|
const removed = await source.remove(resolved.name, resolved.serverUrl);
|
|
14084
14127
|
if (removed) {
|
|
14085
14128
|
await platform2.write(1, `Signed out of ${target}
|
|
@@ -15225,6 +15268,10 @@ var VERBS_WITH_TARGET = /* @__PURE__ */ new Set([
|
|
|
15225
15268
|
"prompts",
|
|
15226
15269
|
"prompt"
|
|
15227
15270
|
]);
|
|
15271
|
+
function withoutVerb(args2, verb) {
|
|
15272
|
+
const at = args2.indexOf(verb);
|
|
15273
|
+
return [...args2.slice(0, at), ...args2.slice(at + 1)];
|
|
15274
|
+
}
|
|
15228
15275
|
function resolveMaxPositional(positional) {
|
|
15229
15276
|
if (positional.length === 0) return 3;
|
|
15230
15277
|
const first = positional[0];
|
|
@@ -16052,12 +16099,10 @@ async function runInner(platform2, version, args2) {
|
|
|
16052
16099
|
const discResult = await dispatchDiscoveryVerb(platform2, parsed, args2);
|
|
16053
16100
|
if (discResult !== void 0) return discResult;
|
|
16054
16101
|
if (parsed.verb === "login") {
|
|
16055
|
-
|
|
16056
|
-
return runLogin(platform2, args2.slice(1), source);
|
|
16102
|
+
return runLogin(platform2, withoutVerb(args2, "login"), parsed.timeoutMs);
|
|
16057
16103
|
}
|
|
16058
16104
|
if (parsed.verb === "logout") {
|
|
16059
|
-
|
|
16060
|
-
return runLogout(platform2, args2.slice(1), source);
|
|
16105
|
+
return runLogout(platform2, withoutVerb(args2, "logout"), parsed.timeoutMs);
|
|
16061
16106
|
}
|
|
16062
16107
|
if (UNIMPLEMENTED_VERBS.has(parsed.verb)) {
|
|
16063
16108
|
await platform2.write(2, `mcpcat: '${parsed.verb}' is not implemented yet
|
|
@@ -16124,7 +16169,7 @@ function classifyError(err) {
|
|
|
16124
16169
|
if (err instanceof McpAuthError) {
|
|
16125
16170
|
return { code: EXIT_AUTH, kind: "auth", msg: err.message };
|
|
16126
16171
|
}
|
|
16127
|
-
if (err instanceof JerkSignInRequiredError) {
|
|
16172
|
+
if (err instanceof JerkSignInRequiredError || err instanceof JerkTimeoutError) {
|
|
16128
16173
|
return { code: EXIT_AUTH, kind: "auth", msg: err.message };
|
|
16129
16174
|
}
|
|
16130
16175
|
if (err instanceof AuthStepUpError) {
|
|
@@ -16148,12 +16193,12 @@ function classifyError(err) {
|
|
|
16148
16193
|
}
|
|
16149
16194
|
return { code: EXIT_RPC_ERROR, kind: "rpc_error", msg };
|
|
16150
16195
|
}
|
|
16151
|
-
async function resolveAuthProvider(platform2, hasAuthHeader, url, target, config, onCredentialObtained) {
|
|
16196
|
+
async function resolveAuthProvider(platform2, hasAuthHeader, url, target, config, timeoutMs, onCredentialObtained) {
|
|
16152
16197
|
if (hasAuthHeader || !url) return void 0;
|
|
16153
|
-
const source = await createTokenSource(platform2);
|
|
16154
16198
|
const entry = config.entry(target);
|
|
16155
16199
|
const oauth = entry && "url" in entry.config ? entry.config.oauth : void 0;
|
|
16156
16200
|
const name = entry ? target : `url:${new URL(url).origin}${new URL(url).pathname}`;
|
|
16201
|
+
const source = await createTokenSource(platform2, name, timeoutMs);
|
|
16157
16202
|
const provider = createMcpAuthProvider({
|
|
16158
16203
|
name,
|
|
16159
16204
|
serverUrl: url,
|
|
@@ -16182,7 +16227,7 @@ function classifyConnectionError(err, target, interrupted) {
|
|
|
16182
16227
|
msg: `${err.reason} (${hint})`
|
|
16183
16228
|
};
|
|
16184
16229
|
}
|
|
16185
|
-
if (err instanceof McpAuthError || err instanceof AuthStepUpError || err instanceof JerkSignInRequiredError) {
|
|
16230
|
+
if (err instanceof McpAuthError || err instanceof AuthStepUpError || err instanceof JerkSignInRequiredError || err instanceof JerkTimeoutError) {
|
|
16186
16231
|
return classifyError(err);
|
|
16187
16232
|
}
|
|
16188
16233
|
if (err.name === "McpOAuthAuthorizationRequiredError" || err.name === "McpAuthRequiredError") {
|
|
@@ -16330,6 +16375,7 @@ async function runClientVerb(platform2, version, parsed) {
|
|
|
16330
16375
|
resolved.url,
|
|
16331
16376
|
target,
|
|
16332
16377
|
config,
|
|
16378
|
+
timeoutMs,
|
|
16333
16379
|
(secret) => {
|
|
16334
16380
|
allSecrets.add(secret);
|
|
16335
16381
|
verbose.secrets.add(secret);
|
|
@@ -16466,10 +16512,11 @@ var USE_PROCESS_GROUPS2 = process.platform !== "win32";
|
|
|
16466
16512
|
function nodeSpawn(options) {
|
|
16467
16513
|
return new Promise((resolve, reject) => {
|
|
16468
16514
|
let rejected = false;
|
|
16515
|
+
const ignoreStdin = options.stdin === "ignore";
|
|
16469
16516
|
const child = cpSpawn(options.argv[0], options.argv.slice(1), {
|
|
16470
16517
|
env: options.env ?? process.env,
|
|
16471
16518
|
cwd: options.cwd,
|
|
16472
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
16519
|
+
stdio: [ignoreStdin ? "ignore" : "pipe", "pipe", "pipe"],
|
|
16473
16520
|
detached: USE_PROCESS_GROUPS2
|
|
16474
16521
|
});
|
|
16475
16522
|
child.on("error", (err) => {
|
|
@@ -16480,7 +16527,7 @@ function nodeSpawn(options) {
|
|
|
16480
16527
|
});
|
|
16481
16528
|
const stdout = Readable.toWeb(child.stdout);
|
|
16482
16529
|
const stderr = Readable.toWeb(child.stderr);
|
|
16483
|
-
const stdin = Writable.toWeb(child.stdin);
|
|
16530
|
+
const stdin = ignoreStdin ? new WritableStream() : Writable.toWeb(child.stdin);
|
|
16484
16531
|
const closePromise = new Promise((res) => {
|
|
16485
16532
|
child.on("close", (code2, signal) => {
|
|
16486
16533
|
res({
|
|
@@ -16687,5 +16734,5 @@ try {
|
|
|
16687
16734
|
});
|
|
16688
16735
|
} catch {
|
|
16689
16736
|
}
|
|
16690
|
-
var code = await run(platform, "0.15.
|
|
16737
|
+
var code = await run(platform, "0.15.4", args);
|
|
16691
16738
|
process.exit(code);
|
package/dist/kernel/mcpcat.mjs
CHANGED
|
@@ -6098,7 +6098,26 @@ var McpOAuthProvider = class {
|
|
|
6098
6098
|
// src/auth/jerk-token-source.ts
|
|
6099
6099
|
var MIN_VERSION = [0, 14, 1];
|
|
6100
6100
|
var VERSION_TIMEOUT_MS = 2e3;
|
|
6101
|
+
var JERK_TIMEOUT_MS = 15e3;
|
|
6101
6102
|
var cachedAvailable;
|
|
6103
|
+
var cachedKnown;
|
|
6104
|
+
async function listMcpProviders(platform2) {
|
|
6105
|
+
const known = /* @__PURE__ */ new Set();
|
|
6106
|
+
try {
|
|
6107
|
+
const result = await runJerk(platform2, ["jerk", "list", "--json"], VERSION_TIMEOUT_MS);
|
|
6108
|
+
if (result.status !== 0) return known;
|
|
6109
|
+
const providers = JSON.parse(result.stdout);
|
|
6110
|
+
for (const p of providers) {
|
|
6111
|
+
if (p?.source === "mcp.json" && typeof p.provider === "string") known.add(p.provider);
|
|
6112
|
+
}
|
|
6113
|
+
} catch {
|
|
6114
|
+
}
|
|
6115
|
+
return known;
|
|
6116
|
+
}
|
|
6117
|
+
async function jerkKnows(platform2, id) {
|
|
6118
|
+
cachedKnown ??= listMcpProviders(platform2);
|
|
6119
|
+
return (await cachedKnown).has(id);
|
|
6120
|
+
}
|
|
6102
6121
|
function parseVersion(raw) {
|
|
6103
6122
|
const match = raw.trim().match(/(\d+)\.(\d+)\.(\d+)/);
|
|
6104
6123
|
if (!match) return void 0;
|
|
@@ -6144,23 +6163,39 @@ async function jerkAvailable(platform2) {
|
|
|
6144
6163
|
return false;
|
|
6145
6164
|
}
|
|
6146
6165
|
try {
|
|
6147
|
-
const
|
|
6148
|
-
const
|
|
6149
|
-
|
|
6150
|
-
});
|
|
6151
|
-
const work = Promise.all([readAll(proc.stdout), proc.wait()]).then(([out, result]) => {
|
|
6152
|
-
proc.stderr.cancel().catch(() => {
|
|
6153
|
-
});
|
|
6154
|
-
if (result.status !== 0) return false;
|
|
6155
|
-
const ver = parseVersion(out);
|
|
6156
|
-
return ver !== void 0 && versionSatisfied(ver);
|
|
6157
|
-
});
|
|
6158
|
-
cachedAvailable = await Promise.race([work, timeout]);
|
|
6166
|
+
const result = await runJerk(platform2, ["jerk", "--version"], VERSION_TIMEOUT_MS);
|
|
6167
|
+
const ver = result.status === 0 ? parseVersion(result.stdout) : void 0;
|
|
6168
|
+
cachedAvailable = ver !== void 0 && versionSatisfied(ver);
|
|
6159
6169
|
} catch {
|
|
6160
6170
|
cachedAvailable = false;
|
|
6161
6171
|
}
|
|
6162
6172
|
return cachedAvailable;
|
|
6163
6173
|
}
|
|
6174
|
+
var JerkTimeoutError = class extends Error {
|
|
6175
|
+
command;
|
|
6176
|
+
constructor(argv) {
|
|
6177
|
+
const command = argv.slice(0, 3).join(" ");
|
|
6178
|
+
super(`jerk did not answer; run \`${command}\` yourself`);
|
|
6179
|
+
this.name = "JerkTimeoutError";
|
|
6180
|
+
this.command = command;
|
|
6181
|
+
}
|
|
6182
|
+
};
|
|
6183
|
+
async function runJerk(platform2, argv, timeoutMs) {
|
|
6184
|
+
const proc = await platform2.spawn({ argv, stdin: "ignore" });
|
|
6185
|
+
let timer;
|
|
6186
|
+
const expired = new Promise((resolve2) => {
|
|
6187
|
+
timer = setTimeout(() => resolve2("timeout"), timeoutMs);
|
|
6188
|
+
});
|
|
6189
|
+
const work = Promise.all([readAll(proc.stdout), readAll(proc.stderr), proc.wait()]);
|
|
6190
|
+
const outcome = await Promise.race([work, expired]);
|
|
6191
|
+
clearTimeout(timer);
|
|
6192
|
+
if (outcome === "timeout") {
|
|
6193
|
+
await proc.kill("SIGKILL");
|
|
6194
|
+
throw new JerkTimeoutError(argv);
|
|
6195
|
+
}
|
|
6196
|
+
const [stdout, stderr, result] = outcome;
|
|
6197
|
+
return { status: result.status, stdout, stderr };
|
|
6198
|
+
}
|
|
6164
6199
|
function jerkId(name) {
|
|
6165
6200
|
if (name.startsWith("mcp:")) return name;
|
|
6166
6201
|
if (name.startsWith("url:")) return `mcp:${name}`;
|
|
@@ -6181,8 +6216,10 @@ var JerkSignInRequiredError = class extends Error {
|
|
|
6181
6216
|
};
|
|
6182
6217
|
var JerkTokenSource = class {
|
|
6183
6218
|
platform;
|
|
6184
|
-
|
|
6219
|
+
timeoutMs;
|
|
6220
|
+
constructor(platform2, timeoutMs = JERK_TIMEOUT_MS) {
|
|
6185
6221
|
this.platform = platform2;
|
|
6222
|
+
this.timeoutMs = timeoutMs;
|
|
6186
6223
|
}
|
|
6187
6224
|
async getToken(name, serverUrl, scope) {
|
|
6188
6225
|
const id = jerkId(name);
|
|
@@ -6190,12 +6227,7 @@ var JerkTokenSource = class {
|
|
|
6190
6227
|
if (scope) {
|
|
6191
6228
|
argv.push("--scope", scope);
|
|
6192
6229
|
}
|
|
6193
|
-
const
|
|
6194
|
-
const [outRaw, , result] = await Promise.all([
|
|
6195
|
-
readAll(proc.stdout),
|
|
6196
|
-
readAll(proc.stderr),
|
|
6197
|
-
proc.wait()
|
|
6198
|
-
]);
|
|
6230
|
+
const result = await runJerk(this.platform, argv, this.timeoutMs);
|
|
6199
6231
|
if (result.status === JERK_EXIT_SIGN_IN) {
|
|
6200
6232
|
throw new JerkSignInRequiredError(id, scope);
|
|
6201
6233
|
}
|
|
@@ -6205,7 +6237,7 @@ var JerkTokenSource = class {
|
|
|
6205
6237
|
if (result.status !== 0) {
|
|
6206
6238
|
return void 0;
|
|
6207
6239
|
}
|
|
6208
|
-
const parsed = JSON.parse(
|
|
6240
|
+
const parsed = JSON.parse(result.stdout.trim());
|
|
6209
6241
|
if (!parsed.token) return void 0;
|
|
6210
6242
|
return {
|
|
6211
6243
|
accessToken: parsed.token,
|
|
@@ -8192,7 +8224,7 @@ async function createStatelessConnection(options) {
|
|
|
8192
8224
|
token
|
|
8193
8225
|
});
|
|
8194
8226
|
} catch (authErr) {
|
|
8195
|
-
if (authErr instanceof AuthStepUpError) throw authErr;
|
|
8227
|
+
if (authErr instanceof AuthStepUpError || authErr instanceof JerkTimeoutError) throw authErr;
|
|
8196
8228
|
throw new McpAuthError(err.response.status, url);
|
|
8197
8229
|
}
|
|
8198
8230
|
}
|
|
@@ -11119,15 +11151,15 @@ function readMcpCommand(value) {
|
|
|
11119
11151
|
}
|
|
11120
11152
|
function readMcpPositionals(value) {
|
|
11121
11153
|
if (!Array.isArray(value)) return [];
|
|
11122
|
-
const
|
|
11154
|
+
const positionals2 = [];
|
|
11123
11155
|
for (const entry of value) {
|
|
11124
11156
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
11125
11157
|
const name = ownString(entry, "name");
|
|
11126
11158
|
if (!name) continue;
|
|
11127
11159
|
const required = Object.getOwnPropertyDescriptor(entry, "required")?.value;
|
|
11128
|
-
|
|
11160
|
+
positionals2.push({ name, required: required !== false, description: "" });
|
|
11129
11161
|
}
|
|
11130
|
-
return
|
|
11162
|
+
return positionals2;
|
|
11131
11163
|
}
|
|
11132
11164
|
function readMcpFlags(value) {
|
|
11133
11165
|
if (!Array.isArray(value)) return [];
|
|
@@ -12561,7 +12593,14 @@ async function runServe(platform2, options, version) {
|
|
|
12561
12593
|
generatedBearer
|
|
12562
12594
|
);
|
|
12563
12595
|
}
|
|
12564
|
-
|
|
12596
|
+
function serveAddress(platform2, host, port) {
|
|
12597
|
+
if (platform2.kind !== "kernel") return { url: `http://${host}:${port}/mcp` };
|
|
12598
|
+
return {
|
|
12599
|
+
url: `http://${port}.kernel.localhost/mcp`,
|
|
12600
|
+
loopbackUrl: `http://127.0.0.1:${port}/mcp`
|
|
12601
|
+
};
|
|
12602
|
+
}
|
|
12603
|
+
async function publishBearer(platform2, token, port, address, json) {
|
|
12565
12604
|
if (!json && platform2.isatty(2)) {
|
|
12566
12605
|
await platform2.write(2, `mcpcat serve: bearer ${token}
|
|
12567
12606
|
`);
|
|
@@ -12578,7 +12617,7 @@ async function publishBearer(platform2, token, port, listenUrl, json) {
|
|
|
12578
12617
|
await platform2.write(2, `mcpcat serve: bearer saved to ${tokenPath}
|
|
12579
12618
|
`);
|
|
12580
12619
|
if (json) {
|
|
12581
|
-
await platform2.write(1, `${JSON.stringify({
|
|
12620
|
+
await platform2.write(1, `${JSON.stringify({ ...address, bearerFile: tokenPath })}
|
|
12582
12621
|
`);
|
|
12583
12622
|
}
|
|
12584
12623
|
return tokenPath;
|
|
@@ -12757,19 +12796,20 @@ async function runWebMcpHttp(platform2, options, getTools, callTool, serverName,
|
|
|
12757
12796
|
const actualPort = listener.port;
|
|
12758
12797
|
const serverOrigins = buildServerOrigins(options.host, actualPort);
|
|
12759
12798
|
const allowedHosts = buildAllowedHosts(options.host, actualPort, options.allowHosts);
|
|
12760
|
-
const
|
|
12799
|
+
const address = serveAddress(platform2, options.host, actualPort);
|
|
12800
|
+
const listenUrl = address.url;
|
|
12761
12801
|
let tokenFilePath;
|
|
12762
12802
|
if (generatedBearer && resolvedBearer) {
|
|
12763
12803
|
tokenFilePath = await publishBearer(
|
|
12764
12804
|
platform2,
|
|
12765
12805
|
resolvedBearer,
|
|
12766
12806
|
actualPort,
|
|
12767
|
-
|
|
12807
|
+
address,
|
|
12768
12808
|
options.json
|
|
12769
12809
|
);
|
|
12770
12810
|
} else {
|
|
12771
12811
|
if (options.json) {
|
|
12772
|
-
await platform2.write(1, `${JSON.stringify(
|
|
12812
|
+
await platform2.write(1, `${JSON.stringify(address)}
|
|
12773
12813
|
`);
|
|
12774
12814
|
}
|
|
12775
12815
|
}
|
|
@@ -12952,19 +12992,20 @@ async function runProxyHttp(platform2, options, proxy, resolvedBearer, generated
|
|
|
12952
12992
|
const actualPort = listener.port;
|
|
12953
12993
|
const serverOrigins = buildServerOrigins(options.host, actualPort);
|
|
12954
12994
|
const allowedHosts = buildAllowedHosts(options.host, actualPort, options.allowHosts);
|
|
12955
|
-
const
|
|
12995
|
+
const address = serveAddress(platform2, options.host, actualPort);
|
|
12996
|
+
const listenUrl = address.url;
|
|
12956
12997
|
let tokenFilePath;
|
|
12957
12998
|
if (generatedBearer && resolvedBearer) {
|
|
12958
12999
|
tokenFilePath = await publishBearer(
|
|
12959
13000
|
platform2,
|
|
12960
13001
|
resolvedBearer,
|
|
12961
13002
|
actualPort,
|
|
12962
|
-
|
|
13003
|
+
address,
|
|
12963
13004
|
options.json
|
|
12964
13005
|
);
|
|
12965
13006
|
} else {
|
|
12966
13007
|
if (options.json) {
|
|
12967
|
-
await platform2.write(1, `${JSON.stringify(
|
|
13008
|
+
await platform2.write(1, `${JSON.stringify(address)}
|
|
12968
13009
|
`);
|
|
12969
13010
|
}
|
|
12970
13011
|
}
|
|
@@ -13128,19 +13169,20 @@ async function runHttpServer(platform2, options, tools, call, serverName, versio
|
|
|
13128
13169
|
const actualPort = listener.port;
|
|
13129
13170
|
const serverOrigins = buildServerOrigins(options.host, actualPort);
|
|
13130
13171
|
const allowedHosts = buildAllowedHosts(options.host, actualPort, options.allowHosts);
|
|
13131
|
-
const
|
|
13172
|
+
const address = serveAddress(platform2, options.host, actualPort);
|
|
13173
|
+
const listenUrl = address.url;
|
|
13132
13174
|
let tokenFilePath;
|
|
13133
13175
|
if (generatedBearer && resolvedBearer) {
|
|
13134
13176
|
tokenFilePath = await publishBearer(
|
|
13135
13177
|
platform2,
|
|
13136
13178
|
resolvedBearer,
|
|
13137
13179
|
actualPort,
|
|
13138
|
-
|
|
13180
|
+
address,
|
|
13139
13181
|
options.json
|
|
13140
13182
|
);
|
|
13141
13183
|
} else {
|
|
13142
13184
|
if (options.json) {
|
|
13143
|
-
await platform2.write(1, `${JSON.stringify(
|
|
13185
|
+
await platform2.write(1, `${JSON.stringify(address)}
|
|
13144
13186
|
`);
|
|
13145
13187
|
}
|
|
13146
13188
|
}
|
|
@@ -13467,16 +13509,20 @@ async function signIn(options) {
|
|
|
13467
13509
|
}
|
|
13468
13510
|
|
|
13469
13511
|
// src/cli/auth-verbs.ts
|
|
13470
|
-
|
|
13471
|
-
|
|
13472
|
-
|
|
13473
|
-
|
|
13474
|
-
|
|
13475
|
-
|
|
13476
|
-
|
|
13477
|
-
|
|
13512
|
+
async function createTokenSource(platform2, name, timeoutMs = JERK_TIMEOUT_MS) {
|
|
13513
|
+
if (!isKernel(platform2) && !name.startsWith("url:") && await jerkAvailable(platform2) && await jerkKnows(platform2, jerkMcpId(name))) {
|
|
13514
|
+
return new JerkTokenSource(platform2, timeoutMs);
|
|
13515
|
+
}
|
|
13516
|
+
return new PiFileTokenSource(platform2);
|
|
13517
|
+
}
|
|
13518
|
+
var VALUE_FLAGS = /* @__PURE__ */ new Set(["--scope", "-m", "--timeout"]);
|
|
13519
|
+
function positionals(args) {
|
|
13520
|
+
const out = [];
|
|
13521
|
+
for (let i = 0; i < args.length; i++) {
|
|
13522
|
+
if (VALUE_FLAGS.has(args[i])) i++;
|
|
13523
|
+
else if (!args[i].startsWith("-")) out.push(args[i]);
|
|
13478
13524
|
}
|
|
13479
|
-
return
|
|
13525
|
+
return out;
|
|
13480
13526
|
}
|
|
13481
13527
|
function resolveServerName(target) {
|
|
13482
13528
|
try {
|
|
@@ -13528,8 +13574,7 @@ async function readStream2(stream) {
|
|
|
13528
13574
|
}
|
|
13529
13575
|
return new TextDecoder().decode(buf);
|
|
13530
13576
|
}
|
|
13531
|
-
async function jerkLogin(platform2, target, args) {
|
|
13532
|
-
const resolved = await resolveLoginTarget(platform2, target);
|
|
13577
|
+
async function jerkLogin(platform2, target, resolved, args) {
|
|
13533
13578
|
const id = jerkMcpId(resolved.name);
|
|
13534
13579
|
const argv = ["jerk", id, "create"];
|
|
13535
13580
|
const scopeIdx = args.indexOf("--scope");
|
|
@@ -13558,18 +13603,9 @@ async function jerkLogin(platform2, target, args) {
|
|
|
13558
13603
|
if (result.status === JERK_EXIT_SIGN_IN) return 4;
|
|
13559
13604
|
return result.status;
|
|
13560
13605
|
}
|
|
13561
|
-
async function jerkLogout(platform2, target) {
|
|
13562
|
-
const resolved = await resolveLoginTarget(platform2, target);
|
|
13606
|
+
async function jerkLogout(platform2, target, resolved, source) {
|
|
13563
13607
|
const id = jerkMcpId(resolved.name);
|
|
13564
|
-
const
|
|
13565
|
-
const proc = await platform2.spawn({ argv });
|
|
13566
|
-
proc.stdin.close().catch(() => {
|
|
13567
|
-
});
|
|
13568
|
-
const [, , result] = await Promise.all([
|
|
13569
|
-
readStream2(proc.stdout),
|
|
13570
|
-
readStream2(proc.stderr),
|
|
13571
|
-
proc.wait()
|
|
13572
|
-
]);
|
|
13608
|
+
const result = await runJerk(platform2, ["jerk", id, "drop", "--yes"], source.timeoutMs);
|
|
13573
13609
|
if (result.status === 0) {
|
|
13574
13610
|
await platform2.write(1, `Signed out of ${target}
|
|
13575
13611
|
`);
|
|
@@ -13579,7 +13615,7 @@ async function jerkLogout(platform2, target) {
|
|
|
13579
13615
|
}
|
|
13580
13616
|
return 0;
|
|
13581
13617
|
}
|
|
13582
|
-
async function runLogin(platform2, args,
|
|
13618
|
+
async function runLogin(platform2, args, timeoutMs) {
|
|
13583
13619
|
if (isKernel(platform2)) {
|
|
13584
13620
|
await platform2.write(
|
|
13585
13621
|
2,
|
|
@@ -13587,15 +13623,24 @@ async function runLogin(platform2, args, source) {
|
|
|
13587
13623
|
);
|
|
13588
13624
|
return 4;
|
|
13589
13625
|
}
|
|
13590
|
-
const positional = args
|
|
13626
|
+
const positional = positionals(args);
|
|
13591
13627
|
if (positional.length === 0) {
|
|
13592
13628
|
await platform2.write(2, "mcpcat: login requires a target\n");
|
|
13593
13629
|
return 2;
|
|
13594
13630
|
}
|
|
13595
13631
|
const target = positional[0];
|
|
13632
|
+
let resolved;
|
|
13633
|
+
try {
|
|
13634
|
+
resolved = await resolveLoginTarget(platform2, target);
|
|
13635
|
+
} catch (err) {
|
|
13636
|
+
await platform2.write(2, `mcpcat: ${err.message}
|
|
13637
|
+
`);
|
|
13638
|
+
return 2;
|
|
13639
|
+
}
|
|
13640
|
+
const source = await createTokenSource(platform2, resolved.name, timeoutMs);
|
|
13596
13641
|
if (source instanceof JerkTokenSource) {
|
|
13597
13642
|
try {
|
|
13598
|
-
return await jerkLogin(platform2, target, args);
|
|
13643
|
+
return await jerkLogin(platform2, target, resolved, args);
|
|
13599
13644
|
} catch (err) {
|
|
13600
13645
|
await platform2.write(2, `mcpcat: login failed: ${err.message}
|
|
13601
13646
|
`);
|
|
@@ -13603,14 +13648,6 @@ async function runLogin(platform2, args, source) {
|
|
|
13603
13648
|
}
|
|
13604
13649
|
}
|
|
13605
13650
|
const noBrowser = args.includes("--no-browser");
|
|
13606
|
-
let resolved;
|
|
13607
|
-
try {
|
|
13608
|
-
resolved = await resolveLoginTarget(platform2, target);
|
|
13609
|
-
} catch (err) {
|
|
13610
|
-
await platform2.write(2, `mcpcat: ${err.message}
|
|
13611
|
-
`);
|
|
13612
|
-
return 2;
|
|
13613
|
-
}
|
|
13614
13651
|
try {
|
|
13615
13652
|
await signIn({
|
|
13616
13653
|
name: resolved.name,
|
|
@@ -13673,26 +13710,17 @@ ${url.href}
|
|
|
13673
13710
|
return 4;
|
|
13674
13711
|
}
|
|
13675
13712
|
}
|
|
13676
|
-
async function runLogout(platform2, args,
|
|
13713
|
+
async function runLogout(platform2, args, timeoutMs) {
|
|
13677
13714
|
if (isKernel(platform2)) {
|
|
13678
13715
|
await platform2.write(2, "mcpcat: logout is not available in seven.\n");
|
|
13679
13716
|
return 4;
|
|
13680
13717
|
}
|
|
13681
|
-
const positional = args
|
|
13718
|
+
const positional = positionals(args);
|
|
13682
13719
|
if (positional.length === 0) {
|
|
13683
13720
|
await platform2.write(2, "mcpcat: logout requires a target\n");
|
|
13684
13721
|
return 2;
|
|
13685
13722
|
}
|
|
13686
13723
|
const target = positional[0];
|
|
13687
|
-
if (source instanceof JerkTokenSource) {
|
|
13688
|
-
try {
|
|
13689
|
-
return await jerkLogout(platform2, target);
|
|
13690
|
-
} catch (err) {
|
|
13691
|
-
await platform2.write(2, `mcpcat: logout failed: ${err.message}
|
|
13692
|
-
`);
|
|
13693
|
-
return 1;
|
|
13694
|
-
}
|
|
13695
|
-
}
|
|
13696
13724
|
let resolved;
|
|
13697
13725
|
try {
|
|
13698
13726
|
resolved = await resolveLoginTarget(platform2, target);
|
|
@@ -13701,6 +13729,21 @@ async function runLogout(platform2, args, source) {
|
|
|
13701
13729
|
`);
|
|
13702
13730
|
return 2;
|
|
13703
13731
|
}
|
|
13732
|
+
const source = await createTokenSource(platform2, resolved.name, timeoutMs);
|
|
13733
|
+
if (source instanceof JerkTokenSource) {
|
|
13734
|
+
try {
|
|
13735
|
+
return await jerkLogout(platform2, target, resolved, source);
|
|
13736
|
+
} catch (err) {
|
|
13737
|
+
if (err instanceof JerkTimeoutError) {
|
|
13738
|
+
await platform2.write(2, `mcpcat: ${err.message}
|
|
13739
|
+
`);
|
|
13740
|
+
return 4;
|
|
13741
|
+
}
|
|
13742
|
+
await platform2.write(2, `mcpcat: logout failed: ${err.message}
|
|
13743
|
+
`);
|
|
13744
|
+
return 1;
|
|
13745
|
+
}
|
|
13746
|
+
}
|
|
13704
13747
|
const removed = await source.remove(resolved.name, resolved.serverUrl);
|
|
13705
13748
|
if (removed) {
|
|
13706
13749
|
await platform2.write(1, `Signed out of ${target}
|
|
@@ -14846,6 +14889,10 @@ var VERBS_WITH_TARGET = /* @__PURE__ */ new Set([
|
|
|
14846
14889
|
"prompts",
|
|
14847
14890
|
"prompt"
|
|
14848
14891
|
]);
|
|
14892
|
+
function withoutVerb(args, verb) {
|
|
14893
|
+
const at = args.indexOf(verb);
|
|
14894
|
+
return [...args.slice(0, at), ...args.slice(at + 1)];
|
|
14895
|
+
}
|
|
14849
14896
|
function resolveMaxPositional(positional) {
|
|
14850
14897
|
if (positional.length === 0) return 3;
|
|
14851
14898
|
const first = positional[0];
|
|
@@ -15673,12 +15720,10 @@ async function runInner(platform2, version, args) {
|
|
|
15673
15720
|
const discResult = await dispatchDiscoveryVerb(platform2, parsed, args);
|
|
15674
15721
|
if (discResult !== void 0) return discResult;
|
|
15675
15722
|
if (parsed.verb === "login") {
|
|
15676
|
-
|
|
15677
|
-
return runLogin(platform2, args.slice(1), source);
|
|
15723
|
+
return runLogin(platform2, withoutVerb(args, "login"), parsed.timeoutMs);
|
|
15678
15724
|
}
|
|
15679
15725
|
if (parsed.verb === "logout") {
|
|
15680
|
-
|
|
15681
|
-
return runLogout(platform2, args.slice(1), source);
|
|
15726
|
+
return runLogout(platform2, withoutVerb(args, "logout"), parsed.timeoutMs);
|
|
15682
15727
|
}
|
|
15683
15728
|
if (UNIMPLEMENTED_VERBS.has(parsed.verb)) {
|
|
15684
15729
|
await platform2.write(2, `mcpcat: '${parsed.verb}' is not implemented yet
|
|
@@ -15745,7 +15790,7 @@ function classifyError(err) {
|
|
|
15745
15790
|
if (err instanceof McpAuthError) {
|
|
15746
15791
|
return { code: EXIT_AUTH, kind: "auth", msg: err.message };
|
|
15747
15792
|
}
|
|
15748
|
-
if (err instanceof JerkSignInRequiredError) {
|
|
15793
|
+
if (err instanceof JerkSignInRequiredError || err instanceof JerkTimeoutError) {
|
|
15749
15794
|
return { code: EXIT_AUTH, kind: "auth", msg: err.message };
|
|
15750
15795
|
}
|
|
15751
15796
|
if (err instanceof AuthStepUpError) {
|
|
@@ -15769,12 +15814,12 @@ function classifyError(err) {
|
|
|
15769
15814
|
}
|
|
15770
15815
|
return { code: EXIT_RPC_ERROR, kind: "rpc_error", msg };
|
|
15771
15816
|
}
|
|
15772
|
-
async function resolveAuthProvider(platform2, hasAuthHeader, url, target, config, onCredentialObtained) {
|
|
15817
|
+
async function resolveAuthProvider(platform2, hasAuthHeader, url, target, config, timeoutMs, onCredentialObtained) {
|
|
15773
15818
|
if (hasAuthHeader || !url) return void 0;
|
|
15774
|
-
const source = await createTokenSource(platform2);
|
|
15775
15819
|
const entry = config.entry(target);
|
|
15776
15820
|
const oauth = entry && "url" in entry.config ? entry.config.oauth : void 0;
|
|
15777
15821
|
const name = entry ? target : `url:${new URL(url).origin}${new URL(url).pathname}`;
|
|
15822
|
+
const source = await createTokenSource(platform2, name, timeoutMs);
|
|
15778
15823
|
const provider = createMcpAuthProvider({
|
|
15779
15824
|
name,
|
|
15780
15825
|
serverUrl: url,
|
|
@@ -15803,7 +15848,7 @@ function classifyConnectionError(err, target, interrupted) {
|
|
|
15803
15848
|
msg: `${err.reason} (${hint})`
|
|
15804
15849
|
};
|
|
15805
15850
|
}
|
|
15806
|
-
if (err instanceof McpAuthError || err instanceof AuthStepUpError || err instanceof JerkSignInRequiredError) {
|
|
15851
|
+
if (err instanceof McpAuthError || err instanceof AuthStepUpError || err instanceof JerkSignInRequiredError || err instanceof JerkTimeoutError) {
|
|
15807
15852
|
return classifyError(err);
|
|
15808
15853
|
}
|
|
15809
15854
|
if (err.name === "McpOAuthAuthorizationRequiredError" || err.name === "McpAuthRequiredError") {
|
|
@@ -15951,6 +15996,7 @@ async function runClientVerb(platform2, version, parsed) {
|
|
|
15951
15996
|
resolved.url,
|
|
15952
15997
|
target,
|
|
15953
15998
|
config,
|
|
15999
|
+
timeoutMs,
|
|
15954
16000
|
(secret) => {
|
|
15955
16001
|
allSecrets.add(secret);
|
|
15956
16002
|
verbose.secrets.add(secret);
|
|
@@ -16108,7 +16154,7 @@ async function kernelSpawn(ctx, options) {
|
|
|
16108
16154
|
argv: options.argv,
|
|
16109
16155
|
env: options.env,
|
|
16110
16156
|
cwd: options.cwd,
|
|
16111
|
-
stdin: "pipe",
|
|
16157
|
+
stdin: options.stdin === "ignore" ? "null" : "pipe",
|
|
16112
16158
|
stdout: "pipe",
|
|
16113
16159
|
stderr: "pipe",
|
|
16114
16160
|
...tryGroup ? { pgid: 0 } : {}
|
|
@@ -16137,7 +16183,7 @@ async function kernelSpawn(ctx, options) {
|
|
|
16137
16183
|
}
|
|
16138
16184
|
const useGroupKill = groupSpawnSupported;
|
|
16139
16185
|
return {
|
|
16140
|
-
stdin: result.stdin,
|
|
16186
|
+
stdin: result.stdin ?? new WritableStream(),
|
|
16141
16187
|
stdout: result.stdout,
|
|
16142
16188
|
stderr: result.stderr,
|
|
16143
16189
|
wait: () => result.wait(),
|
|
@@ -16190,11 +16236,21 @@ async function kernelListen(ctx, options) {
|
|
|
16190
16236
|
};
|
|
16191
16237
|
}
|
|
16192
16238
|
var KERNEL_LOCALHOST_RE = /^(\d+)\.kernel\.localhost$/;
|
|
16239
|
+
var LOOPBACK_HOSTNAMES = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "[::1]"]);
|
|
16193
16240
|
function extractLoopbackPort(url) {
|
|
16194
16241
|
const m = KERNEL_LOCALHOST_RE.exec(url.hostname);
|
|
16195
16242
|
if (m) return Number(m[1]);
|
|
16196
16243
|
return null;
|
|
16197
16244
|
}
|
|
16245
|
+
function extractPlainLoopbackPort(url) {
|
|
16246
|
+
if (url.protocol !== "http:" || !LOOPBACK_HOSTNAMES.has(url.hostname)) return null;
|
|
16247
|
+
return url.port ? Number(url.port) : 80;
|
|
16248
|
+
}
|
|
16249
|
+
function isConnectionRefused(err) {
|
|
16250
|
+
const e = err;
|
|
16251
|
+
if (e?.code === "ECONNREFUSED") return true;
|
|
16252
|
+
return typeof e?.message === "string" && e.message.includes("ECONNREFUSED");
|
|
16253
|
+
}
|
|
16198
16254
|
function collectHeaders(init) {
|
|
16199
16255
|
const entries = [];
|
|
16200
16256
|
if (!init?.headers) return entries;
|
|
@@ -16249,7 +16305,7 @@ function parseHttpResponse(buf, headerPos, bufLen) {
|
|
|
16249
16305
|
const responseBody = dec.decode(buf.slice(headerEndByte, headerEndByte + contentLength));
|
|
16250
16306
|
return { status, statusText, headers: respHeaders, body: responseBody };
|
|
16251
16307
|
}
|
|
16252
|
-
async function kernelLoopbackFetch(ctx, url, port, init) {
|
|
16308
|
+
async function kernelLoopbackFetch(ctx, url, port, init, onRefused) {
|
|
16253
16309
|
const method = (init?.method ?? "GET").toUpperCase();
|
|
16254
16310
|
const enc = new TextEncoder();
|
|
16255
16311
|
const dec = new TextDecoder();
|
|
@@ -16260,7 +16316,13 @@ async function kernelLoopbackFetch(ctx, url, port, init) {
|
|
|
16260
16316
|
const bodyBytes = enc.encode(bodyStr);
|
|
16261
16317
|
const headerEntries = collectHeaders(init);
|
|
16262
16318
|
const reqBytes = buildHttpRequest(method, url, headerEntries, bodyBytes);
|
|
16263
|
-
|
|
16319
|
+
let conn;
|
|
16320
|
+
try {
|
|
16321
|
+
conn = await ctx.net.connect({ host: "127.0.0.1", port });
|
|
16322
|
+
} catch (err) {
|
|
16323
|
+
if (onRefused && isConnectionRefused(err)) return onRefused();
|
|
16324
|
+
throw err;
|
|
16325
|
+
}
|
|
16264
16326
|
const writer = conn.writable.getWriter();
|
|
16265
16327
|
await writer.write(reqBytes);
|
|
16266
16328
|
const reader = conn.readable.getReader();
|
|
@@ -16313,6 +16375,10 @@ function createKernelFetch(ctx) {
|
|
|
16313
16375
|
}
|
|
16314
16376
|
const port = extractLoopbackPort(url);
|
|
16315
16377
|
if (port !== null) return kernelLoopbackFetch(ctx, url, port, init);
|
|
16378
|
+
const plainPort = extractPlainLoopbackPort(url);
|
|
16379
|
+
if (plainPort !== null) {
|
|
16380
|
+
return kernelLoopbackFetch(ctx, url, plainPort, init, () => ctx.fetch(input, init));
|
|
16381
|
+
}
|
|
16316
16382
|
return ctx.fetch(input, init);
|
|
16317
16383
|
};
|
|
16318
16384
|
}
|
|
@@ -16369,7 +16435,7 @@ async function main(ctx) {
|
|
|
16369
16435
|
packageDir: "/node_modules/@ai-ecoverse/mcpcat"
|
|
16370
16436
|
});
|
|
16371
16437
|
const args = ctx.argv.slice(1);
|
|
16372
|
-
return run(platform2, "0.15.
|
|
16438
|
+
return run(platform2, "0.15.4", args);
|
|
16373
16439
|
}
|
|
16374
16440
|
export {
|
|
16375
16441
|
main as default
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/mcpcat",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.4",
|
|
4
4
|
"description": "A curl for the Model Context Protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
"trust:dry": "npx fledgling sync --dry-run -y --skip-publish"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@ai-ecoverse/slicc-kernel": "1.88.
|
|
60
|
-
"@ai-ecoverse/slicc-shared-web": "1.
|
|
59
|
+
"@ai-ecoverse/slicc-kernel": "1.88.1",
|
|
60
|
+
"@ai-ecoverse/slicc-shared-web": "1.14.0",
|
|
61
61
|
"@biomejs/biome": "2.5.15",
|
|
62
62
|
"@earendil-works/pi-codemode": "1.2.0",
|
|
63
63
|
"@earendil-works/pi-mcp": "1.2.0",
|