@starreel/mcp 0.1.137 → 0.1.138

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/SKILL.md CHANGED
@@ -85,6 +85,7 @@ announces a condensed version as MCP `instructions` at connect time.
85
85
  | Their own portraits / scene / prop / shot images | `upload_image` · `set_character_portrait` · `upload_scene_image` · `upload_prop_sheet` · `upload_shot_frame` — **check the image before uploading** (see *Customer-supplied images* below); after a portrait swap, `generate_character_sheet` for that character (the old sheet is invalidated and **not** regenerated automatically) | rendering a "fix" elsewhere and uploading it — use `generate_shot_frame`; uploading a group photo, a captioned/watermarked image, or a multi-view sheet as a portrait; uploading a scene photo with people in it |
86
86
  | Their own **footage** for a shot (screen recording, product b-roll, an existing clip) | `upload_shot_footage` → that shot is no longer AI-generated (frames/video skipped, final cut uses the clip as-is, duration written back from the clip); **it overwrites whatever AI video that shot already had**, and afterwards every AI video call on it (including `edit_video_shot`) is refused with **409** until you `clear_shot_footage` or pass `replace_user_footage: true` | pasting an externally AI-generated clip to "fix" a shot — it carries none of this film's identity / style anchors; use `regenerate_shot_video` instead |
87
87
  | A clip that should **drive the motion** of an AI shot (a blocking/previz pass, a dance or action reference) | `edit_video_shot` with `reference_video_urls` — the shot keeps its AI video and borrows the clip's movement. To make the clip itself the source and restyle it in place, `upload_shot_footage` it first, then `edit_video_shot` with `replace_user_footage: true` | `upload_shot_footage` alone — that registers the clip as the finished shot, so nothing gets restyled and every later AI call on it returns 409 |
88
+ | A clip whose **motion should be kept while the people / outfits are redrawn** (video repaint) — their own footage or a shot already generated here | `get_repaint_capabilities` (is it enabled for this drama; `relayMaxSegments`) → for their own clip, `upload_shot_footage` it onto a shot first → `quote_repaint_shot_video` → `repaint_shot_video` (prompt + reference image; with no `reference_image_url` the shot's character portrait is used — without any reference the person is redrawn too) **or** `quote_reskin_shot_video` → `reskin_shot_video` (`first_frame_url` = an already-reskinned first frame that matches the original first frame's composition, pose and props exactly) → `get_repaint_status` with the returned id until `completed` → `restore_repaint_original` to switch back (free). Motion, lip timing and camera move follow the source and its audio is carried over. ≤5 s is one charge (billed as 5 s); with long-shot relay enabled, 5–~14 s is split into ≤3 relayed segments, one charge each, and the quote is the total and the charge cap. A quote is tied to the shot's current video — if that video changes, generating returns 409; re-quote (free) | `edit_video_shot` to swap the whole cast or wardrobe (it edits by instruction); clips longer than ~14 s (`split_shot` first) |
88
89
  | A scene plate that came out wrong (backdrop, era, light, layout) | `get_scene_prompt` → `update_scene` (`image_prompt`) → `quote_regenerate_scene_image` (tell the customer the points — it includes the lighting reference the platform auto-derives after a plate change when no wide-shot frame exists) → `regenerate_scene_image` with that `quote_id` (after `upload_scene_image` the platform does **not** auto-create the lighting reference — if the reply says `lighting_ref.needed`, quote it with `quote_scene_lighting_ref` and, once the customer agrees, `generate_scene_lighting_ref`); already-rendered shot frames still anchor on the old plate, so regenerate those shots too | re-running `generate_scene_images` (it only fills scenes that have **no** plate — it will not touch this one) |
89
90
  | A voice sample / a required voice | `clone_voice` → `speak_with_voice` → `set_character_voice` / `assign_voices` | cloning without the rights-holder's consent |
90
91
  | No sample, but a character already speaks in a rendered shot | `set_voice_anchor_from_shot` (free; native-audio dramas: locks the voice for later videos) → regenerate `stale_shots` | picking the voice after the whole episode is rendered |
@@ -1191,7 +1192,7 @@ to close") tells the vendor to fit that entire sequence into each 3-second shot.
1191
1192
  and all subtitle/dialogue/SFX offsets are relative to **each shot's own trimmed
1192
1193
  start**, not to the final timeline — add whatever overlapping transitions you like
1193
1194
  and let `compile_timeline.py` expand them, never hand-compute the shift.
1194
- - **Edit**: `edit_video_shot`, `regenerate_shot_video`, `split_shot`,
1195
+ - **Edit**: `edit_video_shot`, `repaint_shot_video` / `reskin_shot_video` (keep the motion, redraw people / outfits), `regenerate_shot_video`, `split_shot`,
1195
1196
  `trim_shot`, `rerender_episode`. One generation per shot at a time: a **409 with
1196
1197
  `in_flight_generation_id`** means that shot is still generating from *different*
1197
1198
  input (another prompt, an edit, a prompt or shot you changed since, a first/last frame
@@ -164,11 +164,25 @@ export const ENTRY_POINTS = [
164
164
  'recommend_trim_window',
165
165
  'regenerate_shot_video',
166
166
  'edit_video_shot(就地编辑;get_edit_capabilities 先看当前引擎支持什么)',
167
+ 'repaint_shot_video / reskin_shot_video(保留原片动作、整体换人换装;get_repaint_capabilities 先看本剧开没开)',
167
168
  'rerender_episode(改完后免费重拼)',
168
169
  ],
169
170
  note: '改了台词而视频已存在 → 视频仍念旧词,必须 `regenerate_shot_video`,重拼救不了。',
170
171
  flow: 'scan_dialogue_coverage / scan_intra_shot_cuts 先定病因 → update_shot / replace_shot_dialogue / repair_episode_dialogue / split_shot / trim_shot / regenerate_shot_video / edit_video_shot → rerender_episode',
171
172
  },
