@kolbo/mcp 1.64.0 → 1.65.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.64.0",
3
+ "version": "1.65.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": {
package/skill/SKILL.md CHANGED
@@ -99,7 +99,7 @@ Each `references/models/*.md` mirrors the matching skill prompt in `kolbo-api/sr
99
99
  | `generate_video` | Text-to-video. Does **not** support Visual DNA — use `generate_elements` for character-consistent video. |
100
100
  | `generate_video_from_image` | Animate a still. Prompt describes motion, not subject. |
101
101
  | `generate_video_from_video` | Restyle/transform an existing video. Keeps original motion. |
102
- | `generate_elements` | Reference-driven video. **Primary route for DNA → video.** |
102
+ | `generate_elements` | Reference-driven video. **Primary route for DNA → video.** Supports `multi_shots` / `multi_shot_count` (badge/metadata/native flag only — never rewrites the prompt) and short `session_name`. Crafted demos: `enhance_prompt:false` + put shot structure in the prompt. |
103
103
  | `generate_first_last_frame` | Keyframe interpolation between two frames. |
104
104
  | `generate_lipsync` | Lipsync audio to an image or video face. |
105
105
  | `generate_music` | Music generation (Suno + variants). |
@@ -9,6 +9,8 @@ Load this file when the user wants a **Seedance 2 / Seedance 2.0** (ByteDance) v
9
9
 
10
10
  **Kolbo MCP routing:** Seedance is a video model — call `generate_video` (text-to-video) or `generate_elements` (when video references / Visual DNA / first-last frames are involved). Run `list_models({ type: "text_to_video" })` and pick a Seedance variant by name.
11
11
 
12
+ **Multishot (Elements):** Seedance has **no** native provider Multishot switch. Pass `multi_shots: true` on `generate_elements` (optional `multi_shot_count`) for the UI Multishot badge only — it does **not** rewrite or reshape your prompt. **Always send `enhance_prompt: false` for crafted demos** (MCP default) so the prompt stays RAW. Put shot structure in the prompt yourself (`Multishot ON`, `Total: … / N shots`, numbered shots). Optional `session_name` sets a short sidebar title (skips AI auto-name from boilerplate).
13
+
12
14
  ## Universal Rules (apply to EVERY Seedance prompt)
13
15
 
14
16
  - **First line ALWAYS declares shot structure**: total duration, shot count, aspect ratio. Example: `Total: 15s / 6 shots / 16:9`. Put it at the BOTTOM of the prompt too. For connected narrative sequences the proven phrasing is `N connected cinematic shots, 15 seconds total, 16:9, Multishot ON` — use it and keep `Multishot ON` for any multi-shot story.
@@ -123,7 +123,7 @@ If the user gives a **product URL** instead of a photo, see `workflows/research-
123
123
 
124
124
  ## Multi-Slot Board Method (structured shot specs + character consistency)
125
125
 
126
- For any multi-shot UGC / review / how-to where the SAME presenter must stay identical across shots, compose the prompt as explicit **slots** and lock identity with a **board-first** pass. This is a prompt-only convention no special MCP mode; it uses `generate_image` (board) + `generate_elements` / `generate_video_from_image` (per-slot animate) that already exist.
126
+ For any multi-shot UGC / review / how-to where the SAME presenter must stay identical across shots, compose the prompt as explicit **slots** and lock identity with a **board-first** pass. Prefer `generate_elements` with `multi_shots: true` (and a short `session_name`) when animating a single multi-cut Seedance spot; board-first still uses `generate_image` + `generate_elements` / `generate_video_from_image` per slot when you need separate clips.
127
127
 
128
128
  ### 1. Structured input slots
129
129
 
@@ -987,10 +987,13 @@ function registerGenerateTools(server, client, options = {}) {
987
987
  image_url: z.string().describe('Public URL of the keyframe image'),
988
988
  timestamp_seconds: z.number().describe('Moment on the OUTPUT timeline (seconds, 0 = first frame) where this image is pinned')
989
989
  })).optional().describe('Timeline-pinned keyframes for multi-keyframe models (e.g. "flux-3-keyframes", "luma-ray-3-2-storyboard"): the model generates the motion BETWEEN the pinned images. Only models with `supports_keyframes: true` in list_models accept this; cap = `max_keyframes` (FLUX 3: 10). Requires an explicit `duration` — timestamps beyond it are clamped. Ignored by ordinary elements models. OPTIONAL for flux-3-keyframes: if omitted, pass the images via reference_images instead — they are played through IN ORDER, timed from timing language in the prompt or spaced evenly. Pass explicit keyframes only when you need exact control.'),
