@starreel/mcp 0.1.32 → 0.1.34
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/dist/tools/produce.js +48 -8
- package/package.json +1 -1
- package/server.json +2 -2
package/dist/tools/produce.js
CHANGED
|
@@ -154,7 +154,9 @@ export function registerProduceTools(server, client) {
|
|
|
154
154
|
// ---------- AI 改写 / 审阅 / 改稿 ----------
|
|
155
155
|
server.tool('rewrite_script', 'AI 改写:把原始剧本改写成可拍稿(读 content → 写 script_content)。按项目类型自动选改写 agent' +
|
|
156
156
|
'(广告走 ad 改写;MV 不走标准改写会被拦)。后台异步(分钟级),文本步按 token 后付、不欠费,无需报价。' +
|
|
157
|
-
'完成后用 get_script 审阅、edit_rewritten_script 改稿。' +
|
|
157
|
+
'完成后用 get_script 审阅、edit_rewritten_script 改稿。' +
|
|
158
|
+
'★典型耗时 2~4 分钟(生产实测 ≈169 秒)。**60 秒内查不到结果是正常的,不是失败**——' +
|
|
159
|
+
'用 get_run_status 判断还在不在跑,别急着重发。' + WORKFLOW_HINT, { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/rewrite`)));
|
|
158
160
|
server.tool('get_script', '读某一集的原始内容 + AI 改写后的可拍稿 + 改写状态(供审阅、决定是否 edit_rewritten_script)。免费。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/script`)));
|
|
159
161
|
server.tool('edit_rewritten_script', '客户改 AI 改写后的可拍稿(写 script_content)。用于人工润色/纠正 AI 改写结果。免费。', {
|
|
160
162
|
episode_id: z.number().int().positive(),
|
|
@@ -162,10 +164,13 @@ export function registerProduceTools(server, client) {
|
|
|
162
164
|
}, async ({ episode_id, script }) => jsonResult(await client.producePut(`/episodes/${episode_id}/rewritten-script`, { script_content: script })));
|
|
163
165
|
// ---------- 提取(角色/场景/道具) ----------
|
|
164
166
|
server.tool('extract_assets', '从可拍稿提取角色/场景/道具(一次写三表,是下游一致性的地基)。后台异步,文本步后付不欠费。' +
|
|
165
|
-
'前置:已 rewrite_script(或至少 set_script)。' +
|
|
167
|
+
'前置:已 rewrite_script(或至少 set_script)。' +
|
|
168
|
+
'★分钟级后台任务;用 get_run_status 判断是否还在跑,别拿 60 秒当失败判据。' + WORKFLOW_HINT, { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/extract`)));
|
|
166
169
|
// ---------- 完整工作流进度 ----------
|
|
167
|
-
server.tool('get_pipeline_status', '
|
|
168
|
-
'
|
|
170
|
+
server.tool('get_pipeline_status', '查某一集完整工作流的进度(script_rewrite/提取/分镜/语音/出图/出视频/合成/配乐/终拼…各步 ' +
|
|
171
|
+
'done/partial/pending/not_required)。照它按序推进、不跳步。免费。' +
|
|
172
|
+
'★not_required=当前模式不需要该步(如原声剧的 TTS 三步、关配乐的 generate_bgm),不是没做完,别去补做。' +
|
|
173
|
+
'图片/视频分母已剔除卡镜(shots_not_applicable);merge_episode.bgm_stale=true 表示配乐晚于成片,重新 compose_episode 即可。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/pipeline-status`)));
|
|
169
174
|
// ---------- 角色定妆图(一致性锚) ----------
|
|
170
175
|
server.tool('quote_character_portraits', '报价:给缺定妆图的角色批量出定妆图要多少点。返回 portraits_to_generate、estimated_points、quote_id。零扣费。' +
|
|
171
176
|
'定妆图是身份一致性的锚(缺它角色会漂移),强烈建议出视频前先出。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/portraits/quote`)));
|
|
@@ -184,7 +189,10 @@ export function registerProduceTools(server, client) {
|
|
|
184
189
|
'拿到后把点数告诉用户征求同意,再用 quote_id 调 generate_storyboards。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/storyboards/quote`)));
|
|
185
190
|
server.tool('generate_storyboards', '确认后拆镜:后台跑(分钟级),立即返回 status:generating。用 get_storyboards 轮询。' +
|
|
186
191
|
'★注意:拆镜会**替换整集所有已有分镜**(已调好/已出图的全丢、要重花钱重来)。每镜 5-7 秒是对 AI 出视频' +
|
|
187
|
-
'优化的**正常**时长,别因「一镜偏长」觉得有问题就重拆。已有分镜时后端会拦,确认重拆才带 confirm_replace=true。' +
|
|
192
|
+
'优化的**正常**时长,别因「一镜偏长」觉得有问题就重拆。已有分镜时后端会拦,确认重拆才带 confirm_replace=true。' +
|
|
193
|
+
'★典型耗时 5~10 分钟(生产实测 7~8.4 分钟;**单次 LLM 调用就可能 3~7 分钟**)。' +
|
|
194
|
+
'**60 秒、甚至 3 分钟内查不到分镜都是正常的**——用 get_run_status 判断是否还在跑。' +
|
|
195
|
+
'running:true 就继续等;重发一次等于把整集分镜重来一遍。' + CONFIRM_HINT, {
|
|
188
196
|
episode_id: z.number().int().positive(),
|
|
189
197
|
quote_id: z.string().describe('来自 quote_storyboards'),
|
|
190
198
|
confirm_replace: z.boolean().optional().describe('本集已有分镜时必须 true 才重拆(会替换整集所有分镜,已出图白费)'),
|
|
@@ -198,6 +206,16 @@ export function registerProduceTools(server, client) {
|
|
|
198
206
|
'★若某镜带 reopen_pair_id:该镜首尾帧同时生成时只有一侧真的有问题、另一侧是无辜陪拒,' +
|
|
199
207
|
'原样传给 generate_shot_frame 的 reopen_pair_id 参数可以只重掷有问题的那一侧(省一半算力/费用,' +
|
|
200
208
|
'不会拿去生成一张这次根本没打算重做的图)。没有这个字段就按 fail_reason/retryable 走常规重试。免费。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/storyboards`)));
|
|
209
|
+
// ---------- 在途运行状态(免费):区分「还在跑」和「已经死了」----------
|
|
210
|
+
server.tool('get_run_status', '(★免费·长耗时操作后必用)查这一集当前有没有 agent 正在跑。' +
|
|
211
|
+
'rewrite_script / extract_assets / generate_storyboards 都是**分钟级**后台任务,' +
|
|
212
|
+
'它们只回一句 status:"generating",本工具是唯一能区分「还在跑」与「已经结束」的手段。\n' +
|
|
213
|
+
'★典型耗时(生产实测):改写 2~4 分钟、拆镜 5~10 分钟——**单次 LLM 调用就可能 3~7 分钟**。' +
|
|
214
|
+
'所以 60 秒内查不到结果是完全正常的,绝不是失败。\n' +
|
|
215
|
+
'用法:发起后每 30~60 秒调一次。running:true = 还在跑,继续等,**千万不要重发**' +
|
|
216
|
+
'(重发拆镜会替换整集分镜,已调好/已出图的全丢、要重花钱);' +
|
|
217
|
+
'running:false = 那次已经结束,这时才去 get_storyboards / get_script 看产物有没有落库。\n' +
|
|
218
|
+
'⚠️ 服务重启会让在途登记归零,重启期间发起的运行也会显示为无在途。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/run-status`)));
|
|
201
219
|
// ---------- 分镜级 AI 操作:2 个免费质量闸 + 3 个 AI 增强(★都在出图前做)----------
|
|
202
220
|
server.tool('run_precheck', '(★推荐·免费质量闸)出图/出视频前跑生成前预检,把会被拒的镜提前揪出。免费、不扣费。' +
|
|
203
221
|
'强烈建议 generate_frames/generate_videos 前调,防白花钱被拒。\n' +
|
|
@@ -271,8 +289,14 @@ export function registerProduceTools(server, client) {
|
|
|
271
289
|
'要求本集已出首帧(未出会被拒)。用 get_storyboards 轮询 video_url 逐镜填充即完成。' + CONFIRM_HINT, { episode_id: z.number().int().positive(), quote_id: z.string().describe('来自 quote_videos') }, async ({ episode_id, quote_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/videos/generate`, { quote_id })));
|
|
272
290
|
// ---------- 成片(compose/终拼) ----------
|
|
273
291
|
server.tool('compose_episode', '把某一集所有镜头视频拼成一条成片(终拼)。**免费**(纯拼接,无需报价确认),后台异步。' +
|
|
274
|
-
'
|
|
275
|
-
|
|
292
|
+
'发起前有终拼预检:缺视频的镜或仍在生成中的视频任务会 400 硬阻断并列出问题镜(blockers),' +
|
|
293
|
+
'补齐后重试;确要拼部分成片传 force=true(缺视频镜被跳过,成片缺镜,留痕)。' +
|
|
294
|
+
'响应里的 advisories(时长偏差/孤儿任务/缺TTS)只提醒不阻断,建议逐条处理后再拼。发起后用 get_final_cut 轮询。', {
|
|
295
|
+
episode_id: z.number().int().positive(),
|
|
296
|
+
force: z.boolean().optional().describe('true=预检有硬阻断也强制照拼(默认拦截)。缺视频的镜会被静默跳过,成片为部分'),
|
|
297
|
+
}, async ({ episode_id, force }) => jsonResult(await client.producePost(`/episodes/${episode_id}/compose`, force ? { force: true } : {})));
|
|
298
|
+
server.tool('get_final_cut', '查某一集成片状态与下载链接。status=completed 时返回 download_url(我方 COS 直链,可直接下载)。免费。' +
|
|
299
|
+
'★bgm_stale=true 表示配乐在成片之后生成/改动、尚未进成片:重新 compose_episode(免费)即可,别用 re-render。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/final-cut`)));
|
|
276
300
|
server.tool('get_export', '查某一集导出/母版状态(成片终拼后的可下载母版)。免费。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/export`)));
|
|
277
301
|
// ========== 项目设定(建后可改)==========
|
|
278
302
|
server.tool('update_project_settings', '建剧后修改项目设定。除画幅/分辨率/世界观Brief/族裔/题材/导演风格外,现覆盖★整剧视觉一致性锚' +
|
|
@@ -431,7 +455,23 @@ export function registerProduceTools(server, client) {
|
|
|
431
455
|
});
|
|
432
456
|
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`)));
|
|
433
457
|
server.tool('replace_shot_dialogue', '换某镜对白音色/声线(转写+克隆重配)。后台异步,按用量后付不欠费。要求本镜有原声视频+角色声线定妆音。', { storyboard_id: z.number().int().positive() }, async ({ storyboard_id }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/dialogue-replace`)));
|
|
434
|
-
server.tool('generate_bgm', '给整集生成/更换 AI 配乐(按情绪弧线)
|
|
458
|
+
server.tool('generate_bgm', '给整集生成/更换 AI 配乐(按情绪弧线)。后台异步,按用量后付不欠费。返回情绪弧线段数与预估耗时;' +
|
|
459
|
+
'用 get_bgm_status 轮询生成进度。★配乐生成/改动**不会自动进已有成片**——完成后必须重新 ' +
|
|
460
|
+
'compose_episode(免费)才能听到;get_final_cut 的 bgm_stale=true 就是在提示这一步。别用 re-render(吃旧时间线,不含新配乐)。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/bgm`)));
|
|
461
|
+
server.tool('set_shot_name_card', '给某一镜加/改/清「角色名卡」(画面侧边竖排人物名+朱红印章,终拼时烧进成片,含预览一致的书法字体)。' +
|
|
462
|
+
'name 传空字符串=清除本镜名卡。免费(纯数据,填了就显示)。适合群像出场镜逐个标注人物名。' +
|
|
463
|
+
'★别自己下载视频叠字再上传——那会绕开渲染机字体与印章素材,预览/成片不一致。', {
|
|
464
|
+
storyboard_id: z.number().int().positive(),
|
|
465
|
+
name: z.string().describe('人物名(竖排渲染);空字符串=清除名卡'),
|
|
466
|
+
seal: z.string().optional().describe('印章文字(默认取名字末字)'),
|
|
467
|
+
side: z.enum(['left', 'right']).optional().describe('名卡在画面哪一侧,默认 right'),
|
|
468
|
+
duration_ms: z.number().int().positive().optional().describe('显示时长毫秒,默认 3000'),
|
|
469
|
+
}, async ({ storyboard_id, name, seal, side, duration_ms }) => jsonResult(await client.producePut(`/storyboards/${storyboard_id}/name-card`, {
|
|
470
|
+
name, ...(seal !== undefined ? { seal } : {}), ...(side !== undefined ? { side } : {}),
|
|
471
|
+
...(duration_ms !== undefined ? { duration_ms } : {}),
|
|
472
|
+
})));
|
|
473
|
+
server.tool('get_bgm_status', '查某集 AI 配乐生成状态:running(是否在生成)+已入库的配乐轨列表(track/覆盖镜段/淡入淡出)+cue 数。免费。' +
|
|
474
|
+
'配乐 done 后需重新 compose_episode 才进成片。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/bgm-status`)));
|
|
435
475
|
server.tool('translate_subtitles', '把某集字幕翻译成第二语言并开启双语。后台异步,按用量后付不欠费。', { episode_id: z.number().int().positive(), lang: z.string().describe('目标语言(如 en/ja/ko)') }, async ({ episode_id, lang }) => jsonResult(await client.producePost(`/episodes/${episode_id}/subtitles/translate`, { lang })));
|
|
436
476
|
// ========== P1 · 读取层(闭环必需:能读回自己建的东西)==========
|
|
437
477
|
server.tool('list_dramas', '列出我名下的所有短剧(drama_id/剧名/类型/集数/进度)。免费。', {}, async () => jsonResult(await client.produceGet('/dramas')));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@starreel/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.34",
|
|
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.34",
|
|
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.34",
|
|
12
12
|
"transport": { "type": "stdio" },
|
|
13
13
|
"environmentVariables": [
|
|
14
14
|
{
|