173
+ {
174
+ customer_has: '一段现成视频(自有素材或已出的镜头),想保留动作、把人物 / 服装整体换掉(视频转绘)',
175
+ use: [
176
+ 'get_repaint_capabilities(看本剧开没开、长镜头接力最多几段)',
177
+ 'upload_shot_footage(自有视频先登记成某镜实拍素材;已是本剧镜头则跳过)',
178
+ 'quote_repaint_shot_video → repaint_shot_video(按描述 + 参考图重画)',
179
+ 'quote_reskin_shot_video → reskin_shot_video(给一张换好装、与原片首帧构图对齐的首帧)',
180
+ 'get_repaint_status(按返回 id 查到完成)',
181
+ 'restore_repaint_original(不满意切回原片,免费)',
182
+ ],
183
+ avoid: '别拿 edit_video_shot 做整体换人换装(那是按指令局部改);超过约 14 秒先 split_shot。',
184
+ flow: 'get_repaint_capabilities → upload_shot_footage(自有视频) → quote_repaint_shot_video / quote_reskin_shot_video → repaint_shot_video / reskin_shot_video → get_repaint_status',
185
+ },
172
186
  {
173
187
  customer_has: '想自己剪:要逐镜素材包(裸片 / 对白轨 / 音效 / 配乐 / 字幕)',
174
188
  use: ['export_handoff_pack', 'get_handoff_toolchain', 'save_handoff_toolchain'],
@@ -249,7 +263,7 @@ export const PIPELINE = [
249
263
  },
250
264
  {
251
265
  step: '8 出视频',
252
- tools: ['quote_videos', 'generate_videos', 'get_scene_group_plan', 'generate_scene_groups', 'quote_regenerate_shot_video', 'regenerate_shot_video', 'quote_edit_video_shot', 'edit_video_shot', 'upload_shot_footage(实拍素材镜:客户录屏/产品实拍直接当该镜视频,不出视频不扣费)', 'get_edit_capabilities'],
266
+ tools: ['quote_videos', 'generate_videos', 'get_scene_group_plan', 'generate_scene_groups', 'quote_regenerate_shot_video', 'regenerate_shot_video', 'quote_edit_video_shot', 'edit_video_shot', 'upload_shot_footage(实拍素材镜:客户录屏/产品实拍直接当该镜视频,不出视频不扣费)', 'get_edit_capabilities', 'get_repaint_capabilities', 'quote_repaint_shot_video', 'repaint_shot_video', 'quote_reskin_shot_video', 'reskin_shot_video', 'get_repaint_status', 'restore_repaint_original'],
253
267
  billing: '报价确认后扣点',
254
268
  note: 'video_engine 必须在出视频前定(seedance-2.5 默认 / hailuo-3 降本 / wan3.0 风格化·绝不用于写实真人);切换不回溯已生成镜头。',
255
269
  },
@@ -1256,6 +1256,63 @@ export function registerProduceTools(server, client) {
1256
1256
  replace_user_footage: z.boolean().optional().describe('本镜是实拍素材镜(upload_shot_footage 传过)时,显式允许以它为源做编辑并用 AI 产物覆盖它。' +
1257
1257
  '不传则被守卫拒(409,带中文出路)。想保留素材就别传,改用 clear_shot_footage 换回 AI 生成。'),
1258
1258
  }, async ({ storyboard_id, ...rest }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/edit/generate`, rest)));
1259
+ // ========== B2 · VACE 视频重绘 / 换装重绘(保留原片动作,重画人物与服装) ==========
1260
+ const VACE_COMMON = '\n★与 edit_video_shot 的分工:edit 是按指令改画面(换背景/调色/局部改动);重绘/换装重绘是**以本镜现有视频为动作骨架,把人物与服装整体重画**,' +
1261
+ '动作、口型时机、镜头运动跟原片走,音轨贴回原片。' +
1262
+ '\n★**客户自己的视频也能转绘**:先 upload_shot_footage 把它登记成某镜的实拍素材(会抽出首尾帧、回写时长),再对该镜报价/发起即可;' +
1263
+ '转绘结果写回后该镜不再是实拍素材镜。' +
1264
+ '\n★时长:≤5 秒一单(按 5 秒计费);本剧开了长镜头接力(get_repaint_capabilities 的 relayMaxSegments>0)时 5~约14 秒自动切 ≤3 段接力,' +
1265
+ '每段一单、报价是合计;再长先 split_shot。' +
1266
+ '\n★异步:发起返回一条生成记录(接力时是段 1),用 get_repaint_status(storyboard_id, generation_id) 查到 completed/failed;' +
1267
+ '接力进行中会带 relay.segments_done/segments。完成后本镜视频即换成转绘结果;不满意用 restore_repaint_original 切回原片(免费)。';
1268
+ server.tool('get_repaint_capabilities', '查本剧能用哪些视频转绘:repaint(视频重绘)/ reskin(换装重绘)是否开放、单段源片上限 maxSourceSec、' +
1269
+ '长镜头接力最多段数 relayMaxSegments(0=没开,>5 秒的镜不能转绘)。免费。', { drama_id: z.number().int().positive() }, async ({ drama_id }) => jsonResult(await client.produceGet(`/dramas/${drama_id}/vace-capabilities`)));
1270
+ server.tool('quote_repaint_shot_video', '报价:对某镜做**视频重绘**(按描述 + 参考图重画人物与服装,保留原片动作)要多少点。返回 quote_id。零扣费。本镜须已有视频。' +
1271
+ '报价只认本镜当前这段视频——之后视频被换(重生/上传/编辑完成),发起会 409,重新报价即可。' + VACE_COMMON, { storyboard_id: z.number().int().positive() }, async ({ storyboard_id }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/repaint/quote`)));
1272
+ server.tool('repaint_shot_video', '确认后对某镜做视频重绘。扣费上限 = 报价的 estimated_points(接力时为整条合计)。' +
1273
+ '\n★参考图:不传 reference_image_url 时自动取本镜角色的(换装)定妆图——**不带参考图人也会被换掉**;' +
1274
+ 'auto_reference=false 表示明确不要参考图(只按描述画)。' +
1275
+ '\n★keep_scene 缺省 true:把本镜场景/道具/动作补进描述,只换人与衣服;传 false = 连场景一起重画。' +
1276
+ '\n★control:posebodyface(缺省,保口型,说话镜用它)/ posebody(不带脸,嘴不动)/ depth(按景深,纯色背景易出竖条纹)/ scribble(线稿)。' +
1277
+ 'strength 只收 0 或 1。' +
1278
+ '\n★本镜绑了产品文字(需保留商品原文)时会被拒(重绘会重画画面里的字)。' + VACE_COMMON + CONFIRM_HINT, {
1279
+ storyboard_id: z.number().int().positive(),
1280
+ quote_id: z.string().describe('来自 quote_repaint_shot_video'),
1281
+ prompt: z.string().describe('要画成什么样(人物外貌、服装、风格)。正向描述,别写「不要 X」'),
1282
+ control: z.enum(['posebodyface', 'posebody', 'depth', 'scribble']).optional().describe('动作控制方式,缺省 posebodyface'),
1283
+ strength: z.union([z.literal(0), z.literal(1)]).optional().describe('0 或 1,缺省 1'),
1284
+ reference_image_url: z.string().optional().describe('主体参考图 URL(先 upload_image 拿);缺省自动取本镜角色定妆图'),
1285
+ auto_reference: z.boolean().optional().describe('false = 明确不带参考图(人会按描述重画)'),
1286
+ keep_scene: z.boolean().optional().describe('缺省 true:保留原片场景与道具,只换人和衣服'),
1287
+ }, async ({ storyboard_id, ...rest }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/repaint/generate`, rest)));
1288
+ server.tool('quote_reskin_shot_video', '报价:对某镜做**换装重绘**(给一张已换好装的首帧,按原片动作把整段视频续成这身打扮)要多少点。返回 quote_id。零扣费。' +
1289
+ '本镜须已有视频;该功能按剧开放,先看 get_repaint_capabilities 的 reskin。' + VACE_COMMON, { storyboard_id: z.number().int().positive() }, async ({ storyboard_id }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/reskin/quote`)));
1290
+ server.tool('reskin_shot_video', '确认后对某镜做换装重绘。扣费上限 = 报价的 estimated_points。' +
1291
+ '\n★first_frame_url 是**换好装的首帧**:必须与原片首帧**构图、人物姿势、道具位置逐一对齐**(只换衣服),' +
1292
+ '否则整段会跑偏——实测失败都出在首帧。完成后它会成为本镜正式首帧。只收公网 https 图片(先 upload_image 拿)。' +
1293
+ '\n★prompt 可留空(系统看首帧自动写);写的话别用「制服/军装」这类服装类别词,模型会自行加肩章条纹,直接描述颜色款式。' +
1294
+ '\n★control:posebodyface(缺省,保口型)/ depth。本镜绑了产品文字时会被拒。' + VACE_COMMON + CONFIRM_HINT, {
1295
+ storyboard_id: z.number().int().positive(),
1296
+ quote_id: z.string().describe('来自 quote_reskin_shot_video'),
1297
+ first_frame_url: z.string().describe('换好装的首帧 https URL,须与原片首帧构图对齐'),
1298
+ prompt: z.string().optional().describe('可留空:系统看首帧自动写'),
1299
+ control: z.enum(['posebodyface', 'depth']).optional().describe('缺省 posebodyface'),
1300
+ }, async ({ storyboard_id, ...rest }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/reskin/generate`, rest)));
1301
+ server.tool('get_repaint_status', '查一次视频重绘/换装重绘的进度。generation_id 用发起时返回的 id(接力时就是段 1 的 id,返回的是整条链的状态)。免费。' +
1302
+ '\n· status=processing:进行中;接力时带 relay.segments_done/segments。' +
1303
+ '\n· status=completed:本镜视频已换成转绘结果(video_url / local_path);接力完成时带 relay.final_generation_id——' +
1304
+ '**切回原片要用这个 final_generation_id**,不是段 1 的 id。' +
1305
+ '\n· status=completed 但 errorMsg 含「未写回」:任务期间本镜视频被换掉,结果存档在这条记录里、没覆盖本镜。' +
1306
+ '\n· status=failed:errorMsg 是中文原因(接力会说明第几段失败),镜头未改动,已扣的按规则退。', {
1307
+ storyboard_id: z.number().int().positive(),
1308
+ generation_id: z.number().int().positive().describe('repaint_shot_video / reskin_shot_video 返回的 id'),
1309
+ }, async ({ storyboard_id, generation_id }) => jsonResult(await client.produceGet(`/storyboards/${storyboard_id}/vace/${generation_id}`)));
1310
+ server.tool('restore_repaint_original', '把某镜从转绘结果切回转绘前的原片(换装重绘连首帧一起恢复)。免费。' +
1311
+ 'generation_id = 本镜当前视频对应的那次转绘(接力取 get_repaint_status 的 relay.final_generation_id)。' +
1312
+ '\n★409 = 之后本镜又出过别的视频,不覆盖(保护后来的结果);有视频任务在跑时也别切回,在跑那单会因源片不符被存档(白花钱)。', {
1313
+ storyboard_id: z.number().int().positive(),
1314
+ generation_id: z.number().int().positive(),
1315
+ }, async ({ storyboard_id, generation_id }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/vace-restore`, { generation_id })));
1259
1316
  server.tool('quote_regenerate_shot_video', '报价:重生某镜视频要多少点。返回 quote_id。零扣费。' +
1260
1317
  '\n★**按镜指定视频引擎**:传 model 即只为这一镜这一次重生换引擎(不改剧级 video_engine,其它镜照旧);' +
1261
1318
  '报价按该引擎计价,quote_id 把引擎钉死,regenerate_shot_video 派发的就是它——要换引擎必须重新报价,生成时再传引擎无效。' +
package/openapi.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "StarReel Production API",
5
- "version": "0.1.137",
6
- "description": "Turn a script into a finished, downloadable short-drama episode over REST.\n\nPipeline: script → AI rewrite → cast/scenes/props extraction → storyboards → portraits & sheets + scene plates → keyframes → video shots → TTS → final cut (.mp4).\n\n**Billing is prepaid and agent-safe**: big-ticket stages are quote-then-generate (`quote_*` returns a `quote_id`). For video, quote == actual charge. For images the quote is a *range* — models billed per reference image are priced before those are assembled, so `estimated_points` is the upper bound (size the balance by it and a run never dies half-way) and `typical_points` is the usual cost; fixed-price models return the two equal. Insufficient balance returns 402 — nothing half-runs and the account never goes negative.\n\nAuth: exchange your API key at `POST /v1/agent/token` for a 15-minute bearer token.\n\nGenerated from the @starreel/mcp v0.1.137 tool surface (operationIds match MCP tool names 1:1)."
5
+ "version": "0.1.138",
6
+ "description": "Turn a script into a finished, downloadable short-drama episode over REST.\n\nPipeline: script → AI rewrite → cast/scenes/props extraction → storyboards → portraits & sheets + scene plates → keyframes → video shots → TTS → final cut (.mp4).\n\n**Billing is prepaid and agent-safe**: big-ticket stages are quote-then-generate (`quote_*` returns a `quote_id`). For video, quote == actual charge. For images the quote is a *range* — models billed per reference image are priced before those are assembled, so `estimated_points` is the upper bound (size the balance by it and a run never dies half-way) and `typical_points` is the usual cost; fixed-price models return the two equal. Insufficient balance returns 402 — nothing half-runs and the account never goes negative.\n\nAuth: exchange your API key at `POST /v1/agent/token` for a 15-minute bearer token.\n\nGenerated from the @starreel/mcp v0.1.138 tool surface (operationIds match MCP tool names 1:1)."
7
7
  },
