@ai-ecoverse/mcpcat 0.18.1 → 0.18.2

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.
@@ -11905,7 +11905,40 @@ function parseRequestLine(buf, endPos) {
11905
11905
  return { method, target, headers, headerEnd: endPos + 4 };
11906
11906
  }
11907
11907
  async function handleConnection(readable, writable, handler) {
11908
- const reader = readable.getReader();
11908
+ const raw = readable.getReader();
11909
+ let ahead = null;
11910
+ const parked = [];
11911
+ const reader = {
11912
+ read() {
11913
+ const queued = parked.shift();
11914
+ if (queued) return Promise.resolve(queued);
11915
+ const next = ahead ?? raw.read();
11916
+ ahead = null;
11917
+ return next;
11918
+ }
11919
+ };
11920
+ const watch = async (live, disconnect) => {
11921
+ let held = 0;
11922
+ while (held <= MAX_HEADER_SIZE + MAX_BODY_SIZE) {
11923
+ const pending = ahead ?? raw.read();
11924
+ ahead = pending;
11925
+ let result;
11926
+ try {
11927
+ result = await pending;
11928
+ } catch {
11929
+ if (live.on) disconnect.abort();
11930
+ return;
11931
+ }
11932
+ if (!live.on) return;
11933
+ ahead = null;
11934
+ parked.push(result);
11935
+ if (result.done) {
11936
+ disconnect.abort();
11937
+ return;
11938
+ }
11939
+ held += result.value.length;
11940
+ }
11941
+ };
11909
11942
  const writer = writable.getWriter();
11910
11943
  let buf = new Uint8Array(4096);
11911
11944
  let bufLen = 0;
@@ -11951,7 +11984,16 @@ async function handleConnection(readable, writable, handler) {
11951
11984
  headers: parsed.headers,
11952
11985
  body
11953
11986
  };
11954
- const response = await handler(request);
11987
+ const disconnect = new AbortController();
11988
+ const live = { on: true };
11989
+ void watch(live, disconnect);
11990
+ let response;
11991
+ try {
11992
+ response = await handler(request, disconnect.signal);
11993
+ } finally {
11994
+ live.on = false;
11995
+ }
11996
+ if (disconnect.signal.aborted) break;
11955
11997
  await writeResponse(writer, response);
11956
11998
  const connectionHeader = (parsed.headers.connection ?? "").toLowerCase();
11957
11999
  if (connectionHeader === "close") break;
@@ -11968,7 +12010,7 @@ async function handleConnection(readable, writable, handler) {
11968
12010
  }
11969
12011
  }
