@kolbo/mcp 1.84.0 → 1.84.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolbo/mcp",
3
- "version": "1.84.0",
3
+ "version": "1.84.1",
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": {
@@ -28,6 +28,7 @@ function registerVisualDnaTools(server, client, options = {}) {
28
28
  name: z.string().describe('Name of the Visual DNA profile. **Pick a short, lowercase, no-space single token** (e.g. `maya`, `tokyo_neon`, `brand_red`, `esther_model`) — never names with spaces (`Sarah Johnson` ❌). The user/LLM types this as `@<name>` inside generation prompts, and the @ parser stops at the first space, so `@Sarah Johnson` matches only `Sarah` and the binding silently drops. Multi-word concepts should use underscores or be a single token. Names are case-insensitive on lookup, but **reserved** values rejected on creation: `Image1`, `Image2`, …, `Video1`, …, `Audio1`, … (any-language characters allowed; max 100 chars).'),
29
29
  dna_type: z.string().optional().describe('Type: "character", "style", "product", "scene", "environment". Default: "character"'),
30
30
  prompt_helper: z.string().optional().describe('Optional description/notes to guide DNA extraction'),
31
+ description: z.string().optional().describe('Alias for `prompt_helper`. Accepted because every tool here REPORTS this field as `description`, so callers round-trip that name back in; without the alias zod stripped it and the notes were silently lost. Ignored when `prompt_helper` is also given.'),
31
32
  images: z.array(z.string()).optional().describe('Array of image sources (URLs or absolute local paths). Max 4. All of them can reach the model on later gens — same subject, same vibe only; no extra heroes on character DNAs, no main characters on environment DNAs.'),
32
33
  video: z.string().optional().describe('Optional video source (URL or absolute local path)'),
33
34
  audio: z.string().optional().describe('Optional audio source (URL or absolute local path) — the character\'s voice, 5-30s of clean speech. Stored on the DNA and used two ways: (1) as REFERENCE AUDIO in video generation — attaching this DNA to an image-to-video generation on a model with audio slots (Seedance 2.x, Wan 3.0) auto-attaches the clip and tells the model it is that character\'s voice; (2) as the source for a real speaking voice, but ONLY when you ask for one — see `voice_source`.'),
@@ -35,7 +36,8 @@ function registerVisualDnaTools(server, client, options = {}) {
35
36
  assigned_voice_id: z.string().optional().describe('Voice to attach when voice_source="assign" — a `custom_<id>` from the user\'s clones or a voice_id from `list_voices`.'),
36
37
  character_sheet_url: z.string().optional().describe('URL of a reference sheet (from `generate_character_sheet`, any sheet_type) to set as the DNA\'s primary reference. Works for ALL DNA types — character turnaround, product detail sheet, location sheet, or style board — and is the single biggest consistency booster. Omit only when the user declines.')
37
38
  },
38
- async ({ name, dna_type, prompt_helper, images, video, audio, voice_source, assigned_voice_id, character_sheet_url }) => {
39
+ async ({ name, dna_type, prompt_helper, description, images, video, audio, voice_source, assigned_voice_id, character_sheet_url }) => {
40
+ const helper = prompt_helper !== undefined ? prompt_helper : description;
39
41
  if (!name || !name.trim()) {
40
42
  throw new Error('name is required');
41
43
  }
@@ -58,7 +60,7 @@ function registerVisualDnaTools(server, client, options = {}) {
58
60
  const form = new FormData();
59
61
  form.append('name', name);
60
62
  if (dna_type) form.append('dnaType', dna_type);
61
- if (prompt_helper) form.append('promptHelper', prompt_helper);
63
+ if (helper) form.append('promptHelper', helper);
62
64
  if (character_sheet_url) form.append('characterSheetUrl', character_sheet_url);
63
65
  // Omitted stays omitted: the server infers 'clone' from a present audio clip, which is the
64
66
  // long-standing behaviour older installs depend on. Only an explicit choice is forwarded.
@@ -193,6 +195,7 @@ function registerVisualDnaTools(server, client, options = {}) {
193
195
  name: z.string().optional().describe('New name. Same no-space single-token rule as create_visual_dna — @Name binding stops at the first space.'),
194
196
  dna_type: z.string().optional().describe('Type: "character", "style", "product", "scene", "environment". Changing type re-analyzes the profile.'),
195
197
  prompt_helper: z.string().optional().describe('New description / intent notes. Replaces the old ones and re-synthesizes the DNA analysis when the text actually changes. Pass "" to clear.'),
198
+ description: z.string().optional().describe('Alias for `prompt_helper`. Accepted because every tool here REPORTS this field as `description`, so callers round-trip that name back in; without the alias zod stripped it and the edit silently did nothing. Ignored when `prompt_helper` is also given.'),
196
199
  images: z.array(z.string()).optional().describe('Full replacement still set (URLs or absolute local paths). Max 4. Omit to keep current stills. Same purity rules as create: one identity, one vibe.'),
197
200
  video: z.string().optional().describe('Replacement video source (URL or absolute local path).'),
198
201
  audio: z.string().optional().describe('Replacement audio source (URL or absolute local path).'),
@@ -208,14 +211,15 @@ function registerVisualDnaTools(server, client, options = {}) {
208
211
  specific_age: z.number().optional().describe('Character attribute (character DNAs).')
209
212
  },
210
213
  async ({
211
- visual_dna_id, name, dna_type, prompt_helper, images, video, audio,
214
+ visual_dna_id, name, dna_type, prompt_helper, description, images, video, audio,
212
215
  character_sheet_url, remove_character_sheet,
213
216
  gender, ethnicity, body_type, hair_color, eye_color, skin_tone, age_range, specific_age
214
217
  }) => {
218
+ const helper = prompt_helper !== undefined ? prompt_helper : description;
215
219
  const imageList = Array.isArray(images) ? images.filter(Boolean) : [];
216
220
  if (imageList.length > 4) throw new Error('Maximum 4 images allowed');
217
221
  const hasMedia = imageList.length > 0 || !!video || !!audio;
218
- const hasMeta = name !== undefined || dna_type !== undefined || prompt_helper !== undefined
222
+ const hasMeta = name !== undefined || dna_type !== undefined || helper !== undefined
219
223
  || character_sheet_url !== undefined || remove_character_sheet !== undefined
220
224
  || gender !== undefined || ethnicity !== undefined || body_type !== undefined
221
225
  || hair_color !== undefined || eye_color !== undefined || skin_tone !== undefined
@@ -240,7 +244,7 @@ function registerVisualDnaTools(server, client, options = {}) {
240
244
  const body = { ...attrs };
241
245
  if (name !== undefined) body.name = name;
242
246
  if (dna_type !== undefined) body.dna_type = dna_type;
243
- if (prompt_helper !== undefined) body.prompt_helper = prompt_helper;
247
+ if (helper !== undefined) body.prompt_helper = helper;
244
248
  if (character_sheet_url !== undefined) body.character_sheet_url = character_sheet_url;
245
249
  if (remove_character_sheet !== undefined) body.remove_character_sheet = remove_character_sheet;
246
250
  const result = await client.put(path, body);
@@ -264,7 +268,7 @@ function registerVisualDnaTools(server, client, options = {}) {
264
268
  const form = new FormData();
265
269
  if (name !== undefined) form.append('name', name);
266
270
  if (dna_type) form.append('dnaType', dna_type);
267
- if (prompt_helper !== undefined) form.append('promptHelper', prompt_helper);
271
+ if (helper !== undefined) form.append('promptHelper', helper);
268
272
  if (character_sheet_url) form.append('characterSheetUrl', character_sheet_url);
269
273
  if (remove_character_sheet !== undefined) {
270
274
  form.append('removeCharacterSheet', remove_character_sheet ? 'true' : 'false');