@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 +87 -21
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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(
|
|
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(() =>
|
|
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(
|
|
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(
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
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
|
|
2282
|
+
if (res !== null) writeLine(res);
|
|
2221
2283
|
}).catch((err) => {
|
|
2222
|
-
console.error(
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
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 =
|
|
2297
|
+
resolveDone = () => {
|
|
2298
|
+
void writeChain.then(() => resolve());
|
|
2299
|
+
};
|
|
2234
2300
|
});
|
|
2235
2301
|
const onEnd = () => {
|
|
2236
2302
|
if (closed) return;
|