11970
12012
  } finally {
11971
- reader.releaseLock();
12013
+ raw.releaseLock();
11972
12014
  try {
11973
12015
  await writer.close();
11974
12016
  } catch {
@@ -12821,7 +12863,8 @@ function capOutput(value, limit) {
12821
12863
  ${value.slice(value.length - half)}`;
12822
12864
  }
12823
12865
  var inflightProcs = /* @__PURE__ */ new Set();
12824
- async function runCommand(platform2, cmdPath, argv, childEnv, stdin, timeoutMs, maxOutput, cwd, signal) {
12866
+ async function runCommand(platform2, cmdPath, argv, childEnv, stdin, timeoutMs, maxOutput, cwd, signal, cancel) {
12867
+ if (cancel?.aborted) return { stdout: "", stderr: "cancelled", exitCode: 124 };
12825
12868
  let proc;
12826
12869
  try {
12827
12870
  proc = await platform2.spawn({
@@ -12834,16 +12877,14 @@ async function runCommand(platform2, cmdPath, argv, childEnv, stdin, timeoutMs,
12834
12877
  return { stdout: "", stderr: `spawn failed: ${err.message}`, exitCode: 127 };
12835
12878
  }
12836
12879
  inflightProcs.add(proc);
12837
- if (stdin !== void 0) {
12880
+ const feedStdin = async () => {
12838
12881
  const writer = proc.stdin.getWriter();
12839
- await writer.write(new TextEncoder().encode(stdin));
12840
- await writer.close();
12841
- } else {
12842
12882
  try {
12843
- await proc.stdin.getWriter().close();
12883
+ if (stdin !== void 0) await writer.write(new TextEncoder().encode(stdin));
12884
+ await writer.close();
12844
12885
  } catch {
12845
12886
  }
12846
- }
12887
+ };
12847
12888
  const stdoutChunks = [];
12848
12889
  const stderrChunks = [];
12849
12890
  const readStream3 = async (stream, into) => {
@@ -12860,6 +12901,7 @@ async function runCommand(platform2, cmdPath, argv, childEnv, stdin, timeoutMs,
12860
12901
  };
12861
12902
  let timerId;
12862
12903
  let onAbort;
12904
+ let onCancel;
12863
12905
  const timer = new Promise((resolve) => {
12864
12906
  timerId = setTimeout(() => resolve("timeout"), timeoutMs);
12865
12907
  });
@@ -12871,34 +12913,40 @@ async function runCommand(platform2, cmdPath, argv, childEnv, stdin, timeoutMs,
12871
12913
  onAbort = () => resolve("timeout");
12872
12914
  signal.addEventListener("abort", onAbort, { once: true });
12873
12915
  }) : null;
12916
+ const cancelPromise = cancel ? new Promise((resolve) => {
12917
+ if (cancel.aborted) {
12918
+ resolve("cancel");
12919
+ return;
12920
+ }
12921
+ onCancel = () => resolve("cancel");
12922
+ cancel.addEventListener("abort", onCancel, { once: true });
12923
+ }) : null;
12874
12924
  const work = Promise.all([
12875
12925
  readStream3(proc.stdout, stdoutChunks),
12876
12926
  readStream3(proc.stderr, stderrChunks),
12877
- proc.wait()
12927
+ proc.wait(),
12928
+ feedStdin()
12878
12929
  ]);
12879
- const racers = [
12880
- work,
12881
- timer
12882
- ];
12930
+ const racers = [work, timer];
12883
12931
  if (abortPromise !== null) racers.push(abortPromise);
12932
+ if (cancelPromise !== null) racers.push(cancelPromise);
12884
12933
  let result;
12885
12934
  try {
12886
12935
  result = await Promise.race(racers);
12887
12936
  } finally {
12888
12937
  clearTimeout(timerId);
12889
12938
  if (onAbort) signal?.removeEventListener("abort", onAbort);
12939
+ if (onCancel) cancel?.removeEventListener("abort", onCancel);
12890
12940
  }
12891
- if (result === "timeout") {
12892
- await proc.kill("SIGTERM");
12893
- if (!signal?.aborted) {
12894
- await new Promise((resolve) => setTimeout(resolve, 5e3));
12895
- try {
12896
- await proc.kill("SIGKILL");
12897
- } catch {
12898
- }
12941
+ if (result === "timeout" || result === "cancel") {
12942
+ if (signal?.aborted) {
12943
+ await proc.kill("SIGTERM");
12944
+ } else {
12945
+ await terminate(proc, CALL_KILL_GRACE_MS);
12899
12946
  }
12900
12947
  inflightProcs.delete(proc);
12901
- return { stdout: "", stderr: "timed out", exitCode: 124 };
12948
+ const stderr = result === "cancel" ? "cancelled" : "timed out";
12949
+ return { stdout: "", stderr, exitCode: 124 };
12902
12950
  }
12903
12951
  inflightProcs.delete(proc);
12904
12952
  try {
@@ -12924,6 +12972,31 @@ function concat(chunks) {
12924
12972
  return out;
12925
12973
  }
12926
12974
  var KILL_GRACE_MS = 2e3;
12975
+ var CALL_KILL_GRACE_MS = 5e3;
12976
+ async function terminate(proc, graceMs) {
12977
+ try {
12978
+ await proc.kill("SIGTERM");
12979
+ } catch {
12980
+ }
12981
+ let graceId;
12982
+ let exited;
12983
+ try {
12984
+ exited = await Promise.race([
12985
+ proc.wait().then(() => true),
12986
+ new Promise((r) => {
12987
+ graceId = setTimeout(() => r(false), graceMs);
12988
+ })
12989
+ ]);
12990
+ } finally {
12991
+ clearTimeout(graceId);
12992
+ }
12993
+ if (!exited) {
12994
+ try {
12995
+ await proc.kill("SIGKILL");
12996
+ } catch {
12997
+ }
12998
+ }
12999
+ }
12927
13000
  var SIGNAL_EXIT = { SIGINT: 130, SIGTERM: 143, SIGHUP: 129 };
12928
13001
  async function trapShutdown(platform2, handler) {
12929
13002
  await Promise.all(
@@ -12935,24 +13008,7 @@ async function trapShutdown(platform2, handler) {
12935
13008
  async function killInflight() {
12936
13009
  const procs = [...inflightProcs];
12937
13010
  if (procs.length === 0) return;
12938
- await Promise.all(
12939
- procs.map(async (proc) => {
12940
- try {
12941
- await proc.kill("SIGTERM");
12942
- } catch {
12943
- }
12944
- const exited = await Promise.race([
12945
- proc.wait().then(() => true),
12946
- new Promise((r) => setTimeout(() => r(false), KILL_GRACE_MS))
12947
- ]);
12948
- if (!exited) {
12949
- try {
12950
- await proc.kill("SIGKILL");
12951
- } catch {
12952
- }
12953
- }
12954
- })
12955
- );
13011
+ await Promise.all(procs.map((proc) => terminate(proc, KILL_GRACE_MS)));
12956
13012
  inflightProcs.clear();
12957
13013
  }
12958
13014
  async function runHelpForCli(platform2, filePath, childEnv, cwd, signal) {
@@ -13049,7 +13105,7 @@ function createToolExecutor(platform2, clis, allTools, childEnv, options, serveC
13049
13105
  );
13050
13106
  return run2;
13051
13107
  }
13052
- function invokeTemplateTool(tool, args2) {
13108
+ function invokeTemplateTool(tool, args2, cancel) {
13053
13109
  const templateArgs = {};
13054
13110
  if (args2 && typeof args2 === "object") {
13055
13111
  for (const [k, v] of Object.entries(args2)) {
@@ -13067,11 +13123,13 @@ function createToolExecutor(platform2, clis, allTools, childEnv, options, serveC
13067
13123
  void 0,
13068
13124
  options.callTimeout,
13069
13125
  options.maxOutput,
13070
- serveCwd
13126
+ serveCwd,
13127
+ void 0,
13128
+ cancel
13071
13129
  )
13072
13130
  );
13073
13131
  }
13074
- async function executeTool(tool, cli, args2) {
13132
+ async function executeTool(tool, cli, args2, cancel) {
13075
13133
  if (tool.kind === "help") {
13076
13134
  const result = await runCommand(
13077
13135
  platform2,
@@ -13081,7 +13139,9 @@ function createToolExecutor(platform2, clis, allTools, childEnv, options, serveC
13081
13139
  void 0,
13082
13140
  options.callTimeout,
13083
13141
  options.maxOutput,
13084
- serveCwd
13142
+ serveCwd,
13143
+ void 0,
13144
+ cancel
13085
13145
  );
13086
13146
  if (result.exitCode === 0) return result;
13087
13147
  return runCommand(
@@ -13092,7 +13152,9 @@ function createToolExecutor(platform2, clis, allTools, childEnv, options, serveC
13092
13152
  void 0,
13093
13153
  options.callTimeout,
13094
13154
  options.maxOutput,
13095
- serveCwd
13155
+ serveCwd,
13156
+ void 0,
13157
+ cancel
13096
13158
  );
13097
13159
  }
13098
13160
  if (tool.kind === "invoke") {
@@ -13107,7 +13169,9 @@ function createToolExecutor(platform2, clis, allTools, childEnv, options, serveC
13107
13169
  parsed2.stdin,
13108
13170
  options.callTimeout,
13109
13171
  options.maxOutput,
13110
- serveCwd
13172
+ serveCwd,
13173
+ void 0,
13174
+ cancel
13111
13175
  );
13112
13176
  }
13113
13177
  const parsed = readToolArguments(args2 ?? {});
@@ -13123,18 +13187,20 @@ function createToolExecutor(platform2, clis, allTools, childEnv, options, serveC
13123
13187
  planned.stdin,
13124
13188
  options.callTimeout,
13125
13189
  options.maxOutput,
13126
- serveCwd
13190
+ serveCwd,
13191
+ void 0,
13192
+ cancel
13127
13193
  );
13128
13194
  }
13129
- async function invoke(name, args2) {
13195
+ async function invoke(name, args2, cancel) {
13130
13196
  const tool = allTools.find((t) => t.name === name);
13131
13197
  if (!tool) return { stdout: "", stderr: `unknown tool ${name}`, exitCode: 1 };
13132
13198
  if (tool.cli === "" && tool.commandPath.length === 0) {
13133
- return invokeTemplateTool(tool, args2);
13199
+ return invokeTemplateTool(tool, args2, cancel);
13134
13200
  }
13135
13201
  const cli = clis.find((c) => c.name === tool.cli);
13136
13202
  if (!cli) return { stdout: "", stderr: `unknown cli ${tool.cli}`, exitCode: 1 };
13137
- return enqueue(cli.name, () => executeTool(tool, cli, args2));
13203
+ return enqueue(cli.name, () => executeTool(tool, cli, args2, cancel));
13138
13204
  }
13139
13205
  return { invoke, rpcTools };
13140
13206
  }
@@ -13878,10 +13944,13 @@ async function runHttpServer(platform2, options, tools, call, serverName, versio
13878
13944
  let tokenFilePath;
13879
13945
  let shutdownRequested = false;
13880
13946
  let inflightDone;
13947
+ const stopCalls = new AbortController();
13948
+ const activeCalls = /* @__PURE__ */ new Set();
13881
13949
  const shutdown = () => {
13882
13950
  if (shutdownRequested) return;
13883
13951
  shutdownRequested = true;
13884
13952
  listener.close();
13953
+ stopCalls.abort();
13885
13954
  inflightDone = killInflight();
13886
13955
  if (tokenFilePath) {
13887
13956
  platform2.fs.unlink?.(tokenFilePath).catch(() => {
@@ -13911,17 +13980,30 @@ async function runHttpServer(platform2, options, tools, call, serverName, versio
13911
13980
  await platform2.write(2, `mcpcat serve: listening on ${listenUrl}
13912
13981
  `);
13913
13982
  }
13914
- const handler = (request) => handleMcpRequest(
13915
- request,
13916
- tools,
13917
- call,
13918
- serverName,
13919
- version,
13920
- serverOrigins,
13921
- allowedOrigins,
13922
- allowedHosts,
13923
- resolvedBearer
13924
- );
13983
+ const handler = (request, signal) => {
13984
+ const cancel = new AbortController();
13985
+ const relay = () => cancel.abort();
13986
+ signal.addEventListener("abort", relay, { once: true });
13987
+ stopCalls.signal.addEventListener("abort", relay, { once: true });
13988
+ if (signal.aborted || stopCalls.signal.aborted) relay();
13989
+ const pending = handleMcpRequest(
13990
+ request,
13991
+ tools,
13992
+ (name, args2) => call(name, args2, cancel.signal),
13993
+ serverName,
13994
+ version,
13995
+ serverOrigins,
13996
+ allowedOrigins,
13997
+ allowedHosts,
13998
+ resolvedBearer
13999
+ ).finally(() => {
14000
+ signal.removeEventListener("abort", relay);
14001
+ stopCalls.signal.removeEventListener("abort", relay);
14002
+ activeCalls.delete(pending);
14003
+ });
14004
+ activeCalls.add(pending);
14005
+ return pending;
14006
+ };
13925
14007
  try {
13926
14008
  for await (const connection of listener) {
13927
14009
  if (shutdownRequested) break;
@@ -13943,6 +14025,7 @@ async function runHttpServer(platform2, options, tools, call, serverName, versio
13943
14025
  } catch {
13944
14026
  }
13945
14027
  }
14028
+ await Promise.allSettled([...activeCalls]);
13946
14029
  return 0;
13947
14030
  }
13948
14031
  async function handleMcpRequest(request, tools, call, serverName, version, serverOrigins, allowedOrigins, allowedHosts, resolvedBearer) {
@@ -17105,5 +17188,5 @@ try {
17105
17188
  });
17106
17189
  } catch {
17107
17190
  }
17108
- var code = await run(platform, "0.18.1", args);
17191
+ var code = await run(platform, "0.18.2", args);
17109
17192
  process.exit(code);
@@ -11526,7 +11526,40 @@ function parseRequestLine(buf, endPos) {
11526
11526
  return { method, target, headers, headerEnd: endPos + 4 };
11527
11527
  }
11528
11528
  async function handleConnection(readable, writable, handler) {
11529
- const reader = readable.getReader();
11529
+ const raw = readable.getReader();
11530
+ let ahead = null;
11531
+ const parked = [];
11532
+ const reader = {
11533
+ read() {
11534
+ const queued = parked.shift();
11535
+ if (queued) return Promise.resolve(queued);
11536
+ const next = ahead ?? raw.read();
11537
+ ahead = null;
11538
+ return next;
11539
+ }
11540
+ };
11541
+ const watch = async (live, disconnect) => {
11542
+ let held = 0;
11543
+ while (held <= MAX_HEADER_SIZE + MAX_BODY_SIZE) {
11544
+ const pending = ahead ?? raw.read();
11545
+ ahead = pending;
11546
+ let result;
11547
+ try {
11548
+ result = await pending;
11549
+ } catch {
11550
+ if (live.on) disconnect.abort();
11551
+ return;
11552
+ }
11553
+ if (!live.on) return;
11554
+ ahead = null;
11555
+ parked.push(result);
11556
+ if (result.done) {
11557
+ disconnect.abort();
11558
+ return;
11559
+ }
11560
+ held += result.value.length;
11561
+ }
11562
+ };
11530
11563
  const writer = writable.getWriter();
11531
11564
  let buf = new Uint8Array(4096);
11532
11565
  let bufLen = 0;
@@ -11572,7 +11605,16 @@ async function handleConnection(readable, writable, handler) {
11572
11605
  headers: parsed.headers,
11573
11606
  body
11574
11607
  };
11575
- const response = await handler(request);
11608
+ const disconnect = new AbortController();
11609
+ const live = { on: true };
11610
+ void watch(live, disconnect);
11611
+ let response;
11612
+ try {
11613
+ response = await handler(request, disconnect.signal);
11614
+ } finally {
11615
+ live.on = false;
11616
+ }
11617
+ if (disconnect.signal.aborted) break;
11576
11618
  await writeResponse(writer, response);
11577
11619
  const connectionHeader = (parsed.headers.connection ?? "").toLowerCase();
11578
11620
  if (connectionHeader === "close") break;
@@ -11589,7 +11631,7 @@ async function handleConnection(readable, writable, handler) {
11589
11631
  }
11590
11632
  }
11591
11633
  } finally {
11592
- reader.releaseLock();
11634
+ raw.releaseLock();
11593
11635
  try {
11594
11636
  await writer.close();
11595
11637
  } catch {
@@ -12442,7 +12484,8 @@ function capOutput(value, limit) {
12442
12484
  ${value.slice(value.length - half)}`;
12443
12485
  }
12444
12486
  var inflightProcs = /* @__PURE__ */ new Set();
12445
- async function runCommand(platform2, cmdPath, argv, childEnv, stdin, timeoutMs, maxOutput, cwd, signal) {
12487
+ async function runCommand(platform2, cmdPath, argv, childEnv, stdin, timeoutMs, maxOutput, cwd, signal, cancel) {
12488
+ if (cancel?.aborted) return { stdout: "", stderr: "cancelled", exitCode: 124 };
12446
12489
  let proc;
12447
12490
  try {
12448
12491
  proc = await platform2.spawn({
@@ -12455,16 +12498,14 @@ async function runCommand(platform2, cmdPath, argv, childEnv, stdin, timeoutMs,
12455
12498
  return { stdout: "", stderr: `spawn failed: ${err.message}`, exitCode: 127 };
12456
12499
  }
12457
12500
  inflightProcs.add(proc);
12458
- if (stdin !== void 0) {
12501
+ const feedStdin = async () => {
12459
12502
  const writer = proc.stdin.getWriter();
12460
- await writer.write(new TextEncoder().encode(stdin));
12461
- await writer.close();
12462
- } else {
12463
12503
  try {
12464
- await proc.stdin.getWriter().close();
12504
+ if (stdin !== void 0) await writer.write(new TextEncoder().encode(stdin));
12505
+ await writer.close();
12465
12506
  } catch {
12466
12507
  }
12467
- }
12508
+ };
12468
12509
  const stdoutChunks = [];
12469
12510
  const stderrChunks = [];
12470
12511
  const readStream3 = async (stream, into) => {
@@ -12481,6 +12522,7 @@ async function runCommand(platform2, cmdPath, argv, childEnv, stdin, timeoutMs,
12481
12522
  };
12482
12523
  let timerId;
12483
12524
  let onAbort;
12525
+ let onCancel;
12484
12526
  const timer = new Promise((resolve2) => {
12485
12527
  timerId = setTimeout(() => resolve2("timeout"), timeoutMs);
12486
12528
  });
@@ -12492,34 +12534,40 @@ async function runCommand(platform2, cmdPath, argv, childEnv, stdin, timeoutMs,
12492
12534
  onAbort = () => resolve2("timeout");
12493
12535
  signal.addEventListener("abort", onAbort, { once: true });
12494
12536
  }) : null;
12537
+ const cancelPromise = cancel ? new Promise((resolve2) => {
12538
+ if (cancel.aborted) {
12539
+ resolve2("cancel");
12540
+ return;
12541
+ }
12542
+ onCancel = () => resolve2("cancel");
12543
+ cancel.addEventListener("abort", onCancel, { once: true });
12544
+ }) : null;
12495
12545
  const work = Promise.all([
12496
12546
  readStream3(proc.stdout, stdoutChunks),
12497
12547
  readStream3(proc.stderr, stderrChunks),
12498
- proc.wait()
12548
+ proc.wait(),
12549
+ feedStdin()
12499
12550
  ]);
12500
- const racers = [
12501
- work,
12502
- timer
12503
- ];
12551
+ const racers = [work, timer];
12504
12552
  if (abortPromise !== null) racers.push(abortPromise);
12553
+ if (cancelPromise !== null) racers.push(cancelPromise);
12505
12554
  let result;
12506
12555
  try {
12507
12556
  result = await Promise.race(racers);
12508
12557
  } finally {
12509
12558
  clearTimeout(timerId);
12510
12559
  if (onAbort) signal?.removeEventListener("abort", onAbort);
12560
+ if (onCancel) cancel?.removeEventListener("abort", onCancel);
12511
12561
  }
12512
- if (result === "timeout") {
12513
- await proc.kill("SIGTERM");
12514
- if (!signal?.aborted) {
12515
- await new Promise((resolve2) => setTimeout(resolve2, 5e3));
12516
- try {
12517
- await proc.kill("SIGKILL");
12518
- } catch {
12519
- }
12562
+ if (result === "timeout" || result === "cancel") {
12563
+ if (signal?.aborted) {
12564
+ await proc.kill("SIGTERM");
12565
+ } else {
12566
+ await terminate(proc, CALL_KILL_GRACE_MS);
12520
12567
  }
12521
12568
  inflightProcs.delete(proc);
12522
- return { stdout: "", stderr: "timed out", exitCode: 124 };
12569
+ const stderr = result === "cancel" ? "cancelled" : "timed out";
12570
+ return { stdout: "", stderr, exitCode: 124 };
12523
12571
  }
12524
12572
  inflightProcs.delete(proc);
12525
12573
  try {
@@ -12545,6 +12593,31 @@ function concat(chunks) {
12545
12593
  return out;
12546
12594
  }
12547
12595
  var KILL_GRACE_MS = 2e3;
12596
+ var CALL_KILL_GRACE_MS = 5e3;
12597
+ async function terminate(proc, graceMs) {
12598
+ try {
12599
+ await proc.kill("SIGTERM");
12600
+ } catch {
12601
+ }
12602
+ let graceId;
12603
+ let exited;
12604
+ try {
12605
+ exited = await Promise.race([
12606
+ proc.wait().then(() => true),
12607
+ new Promise((r) => {
12608
+ graceId = setTimeout(() => r(false), graceMs);
12609
+ })
12610
+ ]);
12611
+ } finally {
12612
+ clearTimeout(graceId);
12613
+ }
12614
+ if (!exited) {
12615
+ try {
12616
+ await proc.kill("SIGKILL");
12617
+ } catch {
12618
+ }
12619
+ }
12620
+ }
12548
12621
  var SIGNAL_EXIT = { SIGINT: 130, SIGTERM: 143, SIGHUP: 129 };
12549
12622
  async function trapShutdown(platform2, handler) {
12550
12623
  await Promise.all(
@@ -12556,24 +12629,7 @@ async function trapShutdown(platform2, handler) {
12556
12629
  async function killInflight() {
12557
12630
  const procs = [...inflightProcs];
12558
12631
  if (procs.length === 0) return;
12559
- await Promise.all(
12560
- procs.map(async (proc) => {
12561
- try {
12562
- await proc.kill("SIGTERM");
12563
- } catch {
12564
- }
12565
- const exited = await Promise.race([
12566
- proc.wait().then(() => true),
12567
- new Promise((r) => setTimeout(() => r(false), KILL_GRACE_MS))
12568
- ]);
12569
- if (!exited) {
12570
- try {
12571
- await proc.kill("SIGKILL");
12572
- } catch {
12573
- }
12574
- }
12575
- })
12576
- );
12632
+ await Promise.all(procs.map((proc) => terminate(proc, KILL_GRACE_MS)));
12577
12633
  inflightProcs.clear();
12578
12634
  }
12579
12635
  async function runHelpForCli(platform2, filePath, childEnv, cwd, signal) {
@@ -12670,7 +12726,7 @@ function createToolExecutor(platform2, clis, allTools, childEnv, options, serveC
12670
12726
  );
12671
12727
  return run2;
12672
12728
  }
12673
- function invokeTemplateTool(tool, args) {
12729
+ function invokeTemplateTool(tool, args, cancel) {
12674
12730
  const templateArgs = {};
12675
12731
  if (args && typeof args === "object") {
12676
12732
  for (const [k, v] of Object.entries(args)) {
@@ -12688,11 +12744,13 @@ function createToolExecutor(platform2, clis, allTools, childEnv, options, serveC
12688
12744
  void 0,
12689
12745
  options.callTimeout,
12690
12746
  options.maxOutput,
12691
- serveCwd
12747
+ serveCwd,
12748
+ void 0,
12749
+ cancel
12692
12750
  )
12693
12751
  );
12694
12752
  }
12695
- async function executeTool(tool, cli, args) {
12753
+ async function executeTool(tool, cli, args, cancel) {
12696
12754
  if (tool.kind === "help") {
12697
12755
  const result = await runCommand(
12698
12756
  platform2,
@@ -12702,7 +12760,9 @@ function createToolExecutor(platform2, clis, allTools, childEnv, options, serveC
12702
12760
  void 0,
12703
12761
  options.callTimeout,
12704
12762
  options.maxOutput,
12705
- serveCwd
12763
+ serveCwd,
12764
+ void 0,
12765
+ cancel
12706
12766
  );
12707
12767
  if (result.exitCode === 0) return result;
12708
12768
  return runCommand(
@@ -12713,7 +12773,9 @@ function createToolExecutor(platform2, clis, allTools, childEnv, options, serveC
12713
12773
  void 0,
12714
12774
  options.callTimeout,
12715
12775
  options.maxOutput,
12716
- serveCwd
12776
+ serveCwd,
12777
+ void 0,
12778
+ cancel
12717
12779
  );
12718
12780
  }
12719
12781
  if (tool.kind === "invoke") {
@@ -12728,7 +12790,9 @@ function createToolExecutor(platform2, clis, allTools, childEnv, options, serveC
12728
12790
  parsed2.stdin,
12729
12791
  options.callTimeout,
12730
12792
  options.maxOutput,
12731
- serveCwd
12793
+ serveCwd,
12794
+ void 0,
12795
+ cancel
12732
12796
  );
12733
12797
  }
12734
12798
  const parsed = readToolArguments(args ?? {});
@@ -12744,18 +12808,20 @@ function createToolExecutor(platform2, clis, allTools, childEnv, options, serveC
12744
12808
  planned.stdin,
12745
12809
  options.callTimeout,
12746
12810
  options.maxOutput,
12747
- serveCwd
12811
+ serveCwd,
12812
+ void 0,
12813
+ cancel
12748
12814
  );
12749
12815
  }
12750
- async function invoke(name, args) {
12816
+ async function invoke(name, args, cancel) {
12751
12817
  const tool = allTools.find((t) => t.name === name);
12752
12818
  if (!tool) return { stdout: "", stderr: `unknown tool ${name}`, exitCode: 1 };
12753
12819
  if (tool.cli === "" && tool.commandPath.length === 0) {
12754
- return invokeTemplateTool(tool, args);
12820
+ return invokeTemplateTool(tool, args, cancel);
12755
12821
  }
12756
12822
  const cli = clis.find((c) => c.name === tool.cli);
12757
12823
  if (!cli) return { stdout: "", stderr: `unknown cli ${tool.cli}`, exitCode: 1 };
12758
- return enqueue(cli.name, () => executeTool(tool, cli, args));
12824
+ return enqueue(cli.name, () => executeTool(tool, cli, args, cancel));
12759
12825
  }
12760
12826
  return { invoke, rpcTools };
12761
12827
  }
@@ -13499,10 +13565,13 @@ async function runHttpServer(platform2, options, tools, call, serverName, versio
13499
13565
  let tokenFilePath;
13500
13566
  let shutdownRequested = false;
13501
13567
  let inflightDone;
13568
+ const stopCalls = new AbortController();
13569
+ const activeCalls = /* @__PURE__ */ new Set();
13502
13570
  const shutdown = () => {
13503
13571
  if (shutdownRequested) return;
13504
13572
  shutdownRequested = true;
13505
13573
  listener.close();
13574
+ stopCalls.abort();
13506
13575
  inflightDone = killInflight();
13507
13576
  if (tokenFilePath) {
13508
13577
  platform2.fs.unlink?.(tokenFilePath).catch(() => {
@@ -13532,17 +13601,30 @@ async function runHttpServer(platform2, options, tools, call, serverName, versio
13532
13601
  await platform2.write(2, `mcpcat serve: listening on ${listenUrl}
13533
13602
  `);
13534
13603
  }
13535
- const handler = (request) => handleMcpRequest(
13536
- request,
13537
- tools,
13538
- call,
13539
- serverName,
13540
- version,
13541
- serverOrigins,
13542
- allowedOrigins,
13543
- allowedHosts,
13544
- resolvedBearer
13545
- );
13604
+ const handler = (request, signal) => {
13605
+ const cancel = new AbortController();
13606
+ const relay = () => cancel.abort();
13607
+ signal.addEventListener("abort", relay, { once: true });
13608
+ stopCalls.signal.addEventListener("abort", relay, { once: true });
13609
+ if (signal.aborted || stopCalls.signal.aborted) relay();
13610
+ const pending = handleMcpRequest(
13611
+ request,
13612
+ tools,
13613
+ (name, args) => call(name, args, cancel.signal),
13614
+ serverName,
13615
+ version,
13616
+ serverOrigins,
13617
+ allowedOrigins,
13618
+ allowedHosts,
13619
+ resolvedBearer
13620
+ ).finally(() => {
13621
+ signal.removeEventListener("abort", relay);
13622
+ stopCalls.signal.removeEventListener("abort", relay);
13623
+ activeCalls.delete(pending);
13624
+ });
13625
+ activeCalls.add(pending);
13626
+ return pending;
13627
+ };
13546
13628
  try {
13547
13629
  for await (const connection of listener) {
13548
13630
  if (shutdownRequested) break;
@@ -13564,6 +13646,7 @@ async function runHttpServer(platform2, options, tools, call, serverName, versio
13564
13646
  } catch {
13565
13647
  }
13566
13648
  }
13649
+ await Promise.allSettled([...activeCalls]);
13567
13650
  return 0;
13568
13651
  }
13569
13652
  async function handleMcpRequest(request, tools, call, serverName, version, serverOrigins, allowedOrigins, allowedHosts, resolvedBearer) {
@@ -16827,7 +16910,7 @@ async function main(ctx) {
16827
16910
  packageDir: "/node_modules/@ai-ecoverse/mcpcat"
16828
16911
  });
16829
16912
  const args = ctx.argv.slice(1);
16830
- return run(platform2, "0.18.1", args);
16913
+ return run(platform2, "0.18.2", args);
16831
16914
  }
16832
16915
  export {
16833
16916
  main as default
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/mcpcat",
3
- "version": "0.18.1",
3
+ "version": "0.18.2",
4
4
  "description": "A curl for the Model Context Protocol",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -62,14 +62,14 @@
62
62
  },
63
63
  "devDependencies": {
64
64
  "@ai-ecoverse/slicc-bios": "1.38.0",
65
- "@ai-ecoverse/slicc-kernel": "1.143.2",
66
- "@ai-ecoverse/slicc-shared-web": "1.30.1",
65
+ "@ai-ecoverse/slicc-kernel": "1.143.4",
66
+ "@ai-ecoverse/slicc-shared-web": "1.30.3",
67
67
  "@biomejs/biome": "2.5.15",
68
68
  "@earendil-works/pi-codemode": "1.2.0",
69
69
  "@earendil-works/pi-mcp": "1.2.0",
70
70
  "@types/node": "26.6.5",
71
71
  "esbuild": "0.28.2",
72
- "kernel-cert-new": "npm:@ai-ecoverse/slicc-kernel@1.143.2",
72
+ "kernel-cert-new": "npm:@ai-ecoverse/slicc-kernel@1.143.4",
73
73
  "lefthook": "2.2.2",
74
74
  "monocart-coverage-reports": "2.13.2",
75
75
  "proper-lockfile": "4.1.2",