8
8
  "servers": [
9
9
  {
@@ -3236,6 +3236,53 @@
3236
3236
  }
3237
3237
  }
3238
3238
  },
3239
+ "/dramas/{drama_id}/vace-capabilities": {
3240
+ "get": {
3241
+ "operationId": "get_repaint_capabilities",
3242
+ "summary": "查本剧能用哪些视频转绘:repaint(视频重绘)/ reskin(换装重绘)是否开放、单段源片上限 maxSourceSec、长镜头接力最多段数 relayMaxSegments(0=没开,>5 秒的镜不能转绘)",
3243
+ "description": "查本剧能用哪些视频转绘:repaint(视频重绘)/ reskin(换装重绘)是否开放、单段源片上限 maxSourceSec、长镜头接力最多段数 relayMaxSegments(0=没开,>5 秒的镜不能转绘)。免费。",
3244
+ "tags": [
3245
+ "dramas"
3246
+ ],
3247
+ "parameters": [
3248
+ {
3249
+ "name": "drama_id",
3250
+ "in": "path",
3251
+ "required": true,
3252
+ "schema": {
3253
+ "type": "integer",
3254
+ "exclusiveMinimum": 0
3255
+ }
3256
+ }
3257
+ ],
3258
+ "responses": {
3259
+ "200": {
3260
+ "description": "StarReel envelope",
3261
+ "content": {
3262
+ "application/json": {
3263
+ "schema": {
3264
+ "type": "object",
3265
+ "properties": {
3266
+ "code": {
3267
+ "type": "integer"
3268
+ },
3269
+ "message": {
3270
+ "type": "string"
3271
+ },
3272
+ "data": {
3273
+ "description": "Operation result payload"
3274
+ }
3275
+ }
3276
+ }
3277
+ }
3278
+ }
3279
+ },
3280
+ "402": {
3281
+ "description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
3282
+ }
3283
+ }
3284
+ }
3285
+ },
3239
3286
  "/dramas/{drama_id}/video-style": {
3240
3287
  "post": {
3241
3288
  "operationId": "generate_video_style",
@@ -12427,6 +12474,277 @@
12427
12474
  }
12428
12475
  }
