@wrongstack/mcp 0.277.2 → 0.280.1

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/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { spawn } from 'child_process';
2
2
  import { expectDefined, ToolCapabilities, buildChildEnv, ToolError, ConfigError } from '@wrongstack/core';
3
+ import { toErrorMessage } from '@wrongstack/core/utils';
3
4
  import { createHash, randomBytes } from 'crypto';
4
5
  import * as https from 'https';
5
6
  import * as net from 'net';
6
- import { toErrorMessage } from '@wrongstack/core/utils';
7
7
  import * as fs from 'fs/promises';
8
8
  import * as path from 'path';
9
9
  import { createServer } from 'http';
@@ -836,6 +836,8 @@ var StreamableHTTPTransport = class extends BaseHTTPTransport {
836
836
  this.disconnectHandlers.splice(0, this.disconnectHandlers.length);
837
837
  }
838
838
  };
839
+
840
+ // src/client.ts
839
841
  var MCPClient = class {
840
842
  constructor(opts) {
841
843
  this.opts = opts;
@@ -1010,6 +1012,10 @@ var MCPClient = class {
1010
1012
  try {
1011
1013
  await this.sseTransport.connect();
1012
1014
  } catch (err) {
1015
+ const t = this.sseTransport;
1016
+ this.sseTransport = void 0;
1017
+ await t.close().catch(() => {
1018
+ });
1013
1019
  this.state = "failed";
1014
1020
  throw err;
1015
1021
  }
@@ -1052,6 +1058,10 @@ var MCPClient = class {
1052
1058
  try {
1053
1059
  await this.httpTransport.connect();
1054
1060
  } catch (err) {
1061
+ const t = this.httpTransport;
1062
+ this.httpTransport = void 0;
1063
+ await t.close().catch(() => {
1064
+ });
1055
1065
  this.state = "failed";
1056
1066
  throw err;
1057
1067
  }
@@ -1202,9 +1212,7 @@ var MCPClient = class {
1202
1212
  });
1203
1213
  }
1204
1214
  } catch (err) {
1205
- throw new Error(
1206
- `[MCP] notify("${method}") failed: ${toErrorMessage(err)}`
1207
- );
1215
+ throw new Error(`[MCP] notify("${method}") failed: ${toErrorMessage(err)}`);
1208
1216
  }
1209
1217
  }
