@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.
@@ -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 proc = await platform2.spawn({ argv: ["jerk", "--version"] });
6527
- const timeout = new Promise((_, reject) => {
6528
- setTimeout(() => reject(new Error("timeout")), VERSION_TIMEOUT_MS);
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
- constructor(platform2) {
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 proc = await this.platform.spawn({ argv });
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(outRaw.trim());
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 positionals = [];
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
- positionals.push({ name, required: required !== false, description: "" });
11539
+ positionals2.push({ name, required: required !== false, description: "" });
11508
11540
  }
11509
- return positionals;
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
- async function publishBearer(platform2, token, port, listenUrl, json) {
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({ url: listenUrl, bearerFile: tokenPath })}
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 listenUrl = `http://${options.host}:${actualPort}/mcp`;
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
- listenUrl,
13186
+ address,
13147
13187
  options.json
13148
13188
  );
13149
13189
  } else {
13150
13190
  if (options.json) {
13151
- await platform2.write(1, `${JSON.stringify({ url: listenUrl })}
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 listenUrl = `http://${options.host}:${actualPort}/mcp`;
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
- listenUrl,
13382
+ address,
13342
13383
  options.json
13343
13384
  );
13344
13385
  } else {
13345
13386
  if (options.json) {
13346
- await platform2.write(1, `${JSON.stringify({ url: listenUrl })}
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 listenUrl = `http://${options.host}:${actualPort}/mcp`;
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
- listenUrl,
13559
+ address,
13518
13560
  options.json
13519
13561
  );
13520
13562
  } else {
13521
13563
  if (options.json) {
13522
- await platform2.write(1, `${JSON.stringify({ url: listenUrl })}
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
- var resolvedSource;
13850
- async function createTokenSource(platform2) {
13851
- if (isKernel(platform2)) return new PiFileTokenSource(platform2);
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 resolvedSource;
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 argv = ["jerk", id, "drop", "--yes"];
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, source) {
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.filter((a) => !a.startsWith("-"));
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, source) {
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.filter((a) => !a.startsWith("-"));
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
- const source = await createTokenSource(platform2);
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
- const source = await createTokenSource(platform2);
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.2", args);
16737
+ var code = await run(platform, "0.15.4", args);
16691
16738
  process.exit(code);
@@ -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 proc = await platform2.spawn({ argv: ["jerk", "--version"] });
6148
- const timeout = new Promise((_, reject) => {
6149
- setTimeout(() => reject(new Error("timeout")), VERSION_TIMEOUT_MS);
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
- constructor(platform2) {
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 proc = await this.platform.spawn({ argv });
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(outRaw.trim());
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 positionals = [];
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
- positionals.push({ name, required: required !== false, description: "" });
11160
+ positionals2.push({ name, required: required !== false, description: "" });
11129
11161
  }
11130
- return positionals;
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
- async function publishBearer(platform2, token, port, listenUrl, json) {
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({ url: listenUrl, bearerFile: tokenPath })}
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 listenUrl = `http://${options.host}:${actualPort}/mcp`;
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
- listenUrl,
12807
+ address,
12768
12808
  options.json
12769
12809
  );
12770
12810
  } else {
12771
12811
  if (options.json) {
12772
- await platform2.write(1, `${JSON.stringify({ url: listenUrl })}
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 listenUrl = `http://${options.host}:${actualPort}/mcp`;
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
- listenUrl,
13003
+ address,
12963
13004
  options.json
12964
13005
  );
12965
13006
  } else {
12966
13007
  if (options.json) {
12967
- await platform2.write(1, `${JSON.stringify({ url: listenUrl })}
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 listenUrl = `http://${options.host}:${actualPort}/mcp`;
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
- listenUrl,
13180
+ address,
13139
13181
  options.json
13140
13182
  );
13141
13183
  } else {
13142
13184
  if (options.json) {
13143
- await platform2.write(1, `${JSON.stringify({ url: listenUrl })}
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
- var resolvedSource;
13471
- async function createTokenSource(platform2) {
13472
- if (isKernel(platform2)) return new PiFileTokenSource(platform2);
13473
- if (resolvedSource) return resolvedSource;
13474
- if (await jerkAvailable(platform2)) {
13475
- resolvedSource = new JerkTokenSource(platform2);
13476
- } else {
13477
- resolvedSource = new PiFileTokenSource(platform2);
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 resolvedSource;
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 argv = ["jerk", id, "drop", "--yes"];
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, source) {
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.filter((a) => !a.startsWith("-"));
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, source) {
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.filter((a) => !a.startsWith("-"));
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
- const source = await createTokenSource(platform2);
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
- const source = await createTokenSource(platform2);
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
- const conn = await ctx.net.connect({ host: "127.0.0.1", port });
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.2", args);
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.2",
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.0",
60
- "@ai-ecoverse/slicc-shared-web": "1.13.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",