12429
12476
  },
12477
+ "/storyboards/{storyboard_id}/repaint/generate": {
12478
+ "post": {
12479
+ "operationId": "repaint_shot_video",
12480
+ "summary": "确认后对某镜做视频重绘",
12481
+ "description": "确认后对某镜做视频重绘。扣费上限 = 报价的 estimated_points(接力时为整条合计)。\n★参考图:不传 reference_image_url 时自动取本镜角色的(换装)定妆图——**不带参考图人也会被换掉**;auto_reference=false 表示明确不要参考图(只按描述画)。\n★keep_scene 缺省 true:把本镜场景/道具/动作补进描述,只换人与衣服;传 false = 连场景一起重画。\n★control:posebodyface(缺省,保口型,说话镜用它)/ posebody(不带脸,嘴不动)/ depth(按景深,纯色背景易出竖条纹)/ scribble(线稿)。strength 只收 0 或 1。\n★本镜绑了产品文字(需保留商品原文)时会被拒(重绘会重画画面里的字)。\n★与 edit_video_shot 的分工:edit 是按指令改画面(换背景/调色/局部改动);重绘/换装重绘是**以本镜现有视频为动作骨架,把人物与服装整体重画**,动作、口型时机、镜头运动跟原片走,音轨贴回原片。\n★**客户自己的视频也能转绘**:先 upload_shot_footage 把它登记成某镜的实拍素材(会抽出首尾帧、回写时长),再对该镜报价/发起即可;转绘结果写回后该镜不再是实拍素材镜。\n★时长:≤5 秒一单(按 5 秒计费);本剧开了长镜头接力(get_repaint_capabilities 的 relayMaxSegments>0)时 5~约14 秒自动切 ≤3 段接力,每段一单、报价是合计;再长先 split_shot。\n★异步:发起返回一条生成记录(接力时是段 1),用 get_repaint_status(storyboard_id, generation_id) 查到 completed/failed;接力进行中会带 relay.segments_done/segments。完成后本镜视频即换成转绘结果;不满意用 restore_repaint_original 切回原片(免费)。⚠️ 批量报价确认流程:先调对应的 quote_* 工具,把返回的 estimated_points 原样告诉用户,用户明确同意后,才用返回的 quote_id 调本工具。不要擅自确认。★**出图类报价(定妆图/场景图/出帧)给的是两个数**:estimated_points 是**上界**(按该模型参考图张数上限估,保证你不会按低了的预算开跑、出到一半 402 中断);同一响应里的 typical_points 是**通常花费**。两个都要告诉客户——只说上界会让人以为贵得多(满参考图的上界可达通常值的 2 倍以上),只说通常值又会让余额准备不足。固定价模型下两者相等,这时说一个数就行。出视频的报价与扣费同函数,不存在这个区间。",
12482
+ "tags": [
12483
+ "storyboards"
12484
+ ],
12485
+ "parameters": [
12486
+ {
12487
+ "name": "storyboard_id",
12488
+ "in": "path",
12489
+ "required": true,
12490
+ "schema": {
12491
+ "type": "integer",
12492
+ "exclusiveMinimum": 0
12493
+ }
12494
+ }
12495
+ ],
12496
+ "requestBody": {
12497
+ "required": true,
12498
+ "content": {
12499
+ "application/json": {
12500
+ "schema": {
12501
+ "type": "object",
12502
+ "properties": {
12503
+ "quote_id": {
12504
+ "type": "string",
12505
+ "description": "来自 quote_repaint_shot_video"
12506
+ },
12507
+ "prompt": {
12508
+ "type": "string",
12509
+ "description": "要画成什么样(人物外貌、服装、风格)。正向描述,别写「不要 X」"
12510
+ },
12511
+ "control": {
12512
+ "type": "string",
12513
+ "enum": [
12514
+ "posebodyface",
12515
+ "posebody",
12516
+ "depth",
12517
+ "scribble"
12518
+ ]
12519
+ },
12520
+ "strength": {
12521
+ "type": "number",
12522
+ "enum": [
12523
+ 0,
12524
+ 1
12525
+ ]
12526
+ },
12527
+ "reference_image_url": {
12528
+ "type": "string"
12529
+ },
12530
+ "auto_reference": {
12531
+ "type": "boolean"
12532
+ },
12533
+ "keep_scene": {
12534
+ "type": "boolean"
12535
+ }
12536
+ },
12537
+ "required": [
12538
+ "quote_id",
12539
+ "prompt"
12540
+ ]
12541
+ }
12542
+ }
12543
+ }
12544
+ },
12545
+ "responses": {
12546
+ "200": {
12547
+ "description": "StarReel envelope",
12548
+ "content": {
12549
+ "application/json": {
12550
+ "schema": {
12551
+ "type": "object",
12552
+ "properties": {
12553
+ "code": {
12554
+ "type": "integer"
12555
+ },
12556
+ "message": {
12557
+ "type": "string"
12558
+ },
12559
+ "data": {
12560
+ "description": "Operation result payload"
12561
+ }
12562
+ }
12563
+ }
12564
+ }
12565
+ }
12566
+ },
12567
+ "402": {
12568
+ "description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
12569
+ }
12570
+ }
12571
+ }
12572
+ },
12573
+ "/storyboards/{storyboard_id}/repaint/quote": {
12574
+ "post": {
12575
+ "operationId": "quote_repaint_shot_video",
12576
+ "summary": "报价:对某镜做**视频重绘**(按描述 + 参考图重画人物与服装,保留原片动作)要多少点",
12577
+ "description": "报价:对某镜做**视频重绘**(按描述 + 参考图重画人物与服装,保留原片动作)要多少点。返回 quote_id。零扣费。本镜须已有视频。报价只认本镜当前这段视频——之后视频被换(重生/上传/编辑完成),发起会 409,重新报价即可。\n★与 edit_video_shot 的分工:edit 是按指令改画面(换背景/调色/局部改动);重绘/换装重绘是**以本镜现有视频为动作骨架,把人物与服装整体重画**,动作、口型时机、镜头运动跟原片走,音轨贴回原片。\n★**客户自己的视频也能转绘**:先 upload_shot_footage 把它登记成某镜的实拍素材(会抽出首尾帧、回写时长),再对该镜报价/发起即可;转绘结果写回后该镜不再是实拍素材镜。\n★时长:≤5 秒一单(按 5 秒计费);本剧开了长镜头接力(get_repaint_capabilities 的 relayMaxSegments>0)时 5~约14 秒自动切 ≤3 段接力,每段一单、报价是合计;再长先 split_shot。\n★异步:发起返回一条生成记录(接力时是段 1),用 get_repaint_status(storyboard_id, generation_id) 查到 completed/failed;接力进行中会带 relay.segments_done/segments。完成后本镜视频即换成转绘结果;不满意用 restore_repaint_original 切回原片(免费)。",
12578
+ "tags": [
12579
+ "storyboards"
12580
+ ],
12581
+ "parameters": [
12582
+ {
12583
+ "name": "storyboard_id",
12584
+ "in": "path",
12585
+ "required": true,
12586
+ "schema": {
12587
+ "type": "integer",
12588
+ "exclusiveMinimum": 0
12589
+ }
12590
+ }
12591
+ ],
12592
+ "responses": {
12593
+ "200": {
12594
+ "description": "StarReel envelope",
12595
+ "content": {
12596
+ "application/json": {
12597
+ "schema": {
12598
+ "type": "object",
12599
+ "properties": {
12600
+ "code": {
12601
+ "type": "integer"
12602
+ },
12603
+ "message": {
12604
+ "type": "string"
12605
+ },
12606
+ "data": {
12607
+ "description": "Operation result payload"
12608
+ }
12609
+ }
12610
+ }
12611
+ }
12612
+ }
12613
+ },
12614
+ "402": {
12615
+ "description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
12616
+ }
12617
+ }
12618
+ }
12619
+ },
12620
+ "/storyboards/{storyboard_id}/reskin/generate": {
12621
+ "post": {
12622
+ "operationId": "reskin_shot_video",
12623
+ "summary": "确认后对某镜做换装重绘",
12624
+ "description": "确认后对某镜做换装重绘。扣费上限 = 报价的 estimated_points。\n★first_frame_url 是**换好装的首帧**:必须与原片首帧**构图、人物姿势、道具位置逐一对齐**(只换衣服),否则整段会跑偏——实测失败都出在首帧。完成后它会成为本镜正式首帧。只收公网 https 图片(先 upload_image 拿)。\n★prompt 可留空(系统看首帧自动写);写的话别用「制服/军装」这类服装类别词,模型会自行加肩章条纹,直接描述颜色款式。\n★control:posebodyface(缺省,保口型)/ depth。本镜绑了产品文字时会被拒。\n★与 edit_video_shot 的分工:edit 是按指令改画面(换背景/调色/局部改动);重绘/换装重绘是**以本镜现有视频为动作骨架,把人物与服装整体重画**,动作、口型时机、镜头运动跟原片走,音轨贴回原片。\n★**客户自己的视频也能转绘**:先 upload_shot_footage 把它登记成某镜的实拍素材(会抽出首尾帧、回写时长),再对该镜报价/发起即可;转绘结果写回后该镜不再是实拍素材镜。\n★时长:≤5 秒一单(按 5 秒计费);本剧开了长镜头接力(get_repaint_capabilities 的 relayMaxSegments>0)时 5~约14 秒自动切 ≤3 段接力,每段一单、报价是合计;再长先 split_shot。\n★异步:发起返回一条生成记录(接力时是段 1),用 get_repaint_status(storyboard_id, generation_id) 查到 completed/failed;接力进行中会带 relay.segments_done/segments。完成后本镜视频即换成转绘结果;不满意用 restore_repaint_original 切回原片(免费)。⚠️ 批量报价确认流程:先调对应的 quote_* 工具,把返回的 estimated_points 原样告诉用户,用户明确同意后,才用返回的 quote_id 调本工具。不要擅自确认。★**出图类报价(定妆图/场景图/出帧)给的是两个数**:estimated_points 是**上界**(按该模型参考图张数上限估,保证你不会按低了的预算开跑、出到一半 402 中断);同一响应里的 typical_points 是**通常花费**。两个都要告诉客户——只说上界会让人以为贵得多(满参考图的上界可达通常值的 2 倍以上),只说通常值又会让余额准备不足。固定价模型下两者相等,这时说一个数就行。出视频的报价与扣费同函数,不存在这个区间。",
12625
+ "tags": [
12626
+ "storyboards"
12627
+ ],
12628
+ "parameters": [
12629
+ {
12630
+ "name": "storyboard_id",
12631
+ "in": "path",
12632
+ "required": true,
12633
+ "schema": {
12634
+ "type": "integer",
12635
+ "exclusiveMinimum": 0
12636
+ }
12637
+ }
12638
+ ],
12639
+ "requestBody": {
12640
+ "required": true,
12641
+ "content": {
12642
+ "application/json": {
12643
+ "schema": {
12644
+ "type": "object",
12645
+ "properties": {
12646
+ "quote_id": {
12647
+ "type": "string",
12648
+ "description": "来自 quote_reskin_shot_video"
12649
+ },
12650
+ "first_frame_url": {
12651
+ "type": "string",
12652
+ "description": "换好装的首帧 https URL,须与原片首帧构图对齐"
12653
+ },
12654
+ "prompt": {
12655
+ "type": "string"
12656
+ },
12657
+ "control": {
12658
+ "type": "string",
12659
+ "enum": [
12660
+ "posebodyface",
12661
+ "depth"
12662
+ ]
12663
+ }
12664
+ },
12665
+ "required": [
12666
+ "quote_id",
12667
+ "first_frame_url"
12668
+ ]
12669
+ }
12670
+ }
12671
+ }
12672
+ },
12673
+ "responses": {
12674
+ "200": {
12675
+ "description": "StarReel envelope",
12676
+ "content": {
12677
+ "application/json": {
12678
+ "schema": {
12679
+ "type": "object",
12680
+ "properties": {
12681
+ "code": {
12682
+ "type": "integer"
12683
+ },
12684
+ "message": {
12685
+ "type": "string"
12686
+ },
12687
+ "data": {
12688
+ "description": "Operation result payload"
12689
+ }
12690
+ }
12691
+ }
12692
+ }
12693
+ }
12694
+ },
12695
+ "402": {
12696
+ "description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
12697
+ }
12698
+ }
12699
+ }
12700
+ },
12701
+ "/storyboards/{storyboard_id}/reskin/quote": {
12702
+ "post": {
12703
+ "operationId": "quote_reskin_shot_video",
12704
+ "summary": "报价:对某镜做**换装重绘**(给一张已换好装的首帧,按原片动作把整段视频续成这身打扮)要多少点",
12705
+ "description": "报价:对某镜做**换装重绘**(给一张已换好装的首帧,按原片动作把整段视频续成这身打扮)要多少点。返回 quote_id。零扣费。本镜须已有视频;该功能按剧开放,先看 get_repaint_capabilities 的 reskin。\n★与 edit_video_shot 的分工:edit 是按指令改画面(换背景/调色/局部改动);重绘/换装重绘是**以本镜现有视频为动作骨架,把人物与服装整体重画**,动作、口型时机、镜头运动跟原片走,音轨贴回原片。\n★**客户自己的视频也能转绘**:先 upload_shot_footage 把它登记成某镜的实拍素材(会抽出首尾帧、回写时长),再对该镜报价/发起即可;转绘结果写回后该镜不再是实拍素材镜。\n★时长:≤5 秒一单(按 5 秒计费);本剧开了长镜头接力(get_repaint_capabilities 的 relayMaxSegments>0)时 5~约14 秒自动切 ≤3 段接力,每段一单、报价是合计;再长先 split_shot。\n★异步:发起返回一条生成记录(接力时是段 1),用 get_repaint_status(storyboard_id, generation_id) 查到 completed/failed;接力进行中会带 relay.segments_done/segments。完成后本镜视频即换成转绘结果;不满意用 restore_repaint_original 切回原片(免费)。",
12706
+ "tags": [
12707
+ "storyboards"
12708
+ ],
12709
+ "parameters": [
12710
+ {
12711
+ "name": "storyboard_id",
12712
+ "in": "path",
12713
+ "required": true,
12714
+ "schema": {
12715
+ "type": "integer",
12716
+ "exclusiveMinimum": 0
12717
+ }
12718
+ }
12719
+ ],
12720
+ "responses": {
12721
+ "200": {
12722
+ "description": "StarReel envelope",
12723
+ "content": {
12724
+ "application/json": {
12725
+ "schema": {
12726
+ "type": "object",
12727
+ "properties": {
12728
+ "code": {
12729
+ "type": "integer"
12730
+ },
12731
+ "message": {
12732
+ "type": "string"
12733
+ },
12734
+ "data": {
12735
+ "description": "Operation result payload"
12736
+ }
12737
+ }
12738
+ }
12739
+ }
12740
+ }
12741
+ },
12742
+ "402": {
12743
+ "description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
12744
+ }
12745
+ }
12746
+ }
12747
+ },
12430
12748
  "/storyboards/{storyboard_id}/split": {
12431
12749
  "post": {
12432
12750
  "operationId": "split_shot",
@@ -12588,6 +12906,129 @@
12588
12906
  }
12589
12907
  }