1210
1218
  onData(s) {
@@ -1243,7 +1251,9 @@ var MCPClient = class {
1243
1251
  async handleToolsListChanged() {
1244
1252
  try {
1245
1253
  const toolsRes = await this.request("tools/list", {});
1246
- const tools = normalizeMCPTools(toolsRes.result?.tools);
1254
+ const tools = normalizeMCPTools(
1255
+ toolsRes.result?.tools
1256
+ );
1247
1257
  this._tools = tools;
1248
1258
  this._toolsCache = tools;
1249
1259
  for (const listener of this.toolsChangedListeners) {
@@ -1376,6 +1386,11 @@ var MCPRegistry = class _MCPRegistry {
1376
1386
  }
1377
1387
  async start(cfg) {
1378
1388
  if (cfg.enabled === false) return;
1389
+ if (this.servers.has(cfg.name)) {
1390
+ throw new Error(
1391
+ `MCP server "${cfg.name}" is already registered \u2014 use restart() to re-cycle a running server`
1392
+ );
1393
+ }
1379
1394
  const lazy = !!cfg.lazy && !!this.cacheDir;
1380
1395
  const slot = {
1381
1396
  cfg,
@@ -1503,6 +1518,10 @@ var MCPRegistry = class _MCPRegistry {
1503
1518
  const slot = this.servers.get(name);
1504
1519
  if (!slot) return;
1505
1520
  slot.reconnectPending = false;
1521
+ if (slot.reconnectTimer) {
1522
+ clearTimeout(slot.reconnectTimer);
1523
+ slot.reconnectTimer = void 0;
1524
+ }
1506
1525
  if (slot.client) {
1507
1526
  slot.client.removeExitListener(this.onChildExit);
1508
1527
  if (slot.onDisconnect) slot.client.removeDisconnectListener(slot.onDisconnect);
@@ -1600,6 +1619,10 @@ var MCPRegistry = class _MCPRegistry {
1600
1619
  */
1601
1620
  async sleepIdle(slot) {
1602
1621
  slot.reconnectPending = false;
1622
+ if (slot.reconnectTimer) {
1623
+ clearTimeout(slot.reconnectTimer);
1624
+ slot.reconnectTimer = void 0;
1625
+ }
1603
1626
  if (slot.client) {
1604
1627
  slot.client.removeExitListener(this.onChildExit);
1605
1628
  if (slot.onDisconnect) slot.client.removeDisconnectListener(slot.onDisconnect);
@@ -1751,13 +1774,20 @@ var MCPRegistry = class _MCPRegistry {
1751
1774
  return;
1752
1775
  }
1753
1776
  slot.reconnectPending = true;
1777
+ if (slot.reconnectTimer) {
1778
+ clearTimeout(slot.reconnectTimer);
1779
+ slot.reconnectTimer = void 0;
1780
+ }
1754
1781
  const base = Math.min(
1755
1782
  _MCPRegistry.BASE_RECONNECT_DELAY_MS * 2 ** slot.reconnectCycles,
1756
1783
  _MCPRegistry.MAX_RECONNECT_DELAY_MS
1757
1784
  );
1758
1785
  const jitter = base * MCP_CONSTANTS.RECONNECT.JITTER_FACTOR * (Math.random() * 2 - 1);
1759
1786
  const delay = Math.max(100, Math.round(base + jitter));
1760
- setTimeout(() => this.attemptReconnect(slot), delay);
1787
+ slot.reconnectTimer = setTimeout(() => {
1788
+ slot.reconnectTimer = void 0;
1789
+ void this.attemptReconnect(slot);
1790
+ }, delay);
1761
1791
  }
1762
1792
  async attemptReconnect(slot) {
1763
1793
  slot.reconnectPending = false;
@@ -1841,6 +1871,11 @@ var MCPRegistry = class _MCPRegistry {
1841
1871
  );
1842
1872
  slot.state = "failed";
1843
1873
  slot.client = void 0;
1874
+ if (slot.reconnectTimer) {
1875
+ clearTimeout(slot.reconnectTimer);
1876
+ slot.reconnectTimer = void 0;
1877
+ }
1878
+ slot.reconnectPending = false;
1844
1879
  this.events.emit("mcp.server.disconnected", {
1845
1880
  name: slot.cfg.name,
1846
1881
  reason: err instanceof Error ? err.message : "unknown"
@@ -2125,7 +2160,11 @@ var MCPServer = class {
2125
2160
  try {
2126
2161
  const result = await this.dispatch(msg.method, msg.params);
2127
2162
  if (result === METHOD_NOT_FOUND_SENTINEL) {
2128
- return this.encodeError(expectDefined(msg.id), METHOD_NOT_FOUND, `Method not found: ${msg.method}`);
2163
+ return this.encodeError(
2164
+ expectDefined(msg.id),
2165
+ METHOD_NOT_FOUND,
2166
+ `Method not found: ${msg.method}`
2167
+ );
2129
2168
  }
2130
2169
  return JSON.stringify({ jsonrpc: "2.0", id: msg.id, result });
2131
2170
  } catch (err) {
@@ -2191,6 +2230,7 @@ function serveStdio(server, opts = {}) {
2191
2230
  const stdout = opts.stdout ?? process.stdout;
2192
2231
  let buffer = "";
2193
2232
  let closed = false;
2233
+ let bufferTooLarge = false;
2194
2234
  let writeChain = Promise.resolve();
2195
2235
  const writeLine = (s) => {
2196
2236
  writeChain = writeChain.then(
@@ -2200,16 +2240,38 @@ function serveStdio(server, opts = {}) {
2200
2240
  })
2201
2241
  ).catch((err) => {
2202
2242
  const msg = toErrorMessage(err);
2203
- console.error(JSON.stringify({
2204
- level: "error",
2205
- event: "mcp_server.stdout_write_failed",
2206
- message: msg,
2207
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
2208
- }));
2243
+ console.error(
2244
+ JSON.stringify({
2245
+ level: "error",
2246
+ event: "mcp_server.stdout_write_failed",
2247
+ message: msg,
2248
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2249
+ })
2250
+ );
2209
2251
  });
2210
2252
  };
2211
2253
  const onData = (chunk) => {
2254
+ if (bufferTooLarge) return;
2212
2255
  buffer += typeof chunk === "string" ? chunk : chunk.toString("utf8");
2256
+ if (buffer.length > HTTP_BODY_CAP) {
2257
+ bufferTooLarge = true;
2258
+ buffer = "";
2259
+ console.error(
2260
+ JSON.stringify({
2261
+ level: "error",
2262
+ event: "mcp_server.line_buffer_overflow",
2263
+ message: `stdio line exceeded ${HTTP_BODY_CAP} bytes without newline \u2014 aborting stream`,
2264
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2265
+ })
2266
+ );
2267
+ try {
2268
+ stdin.pause?.();
2269
+ stdin.destroy?.();
2270
+ } catch {
2271
+ }
2272
+ onEnd();
2273
+ return;
2274
+ }
2213
2275
  let idx = buffer.indexOf("\n");
2214
2276
  while (idx !== -1) {
2215
2277
  const line = buffer.slice(0, idx);
@@ -2217,20 +2279,24 @@ function serveStdio(server, opts = {}) {
2217
2279
  idx = buffer.indexOf("\n");
2218
2280
  if (!line.trim()) continue;
2219
2281
  void server.handleMessage(line).then((res) => {
2220
- if (res !== null && !closed) writeLine(res);
2282
+ if (res !== null) writeLine(res);
2221
2283
  }).catch((err) => {
2222
- console.error(JSON.stringify({
2223
- level: "error",
2224
- event: "mcp_server.handle_message_failed",
2225
- message: toErrorMessage(err),
2226
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
2227
- }));
2284
+ console.error(
2285
+ JSON.stringify({
2286
+ level: "error",
2287
+ event: "mcp_server.handle_message_failed",
2288
+ message: toErrorMessage(err),
2289
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2290
+ })
2291
+ );
2228
2292
  });
2229
2293
  }
2230
2294
  };
2231
2295
  let resolveDone;
2232
2296
  const done = new Promise((resolve) => {
2233
- resolveDone = resolve;
2297
+ resolveDone = () => {
2298
+ void writeChain.then(() => resolve());
2299
+ };
2234
2300
  });
2235
2301
  const onEnd = () => {
2236
2302
  if (closed) return;