990
+ multi_shots: z.boolean().optional().describe('Enable Multishot metadata/UI badge (and native provider flag when the model supportsMultiShot). Never rewrites or reshapes the prompt — craft shot structure yourself (`Multishot ON`, Total/SHOT lines). MCP default enhance_prompt=false keeps the prompt raw; multi_shots alone is badge/flag only. For crafted demos: enhance_prompt:false + multi_shots:true.'),
991
+ multi_shot_count: z.number().optional().describe('Explicit shot count when multi_shots=true (e.g. 2). Clamped to ~2 shots/sec of duration.'),
992
+ session_name: z.string().optional().describe('Short sidebar session title (max ~60 chars), e.g. "UGC — Hana bathroom light". When set, skips AI auto-naming from the prompt boilerplate.'),
990
993
  project_id: projectIdField,
991
994
  session_id: sessionIdField
992
995
  },
993
- async ({ prompt, model, reference_images, reference_videos, reference_audio_urls, audio_url, files, duration, aspect_ratio, motion, preset_id, enhance_prompt = false, visual_dna_ids, resolution, keyframes, project_id, session_id }) => {
996
+ async ({ prompt, model, reference_images, reference_videos, reference_audio_urls, audio_url, files, duration, aspect_ratio, motion, preset_id, enhance_prompt = false, visual_dna_ids, resolution, keyframes, multi_shots, multi_shot_count, session_name, project_id, session_id }) => {
994
997
  model = await canonicalModelId(client, model, 'elements'); // lenient id resolution ("z-image" → "z-image/turbo")
995
998
  if (!prompt) throw new Error('prompt is required');
996
999
 
@@ -1013,6 +1016,9 @@ function registerGenerateTools(server, client, options = {}) {
1013
1016
  if (audio_url) form.append('audio_url', audio_url);
1014
1017
  if (resolution) form.append('resolution', resolution);
1015
1018
  if (keyframes) form.append('keyframes', JSON.stringify(keyframes));
1019
+ if (multi_shots !== undefined) form.append('multi_shots', String(multi_shots));
1020
+ if (multi_shot_count !== undefined) form.append('multi_shot_count', String(multi_shot_count));
1021
+ if (session_name) form.append('session_name', session_name);
1016
1022
  if (project_id) form.append('project_id', project_id);
1017
1023
  if (session_id) form.append('session_id', session_id);
1018
1024
  for (const f of resolved) {
@@ -1022,7 +1028,7 @@ function registerGenerateTools(server, client, options = {}) {
1022
1028
  } else {
1023
1029
  // URL-only mode: plain JSON.
1024
1030
  startResponse = await client.post('/v1/generate/elements', {
1025
- prompt, model, reference_images, reference_videos, reference_audio_urls, audio_url, duration, aspect_ratio, motion, preset_id, enhance_prompt, visual_dna_ids, resolution, keyframes, project_id, session_id
1031
+ prompt, model, reference_images, reference_videos, reference_audio_urls, audio_url, duration, aspect_ratio, motion, preset_id, enhance_prompt, visual_dna_ids, resolution, keyframes, multi_shots, multi_shot_count, session_name, project_id, session_id
1026
1032
  });
1027
1033
  }
1028
1034
 
@@ -197,7 +197,7 @@ function registerVisualDnaTools(server, client, options = {}) {
197
197
  'Generate a reference sheet for a Visual DNA from 1+ reference image URLs — the same step the in-app Visual DNA wizard offers, for EVERY DNA type via `sheet_type`: character = multi-angle turnaround, product = angles + branding/material/construction close-ups, environment = location angles + one signature detail, style = a style board (the same look applied to six varied subjects). The sheet is the single strongest consistency booster for a DNA, and it always preserves the reference\'s original art style (2D stays 2D, photo stays photo). CHARGES CREDITS, so when the user is about to create a DNA, OFFER this first ("want me to generate a reference sheet for stronger consistency? it costs a few credits") and only run it on a yes. Returns `character_sheet_url` — pass it as `character_sheet_url` to `create_visual_dna` with the matching `dna_type`.',
198
198
  {
199
199
  image_urls: z.array(z.string()).min(1).describe('Reference image URLs of the subject (for characters: front/side/varied angles work best). Use generated-image URLs or upload_media output.'),
200
- sheet_type: z.enum(['character', 'product', 'environment', 'style']).optional().describe('Which sheet layout to generate match the DNA type it will be attached to. Defaults to character.')
200
+ sheet_type: z.enum(['character', 'character_headless', 'product', 'environment', 'style']).optional().describe('Sheet layout. character = front/back/face turnaround. character_headless = wardrobe/body refs with a headless front panel (use when clothing must change without fighting the face sheet). product / environment / style = matching DNA types. Defaults to character.')
201
201
  },
202
202
  async ({ image_urls, sheet_type }) => {
203
203
  const result = await client.post('/v1/visual-dna/character-sheet', { image_urls, ...(sheet_type ? { sheet_type } : {}) });