@starreel/mcp 0.1.23 → 0.1.25
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 +3 -1
- package/dist/tools/produce.js +61 -15
- package/package.json +1 -1
- package/server.json +2 -2
package/SKILL.md
CHANGED
|
@@ -157,7 +157,9 @@ Failures surface as a human-readable `message` (MCP throws `Error(message)`;
|
|
|
157
157
|
REST returns `{ code, message }`, or on `/v1/ai/*`:
|
|
158
158
|
`{ error: { message, type, needed?, retryable? } }`). Per-shot, `get_storyboards`
|
|
159
159
|
gives structured `frame_status` / `video_status` / `fail_reason` / `retryable` /
|
|
160
|
-
`fail_hint`.
|
|
160
|
+
`fail_hint`. A status of `not_required` marks a narration/end-card shot: its frame
|
|
161
|
+
and video are rendered by the final-cut layer — count it as done, never retry it.
|
|
162
|
+
Map the reason to an action:
|
|
161
163
|
|
|
162
164
|
| fail_reason | retryable | What it means | Do |
|
|
163
165
|
|---|---|---|---|
|
package/dist/tools/produce.js
CHANGED
|
@@ -18,19 +18,27 @@ const CONFIRM_HINT = '⚠️ 批量报价确认流程:先调对应的 quote_*
|
|
|
18
18
|
'用户明确同意后,才用返回的 quote_id 调本工具。不要擅自确认。';
|
|
19
19
|
// 完整工作流顺序(照 get_pipeline_status 的 10 步真相走,不要跳步):
|
|
20
20
|
// create_drama → set_script(原始) → rewrite_script(AI改写) → [get_script/edit_rewritten_script 审改]
|
|
21
|
-
// → extract_assets(角色/场景/道具) →
|
|
22
|
-
// →
|
|
21
|
+
// → extract_assets(角色/场景/道具) → quote/generate_storyboards(先分镜·纯文本拆镜)
|
|
22
|
+
// → generate_character_portraits(定妆图·一致性关键·分镜后建只给出场角色更省) → quote/generate_frames → quote/generate_videos
|
|
23
23
|
// → compose_episode → get_final_cut / get_export
|
|
24
24
|
// 项目设定随时可 update_project_settings;剧目级资产(色彩脚本/动作模板/世界观图/美术圣经)可选增强。
|
|
25
25
|
const WORKFLOW_HINT = '★三档执行策略(别把三档混着问客户):' +
|
|
26
26
|
'①【基础项目设定·免费·必做地基·建剧即设好,别建空壳】project_type/setting_brief(世界观·ERA LOCK)/' +
|
|
27
27
|
'ethnicity(族裔)/画幅分辨率,以及一致性锚 cinematography_prompt(摄影DNA)·art_bible(美术圣经)·visual_lock(视觉锁定)——' +
|
|
28
28
|
'全免费,是驱动全链一致性的地基;不设好,后续所有生成都跑偏、返工重花钱。用 create_drama/update_project_settings 直接设。' +
|
|
29
|
-
'
|
|
30
|
-
'assign_voices(分配音色)→
|
|
29
|
+
'②【产线主干·按序不跳步·★先分镜再建资产】set_script→rewrite_script→extract_assets→storyboards(先分镜·纯文本拆镜)→' +
|
|
30
|
+
'generate_portraits_and_sheets(定妆图+设定图·分镜后建只给出场角色出图更省)→assign_voices(分配音色)→frames→videos→generate_tts→compose;' +
|
|
31
|
+
'★别先建角色形象/道具设定图/动作模板再分镜——分镜是纯文本步、不依赖任何图;资产在分镜后建更省更准(动作模板本就必须分镜后)。收费步照现有 quote 报价确认流程。' +
|
|
31
32
|
'广告另需 add_product+generate_product_sheet;MV 走 set_mv_lyrics→generate_mv_story→generate_mv_script。' +
|
|
32
|
-
'
|
|
33
|
+
'★世界观概念图=默认必做(提升整剧一致性、很多第三方平台漏做这步):分镜后默认调 generate_world_concept,' +
|
|
34
|
+
'仍走报价确认流程(告知客户预估点数、确认再扣)——不静默扣费、也别跳过。' +
|
|
35
|
+
'★音频默认用视频原声(use_clip_audio 默认开、跳过 TTS 直接用 AI 视频自带声):' +
|
|
36
|
+
'建剧/改设定时 AI 应主动告知客户「默认用视频原声,如需 TTS 配音把 use_clip_audio 设 false」,让客户选。' +
|
|
37
|
+
'③【可选增强·AI 主动提示客户·报价确认才做】美术圣经生成/视觉锁抽取/色彩脚本/动作模板/场景图/场景组/口型/海报/音效/配乐/字幕翻译——' +
|
|
33
38
|
'这些提升一致性/质量、大多收费。★AI 应主动告知客户这些可做并给报价,客户确认才跑;既不默默跳过、也不擅自扣费。' +
|
|
39
|
+
'★两条锁定纪律:①**画幅比例**在 create_drama 即定、drama 级锁定,之后所有出图/出视频/成片都用它、**别中途改**' +
|
|
40
|
+
'(改了已生成内容画幅会不一致、漂移);不设默认 9:16。②**拆镜每镜 5-7 秒是对 AI 出视频优化的正常时长**,' +
|
|
41
|
+
'别因「镜偏长」误判就重拆——generate_storyboards 会**替换整集所有分镜**、已出图白费,已有分镜后端会拦、需 confirm_replace。' +
|
|
34
42
|
'用 get_pipeline_status 查进度(按项目类型返回专属步骤)。';
|
|
35
43
|
const ETHNICITY_CODES = [
|
|
36
44
|
'east_asian', 'southeast_asian', 'south_asian', 'central_asian',
|
|
@@ -61,7 +69,7 @@ const PROJECT_SETTINGS_FIELDS = {
|
|
|
61
69
|
bgm_source: z.enum(['own', 'clip']).optional().describe("BGM来源:own=自有BGM流水线(默认,抑制裸片BGM);clip=保留视频原生BGM、终拼不叠加"),
|
|
62
70
|
bgm_volume_preset: z.enum(['off', 'low', 'auto', 'high']).optional().describe('BGM音量档:off静音/low轻(-28dB)/auto自适应(默认,静段可闻·对白不压麦)/high强'),
|
|
63
71
|
bgm_volume_db: z.number().optional().describe('自定义BGM音量(dB,负值),覆盖预设档、关自适应'),
|
|
64
|
-
use_clip_audio: z.boolean().optional().describe('
|
|
72
|
+
use_clip_audio: z.boolean().optional().describe('用视频原声(★默认开):true/不传=跳过TTS配音直接用视频自带声;false=改回TTS配音。所有类型默认视频原声,建剧时应主动告知客户可切换配音(★直接改成片音频)'),
|
|
65
73
|
// 字幕(烧录/双语/仅译文/位置/边距/动效)
|
|
66
74
|
show_subtitles: z.boolean().optional().describe('字幕烧录总开关:false=不烧字幕轨'),
|
|
67
75
|
subtitle_secondary_lang: z.string().optional().describe('双语字幕第二语言(如 en/ja);设了即双语(需先字幕同步翻译该语言)'),
|
|
@@ -100,7 +108,7 @@ export function registerProduceTools(server, client) {
|
|
|
100
108
|
genre: z.string().optional().describe('题材,如 都市/悬疑/古装'),
|
|
101
109
|
style: z.string().optional().describe('风格描述'),
|
|
102
110
|
description: z.string().optional(),
|
|
103
|
-
aspect_ratio: z.enum(ASPECT_RATIOS).optional().describe('画幅比例(默认 9:16 竖屏短剧)'),
|
|
111
|
+
aspect_ratio: z.enum(ASPECT_RATIOS).optional().describe('画幅比例(默认 9:16 竖屏短剧)。★drama级锁定:建剧即定、之后所有出图/出视频/成片都用它,别中途改(改了已生成内容画幅不一致、漂移)'),
|
|
104
112
|
video_resolution: z.enum(VIDEO_RESOLUTIONS).optional().describe('视频分辨率(默认 720p;成本随分辨率上升)'),
|
|
105
113
|
setting_brief: z
|
|
106
114
|
.string()
|
|
@@ -160,12 +168,22 @@ export function registerProduceTools(server, client) {
|
|
|
160
168
|
// ---------- 拆镜(storyboards) ----------
|
|
161
169
|
server.tool('quote_storyboards', '报价:把某一集的剧本拆成分镜(storyboards)要多少点。返回 estimated_points 与 quote_id。零扣费。' +
|
|
162
170
|
'拿到后把点数告诉用户征求同意,再用 quote_id 调 generate_storyboards。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/storyboards/quote`)));
|
|
163
|
-
server.tool('generate_storyboards', '确认后拆镜:后台跑(分钟级),立即返回 status:generating。用 get_storyboards
|
|
171
|
+
server.tool('generate_storyboards', '确认后拆镜:后台跑(分钟级),立即返回 status:generating。用 get_storyboards 轮询。' +
|
|
172
|
+
'★注意:拆镜会**替换整集所有已有分镜**(已调好/已出图的全丢、要重花钱重来)。每镜 5-7 秒是对 AI 出视频' +
|
|
173
|
+
'优化的**正常**时长,别因「一镜偏长」觉得有问题就重拆。已有分镜时后端会拦,确认重拆才带 confirm_replace=true。' + CONFIRM_HINT, {
|
|
174
|
+
episode_id: z.number().int().positive(),
|
|
175
|
+
quote_id: z.string().describe('来自 quote_storyboards'),
|
|
176
|
+
confirm_replace: z.boolean().optional().describe('本集已有分镜时必须 true 才重拆(会替换整集所有分镜,已出图白费)'),
|
|
177
|
+
}, async ({ episode_id, quote_id, confirm_replace }) => jsonResult(await client.producePost(`/episodes/${episode_id}/storyboards/generate`, confirm_replace ? { quote_id, confirm_replace } : { quote_id })));
|
|
164
178
|
server.tool('get_storyboards', '读某一集的分镜列表(供审阅/查进度)。含每镜首帧(first_frame_image)与视频(video_url)是否就绪。' +
|
|
165
|
-
'★每镜还带**结构化状态**:frame_status/video_status(ready/pending/authorizing/rejected/failed/none)、' +
|
|
179
|
+
'★每镜还带**结构化状态**:frame_status/video_status(ready/pending/authorizing/rejected/failed/none/not_required)、' +
|
|
180
|
+
'★not_required=旁白/片尾卡镜:帧与视频由成片层渲染,本镜不需要生成——数补齐进度时把它当已完成,别重试。' +
|
|
166
181
|
'fail_reason(sensitive/text_sensitive/copyright/face_mismatch/account_overdue/quota_full/authorizing/' +
|
|
167
182
|
'insufficient_credits/transient)、retryable(true=可重试;false=改内容换图,重试无效)、fail_hint(人读文案)。' +
|
|
168
|
-
'照 retryable
|
|
183
|
+
'照 retryable 判该重试还是该改内容,别解析中文。' +
|
|
184
|
+
'★若某镜带 reopen_pair_id:该镜首尾帧同时生成时只有一侧真的有问题、另一侧是无辜陪拒,' +
|
|
185
|
+
'原样传给 generate_shot_frame 的 reopen_pair_id 参数可以只重掷有问题的那一侧(省一半算力/费用,' +
|
|
186
|
+
'不会拿去生成一张这次根本没打算重做的图)。没有这个字段就按 fail_reason/retryable 走常规重试。免费。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/storyboards`)));
|
|
169
187
|
// ---------- 分镜级 AI 操作:2 个免费质量闸 + 3 个 AI 增强(★都在出图前做)----------
|
|
170
188
|
server.tool('run_precheck', '(★推荐·免费质量闸)出图/出视频前跑生成前预检:查合规/敏感/就绪度,把会被厂商拒的镜提前揪出。免费、不扣费。' +
|
|
171
189
|
'强烈建议 generate_frames/generate_videos 前调,防白花钱被拒。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/precheck`)));
|
|
@@ -197,12 +215,18 @@ export function registerProduceTools(server, client) {
|
|
|
197
215
|
server.tool('generate_shot_frame', '确认后给**某一镜**出帧或重生该帧(异步)。这是修某一镜画面的正路:平台会带上该镜的角色身份锚、' +
|
|
198
216
|
'场景/道具参考图、画风锚与帧审计,重生出的图与全片一致;用外部工具出图再上传会绕开这整条链路,人物/服装/画风必漂。' +
|
|
199
217
|
'重生会覆盖该帧现有图(含此前上传的),并把本镜视频标为待重生。尾帧需本镜首帧已就绪(否则先用 first_frame 或 both)。' +
|
|
200
|
-
'完成判据:轮询 get_storyboards 看该镜 first_frame_image/last_frame_image
|
|
218
|
+
'完成判据:轮询 get_storyboards 看该镜 first_frame_image/last_frame_image 变化。\n' +
|
|
219
|
+
'★继承重开(reopen_pair_id):get_storyboards 某镜带这个字段时,原样传进来可以只重掷首尾帧里' +
|
|
220
|
+
'真正有问题的那一侧——另一侧此前已经生成好的候选原样保留,不重新生成、不重新计费。传了它就' +
|
|
221
|
+
'不用再传 frame_type(会被忽略,由平台判定该重哪一侧);quote_id 仍要用 quote_shot_frame 报价' +
|
|
222
|
+
'(frame_type 传 first_frame 或 last_frame 均可,单帧同价)。若该镜没有 reopen_pair_id 字段' +
|
|
223
|
+
'(不满足继承条件),这个参数不要传,走常规 frame_type 重试。' + CONFIRM_HINT, {
|
|
201
224
|
storyboard_id: z.number().int().positive(),
|
|
202
225
|
quote_id: z.string().describe('来自 quote_shot_frame'),
|
|
203
|
-
frame_type: FRAME_TYPE_ARG.optional().describe('默认 first_frame
|
|
226
|
+
frame_type: FRAME_TYPE_ARG.optional().describe('默认 first_frame,须与报价时一致;传了 reopen_pair_id 时会被忽略'),
|
|
204
227
|
replace_user_frame: z.boolean().optional().describe('默认 true(显式重生允许覆盖已上传帧);传 false 则保护已上传帧'),
|
|
205
|
-
|
|
228
|
+
reopen_pair_id: z.string().optional().describe('来自 get_storyboards 该镜的同名字段;只重掷有问题的那一侧,不必再传 frame_type'),
|
|
229
|
+
}, async ({ storyboard_id, quote_id, frame_type, replace_user_frame, reopen_pair_id }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/frame/generate`, { quote_id, frame_type, replace_user_frame, reopen_pair_id })));
|
|
206
230
|
// ---------- 出视频(videos,大额) ----------
|
|
207
231
|
server.tool('quote_videos', '报价:给某一集所有分镜批量出视频要多少点(与实际扣费同函数,较准)。返回 estimated_points、quote_id。零扣费。' +
|
|
208
232
|
'⚠️ 视频是大额花费,务必把点数清楚告诉用户并等其确认。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/videos/quote`)));
|
|
@@ -255,8 +279,8 @@ export function registerProduceTools(server, client) {
|
|
|
255
279
|
return jsonResult(await client.producePut(`/dramas/${drama_id}`, body));
|
|
256
280
|
});
|
|
257
281
|
// ========== 项目设定页子资源(可选增强,提升一致性/风格锁)==========
|
|
258
|
-
server.tool('generate_world_concept', '(
|
|
259
|
-
'
|
|
282
|
+
server.tool('generate_world_concept', '(★默认必做·很多第三方平台漏做这步·仍走报价确认)生成世界观概念图(固定4格:全景/时代/主场景/色彩),提升整剧视觉一致性。' +
|
|
283
|
+
'★分镜后默认调这个,别跳过;但仍要告知客户预估点数、客户确认才跑(不静默扣费)。需 setting_brief ≥30字。图片步,按固定成本后付、不欠费。', { drama_id: z.number().int().positive() }, async ({ drama_id }) => jsonResult(await client.producePost(`/dramas/${drama_id}/world-concept`)));
|
|
260
284
|
server.tool('generate_art_bible', '生成美术圣经(色调/材质/气质,读角色+元数据)。文本步后付不欠费。', { drama_id: z.number().int().positive() }, async ({ drama_id }) => jsonResult(await client.producePost(`/dramas/${drama_id}/art-bible`)));
|
|
261
285
|
server.tool('extract_visual_lock', '从世界观 Brief + 角色抽取「视觉锁定」规则(写 visual_lock,统一出图风格/族裔)。文本步后付不欠费。', {
|
|
262
286
|
drama_id: z.number().int().positive(),
|
|
@@ -343,6 +367,28 @@ export function registerProduceTools(server, client) {
|
|
|
343
367
|
in_ms: z.number().int().min(0).optional(),
|
|
344
368
|
out_ms: z.number().int().min(0).optional(),
|
|
345
369
|
}, async ({ storyboard_id, in_ms, out_ms }) => jsonResult(await client.producePut(`/storyboards/${storyboard_id}/trim`, { in_ms, out_ms })));
|
|
370
|
+
server.tool('update_shot', '逐镜文本编辑:改单个分镜的文本内容(景别/动作/台词/画面描述/运镜/提示词等)。只传要改的字段、其余不动。' +
|
|
371
|
+
'**免费**(纯文本写库)。★改 dialogue 会自动失效本镜已生成的 TTS 配音与字幕(需重出 tts);' +
|
|
372
|
+
'改文本不会自动重出图/视频,如需让画面跟上文本改动,改完再 regen 对应镜。用 get_storyboards 查改后结果。', {
|
|
373
|
+
storyboard_id: z.number().int().positive(),
|
|
374
|
+
title: z.string().optional().describe('镜头标题'),
|
|
375
|
+
description: z.string().optional().describe('画面描述'),
|
|
376
|
+
shot_type: z.string().optional().describe('景别(如 特写/中景/全景/远景)'),
|
|
377
|
+
angle: z.string().optional().describe('机位角度'),
|
|
378
|
+
camera_movement: z.string().optional().describe('运镜(推/拉/摇/移/跟/固定)'),
|
|
379
|
+
action: z.string().optional().describe('动作描述'),
|
|
380
|
+
dialogue: z.string().optional().describe('台词(★改后自动失效本镜 TTS/字幕,需重出配音)'),
|
|
381
|
+
location: z.string().optional().describe('地点'),
|
|
382
|
+
time: z.string().optional().describe('时间/时段'),
|
|
383
|
+
atmosphere: z.string().optional().describe('氛围'),
|
|
384
|
+
video_prompt: z.string().optional().describe('视频生成提示词'),
|
|
385
|
+
image_prompt: z.string().optional().describe('图像生成提示词'),
|
|
386
|
+
director_note: z.string().optional().describe('导演注释'),
|
|
387
|
+
shot_intent: z.string().optional().describe('这镜为什么存在(叙事意图)'),
|
|
388
|
+
}, async ({ storyboard_id, ...fields }) => {
|
|
389
|
+
const payload = Object.fromEntries(Object.entries(fields).filter(([, v]) => v !== undefined));
|
|
390
|
+
return jsonResult(await client.producePut(`/storyboards/${storyboard_id}`, payload));
|
|
391
|
+
});
|
|
346
392
|
server.tool('rerender_episode', '按当前 timeline 重拼成片(改完镜/裁剪后用)。**免费**(纯 ffmpeg+COS),后台异步。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/re-render`)));
|
|
347
393
|
server.tool('replace_shot_dialogue', '换某镜对白音色/声线(转写+克隆重配)。后台异步,按用量后付不欠费。要求本镜有原声视频+角色声线定妆音。', { storyboard_id: z.number().int().positive() }, async ({ storyboard_id }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/dialogue-replace`)));
|
|
348
394
|
server.tool('generate_bgm', '给整集生成/更换 AI 配乐(按情绪弧线)。后台异步,按用量后付不欠费。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/bgm`)));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@starreel/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.25",
|
|
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.
|
|
5
|
+
"version": "0.1.25",
|
|
6
6
|
"websiteUrl": "https://starreel.ai",
|
|
7
7
|
"packages": [
|
|
8
8
|
{
|
|
9
9
|
"registryType": "npm",
|
|
10
10
|
"identifier": "@starreel/mcp",
|
|
11
|
-
"version": "0.1.
|
|
11
|
+
"version": "0.1.25",
|
|
12
12
|
"transport": { "type": "stdio" },
|
|
13
13
|
"environmentVariables": [
|
|
14
14
|
{
|