@wrongstack/mcp 0.283.1 → 0.284.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.d.ts +9 -3
- package/dist/index.js +74 -17
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -102,7 +102,9 @@ declare class MCPClient {
|
|
|
102
102
|
private connectStdio;
|
|
103
103
|
private connectSSE;
|
|
104
104
|
private connectStreamableHTTP;
|
|
105
|
-
callTool(name: string, input: unknown
|
|
105
|
+
callTool(name: string, input: unknown, opts?: {
|
|
106
|
+
signal?: AbortSignal | undefined;
|
|
107
|
+
}): Promise<ToolCallResult>;
|
|
106
108
|
close(): Promise<void>;
|
|
107
109
|
private request;
|
|
108
110
|
/**
|
|
@@ -633,7 +635,9 @@ declare class SSETransport extends BaseHTTPTransport {
|
|
|
633
635
|
private readSSEBody;
|
|
634
636
|
private buildSSEUrl;
|
|
635
637
|
private httpPost;
|
|
636
|
-
callTool(name: string, input: unknown
|
|
638
|
+
callTool(name: string, input: unknown, opts?: {
|
|
639
|
+
signal?: AbortSignal | undefined;
|
|
640
|
+
}): Promise<ToolCallResult>;
|
|
637
641
|
/** Generic JSON-RPC request — used by MCPClient.request() for SSE transports. */
|
|
638
642
|
request(method: string, params: unknown, timeoutMs?: number): Promise<JsonRpcResponse>;
|
|
639
643
|
close(): Promise<void>;
|
|
@@ -652,7 +656,9 @@ declare class StreamableHTTPTransport extends BaseHTTPTransport {
|
|
|
652
656
|
private postRaw;
|
|
653
657
|
/** Generic JSON-RPC request — used by MCPClient.request() for SSE/streamable-http transports. */
|
|
654
658
|
request(method: string, params: unknown, timeoutMs?: number): Promise<JsonRpcResponse>;
|
|
655
|
-
callTool(name: string, input: unknown
|
|
659
|
+
callTool(name: string, input: unknown, opts?: {
|
|
660
|
+
signal?: AbortSignal | undefined;
|
|
661
|
+
}): Promise<ToolCallResult>;
|
|
656
662
|
close(): Promise<void>;
|
|
657
663
|
}
|
|
658
664
|
|
package/dist/index.js
CHANGED
|
@@ -305,6 +305,11 @@ function assertMatchingJsonRpcResult(data, expectedId, method) {
|
|
|
305
305
|
}
|
|
306
306
|
return data;
|
|
307
307
|
}
|
|
308
|
+
function makeAbortError(method) {
|
|
309
|
+
const err = new Error(`MCP request "${method}" aborted by client`);
|
|
310
|
+
err.name = "AbortError";
|
|
311
|
+
return err;
|
|
312
|
+
}
|
|
308
313
|
function createTimeoutSignal(parent, timeoutMs) {
|
|
309
314
|
const ctrl = new AbortController();
|
|
310
315
|
const onAbort = () => ctrl.abort(parent?.reason);
|
|
@@ -543,10 +548,12 @@ var SSETransport = class extends BaseHTTPTransport {
|
|
|
543
548
|
return this.url;
|
|
544
549
|
}
|
|
545
550
|
}
|
|
546
|
-
async httpPost(method, params) {
|
|
551
|
+
async httpPost(method, params, opts) {
|
|
547
552
|
const id = this.genId();
|
|
548
553
|
const body = JSON.stringify({ jsonrpc: "2.0", id, method, params });
|
|
549
|
-
const
|
|
554
|
+
const external = opts?.signal;
|
|
555
|
+
const parent = external && this.abortController ? AbortSignal.any([this.abortController.signal, external]) : external ?? this.abortController?.signal;
|
|
556
|
+
const timeoutSignal = createTimeoutSignal(parent, this.requestTimeout);
|
|
550
557
|
const fetchOpts = {
|
|
551
558
|
method: "POST",
|
|
552
559
|
headers: {
|
|
@@ -557,8 +564,8 @@ var SSETransport = class extends BaseHTTPTransport {
|
|
|
557
564
|
signal: timeoutSignal.signal
|
|
558
565
|
};
|
|
559
566
|
this.applyTlsAgent(fetchOpts);
|
|
560
|
-
const res = await fetch(this.url, fetchOpts);
|
|
561
567
|
try {
|
|
568
|
+
const res = await fetch(this.url, fetchOpts);
|
|
562
569
|
if (!res.ok) {
|
|
563
570
|
const body2 = await res.text();
|
|
564
571
|
const cap = MCP_CONSTANTS.REQUEST_LOG_CAP;
|
|
@@ -583,11 +590,21 @@ var SSETransport = class extends BaseHTTPTransport {
|
|
|
583
590
|
});
|
|
584
591
|
}
|
|
585
592
|
return assertMatchingJsonRpcResult(data, id, method);
|
|
593
|
+
} catch (err) {
|
|
594
|
+
if (external?.aborted && !method.startsWith("notifications/")) {
|
|
595
|
+
void this.httpPost("notifications/cancelled", {
|
|
596
|
+
requestId: id,
|
|
597
|
+
reason: "client aborted"
|
|
598
|
+
}).catch(() => {
|
|
599
|
+
});
|
|
600
|
+
throw makeAbortError(method);
|
|
601
|
+
}
|
|
602
|
+
throw err;
|
|
586
603
|
} finally {
|
|
587
604
|
timeoutSignal.dispose();
|
|
588
605
|
}
|
|
589
606
|
}
|
|
590
|
-
async callTool(name, input) {
|
|
607
|
+
async callTool(name, input, opts) {
|
|
591
608
|
if (this.state !== "connected") {
|
|
592
609
|
throw new ToolError({
|
|
593
610
|
message: `SSE transport not connected (state=${this.state})`,
|
|
@@ -596,7 +613,7 @@ var SSETransport = class extends BaseHTTPTransport {
|
|
|
596
613
|
context: { transport: "sse", state: this.state }
|
|
597
614
|
});
|
|
598
615
|
}
|
|
599
|
-
const res = await this.httpPost("tools/call", { name, arguments: input });
|
|
616
|
+
const res = await this.httpPost("tools/call", { name, arguments: input }, opts);
|
|
600
617
|
if (res.error) {
|
|
601
618
|
return { content: res.error.message, isError: true };
|
|
602
619
|
}
|
|
@@ -746,10 +763,12 @@ var StreamableHTTPTransport = class extends BaseHTTPTransport {
|
|
|
746
763
|
throw err;
|
|
747
764
|
}
|
|
748
765
|
}
|
|
749
|
-
async postRaw(method, params) {
|
|
766
|
+
async postRaw(method, params, opts) {
|
|
750
767
|
const id = this.genId();
|
|
751
768
|
const body = JSON.stringify({ jsonrpc: "2.0", id, method, params });
|
|
752
|
-
const
|
|
769
|
+
const external = opts?.signal;
|
|
770
|
+
const parent = external && this.abortController ? AbortSignal.any([this.abortController.signal, external]) : external ?? this.abortController?.signal;
|
|
771
|
+
const timeoutSignal = createTimeoutSignal(parent, this.requestTimeout);
|
|
753
772
|
const fetchOpts = {
|
|
754
773
|
method: "POST",
|
|
755
774
|
headers: {
|
|
@@ -762,8 +781,8 @@ var StreamableHTTPTransport = class extends BaseHTTPTransport {
|
|
|
762
781
|
signal: timeoutSignal.signal
|
|
763
782
|
};
|
|
764
783
|
this.applyTlsAgent(fetchOpts);
|
|
765
|
-
const res = await fetch(this.url, fetchOpts);
|
|
766
784
|
try {
|
|
785
|
+
const res = await fetch(this.url, fetchOpts);
|
|
767
786
|
if (!res.ok) {
|
|
768
787
|
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
769
788
|
}
|
|
@@ -776,6 +795,16 @@ var StreamableHTTPTransport = class extends BaseHTTPTransport {
|
|
|
776
795
|
return assertMatchingJsonRpcResult(match, id, method);
|
|
777
796
|
}
|
|
778
797
|
throw new Error("Could not parse response as JSON-RPC");
|
|
798
|
+
} catch (err) {
|
|
799
|
+
if (external?.aborted && !method.startsWith("notifications/")) {
|
|
800
|
+
void this.postRaw("notifications/cancelled", {
|
|
801
|
+
requestId: id,
|
|
802
|
+
reason: "client aborted"
|
|
803
|
+
}).catch(() => {
|
|
804
|
+
});
|
|
805
|
+
throw makeAbortError(method);
|
|
806
|
+
}
|
|
807
|
+
throw err;
|
|
779
808
|
} finally {
|
|
780
809
|
timeoutSignal.dispose();
|
|
781
810
|
}
|
|
@@ -823,11 +852,11 @@ var StreamableHTTPTransport = class extends BaseHTTPTransport {
|
|
|
823
852
|
timeoutSignal.dispose();
|
|
824
853
|
}
|
|
825
854
|
}
|
|
826
|
-
async callTool(name, input) {
|
|
855
|
+
async callTool(name, input, opts) {
|
|
827
856
|
if (this.state !== "connected") {
|
|
828
857
|
throw new Error(`streamable-http transport not connected (state=${this.state})`);
|
|
829
858
|
}
|
|
830
|
-
const res = await this.postRaw("tools/call", { name, arguments: input });
|
|
859
|
+
const res = await this.postRaw("tools/call", { name, arguments: input }, opts);
|
|
831
860
|
if (res.error) {
|
|
832
861
|
return { content: res.error.message, isError: true };
|
|
833
862
|
}
|
|
@@ -1087,17 +1116,17 @@ var MCPClient = class {
|
|
|
1087
1116
|
this._toolsCache = this._tools;
|
|
1088
1117
|
this.state = "connected";
|
|
1089
1118
|
}
|
|
1090
|
-
async callTool(name, input) {
|
|
1119
|
+
async callTool(name, input, opts) {
|
|
1091
1120
|
if (this.state !== "connected") {
|
|
1092
1121
|
throw new Error(`MCP client "${this.opts.name}" not connected (state=${this.state})`);
|
|
1093
1122
|
}
|
|
1094
1123
|
if (this.sseTransport) {
|
|
1095
|
-
return this.sseTransport.callTool(name, input);
|
|
1124
|
+
return this.sseTransport.callTool(name, input, opts);
|
|
1096
1125
|
}
|
|
1097
1126
|
if (this.httpTransport) {
|
|
1098
|
-
return this.httpTransport.callTool(name, input);
|
|
1127
|
+
return this.httpTransport.callTool(name, input, opts);
|
|
1099
1128
|
}
|
|
1100
|
-
const res = await this.request("tools/call", { name, arguments: input });
|
|
1129
|
+
const res = await this.request("tools/call", { name, arguments: input }, void 0, opts);
|
|
1101
1130
|
if (res.error) {
|
|
1102
1131
|
return { content: res.error.message, isError: true };
|
|
1103
1132
|
}
|
|
@@ -1140,14 +1169,38 @@ var MCPClient = class {
|
|
|
1140
1169
|
this.httpTransport?.close();
|
|
1141
1170
|
this.state = "disconnected";
|
|
1142
1171
|
}
|
|
1143
|
-
request(method, params, timeoutMs = this.opts.requestTimeoutMs ?? 6e4) {
|
|
1172
|
+
request(method, params, timeoutMs = this.opts.requestTimeoutMs ?? 6e4, opts) {
|
|
1144
1173
|
if (this.sseTransport) return this.sseTransport.request(method, params, timeoutMs);
|
|
1145
1174
|
if (this.httpTransport) return this.httpTransport.request(method, params, timeoutMs);
|
|
1175
|
+
const signal = opts?.signal;
|
|
1176
|
+
if (signal?.aborted) {
|
|
1177
|
+
const err = new Error(`MCP "${this.opts.name}" request "${method}" aborted before send`);
|
|
1178
|
+
err.name = "AbortError";
|
|
1179
|
+
return Promise.reject(err);
|
|
1180
|
+
}
|
|
1146
1181
|
const id = this.nextId++;
|
|
1147
1182
|
const req = { jsonrpc: "2.0", id, method, params };
|
|
1148
1183
|
return new Promise((resolve, reject) => {
|
|
1184
|
+
const onAbort = signal ? () => {
|
|
1185
|
+
const pending = this.pending.get(id);
|
|
1186
|
+
this.pending.delete(id);
|
|
1187
|
+
if (pending) clearTimeout(pending.timer);
|
|
1188
|
+
void this.notify("notifications/cancelled", {
|
|
1189
|
+
requestId: id,
|
|
1190
|
+
reason: "client aborted"
|
|
1191
|
+
}).catch(() => {
|
|
1192
|
+
});
|
|
1193
|
+
const err = new Error(`MCP "${this.opts.name}" request "${method}" aborted by client`);
|
|
1194
|
+
err.name = "AbortError";
|
|
1195
|
+
reject(err);
|
|
1196
|
+
} : void 0;
|
|
1197
|
+
if (signal && onAbort) signal.addEventListener("abort", onAbort, { once: true });
|
|
1198
|
+
const detach = () => {
|
|
1199
|
+
if (signal && onAbort) signal.removeEventListener("abort", onAbort);
|
|
1200
|
+
};
|
|
1149
1201
|
const timer = setTimeout(() => {
|
|
1150
1202
|
this.pending.delete(id);
|
|
1203
|
+
detach();
|
|
1151
1204
|
reject(
|
|
1152
1205
|
new Error(`MCP "${this.opts.name}" request "${method}" timed out after ${timeoutMs}ms`)
|
|
1153
1206
|
);
|
|
@@ -1155,10 +1208,12 @@ var MCPClient = class {
|
|
|
1155
1208
|
this.pending.set(id, {
|
|
1156
1209
|
resolve: (res) => {
|
|
1157
1210
|
clearTimeout(timer);
|
|
1211
|
+
detach();
|
|
1158
1212
|
resolve(res);
|
|
1159
1213
|
},
|
|
1160
1214
|
reject: (err) => {
|
|
1161
1215
|
clearTimeout(timer);
|
|
1216
|
+
detach();
|
|
1162
1217
|
reject(err);
|
|
1163
1218
|
},
|
|
1164
1219
|
timer
|
|
@@ -1168,6 +1223,7 @@ var MCPClient = class {
|
|
|
1168
1223
|
const pending = this.pending.get(id);
|
|
1169
1224
|
this.pending.delete(id);
|
|
1170
1225
|
if (pending) clearTimeout(pending.timer);
|
|
1226
|
+
detach();
|
|
1171
1227
|
reject(new Error(`MCP "${this.opts.name}" request "${method}": stdin not writable`));
|
|
1172
1228
|
return;
|
|
1173
1229
|
}
|
|
@@ -1177,6 +1233,7 @@ var MCPClient = class {
|
|
|
1177
1233
|
const pending = this.pending.get(id);
|
|
1178
1234
|
this.pending.delete(id);
|
|
1179
1235
|
if (pending) clearTimeout(pending.timer);
|
|
1236
|
+
detach();
|
|
1180
1237
|
reject(err);
|
|
1181
1238
|
}
|
|
1182
1239
|
});
|
|
@@ -1333,9 +1390,9 @@ function wrapMCPTool(serverName, mcpTool, client, permission = "confirm") {
|
|
|
1333
1390
|
mutating: isMutatingTool(mcpTool),
|
|
1334
1391
|
capabilities: [ToolCapabilities.MCP_PROXY],
|
|
1335
1392
|
inputSchema: mcpTool.inputSchema ?? { type: "object", properties: {} },
|
|
1336
|
-
async execute(input, _ctx,
|
|
1393
|
+
async execute(input, _ctx, opts) {
|
|
1337
1394
|
const live = typeof client === "function" ? await client() : client;
|
|
1338
|
-
const res = await live.callTool(mcpTool.name, input);
|
|
1395
|
+
const res = await live.callTool(mcpTool.name, input, { signal: opts.signal });
|
|
1339
1396
|
if (res.isError) {
|
|
1340
1397
|
throw new Error(stringify(res.content));
|
|
1341
1398
|
}
|