@kolbo/mcp 1.79.2 → 1.79.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolbo/mcp",
3
- "version": "1.79.2",
3
+ "version": "1.79.3",
4
4
  "description": "Kolbo AI MCP Server - Generate images, videos, music, speech, and sound effects from Claude Code",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/progress.js CHANGED
@@ -77,6 +77,19 @@ function trackGeneration(id, cancel) {
77
77
  if (extra.signal.aborted) cancelTracked();
78
78
  }
79
79
 
80
+ /**
81
+ * Remove a generation from the tracked set so it will NOT be cancelled when
82
+ * the MCP host aborts the tool call. Use this when the CLIENT-SIDE poll
83
+ * window times out but the generation should keep running server-side — the
84
+ * tool returns early with generation_id + _timed_out:true, and the caller
85
+ * re-issues get_generation_status to collect the result later.
86
+ */
87
+ function untrackGeneration(id) {
88
+ const extra = storage.getStore();
89
+ if (!extra?.__kolboTrackedGenerations || !id) return;
90
+ extra.__kolboTrackedGenerations.delete(String(id));
91
+ }
92
+
80
93
  async function generation(id) {
81
94
  const extra = storage.getStore();
82
95
  const token = extra?._meta?.progressToken;
@@ -123,4 +136,4 @@ async function sendGenerationProgress(extra, token, id) {
123
136
  });
124
137
  }
125
138
 
