@zswarm/pi 0.1.3 → 0.1.5

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.
@@ -73,8 +73,8 @@ function defaultServers(): Record<string, ServerSpec> {
73
73
 
74
74
  /** How long to wait for a server to answer initialize/tools-list before giving up. */
75
75
  const HANDSHAKE_MS = 20_000;
76
- /** Tool calls can legitimately block — `wait` holds until a pane goes idle. */
77
- const CALL_MS = 15 * 60_000;
76
+ /** Core wait max is 15 minutes; slack covers framing so the client does not give up first. */
77
+ const CALL_MS = 16 * 60_000;
78
78
 
79
79
  function readServers(): Record<string, ServerSpec> {
80
80
  const raw = process.env.ZSWARM_MCP_SERVERS?.trim();
@@ -189,20 +189,38 @@ class McpClient {
189
189
  method: string,
190
190
  params: unknown,
191
191
  timeoutMs: number,
192
+ signal?: AbortSignal,
192
193
  ): Promise<unknown> {
193
194
  const id = this.nextId++;
194
195
  return new Promise<unknown>((resolve, reject) => {
196
+ if (signal?.aborted) {
197
+ reject(new Error("Cancelled"));
198
+ return;
199
+ }
200
+ const onAbort = () => {
201
+ this.notify("notifications/cancelled", {
202
+ requestId: id,
203
+ reason: "Cancelled",
204
+ });
205
+ this.pending.delete(id);
206
+ clearTimeout(timer);
207
+ reject(new Error("Cancelled"));
208
+ };
195
209
  const timer = setTimeout(() => {
196
210
  this.pending.delete(id);
211
+ signal?.removeEventListener("abort", onAbort);
197
212
  reject(new Error(`${this.name} ${method} timed out`));
198
213
  }, timeoutMs);
214
+ signal?.addEventListener("abort", onAbort, { once: true });
199
215
  this.pending.set(id, {
200
216
  resolve: (value) => {
201
217
  clearTimeout(timer);
218
+ signal?.removeEventListener("abort", onAbort);
202
219
  resolve(value);
203
220
  },
204
221
  reject: (error) => {
205
222
  clearTimeout(timer);
223
+ signal?.removeEventListener("abort", onAbort);
206
224
  reject(error);
207
225
  },
208
226
  });
@@ -210,11 +228,16 @@ class McpClient {
210
228
  });
211
229
  }
212
230
 
213
- async call(tool: string, args: Record<string, unknown>): Promise<string> {
231
+ async call(
232
+ tool: string,
233
+ args: Record<string, unknown>,
234
+ signal?: AbortSignal,
235
+ ): Promise<string> {
214
236
  const result = (await this.request(
215
237
  "tools/call",
216
238
  { name: tool, arguments: args },
217
239
  CALL_MS,
240
+ signal,
218
241
  )) as { content?: Array<{ type?: string; text?: string }> };
219
242
  const text = (result.content ?? [])
220
243
  .filter((part) => part.type === "text" && typeof part.text === "string")
@@ -280,16 +303,21 @@ export default function (pi: ExtensionAPI) {
280
303
  properties: {},
281
304
  }) as never,
282
305
  async execute(_toolCallId, params, signal) {
283
- if (signal?.aborted) {
284
- return { content: [{ type: "text", text: "Cancelled" }], details: {} };
285
- }
306
+ const cancelled = () => ({
307
+ content: [{ type: "text" as const, text: "Cancelled" }],
308
+ details: {},
309
+ });
310
+ if (signal?.aborted) return cancelled();
286
311
  try {
287
312
  const text = await client.call(
288
313
  tool.name,
289
314
  (params ?? {}) as Record<string, unknown>,
315
+ signal,
290
316
  );
317
+ if (signal?.aborted) return cancelled();
291
318
  return { content: [{ type: "text", text }], details: {} };
292
319
  } catch (err) {
320
+ if (signal?.aborted) return cancelled();
293
321
  const message = err instanceof Error ? err.message : String(err);
294
322
  return {
295
323
  content: [{ type: "text", text: `MCP ${name} error: ${message}` }],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zswarm/pi",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "description": "Bridge stdio MCP servers into pi as native tools",
6
6
  "keywords": [
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@zswarm/mcp": "0.1.3"
37
+ "@zswarm/mcp": "0.1.5"
38
38
  },
39
39
  "scripts": {}
40
40
  }