@shuffll/mcp-server 1.0.0
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/build/api-client.d.ts +56 -0
- package/build/api-client.js +216 -0
- package/build/api-client.js.map +1 -0
- package/build/config.d.ts +7 -0
- package/build/config.js +17 -0
- package/build/config.js.map +1 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +35 -0
- package/build/index.js.map +1 -0
- package/build/resources.d.ts +4 -0
- package/build/resources.js +119 -0
- package/build/resources.js.map +1 -0
- package/build/tools/content-tools.d.ts +4 -0
- package/build/tools/content-tools.js +112 -0
- package/build/tools/content-tools.js.map +1 -0
- package/build/tools/edit-tools.d.ts +4 -0
- package/build/tools/edit-tools.js +290 -0
- package/build/tools/edit-tools.js.map +1 -0
- package/build/tools/project-tools.d.ts +4 -0
- package/build/tools/project-tools.js +179 -0
- package/build/tools/project-tools.js.map +1 -0
- package/build/tools/scene-tools.d.ts +4 -0
- package/build/tools/scene-tools.js +157 -0
- package/build/tools/scene-tools.js.map +1 -0
- package/build/types.d.ts +169 -0
- package/build/types.js +5 -0
- package/build/types.js.map +1 -0
- package/build/utils/logger.d.ts +5 -0
- package/build/utils/logger.js +15 -0
- package/build/utils/logger.js.map +1 -0
- package/build/utils/polling.d.ts +5 -0
- package/build/utils/polling.js +11 -0
- package/build/utils/polling.js.map +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ShufflApiError } from "../api-client.js";
|
|
3
|
+
function formatError(error) {
|
|
4
|
+
if (error instanceof ShufflApiError) {
|
|
5
|
+
return `Shuffll API error (${error.statusCode}): ${JSON.stringify(error.responseBody)}`;
|
|
6
|
+
}
|
|
7
|
+
if (error instanceof Error) {
|
|
8
|
+
return `Error: ${error.message}`;
|
|
9
|
+
}
|
|
10
|
+
return `Unknown error: ${String(error)}`;
|
|
11
|
+
}
|
|
12
|
+
export function registerEditTools(server, apiClient, _config) {
|
|
13
|
+
// ----------------------------------------------------------------
|
|
14
|
+
// create_edit
|
|
15
|
+
// ----------------------------------------------------------------
|
|
16
|
+
server.tool("create_edit", "Create a default edit (video compilation) for a project. This automatically configures the edit with all scenes and their selected takes. Returns the full project with the new edit.", {
|
|
17
|
+
projectId: z.string().describe("The project ID"),
|
|
18
|
+
}, async (args) => {
|
|
19
|
+
try {
|
|
20
|
+
const result = await apiClient.createDefaultEdit(args.projectId);
|
|
21
|
+
return {
|
|
22
|
+
content: [
|
|
23
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
24
|
+
],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
30
|
+
isError: true,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
// ----------------------------------------------------------------
|
|
35
|
+
// configure_edit
|
|
36
|
+
// ----------------------------------------------------------------
|
|
37
|
+
server.tool("configure_edit", "Update edit configuration properties. Common properties: 'exportQuality' (1080, 720, 480), 'aspectRatio' ('16/9', '1/1', '9/16'), 'toCleanAudio' (boolean), 'toAddWatermark' (boolean), 'toSegmentVideo' (boolean).", {
|
|
38
|
+
projectId: z.string().describe("The project ID"),
|
|
39
|
+
editId: z.string().describe("The edit ID to configure"),
|
|
40
|
+
properties: z
|
|
41
|
+
.array(z.object({
|
|
42
|
+
key: z.string().describe("Property key"),
|
|
43
|
+
value: z.any().describe("Property value"),
|
|
44
|
+
}))
|
|
45
|
+
.describe("Array of properties to update (e.g., [{ key: 'exportQuality', value: 1080 }])"),
|
|
46
|
+
}, async (args) => {
|
|
47
|
+
try {
|
|
48
|
+
const result = await apiClient.updateEditProperty(args.projectId, args.editId, args.properties);
|
|
49
|
+
return {
|
|
50
|
+
content: [
|
|
51
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return {
|
|
57
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
58
|
+
isError: true,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
// ----------------------------------------------------------------
|
|
63
|
+
// update_edit_shots
|
|
64
|
+
// ----------------------------------------------------------------
|
|
65
|
+
server.tool("update_edit_shots", "Update which scene/take pairs are included in the edit timeline and their order. Each shot references a scene and its selected take.", {
|
|
66
|
+
projectId: z.string().describe("The project ID"),
|
|
67
|
+
editId: z.string().describe("The edit ID"),
|
|
68
|
+
selectedShots: z
|
|
69
|
+
.array(z.object({
|
|
70
|
+
sceneId: z.string().describe("Scene ID"),
|
|
71
|
+
takeId: z.string().describe("Take ID from the scene"),
|
|
72
|
+
trims: z
|
|
73
|
+
.object({
|
|
74
|
+
videoTrims: z
|
|
75
|
+
.object({
|
|
76
|
+
start: z.number(),
|
|
77
|
+
end: z.number(),
|
|
78
|
+
})
|
|
79
|
+
.optional(),
|
|
80
|
+
lottieTrims: z
|
|
81
|
+
.object({
|
|
82
|
+
start: z.number(),
|
|
83
|
+
end: z.number(),
|
|
84
|
+
})
|
|
85
|
+
.optional(),
|
|
86
|
+
})
|
|
87
|
+
.optional()
|
|
88
|
+
.describe("Optional trim settings for this shot"),
|
|
89
|
+
}))
|
|
90
|
+
.describe("Array of scene/take pairs defining the edit timeline order"),
|
|
91
|
+
}, async (args) => {
|
|
92
|
+
try {
|
|
93
|
+
const result = await apiClient.updateEditShots(args.projectId, args.editId, args.selectedShots);
|
|
94
|
+
return {
|
|
95
|
+
content: [
|
|
96
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
97
|
+
],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
return {
|
|
102
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
103
|
+
isError: true,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
// ----------------------------------------------------------------
|
|
108
|
+
// export_video
|
|
109
|
+
// ----------------------------------------------------------------
|
|
110
|
+
server.tool("export_video", "Start exporting/rendering the final video. Returns the edit ID. Use get_export_status to track rendering progress and get the download URLs when complete.", {
|
|
111
|
+
projectId: z.string().describe("The project ID"),
|
|
112
|
+
editId: z
|
|
113
|
+
.string()
|
|
114
|
+
.describe("The edit ID to export"),
|
|
115
|
+
}, async (args) => {
|
|
116
|
+
try {
|
|
117
|
+
const result = await apiClient.exportEdit(args.projectId, args.editId);
|
|
118
|
+
return {
|
|
119
|
+
content: [
|
|
120
|
+
{
|
|
121
|
+
type: "text",
|
|
122
|
+
text: JSON.stringify({
|
|
123
|
+
...result,
|
|
124
|
+
message: "Export started. Use get_export_status to track progress.",
|
|
125
|
+
}, null, 2),
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
return {
|
|
132
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
133
|
+
isError: true,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
// ----------------------------------------------------------------
|
|
138
|
+
// get_export_status
|
|
139
|
+
// ----------------------------------------------------------------
|
|
140
|
+
server.tool("get_export_status", "Check the export/rendering progress of a video. Returns whether it is done and the download URLs (uploadPath for MP4, dashPath for DASH streaming) when complete.", {
|
|
141
|
+
projectId: z.string().describe("The project ID"),
|
|
142
|
+
editId: z.string().describe("The edit ID to check"),
|
|
143
|
+
}, async (args) => {
|
|
144
|
+
try {
|
|
145
|
+
const result = await apiClient.getExportStatus(args.projectId, args.editId);
|
|
146
|
+
return {
|
|
147
|
+
content: [
|
|
148
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
149
|
+
],
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
return {
|
|
154
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
155
|
+
isError: true,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
// ----------------------------------------------------------------
|
|
160
|
+
// get_enhance_status
|
|
161
|
+
// ----------------------------------------------------------------
|
|
162
|
+
server.tool("get_enhance_status", "Check the enhancement progress of a video edit. Enhancements include AI voice generation, subtitle generation, audio cleaning, and video segmentation. Returns percentage and done status.", {
|
|
163
|
+
projectId: z.string().describe("The project ID"),
|
|
164
|
+
editId: z.string().describe("The edit ID to check"),
|
|
165
|
+
}, async (args) => {
|
|
166
|
+
try {
|
|
167
|
+
const result = await apiClient.getEnhanceStatus(args.projectId, args.editId);
|
|
168
|
+
return {
|
|
169
|
+
content: [
|
|
170
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
171
|
+
],
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
return {
|
|
176
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
177
|
+
isError: true,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
// ----------------------------------------------------------------
|
|
182
|
+
// generate_ai_voice
|
|
183
|
+
// ----------------------------------------------------------------
|
|
184
|
+
server.tool("generate_ai_voice", "Trigger AI text-to-speech voice generation for all scenes in an edit. This generates audio from the scene scripts using the project's AI voice settings.", {
|
|
185
|
+
projectId: z.string().describe("The project ID"),
|
|
186
|
+
editId: z.string().describe("The edit ID"),
|
|
187
|
+
}, async (args) => {
|
|
188
|
+
try {
|
|
189
|
+
const result = await apiClient.generateAiVoiceForEdit(args.projectId, args.editId);
|
|
190
|
+
return {
|
|
191
|
+
content: [
|
|
192
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
193
|
+
],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
return {
|
|
198
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
199
|
+
isError: true,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
// ----------------------------------------------------------------
|
|
204
|
+
// update_background_music
|
|
205
|
+
// ----------------------------------------------------------------
|
|
206
|
+
server.tool("update_background_music", "Update background music settings for an edit. Properties include 'volume' (0-1), 'toFadeAudio' (boolean), 'path' (music file path).", {
|
|
207
|
+
projectId: z.string().describe("The project ID"),
|
|
208
|
+
editId: z.string().describe("The edit ID"),
|
|
209
|
+
properties: z
|
|
210
|
+
.array(z.object({
|
|
211
|
+
key: z.string().describe("BGM property key (e.g., 'volume', 'toFadeAudio')"),
|
|
212
|
+
value: z.any().describe("The new value"),
|
|
213
|
+
}))
|
|
214
|
+
.describe("Array of background music properties to update"),
|
|
215
|
+
}, async (args) => {
|
|
216
|
+
try {
|
|
217
|
+
const result = await apiClient.updateBGMusic(args.projectId, args.editId, args.properties);
|
|
218
|
+
return {
|
|
219
|
+
content: [
|
|
220
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
221
|
+
],
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
return {
|
|
226
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
227
|
+
isError: true,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
// ----------------------------------------------------------------
|
|
232
|
+
// update_ai_voice_settings
|
|
233
|
+
// ----------------------------------------------------------------
|
|
234
|
+
server.tool("update_ai_voice_settings", "Update AI voice settings for a project. Settings include 'voiceId' (voice identifier), 'voiceSpeed' (playback speed multiplier), 'voiceInstructions' (text instructions for the AI voice), 'voiceType' (voice category).", {
|
|
235
|
+
projectId: z.string().describe("The project ID"),
|
|
236
|
+
key: z
|
|
237
|
+
.string()
|
|
238
|
+
.describe("Setting to update: 'voiceId', 'voiceSpeed', 'voiceInstructions', 'voiceType'"),
|
|
239
|
+
value: z.any().describe("New value for the setting"),
|
|
240
|
+
regenerateVoice: z
|
|
241
|
+
.boolean()
|
|
242
|
+
.default(false)
|
|
243
|
+
.describe("Whether to regenerate the AI voice immediately after updating the setting"),
|
|
244
|
+
}, async (args) => {
|
|
245
|
+
try {
|
|
246
|
+
const result = await apiClient.updateAiVoice(args.projectId, args.key, args.value, args.regenerateVoice);
|
|
247
|
+
return {
|
|
248
|
+
content: [
|
|
249
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
250
|
+
],
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
return {
|
|
255
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
256
|
+
isError: true,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
// ----------------------------------------------------------------
|
|
261
|
+
// update_ai_avatar_settings
|
|
262
|
+
// ----------------------------------------------------------------
|
|
263
|
+
server.tool("update_ai_avatar_settings", "Update AI avatar settings for a project. Settings include 'avatarId' (avatar identifier), 'accent' (speech accent), 'avatarName' (display name), 'avatarType' (avatar category).", {
|
|
264
|
+
projectId: z.string().describe("The project ID"),
|
|
265
|
+
key: z
|
|
266
|
+
.string()
|
|
267
|
+
.describe("Setting to update: 'avatarId', 'accent', 'avatarName', 'avatarType'"),
|
|
268
|
+
value: z.any().describe("New value for the setting"),
|
|
269
|
+
regenerateVoice: z
|
|
270
|
+
.boolean()
|
|
271
|
+
.default(false)
|
|
272
|
+
.describe("Whether to regenerate the voice after changing avatar settings"),
|
|
273
|
+
}, async (args) => {
|
|
274
|
+
try {
|
|
275
|
+
const result = await apiClient.updateAiAvatar(args.projectId, args.key, args.value, args.regenerateVoice);
|
|
276
|
+
return {
|
|
277
|
+
content: [
|
|
278
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
279
|
+
],
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
return {
|
|
284
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
285
|
+
isError: true,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
//# sourceMappingURL=edit-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-tools.js","sourceRoot":"","sources":["../../src/tools/edit-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { ShufflApiClient } from "../api-client.js";
|
|
3
|
+
import { ShufflMcpConfig } from "../config.js";
|
|
4
|
+
export declare function registerProjectTools(server: McpServer, apiClient: ShufflApiClient, _config: ShufflMcpConfig): void;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ShufflApiError } from "../api-client.js";
|
|
3
|
+
function formatError(error) {
|
|
4
|
+
if (error instanceof ShufflApiError) {
|
|
5
|
+
return `Shuffll API error (${error.statusCode}): ${JSON.stringify(error.responseBody)}`;
|
|
6
|
+
}
|
|
7
|
+
if (error instanceof Error) {
|
|
8
|
+
return `Error: ${error.message}`;
|
|
9
|
+
}
|
|
10
|
+
return `Unknown error: ${String(error)}`;
|
|
11
|
+
}
|
|
12
|
+
export function registerProjectTools(server, apiClient, _config) {
|
|
13
|
+
// ----------------------------------------------------------------
|
|
14
|
+
// create_video_project
|
|
15
|
+
// ----------------------------------------------------------------
|
|
16
|
+
server.tool("create_video_project", "Create a new Shuffll video project from a text prompt. Returns the project ID. Use get_project_creation_status to poll progress, then get_project to retrieve full details once done.", {
|
|
17
|
+
prompt: z
|
|
18
|
+
.string()
|
|
19
|
+
.describe("Creative brief describing the video (e.g., 'A product demo for our new CRM software')"),
|
|
20
|
+
videoType: z
|
|
21
|
+
.enum(["ai-voice", "avatar", "camera", "mic"])
|
|
22
|
+
.default("ai-voice")
|
|
23
|
+
.describe("Type of video: 'ai-voice' for AI voiceover, 'avatar' for AI avatar, 'camera' for user-recorded video, 'mic' for audio-only recording"),
|
|
24
|
+
toneOfVoice: z
|
|
25
|
+
.enum([
|
|
26
|
+
"natural",
|
|
27
|
+
"professional",
|
|
28
|
+
"informative",
|
|
29
|
+
"inspirational",
|
|
30
|
+
"energetic",
|
|
31
|
+
])
|
|
32
|
+
.default("natural")
|
|
33
|
+
.optional()
|
|
34
|
+
.describe("The tone of the generated script"),
|
|
35
|
+
language: z
|
|
36
|
+
.enum(["auto", "en", "iw", "es", "fr", "zh"])
|
|
37
|
+
.default("en")
|
|
38
|
+
.optional()
|
|
39
|
+
.describe("Language code for the video content"),
|
|
40
|
+
templateId: z
|
|
41
|
+
.string()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe("Optional template ID to base the project on. Use the shuffll://templates resource to find available templates."),
|
|
44
|
+
autoEnhance: z
|
|
45
|
+
.boolean()
|
|
46
|
+
.default(true)
|
|
47
|
+
.optional()
|
|
48
|
+
.describe("Whether to auto-enhance the video (AI voice, images, etc.) after creation"),
|
|
49
|
+
autoExport: z
|
|
50
|
+
.boolean()
|
|
51
|
+
.default(true)
|
|
52
|
+
.optional()
|
|
53
|
+
.describe("Whether to auto-export the video after enhancement completes"),
|
|
54
|
+
}, async (args) => {
|
|
55
|
+
try {
|
|
56
|
+
const body = {
|
|
57
|
+
prompt: args.prompt,
|
|
58
|
+
recordingType: args.videoType,
|
|
59
|
+
toneOfVoice: args.toneOfVoice,
|
|
60
|
+
language: { code: args.language || "en" },
|
|
61
|
+
templateId: args.templateId,
|
|
62
|
+
toAutoEnhance: args.autoEnhance,
|
|
63
|
+
toAutoExport: args.autoExport,
|
|
64
|
+
};
|
|
65
|
+
const result = await apiClient.createProject(body);
|
|
66
|
+
return {
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: "text",
|
|
70
|
+
text: JSON.stringify({
|
|
71
|
+
projectId: result.projectId,
|
|
72
|
+
message: "Project creation started. Use get_project_creation_status to check progress.",
|
|
73
|
+
}, null, 2),
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
return {
|
|
80
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
81
|
+
isError: true,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
// ----------------------------------------------------------------
|
|
86
|
+
// get_project
|
|
87
|
+
// ----------------------------------------------------------------
|
|
88
|
+
server.tool("get_project", "Get full details of a Shuffll video project including all scenes, takes, edits, status, and configuration.", {
|
|
89
|
+
projectId: z.string().describe("The project ID to retrieve"),
|
|
90
|
+
}, async (args) => {
|
|
91
|
+
try {
|
|
92
|
+
const project = await apiClient.getProject(args.projectId);
|
|
93
|
+
return {
|
|
94
|
+
content: [
|
|
95
|
+
{ type: "text", text: JSON.stringify(project, null, 2) },
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
return {
|
|
101
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
102
|
+
isError: true,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
// ----------------------------------------------------------------
|
|
107
|
+
// get_project_creation_status
|
|
108
|
+
// ----------------------------------------------------------------
|
|
109
|
+
server.tool("get_project_creation_status", "Check the AI generation progress of a video project. Returns 'STRUCTURE' (generating scene structure), 'GENERATING_IMAGES' (creating visual assets), or 'DONE' (ready for editing/export). Poll this after create_video_project.", {
|
|
110
|
+
projectId: z.string().describe("The project ID to check"),
|
|
111
|
+
}, async (args) => {
|
|
112
|
+
try {
|
|
113
|
+
const status = await apiClient.getCreationStatus(args.projectId);
|
|
114
|
+
return {
|
|
115
|
+
content: [
|
|
116
|
+
{ type: "text", text: JSON.stringify(status, null, 2) },
|
|
117
|
+
],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
return {
|
|
122
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
123
|
+
isError: true,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
// ----------------------------------------------------------------
|
|
128
|
+
// update_project
|
|
129
|
+
// ----------------------------------------------------------------
|
|
130
|
+
server.tool("update_project", "Update a property of a video project. Common keys: 'name' (project name), 'statuses.general' (project status), 'aiVoiceSettings.voiceId', 'aiVoiceSettings.voiceSpeed'.", {
|
|
131
|
+
projectId: z.string().describe("The project ID to update"),
|
|
132
|
+
key: z
|
|
133
|
+
.string()
|
|
134
|
+
.describe("The property key to update (e.g., 'name', 'statuses.general')"),
|
|
135
|
+
value: z.any().describe("The new value for the property"),
|
|
136
|
+
}, async (args) => {
|
|
137
|
+
try {
|
|
138
|
+
const result = await apiClient.updateProject(args.projectId, args.key, args.value);
|
|
139
|
+
return {
|
|
140
|
+
content: [
|
|
141
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
142
|
+
],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
return {
|
|
147
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
148
|
+
isError: true,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
// ----------------------------------------------------------------
|
|
153
|
+
// delete_project
|
|
154
|
+
// ----------------------------------------------------------------
|
|
155
|
+
server.tool("delete_project", "Permanently delete a video project and all its associated data.", {
|
|
156
|
+
projectId: z.string().describe("The project ID to delete"),
|
|
157
|
+
}, async (args) => {
|
|
158
|
+
try {
|
|
159
|
+
await apiClient.deleteProject(args.projectId);
|
|
160
|
+
return {
|
|
161
|
+
content: [
|
|
162
|
+
{
|
|
163
|
+
type: "text",
|
|
164
|
+
text: JSON.stringify({
|
|
165
|
+
message: `Project ${args.projectId} deleted successfully.`,
|
|
166
|
+
}),
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
return {
|
|
173
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
174
|
+
isError: true,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=project-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-tools.js","sourceRoot":"","sources":["../../src/tools/project-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { ShufflApiClient } from "../api-client.js";
|
|
3
|
+
import { ShufflMcpConfig } from "../config.js";
|
|
4
|
+
export declare function registerSceneTools(server: McpServer, apiClient: ShufflApiClient, _config: ShufflMcpConfig): void;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ShufflApiError } from "../api-client.js";
|
|
3
|
+
function formatError(error) {
|
|
4
|
+
if (error instanceof ShufflApiError) {
|
|
5
|
+
return `Shuffll API error (${error.statusCode}): ${JSON.stringify(error.responseBody)}`;
|
|
6
|
+
}
|
|
7
|
+
if (error instanceof Error) {
|
|
8
|
+
return `Error: ${error.message}`;
|
|
9
|
+
}
|
|
10
|
+
return `Unknown error: ${String(error)}`;
|
|
11
|
+
}
|
|
12
|
+
export function registerSceneTools(server, apiClient, _config) {
|
|
13
|
+
// ----------------------------------------------------------------
|
|
14
|
+
// add_scene
|
|
15
|
+
// ----------------------------------------------------------------
|
|
16
|
+
server.tool("add_scene", "Add a new scene to a video project. Scenes are the building blocks of a video — each has a layout (composition) and content. Common composition types: 'vid_clean' (clean video), 'headline_and_subtitle_txt' (text overlay), 'img_single' (single image), 'logo_intro' (logo animation), 'cta_txt' (call to action).", {
|
|
17
|
+
projectId: z.string().describe("The project ID"),
|
|
18
|
+
compositionType: z
|
|
19
|
+
.string()
|
|
20
|
+
.describe("The composition/layout type for the new scene (e.g., 'vid_clean', 'headline_and_subtitle_txt', 'img_single', 'logo_intro', 'cta_txt'). Use get_project to see composition types of existing scenes."),
|
|
21
|
+
position: z
|
|
22
|
+
.enum(["before", "after"])
|
|
23
|
+
.default("after")
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Insert the scene before or after the reference scene"),
|
|
26
|
+
referenceSceneId: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("The scene ID to position relative to. If omitted, the scene is added at the end."),
|
|
30
|
+
}, async (args) => {
|
|
31
|
+
try {
|
|
32
|
+
const relativePosition = args.referenceSceneId
|
|
33
|
+
? {
|
|
34
|
+
position: args.position || "after",
|
|
35
|
+
sceneId: args.referenceSceneId,
|
|
36
|
+
}
|
|
37
|
+
: undefined;
|
|
38
|
+
const result = await apiClient.addScene(args.projectId, args.compositionType, relativePosition);
|
|
39
|
+
return {
|
|
40
|
+
content: [
|
|
41
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
return {
|
|
47
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
48
|
+
isError: true,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
// ----------------------------------------------------------------
|
|
53
|
+
// update_scene
|
|
54
|
+
// ----------------------------------------------------------------
|
|
55
|
+
server.tool("update_scene", "Update a scene's properties. Common keys: 'copy.script' (voiceover script text), 'copy.directorTip' (recording directions), 'copy.imagePrompt' (AI image generation prompt), 'name' (scene title), 'isHidden' (hide from edit).", {
|
|
56
|
+
projectId: z.string().describe("The project ID"),
|
|
57
|
+
sceneId: z.string().describe("The scene ID to update"),
|
|
58
|
+
key: z
|
|
59
|
+
.string()
|
|
60
|
+
.describe("The property key to update (e.g., 'copy.script', 'name', 'isHidden')"),
|
|
61
|
+
value: z
|
|
62
|
+
.any()
|
|
63
|
+
.describe("The new value for the property"),
|
|
64
|
+
}, async (args) => {
|
|
65
|
+
try {
|
|
66
|
+
const result = await apiClient.updateScene(args.projectId, args.sceneId, args.key, args.value);
|
|
67
|
+
return {
|
|
68
|
+
content: [
|
|
69
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return {
|
|
75
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
76
|
+
isError: true,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
// ----------------------------------------------------------------
|
|
81
|
+
// update_scene_composition
|
|
82
|
+
// ----------------------------------------------------------------
|
|
83
|
+
server.tool("update_scene_composition", "Change the layout/composition type of an existing scene (e.g., switch from text-only to image+text).", {
|
|
84
|
+
projectId: z.string().describe("The project ID"),
|
|
85
|
+
sceneId: z.string().describe("The scene ID to update"),
|
|
86
|
+
compositionType: z
|
|
87
|
+
.string()
|
|
88
|
+
.describe("The new composition type (e.g., 'vid_clean', 'headline_and_subtitle_txt', 'img_single')"),
|
|
89
|
+
}, async (args) => {
|
|
90
|
+
try {
|
|
91
|
+
const result = await apiClient.updateSceneComposition(args.projectId, args.sceneId, args.compositionType);
|
|
92
|
+
return {
|
|
93
|
+
content: [
|
|
94
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
95
|
+
],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
return {
|
|
100
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
101
|
+
isError: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
// ----------------------------------------------------------------
|
|
106
|
+
// delete_scene
|
|
107
|
+
// ----------------------------------------------------------------
|
|
108
|
+
server.tool("delete_scene", "Remove a scene from a video project.", {
|
|
109
|
+
projectId: z.string().describe("The project ID"),
|
|
110
|
+
sceneId: z.string().describe("The scene ID to delete"),
|
|
111
|
+
}, async (args) => {
|
|
112
|
+
try {
|
|
113
|
+
await apiClient.deleteScene(args.projectId, args.sceneId);
|
|
114
|
+
return {
|
|
115
|
+
content: [
|
|
116
|
+
{
|
|
117
|
+
type: "text",
|
|
118
|
+
text: JSON.stringify({
|
|
119
|
+
message: `Scene ${args.sceneId} deleted successfully.`,
|
|
120
|
+
}),
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
return {
|
|
127
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
128
|
+
isError: true,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
// ----------------------------------------------------------------
|
|
133
|
+
// generate_scene_script
|
|
134
|
+
// ----------------------------------------------------------------
|
|
135
|
+
server.tool("generate_scene_script", "Use AI to generate or regenerate the voiceover script for a specific scene, based on the overall project context and prompt.", {
|
|
136
|
+
projectId: z.string().describe("The project ID"),
|
|
137
|
+
sceneId: z
|
|
138
|
+
.string()
|
|
139
|
+
.describe("The scene ID to generate a script for"),
|
|
140
|
+
}, async (args) => {
|
|
141
|
+
try {
|
|
142
|
+
const result = await apiClient.writeSceneScript(args.projectId, args.sceneId);
|
|
143
|
+
return {
|
|
144
|
+
content: [
|
|
145
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
146
|
+
],
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
return {
|
|
151
|
+
content: [{ type: "text", text: formatError(error) }],
|
|
152
|
+
isError: true,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=scene-tools.js.map
|