126
- module.exports = { run, generation, tick, signal, wait, trackGeneration };
139
+ module.exports = { run, generation, tick, signal, wait, trackGeneration, untrackGeneration };
@@ -290,7 +290,13 @@ async function resolveToBuffer(source, kind, opts = {}) {
290
290
  // it instead of duplicating the try/catch. Genuine failures (state
291
291
  // failed/cancelled → GenerationFailedError) are NOT caught here; they still
292
292
  // throw and surface as a real tool error.
293
+ //
294
+ // CRITICAL: when the poll window times out, we UNTRACK the generation so that
295
+ // when the MCP host eventually aborts the tool call (e.g., at ~180s), it does
296
+ // NOT cancel the server-side generation. The generation keeps running, and the
297
+ // caller can collect it later with get_generation_status.
293
298
  const { pollUntilDone } = require('../polling');
299
+ const progress = require('../progress');
294
300
 
295
301
  /**
296
302
  * @returns {Promise<{result: object}|{timedOut: object}>}
@@ -301,6 +307,8 @@ async function pollOrTimedOut(client, generationId, pollOpts) {
301
307
  return { result: await pollUntilDone(client, generationId, pollOpts) };
302
308
  } catch (err) {
303
309
  if (!err || !err.timedOut) throw err;
310
+ // Untrack so the MCP host aborting this tool call does NOT cancel the generation.
311
+ progress.untrackGeneration(generationId);
304
312
  return {
305
313
  timedOut: {
306
314
  content: [{
package/src/tools/chat.js CHANGED
@@ -43,9 +43,9 @@ function registerChatTools(server, client) {
43
43
  project_id
44
44
  });
45
45
 
46
- // Deep think reasoning can run far longer than normal chat. Also grant
47
- // extra time when web_search is on (may fetch + analyze multiple pages).
48
- const timeout = deep_think ? 600000 : (web_search ? 240000 : 120000);
46
+ // Return before host cutoff (150s) even for deep think / web search.
47
+ // The LLM can call this tool again with the same session_id to continue.
48
+ const timeout = 150000;
49
49
 
50
50
  const poll = await pollOrTimedOut(client, gen.message_id, {
51
51
  interval: (gen.poll_interval_hint || 2) * 1000,
@@ -245,7 +245,7 @@ function registerGenerateTools(server, client, options = {}) {
245
245
  status_args: { generation_ids: batch.ids, wait: true },
246
246
  reference_images
247
247
  });
248
- return pollBatch(client, batch, { interval: (batch.ok[0].gen.poll_interval_hint || 3) * 1000, timeout: 240000 }, 'generate_image');
248
+ return pollBatch(client, batch, { interval: (batch.ok[0].gen.poll_interval_hint || 3) * 1000, timeout: 150000 }, 'generate_image');
249
249
  }
250
250
 
251
251
  const gen = await client.post('/v1/generate/image', { ...shared, prompt, num_images });
@@ -258,7 +258,7 @@ function registerGenerateTools(server, client, options = {}) {
258
258
 
259
259
  const poll = await pollOrTimedOut(client, gen.generation_id, {
260
260
  interval: (gen.poll_interval_hint || 3) * 1000,
261
- timeout: 120000
261
+ timeout: 150000
262
262
  });
263
263
  if (poll.timedOut) return poll.timedOut;
264
264
  const result = poll.result;
@@ -328,7 +328,7 @@ function registerGenerateTools(server, client, options = {}) {
328
328
  status_args: { generation_ids: batch.ids, wait: true },
329
329
  reference_images: source_images
330
330
  });
331
- return pollBatch(client, batch, { interval: (batch.ok[0].gen.poll_interval_hint || 3) * 1000, timeout: 240000 }, 'generate_image_edit');
331
+ return pollBatch(client, batch, { interval: (batch.ok[0].gen.poll_interval_hint || 3) * 1000, timeout: 150000 }, 'generate_image_edit');
332
332
  }
333
333
 
334
334
  const gen = await client.post('/v1/generate/image-edit', { ...shared, prompt, num_images });
@@ -341,12 +341,12 @@ function registerGenerateTools(server, client, options = {}) {
341
341
  });
342
342
 
343
343
  // Multi-source compositing or DNA-anchored edits routinely exceed 120s
344
- // server-side. Extend the polling window in those cases to avoid forcing
345
- // every call into the timeout-and-recover path via get_generation_status.
346
- const heavy = (source_images && source_images.length > 1) || (visual_dna_ids && visual_dna_ids.length > 0);
344
+ // server-side. But we still need to return before the 180s host cutoff,
345
+ // so use 150s for all cases. The LLM can call get_generation_status
346
+ // with wait=true to continue polling.
347
347
  const poll = await pollOrTimedOut(client, gen.generation_id, {
348
348
  interval: (gen.poll_interval_hint || 3) * 1000,
349
- timeout: heavy ? 240000 : 120000
349
+ timeout: 150000
350
350
  });
351
351
  if (poll.timedOut) return poll.timedOut;
352
352
  const result = poll.result;
@@ -576,7 +576,7 @@ function registerGenerateTools(server, client, options = {}) {
576
576
  status_args: { generation_ids: batch.ids, wait: true },
577
577
  reference_images
578
578
  });
579
- return pollBatch(client, batch, { interval: (batch.ok[0].gen.poll_interval_hint || 8) * 1000, timeout: 900000 }, 'generate_video');
579
+ return pollBatch(client, batch, { interval: (batch.ok[0].gen.poll_interval_hint || 8) * 1000, timeout: 150000 }, 'generate_video');
580
580
  }
581
581
 
582
582
  const gen = await client.post('/v1/generate/video', { ...shared, prompt });
@@ -592,7 +592,7 @@ function registerGenerateTools(server, client, options = {}) {
592
592
  // 5-min window forced routine calls into the timeout-and-recover path.
593
593
  const poll = await pollOrTimedOut(client, gen.generation_id, {
594
594
  interval: (gen.poll_interval_hint || 8) * 1000,
595
- timeout: 900000
595
+ timeout: 150000
596
596
  });
597
597
  if (poll.timedOut) return poll.timedOut;
598
598
  const result = poll.result;
@@ -678,7 +678,7 @@ function registerGenerateTools(server, client, options = {}) {
678
678
  // Veo 3.1, Hailuo 2.3, Seedance 2 at higher durations/resolutions).
679
679
  const poll = await pollOrTimedOut(client, gen.generation_id, {
680
680
  interval: (gen.poll_interval_hint || 8) * 1000,
681
- timeout: 900000
681
+ timeout: 150000
682
682
  });
683
683
  if (poll.timedOut) return poll.timedOut;
684
684
  const result = poll.result;
@@ -746,7 +746,7 @@ function registerGenerateTools(server, client, options = {}) {
746
746
 
747
747
  const poll = await pollOrTimedOut(client, gen.generation_id, {
748
748
  interval: (gen.poll_interval_hint || 8) * 1000,
749
- timeout: 300000
749
+ timeout: 150000
750
750
  });
751
751
  if (poll.timedOut) return poll.timedOut;
752
752
  const result = poll.result;
@@ -1334,7 +1334,7 @@ function registerGenerateTools(server, client, options = {}) {
1334
1334
 
1335
1335
  const poll = await pollOrTimedOut(client, startResponse.generation_id, {
1336
1336
  interval: (startResponse.poll_interval_hint || 8) * 1000,
1337
- timeout: 600000
1337
+ timeout: 150000
1338
1338
  });
1339
1339
  if (poll.timedOut) return poll.timedOut;
1340
1340
  const result = poll.result;
@@ -1435,7 +1435,7 @@ function registerGenerateTools(server, client, options = {}) {
1435
1435
 
1436
1436
  const poll = await pollOrTimedOut(client, startResponse.generation_id, {
1437
1437
  interval: (startResponse.poll_interval_hint || 8) * 1000,
1438
- timeout: 300000
1438
+ timeout: 150000
1439
1439
  });
1440
1440
  if (poll.timedOut) return poll.timedOut;
1441
1441
  const result = poll.result;
@@ -1553,7 +1553,7 @@ function registerGenerateTools(server, client, options = {}) {
1553
1553
 
1554
1554
  const poll = await pollOrTimedOut(client, startResponse.generation_id, {
1555
1555
  interval: (startResponse.poll_interval_hint || 8) * 1000,
1556
- timeout: 600000
1556
+ timeout: 150000
1557
1557
  });
1558
1558
  if (poll.timedOut) return poll.timedOut;
1559
1559
  const result = poll.result;
@@ -1684,7 +1684,7 @@ function registerGenerateTools(server, client, options = {}) {
1684
1684
 
1685
1685
  const poll = await pollOrTimedOut(client, startResponse.generation_id, {
1686
1686
  interval: (startResponse.poll_interval_hint || 8) * 1000,
1687
- timeout: 600000
1687
+ timeout: 150000
1688
1688
  });
1689
1689
  if (poll.timedOut) return poll.timedOut;
1690
1690
  const result = poll.result;
@@ -1770,7 +1770,7 @@ function registerGenerateTools(server, client, options = {}) {
1770
1770
 
1771
1771
  const poll = await pollOrTimedOut(client, startResponse.generation_id, {
1772
1772
  interval: (startResponse.poll_interval_hint || 5) * 1000,
1773
- timeout: 1800000 // 30 minutes long podcasts are a thing
1773
+ timeout: 150000 // Return before host cutoff; LLM can call get_generation_status with wait=true for long podcasts
1774
1774
  });
1775
1775
  if (poll.timedOut) return poll.timedOut;
1776
1776
  const result = poll.result;
@@ -1835,7 +1835,7 @@ function registerGenerateTools(server, client, options = {}) {
1835
1835
 
1836
1836
  const poll = await pollOrTimedOut(client, startResponse.generation_id, {
1837
1837
  interval: (startResponse.poll_interval_hint || 8) * 1000,
1838
- timeout: 900000 // 15 minutes 3D generation is slow
1838
+ timeout: 150000 // Return before host cutoff; LLM can call get_generation_status with wait=true for slow 3D jobs
1839
1839
  });
1840
1840
  if (poll.timedOut) return poll.timedOut;
1841
1841
  const result = poll.result;
@@ -1996,7 +1996,7 @@ function registerGenerateTools(server, client, options = {}) {
1996
1996
 
1997
1997
  const poll = await pollOrTimedOut(client, gen.generation_id, {
1998
1998
  interval: (gen.poll_interval_hint || 5) * 1000,
1999
- timeout: 300000 // 5 min split_upscale and multi_shot can take longer
1999
+ timeout: 150000 // Return before host cutoff; LLM can call get_generation_status with wait=true for split_upscale and multi_shot
2000
2000
  });
2001
2001
  if (poll.timedOut) return poll.timedOut;
2002
2002
  const result = poll.result;
@@ -2165,7 +2165,7 @@ function registerGenerateTools(server, client, options = {}) {
2165
2165
 
2166
2166
  const poll = await pollOrTimedOut(client, gen.generation_id, {
2167
2167
  interval: (gen.poll_interval_hint || 8) * 1000,
2168
- timeout: 600000
2168
+ timeout: 150000
2169
2169
  });
2170
2170
  if (poll.timedOut) return poll.timedOut;
2171
2171
  const result = poll.result;