12590
12908
  },
12909
+ "/storyboards/{storyboard_id}/vace-restore": {
12910
+ "post": {
12911
+ "operationId": "restore_repaint_original",
12912
+ "summary": "把某镜从转绘结果切回转绘前的原片(换装重绘连首帧一起恢复)",
12913
+ "description": "把某镜从转绘结果切回转绘前的原片(换装重绘连首帧一起恢复)。免费。generation_id = 本镜当前视频对应的那次转绘(接力取 get_repaint_status 的 relay.final_generation_id)。\n★409 = 之后本镜又出过别的视频,不覆盖(保护后来的结果);有视频任务在跑时也别切回,在跑那单会因源片不符被存档(白花钱)。",
12914
+ "tags": [
12915
+ "storyboards"
12916
+ ],
12917
+ "parameters": [
12918
+ {
12919
+ "name": "storyboard_id",
12920
+ "in": "path",
12921
+ "required": true,
12922
+ "schema": {
12923
+ "type": "integer",
12924
+ "exclusiveMinimum": 0
12925
+ }
12926
+ }
12927
+ ],
12928
+ "requestBody": {
12929
+ "required": true,
12930
+ "content": {
12931
+ "application/json": {
12932
+ "schema": {
12933
+ "type": "object",
12934
+ "properties": {
12935
+ "generation_id": {
12936
+ "type": "integer",
12937
+ "exclusiveMinimum": 0
12938
+ }
12939
+ },
12940
+ "required": [
12941
+ "generation_id"
12942
+ ]
12943
+ }
12944
+ }
12945
+ }
12946
+ },
12947
+ "responses": {
12948
+ "200": {
12949
+ "description": "StarReel envelope",
12950
+ "content": {
12951
+ "application/json": {
12952
+ "schema": {
12953
+ "type": "object",
12954
+ "properties": {
12955
+ "code": {
12956
+ "type": "integer"
12957
+ },
12958
+ "message": {
12959
+ "type": "string"
12960
+ },
12961
+ "data": {
12962
+ "description": "Operation result payload"
12963
+ }
12964
+ }
12965
+ }
12966
+ }
12967
+ }
12968
+ },
12969
+ "402": {
12970
+ "description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
12971
+ }
12972
+ }
12973
+ }
12974
+ },
12975
+ "/storyboards/{storyboard_id}/vace/{generation_id}": {
12976
+ "get": {
12977
+ "operationId": "get_repaint_status",
12978
+ "summary": "查一次视频重绘/换装重绘的进度",
12979
+ "description": "查一次视频重绘/换装重绘的进度。generation_id 用发起时返回的 id(接力时就是段 1 的 id,返回的是整条链的状态)。免费。\n· status=processing:进行中;接力时带 relay.segments_done/segments。\n· status=completed:本镜视频已换成转绘结果(video_url / local_path);接力完成时带 relay.final_generation_id——**切回原片要用这个 final_generation_id**,不是段 1 的 id。\n· status=completed 但 errorMsg 含「未写回」:任务期间本镜视频被换掉,结果存档在这条记录里、没覆盖本镜。\n· status=failed:errorMsg 是中文原因(接力会说明第几段失败),镜头未改动,已扣的按规则退。",
12980
+ "tags": [
12981
+ "storyboards"
12982
+ ],
12983
+ "parameters": [
12984
+ {
12985
+ "name": "storyboard_id",
12986
+ "in": "path",
12987
+ "required": true,
12988
+ "schema": {
12989
+ "type": "integer",
12990
+ "exclusiveMinimum": 0
12991
+ }
12992
+ },
12993
+ {
12994
+ "name": "generation_id",
12995
+ "in": "path",
12996
+ "required": true,
12997
+ "schema": {
12998
+ "type": "integer",
12999
+ "exclusiveMinimum": 0,
13000
+ "description": "repaint_shot_video / reskin_shot_video 返回的 id"
13001
+ }
13002
+ }
13003
+ ],
13004
+ "responses": {
13005
+ "200": {
13006
+ "description": "StarReel envelope",
13007
+ "content": {
13008
+ "application/json": {
13009
+ "schema": {
13010
+ "type": "object",
13011
+ "properties": {
13012
+ "code": {
13013
+ "type": "integer"
13014
+ },
13015
+ "message": {
13016
+ "type": "string"
13017
+ },
13018
+ "data": {
13019
+ "description": "Operation result payload"
13020
+ }
13021
+ }
13022
+ }
13023
+ }
13024
+ }
13025
+ },
13026
+ "402": {
13027
+ "description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
13028
+ }
13029
+ }
13030
+ }
13031
+ },
12591
13032
  "/videos/edit-capabilities": {
12592
13033
  "get": {
12593
13034
  "operationId": "get_edit_capabilities",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@starreel/mcp",
3
- "version": "0.1.137",
3
+ "version": "0.1.138",
4
4
  "mcpName": "ai.starreel/starreel",
5
5
  "description": "StarReel MCP server — drive the AI short-drama production pipeline (script → storyboards → frames → video → final cut) from Claude, Cursor, or any MCP client",
6
6
  "license": "MIT",
package/server.json CHANGED
@@ -2,13 +2,13 @@
2
2
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
3
3
  "name": "ai.starreel/starreel",
4
4
  "description": "Turn a script into a finished, downloadable short-drama episode — via MCP or REST.",
5
- "version": "0.1.137",
5
+ "version": "0.1.138",
6
6
  "websiteUrl": "https://starreel.ai",
7
7
  "packages": [
8
8
  {
9
9
  "registryType": "npm",
10
10
  "identifier": "@starreel/mcp",
11
- "version": "0.1.137",
11
+ "version": "0.1.138",
12
12
  "transport": {
13
13
  "type": "stdio"
14
14
  },