@kolbo/mcp 1.75.3 → 1.75.4

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.75.3",
3
+ "version": "1.75.4",
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": {
@@ -77,22 +77,35 @@ async function submitBatch(rawItems, submitOne) {
77
77
  }
78
78
 
79
79
  // Blocking path for text-only hosts: wait for every batch member, aggregate.
80
- async function pollBatch(client, batch, { interval, timeout }) {
80
+ // This is the exact path Kolbo Code takes for a `prompts`-array batch call
81
+ // (ui() is false there, so the uiGenerating branch above never runs) — it was
82
+ // text-only, no structuredContent, so a batch of N prompts rendered as a bare
83
+ // JSON dump instead of N cards. Same class of bug as get_generation_status's
84
+ // multi-id branch, same fix: always ship structuredContent via the shared
85
+ // kind:'status' grid, which already renders any mix of completed/processing
86
+ // items correctly.
87
+ async function pollBatch(client, batch, { interval, timeout }, toolName) {
81
88
  const polls = await Promise.all(batch.ids.map((id) => pollOrTimedOut(client, id, { interval, timeout })));
82
89
  const generations = polls.map((p, i) => p.timedOut
83
90
  ? { prompt: batch.ok[i].prompt, generation_id: batch.ids[i], status: 'processing', note: 'Still running — call get_generation_status with wait=true to collect it.' }
84
91
  : { prompt: batch.ok[i].prompt, generation_id: batch.ids[i], status: 'completed', ...creditFields(polls[i].result), urls: p.result.result.urls });
85
- return {
86
- content: [{
87
- type: 'text',
88
- text: JSON.stringify({
89
- batch: true,
90
- session_id: batch.ok[0].gen.session_id,
91
- generations,
92
- failed_submissions: batch.failed.length ? batch.failed : undefined
93
- }, null, 2)
94
- }]
95
- };
92
+ const text = JSON.stringify({
93
+ batch: true,
94
+ session_id: batch.ok[0].gen.session_id,
95
+ generations,
96
+ failed_submissions: batch.failed.length ? batch.failed : undefined
97
+ }, null, 2);
98
+ return uiCompleted({
99
+ tool: toolName, kind: 'status', client,
100
+ model: 'Generations', gen: { generation_id: batch.ids[0], session_id: batch.ok[0].gen.session_id },
101
+ settings: {},
102
+ items: generations.map(g => ({
103
+ id: g.generation_id,
104
+ state: g.status,
105
+ title: g.prompt,
106
+ url: Array.isArray(g.urls) ? g.urls[0] : undefined,
107
+ })),
108
+ }, text);
96
109
  }
97
110
 
98
111
  // ─── Widget settings block ──────────────────────────────────────────────────
@@ -205,7 +218,7 @@ function registerGenerateTools(server, client, options = {}) {
205
218
  status_args: { generation_ids: batch.ids, wait: true },
206
219
  reference_images
207
220
  });
208
- return pollBatch(client, batch, { interval: (batch.ok[0].gen.poll_interval_hint || 3) * 1000, timeout: 240000 });
221
+ return pollBatch(client, batch, { interval: (batch.ok[0].gen.poll_interval_hint || 3) * 1000, timeout: 240000 }, 'generate_image');
209
222
  }
210
223
 
211
224
  const gen = await client.post('/v1/generate/image', { ...shared, prompt, num_images });
@@ -288,7 +301,7 @@ function registerGenerateTools(server, client, options = {}) {
288
301
  status_args: { generation_ids: batch.ids, wait: true },
289
302
  reference_images: source_images
290
303
  });
291
- return pollBatch(client, batch, { interval: (batch.ok[0].gen.poll_interval_hint || 3) * 1000, timeout: 240000 });
304
+ return pollBatch(client, batch, { interval: (batch.ok[0].gen.poll_interval_hint || 3) * 1000, timeout: 240000 }, 'generate_image_edit');
292
305
  }
293
306
 
294
307
  const gen = await client.post('/v1/generate/image-edit', { ...shared, prompt, num_images });
@@ -519,7 +532,7 @@ function registerGenerateTools(server, client, options = {}) {
519
532
  status_args: { generation_ids: batch.ids, wait: true },
520
533
  reference_images
521
534
  });
522
- return pollBatch(client, batch, { interval: (batch.ok[0].gen.poll_interval_hint || 8) * 1000, timeout: 900000 });
535
+ return pollBatch(client, batch, { interval: (batch.ok[0].gen.poll_interval_hint || 8) * 1000, timeout: 900000 }, 'generate_video');
523
536
  }
524
537
 
525
538
  const gen = await client.post('/v1/generate/video', { ...shared, prompt });
@@ -606,7 +619,7 @@ function registerGenerateTools(server, client, options = {}) {
606
619
  status_args: { generation_ids: batch.ids, wait: true },
607
620
  reference_images: items.map((item) => item.image_url)
608
621
  });
609
- return pollBatch(client, batch, { interval: (batch.ok[0].gen.poll_interval_hint || 8) * 1000, timeout: 900000 });
622
+ return pollBatch(client, batch, { interval: (batch.ok[0].gen.poll_interval_hint || 8) * 1000, timeout: 900000 }, 'generate_video_from_image');
610
623
  }
611
624
 
612
625
  const gen = await client.post('/v1/generate/video/from-image', { ...shared, image_url, prompt });
@@ -965,17 +978,38 @@ function registerGenerateTools(server, client, options = {}) {
965
978
  : '';
966
979
  const pendingHint = stillRunningHint(idsPhrase);
967
980
 
968
- // Single-id calls keep the original flat shape — the generation widget
969
- // waits on this tool with { generation_id, wait:true } and reads
970
- // state/result at the top level.
981
+ // Single-id calls keep the original flat TEXT shape — a live uiGenerating
982
+ // widget (ui()==true, still open from the original generate_* call) polls
983
+ // this tool directly from its own iframe JS and reads state/result at the
984
+ // top level, so `text` must stay exactly what it always was.
985
+ //
986
+ // But a single id checked here often has NO live widget behind it at all:
987
+ // Kolbo Code never opens one (ui() is false there), and even on hosts that
988
+ // do, the original call can have returned poll.timedOut before uiGenerating
989
+ // ever ran (see pollOrTimedOut) — a parallel batch is exactly when that
990
+ // happens, since every concurrent generation competes for the same
991
+ // per-call poll window. Either way this is then a FRESH, standalone tool
992
+ // response that needs its own renderable card, same reasoning as the
993
+ // multi-id fix just above. Reuse the same kind:'status' single-item grid
994
+ // rather than inventing per-media-type rendering here.
971
995
  if (!generation_ids || generation_ids.length === 0) {
972
996
  const single = results[0];
973
997
  single._hint = pending.length === 0
974
998
  ? 'This generation is in a FINAL state — do not poll it again.'
975
999
  : pendingHint;
976
- return {
977
- content: [{ type: 'text', text: JSON.stringify(single, null, 2) }]
978
- };
1000
+ const singleText = JSON.stringify(single, null, 2);
1001
+ const res = single.result || {};
1002
+ return uiCompleted({
1003
+ tool: 'get_generation_status', kind: 'status', client,
1004
+ model: 'Generations', gen: { generation_id: single.generation_id },
1005
+ settings: {},
1006
+ items: [{
1007
+ id: single.generation_id,
1008
+ state: single.state,
1009
+ title: res.prompt_used || res.prompt || undefined,
1010
+ url: Array.isArray(res.urls) ? res.urls[0] : undefined,
1011
+ }],
1012
+ }, singleText);
979
1013
  }
980
1014
 
981
1015
  const text = JSON.stringify({