@studiomeyer/mcp-video 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/.github/ISSUE_TEMPLATE/bug_report.md +31 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- package/.github/workflows/ci.yml +34 -0
- package/CHANGELOG.md +24 -0
- package/CONTRIBUTING.md +75 -0
- package/LICENSE +21 -0
- package/README.md +198 -0
- package/USAGE.md +144 -0
- package/dist/handlers/capcut.d.ts +6 -0
- package/dist/handlers/capcut.js +229 -0
- package/dist/handlers/capcut.js.map +1 -0
- package/dist/handlers/editing.d.ts +6 -0
- package/dist/handlers/editing.js +242 -0
- package/dist/handlers/editing.js.map +1 -0
- package/dist/handlers/index.d.ts +2 -0
- package/dist/handlers/index.js +33 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/post-production.d.ts +5 -0
- package/dist/handlers/post-production.js +109 -0
- package/dist/handlers/post-production.js.map +1 -0
- package/dist/handlers/smart-screenshot.d.ts +5 -0
- package/dist/handlers/smart-screenshot.js +83 -0
- package/dist/handlers/smart-screenshot.js.map +1 -0
- package/dist/handlers/tts.d.ts +5 -0
- package/dist/handlers/tts.js +83 -0
- package/dist/handlers/tts.js.map +1 -0
- package/dist/handlers/video.d.ts +5 -0
- package/dist/handlers/video.js +127 -0
- package/dist/handlers/video.js.map +1 -0
- package/dist/lib/dual-transport.d.ts +42 -0
- package/dist/lib/dual-transport.js +208 -0
- package/dist/lib/dual-transport.js.map +1 -0
- package/dist/lib/logger.d.ts +12 -0
- package/dist/lib/logger.js +42 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/types.d.ts +16 -0
- package/dist/lib/types.js +15 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/schemas/capcut.d.ts +608 -0
- package/dist/schemas/capcut.js +411 -0
- package/dist/schemas/capcut.js.map +1 -0
- package/dist/schemas/editing.d.ts +822 -0
- package/dist/schemas/editing.js +466 -0
- package/dist/schemas/editing.js.map +1 -0
- package/dist/schemas/index.d.ts +2366 -0
- package/dist/schemas/index.js +15 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/post-production.d.ts +379 -0
- package/dist/schemas/post-production.js +268 -0
- package/dist/schemas/post-production.js.map +1 -0
- package/dist/schemas/smart-screenshot.d.ts +127 -0
- package/dist/schemas/smart-screenshot.js +122 -0
- package/dist/schemas/smart-screenshot.js.map +1 -0
- package/dist/schemas/tts.d.ts +220 -0
- package/dist/schemas/tts.js +194 -0
- package/dist/schemas/tts.js.map +1 -0
- package/dist/schemas/video.d.ts +236 -0
- package/dist/schemas/video.js +210 -0
- package/dist/schemas/video.js.map +1 -0
- package/dist/server.d.ts +11 -0
- package/dist/server.js +239 -0
- package/dist/server.js.map +1 -0
- package/dist/server.test.d.ts +1 -0
- package/dist/server.test.js +87 -0
- package/dist/server.test.js.map +1 -0
- package/dist/tools/engine/audio-mixer.d.ts +40 -0
- package/dist/tools/engine/audio-mixer.js +169 -0
- package/dist/tools/engine/audio-mixer.js.map +1 -0
- package/dist/tools/engine/audio.d.ts +22 -0
- package/dist/tools/engine/audio.js +73 -0
- package/dist/tools/engine/audio.js.map +1 -0
- package/dist/tools/engine/beat-sync.d.ts +31 -0
- package/dist/tools/engine/beat-sync.js +270 -0
- package/dist/tools/engine/beat-sync.js.map +1 -0
- package/dist/tools/engine/capture.d.ts +12 -0
- package/dist/tools/engine/capture.js +290 -0
- package/dist/tools/engine/capture.js.map +1 -0
- package/dist/tools/engine/chroma-key.d.ts +27 -0
- package/dist/tools/engine/chroma-key.js +154 -0
- package/dist/tools/engine/chroma-key.js.map +1 -0
- package/dist/tools/engine/concat.d.ts +49 -0
- package/dist/tools/engine/concat.js +149 -0
- package/dist/tools/engine/concat.js.map +1 -0
- package/dist/tools/engine/cursor.d.ts +26 -0
- package/dist/tools/engine/cursor.js +185 -0
- package/dist/tools/engine/cursor.js.map +1 -0
- package/dist/tools/engine/easing.d.ts +15 -0
- package/dist/tools/engine/easing.js +100 -0
- package/dist/tools/engine/easing.js.map +1 -0
- package/dist/tools/engine/editing.d.ts +158 -0
- package/dist/tools/engine/editing.js +541 -0
- package/dist/tools/engine/editing.js.map +1 -0
- package/dist/tools/engine/encoder.d.ts +31 -0
- package/dist/tools/engine/encoder.js +154 -0
- package/dist/tools/engine/encoder.js.map +1 -0
- package/dist/tools/engine/index.d.ts +30 -0
- package/dist/tools/engine/index.js +23 -0
- package/dist/tools/engine/index.js.map +1 -0
- package/dist/tools/engine/lut-presets.d.ts +25 -0
- package/dist/tools/engine/lut-presets.js +141 -0
- package/dist/tools/engine/lut-presets.js.map +1 -0
- package/dist/tools/engine/narrated-video.d.ts +63 -0
- package/dist/tools/engine/narrated-video.js +163 -0
- package/dist/tools/engine/narrated-video.js.map +1 -0
- package/dist/tools/engine/scenes.d.ts +17 -0
- package/dist/tools/engine/scenes.js +223 -0
- package/dist/tools/engine/scenes.js.map +1 -0
- package/dist/tools/engine/smart-screenshot.d.ts +80 -0
- package/dist/tools/engine/smart-screenshot.js +744 -0
- package/dist/tools/engine/smart-screenshot.js.map +1 -0
- package/dist/tools/engine/social-format.d.ts +66 -0
- package/dist/tools/engine/social-format.js +107 -0
- package/dist/tools/engine/social-format.js.map +1 -0
- package/dist/tools/engine/template-renderer.d.ts +45 -0
- package/dist/tools/engine/template-renderer.js +233 -0
- package/dist/tools/engine/template-renderer.js.map +1 -0
- package/dist/tools/engine/templates.d.ts +87 -0
- package/dist/tools/engine/templates.js +272 -0
- package/dist/tools/engine/templates.js.map +1 -0
- package/dist/tools/engine/text-animations.d.ts +33 -0
- package/dist/tools/engine/text-animations.js +192 -0
- package/dist/tools/engine/text-animations.js.map +1 -0
- package/dist/tools/engine/text-overlay.d.ts +27 -0
- package/dist/tools/engine/text-overlay.js +84 -0
- package/dist/tools/engine/text-overlay.js.map +1 -0
- package/dist/tools/engine/tts.d.ts +54 -0
- package/dist/tools/engine/tts.js +186 -0
- package/dist/tools/engine/tts.js.map +1 -0
- package/dist/tools/engine/types.d.ts +166 -0
- package/dist/tools/engine/types.js +13 -0
- package/dist/tools/engine/types.js.map +1 -0
- package/dist/tools/engine/voice-effects.d.ts +18 -0
- package/dist/tools/engine/voice-effects.js +215 -0
- package/dist/tools/engine/voice-effects.js.map +1 -0
- package/dist/tools/index.d.ts +32 -0
- package/dist/tools/index.js +23 -0
- package/dist/tools/index.js.map +1 -0
- package/package.json +56 -0
- package/scripts/check-deps.js +39 -0
- package/src/handlers/capcut.ts +245 -0
- package/src/handlers/editing.ts +260 -0
- package/src/handlers/index.ts +34 -0
- package/src/handlers/post-production.ts +136 -0
- package/src/handlers/smart-screenshot.ts +86 -0
- package/src/handlers/tts.ts +103 -0
- package/src/handlers/video.ts +137 -0
- package/src/lib/dual-transport.ts +272 -0
- package/src/lib/logger.ts +59 -0
- package/src/lib/types.ts +25 -0
- package/src/schemas/capcut.ts +418 -0
- package/src/schemas/editing.ts +476 -0
- package/src/schemas/index.ts +15 -0
- package/src/schemas/post-production.ts +273 -0
- package/src/schemas/smart-screenshot.ts +122 -0
- package/src/schemas/tts.ts +197 -0
- package/src/schemas/video.ts +211 -0
- package/src/server.test.ts +99 -0
- package/src/server.ts +289 -0
- package/src/tools/engine/audio-mixer.ts +244 -0
- package/src/tools/engine/audio.ts +115 -0
- package/src/tools/engine/beat-sync.ts +356 -0
- package/src/tools/engine/capture.ts +360 -0
- package/src/tools/engine/chroma-key.ts +202 -0
- package/src/tools/engine/concat.ts +242 -0
- package/src/tools/engine/cursor.ts +222 -0
- package/src/tools/engine/easing.ts +120 -0
- package/src/tools/engine/editing.ts +809 -0
- package/src/tools/engine/encoder.ts +208 -0
- package/src/tools/engine/index.ts +33 -0
- package/src/tools/engine/lut-presets.ts +235 -0
- package/src/tools/engine/narrated-video.ts +267 -0
- package/src/tools/engine/scenes.ts +309 -0
- package/src/tools/engine/smart-screenshot.ts +923 -0
- package/src/tools/engine/social-format.ts +146 -0
- package/src/tools/engine/template-renderer.ts +294 -0
- package/src/tools/engine/templates.ts +370 -0
- package/src/tools/engine/text-animations.ts +282 -0
- package/src/tools/engine/text-overlay.ts +143 -0
- package/src/tools/engine/tts.ts +284 -0
- package/src/tools/engine/types.ts +191 -0
- package/src/tools/engine/voice-effects.ts +258 -0
- package/src/tools/index.ts +67 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +7 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Tool Schemas for Post-Production features
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export const postProductionSchemas = [
|
|
6
|
+
// --- Background Music ---
|
|
7
|
+
{
|
|
8
|
+
name: 'add_background_music',
|
|
9
|
+
description: 'Add background music to a video. Supports fade in/out, volume control, and automatic looping. Does NOT re-encode the video (fast). Output: MP4 with AAC audio.',
|
|
10
|
+
annotations: {
|
|
11
|
+
title: 'Add Background Music',
|
|
12
|
+
readOnlyHint: false,
|
|
13
|
+
destructiveHint: false,
|
|
14
|
+
openWorldHint: false,
|
|
15
|
+
idempotentHint: true,
|
|
16
|
+
},
|
|
17
|
+
inputSchema: {
|
|
18
|
+
type: 'object' as const,
|
|
19
|
+
properties: {
|
|
20
|
+
videoPath: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
description: 'Path to the video file',
|
|
23
|
+
},
|
|
24
|
+
musicPath: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description: 'Path to the music file (mp3, wav, aac, ogg)',
|
|
27
|
+
},
|
|
28
|
+
outputPath: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'Output path (default: adds -music suffix)',
|
|
31
|
+
},
|
|
32
|
+
musicVolume: {
|
|
33
|
+
type: 'number',
|
|
34
|
+
description: 'Music volume 0.0-1.0 (default: 0.25). Recommended: 0.15-0.3 for background.',
|
|
35
|
+
},
|
|
36
|
+
fadeInDuration: {
|
|
37
|
+
type: 'number',
|
|
38
|
+
description: 'Fade in duration in seconds (default: 2)',
|
|
39
|
+
},
|
|
40
|
+
fadeOutDuration: {
|
|
41
|
+
type: 'number',
|
|
42
|
+
description: 'Fade out duration in seconds (default: 3)',
|
|
43
|
+
},
|
|
44
|
+
loopMusic: {
|
|
45
|
+
type: 'boolean',
|
|
46
|
+
description: 'Loop music if shorter than video (default: true)',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
required: ['videoPath', 'musicPath'],
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
// --- Concatenation ---
|
|
54
|
+
{
|
|
55
|
+
name: 'concatenate_videos',
|
|
56
|
+
description: 'Concatenate multiple video clips into one with cinematic transitions. Automatically normalizes resolution and framerate. Supports 30+ transition types: fade, dissolve, wipeleft, slideright, circleopen, radial, etc.',
|
|
57
|
+
annotations: {
|
|
58
|
+
title: 'Concatenate Videos',
|
|
59
|
+
readOnlyHint: false,
|
|
60
|
+
destructiveHint: false,
|
|
61
|
+
openWorldHint: false,
|
|
62
|
+
idempotentHint: true,
|
|
63
|
+
},
|
|
64
|
+
inputSchema: {
|
|
65
|
+
type: 'object' as const,
|
|
66
|
+
properties: {
|
|
67
|
+
clips: {
|
|
68
|
+
type: 'array',
|
|
69
|
+
items: {
|
|
70
|
+
type: 'object',
|
|
71
|
+
properties: {
|
|
72
|
+
path: { type: 'string', description: 'Path to video clip' },
|
|
73
|
+
trimStart: { type: 'number', description: 'Optional: start time in seconds' },
|
|
74
|
+
trimEnd: { type: 'number', description: 'Optional: end time in seconds' },
|
|
75
|
+
},
|
|
76
|
+
required: ['path'],
|
|
77
|
+
},
|
|
78
|
+
description: 'Video clips in order',
|
|
79
|
+
},
|
|
80
|
+
outputPath: {
|
|
81
|
+
type: 'string',
|
|
82
|
+
description: 'Output path',
|
|
83
|
+
},
|
|
84
|
+
transition: {
|
|
85
|
+
type: 'string',
|
|
86
|
+
enum: [
|
|
87
|
+
'fade', 'fadeblack', 'fadewhite', 'dissolve',
|
|
88
|
+
'wipeleft', 'wiperight', 'wipeup', 'wipedown',
|
|
89
|
+
'slideleft', 'slideright', 'slideup', 'slidedown',
|
|
90
|
+
'smoothleft', 'smoothright', 'circleopen', 'circleclose',
|
|
91
|
+
'radial', 'pixelize', 'diagtl', 'diagtr',
|
|
92
|
+
],
|
|
93
|
+
description: 'Transition type between clips (default: fade)',
|
|
94
|
+
},
|
|
95
|
+
transitionDuration: {
|
|
96
|
+
type: 'number',
|
|
97
|
+
description: 'Transition duration in seconds (default: 1)',
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
required: ['clips', 'outputPath'],
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
// --- Intro/Outro Generator ---
|
|
105
|
+
{
|
|
106
|
+
name: 'generate_intro',
|
|
107
|
+
description: 'Generate a cinematic intro or outro clip with animated text. Creates a solid-color background with fade-in title and optional subtitle. Perfect for branding.',
|
|
108
|
+
annotations: {
|
|
109
|
+
title: 'Generate Intro/Outro Clip',
|
|
110
|
+
readOnlyHint: false,
|
|
111
|
+
destructiveHint: false,
|
|
112
|
+
openWorldHint: false,
|
|
113
|
+
idempotentHint: true,
|
|
114
|
+
},
|
|
115
|
+
inputSchema: {
|
|
116
|
+
type: 'object' as const,
|
|
117
|
+
properties: {
|
|
118
|
+
text: {
|
|
119
|
+
type: 'string',
|
|
120
|
+
description: 'Main title text',
|
|
121
|
+
},
|
|
122
|
+
subtitle: {
|
|
123
|
+
type: 'string',
|
|
124
|
+
description: 'Optional subtitle text',
|
|
125
|
+
},
|
|
126
|
+
duration: {
|
|
127
|
+
type: 'number',
|
|
128
|
+
description: 'Duration in seconds (default: 3)',
|
|
129
|
+
},
|
|
130
|
+
backgroundColor: {
|
|
131
|
+
type: 'string',
|
|
132
|
+
description: 'Background color hex (default: #0a0a0a)',
|
|
133
|
+
},
|
|
134
|
+
textColor: {
|
|
135
|
+
type: 'string',
|
|
136
|
+
description: 'Text color (default: white)',
|
|
137
|
+
},
|
|
138
|
+
outputPath: {
|
|
139
|
+
type: 'string',
|
|
140
|
+
description: 'Output path',
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
required: ['text', 'outputPath'],
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
// --- Social Media Format ---
|
|
148
|
+
{
|
|
149
|
+
name: 'convert_social_format',
|
|
150
|
+
description: 'Convert a video to a specific social media format. Handles aspect ratio conversion with crop, padding, or blur-background strategy. Supports: instagram-reel, instagram-feed, youtube, youtube-short, tiktok, linkedin.',
|
|
151
|
+
annotations: {
|
|
152
|
+
title: 'Convert to Social Media Format',
|
|
153
|
+
readOnlyHint: false,
|
|
154
|
+
destructiveHint: false,
|
|
155
|
+
openWorldHint: false,
|
|
156
|
+
idempotentHint: true,
|
|
157
|
+
},
|
|
158
|
+
inputSchema: {
|
|
159
|
+
type: 'object' as const,
|
|
160
|
+
properties: {
|
|
161
|
+
inputPath: {
|
|
162
|
+
type: 'string',
|
|
163
|
+
description: 'Path to input video',
|
|
164
|
+
},
|
|
165
|
+
outputPath: {
|
|
166
|
+
type: 'string',
|
|
167
|
+
description: 'Output path',
|
|
168
|
+
},
|
|
169
|
+
format: {
|
|
170
|
+
type: 'string',
|
|
171
|
+
enum: ['instagram-reel', 'instagram-feed', 'instagram-story', 'youtube', 'youtube-short', 'tiktok', 'linkedin-landscape', 'linkedin-square'],
|
|
172
|
+
description: 'Target social media format',
|
|
173
|
+
},
|
|
174
|
+
strategy: {
|
|
175
|
+
type: 'string',
|
|
176
|
+
enum: ['crop', 'pad', 'blur-background'],
|
|
177
|
+
description: 'How to handle aspect ratio: crop (cut edges), pad (black bars), blur-background (blurred fill). Default: blur-background.',
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
required: ['inputPath', 'outputPath', 'format'],
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
// --- Batch Social Format ---
|
|
185
|
+
{
|
|
186
|
+
name: 'convert_all_social_formats',
|
|
187
|
+
description: 'Convert a video to multiple social media formats at once. Creates separate files for each platform. Great for preparing content for all channels simultaneously.',
|
|
188
|
+
annotations: {
|
|
189
|
+
title: 'Convert to All Social Formats',
|
|
190
|
+
readOnlyHint: false,
|
|
191
|
+
destructiveHint: false,
|
|
192
|
+
openWorldHint: false,
|
|
193
|
+
idempotentHint: true,
|
|
194
|
+
},
|
|
195
|
+
inputSchema: {
|
|
196
|
+
type: 'object' as const,
|
|
197
|
+
properties: {
|
|
198
|
+
inputPath: {
|
|
199
|
+
type: 'string',
|
|
200
|
+
description: 'Path to input video',
|
|
201
|
+
},
|
|
202
|
+
outputDir: {
|
|
203
|
+
type: 'string',
|
|
204
|
+
description: 'Output directory (default: ./output/)',
|
|
205
|
+
},
|
|
206
|
+
formats: {
|
|
207
|
+
type: 'array',
|
|
208
|
+
items: {
|
|
209
|
+
type: 'string',
|
|
210
|
+
enum: ['instagram-reel', 'instagram-feed', 'instagram-story', 'youtube', 'youtube-short', 'tiktok', 'linkedin-landscape', 'linkedin-square'],
|
|
211
|
+
},
|
|
212
|
+
description: 'Formats to generate (default: instagram-reel, instagram-feed, youtube, tiktok)',
|
|
213
|
+
},
|
|
214
|
+
strategy: {
|
|
215
|
+
type: 'string',
|
|
216
|
+
enum: ['crop', 'pad', 'blur-background'],
|
|
217
|
+
description: 'Aspect ratio strategy (default: blur-background)',
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
required: ['inputPath'],
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
// --- Text Overlays ---
|
|
225
|
+
{
|
|
226
|
+
name: 'add_text_overlay',
|
|
227
|
+
description: 'Add animated text overlays to a video. Supports fade-in/out, positioning (center, top, bottom, corners), background boxes, and multiple text layers.',
|
|
228
|
+
annotations: {
|
|
229
|
+
title: 'Add Text Overlay to Video',
|
|
230
|
+
readOnlyHint: false,
|
|
231
|
+
destructiveHint: false,
|
|
232
|
+
openWorldHint: false,
|
|
233
|
+
idempotentHint: true,
|
|
234
|
+
},
|
|
235
|
+
inputSchema: {
|
|
236
|
+
type: 'object' as const,
|
|
237
|
+
properties: {
|
|
238
|
+
inputPath: {
|
|
239
|
+
type: 'string',
|
|
240
|
+
description: 'Path to input video',
|
|
241
|
+
},
|
|
242
|
+
outputPath: {
|
|
243
|
+
type: 'string',
|
|
244
|
+
description: 'Output path',
|
|
245
|
+
},
|
|
246
|
+
overlays: {
|
|
247
|
+
type: 'array',
|
|
248
|
+
items: {
|
|
249
|
+
type: 'object',
|
|
250
|
+
properties: {
|
|
251
|
+
text: { type: 'string', description: 'Text to display' },
|
|
252
|
+
position: {
|
|
253
|
+
type: 'string',
|
|
254
|
+
enum: ['center', 'top', 'bottom', 'top-left', 'top-right', 'bottom-left', 'bottom-right'],
|
|
255
|
+
description: 'Position (default: center)',
|
|
256
|
+
},
|
|
257
|
+
fontSize: { type: 'number', description: 'Font size (default: 48)' },
|
|
258
|
+
fontColor: { type: 'string', description: 'Color (default: white)' },
|
|
259
|
+
startTime: { type: 'number', description: 'Start time in seconds' },
|
|
260
|
+
endTime: { type: 'number', description: 'End time in seconds' },
|
|
261
|
+
fadeIn: { type: 'number', description: 'Fade in seconds (default: 0.5)' },
|
|
262
|
+
fadeOut: { type: 'number', description: 'Fade out seconds (default: 0.5)' },
|
|
263
|
+
showBackground: { type: 'boolean', description: 'Show background box (default: false)' },
|
|
264
|
+
},
|
|
265
|
+
required: ['text', 'startTime', 'endTime'],
|
|
266
|
+
},
|
|
267
|
+
description: 'Array of text overlays',
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
required: ['inputPath', 'outputPath', 'overlays'],
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
];
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Tool Schema for Smart Screenshot Engine
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export const smartScreenshotSchemas = [
|
|
6
|
+
{
|
|
7
|
+
name: 'screenshot_element',
|
|
8
|
+
description: `Smart element-aware screenshot tool. Automatically detects and photographs specific features on a webpage.
|
|
9
|
+
|
|
10
|
+
Instead of full-page screenshots, this finds and captures specific UI elements like:
|
|
11
|
+
- Chat widgets, booking forms, pricing sections
|
|
12
|
+
- Wizards/steppers, navigation, galleries
|
|
13
|
+
- Contact forms, testimonials, CTAs, maps, video sections
|
|
14
|
+
- Or ANY element via CSS selector
|
|
15
|
+
|
|
16
|
+
Usage examples:
|
|
17
|
+
targets: ["chat"] → finds and screenshots the chat widget
|
|
18
|
+
targets: ["pricing", "booking"] → screenshots pricing section AND booking form
|
|
19
|
+
targets: ["all"] → auto-detects ALL features on the page
|
|
20
|
+
targets: [{ "feature": "hero", "selector": ".custom-hero" }] → custom selector
|
|
21
|
+
targets: [".my-section"] → direct CSS selector
|
|
22
|
+
|
|
23
|
+
Supports 15+ feature types with intelligent DOM analysis.`,
|
|
24
|
+
annotations: {
|
|
25
|
+
title: 'Screenshot Page Element',
|
|
26
|
+
readOnlyHint: true,
|
|
27
|
+
destructiveHint: false,
|
|
28
|
+
openWorldHint: true,
|
|
29
|
+
idempotentHint: true,
|
|
30
|
+
},
|
|
31
|
+
inputSchema: {
|
|
32
|
+
type: 'object' as const,
|
|
33
|
+
properties: {
|
|
34
|
+
url: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
description: 'URL of the website to screenshot',
|
|
37
|
+
},
|
|
38
|
+
targets: {
|
|
39
|
+
type: 'array',
|
|
40
|
+
items: {
|
|
41
|
+
oneOf: [
|
|
42
|
+
{
|
|
43
|
+
type: 'string',
|
|
44
|
+
description: 'Feature keyword (chat, pricing, booking, hero, nav, footer, gallery, wizard, testimonial, services, cta, map, video, newsletter, contact) or "all" for auto-detect, or CSS selector (.class, #id)',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
type: 'object',
|
|
48
|
+
properties: {
|
|
49
|
+
feature: { type: 'string', description: 'Feature name or keyword' },
|
|
50
|
+
selector: { type: 'string', description: 'Custom CSS selector override' },
|
|
51
|
+
padding: { type: 'number', description: 'Padding around element in px' },
|
|
52
|
+
revealFirst: { type: 'boolean', description: 'Click to reveal element first (e.g. chat popup)' },
|
|
53
|
+
},
|
|
54
|
+
required: ['feature'],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
description: 'What to capture. Array of feature keywords, CSS selectors, or target objects. Use "all" to auto-detect everything.',
|
|
59
|
+
},
|
|
60
|
+
outputDir: {
|
|
61
|
+
type: 'string',
|
|
62
|
+
description: 'Output directory (default: ./output/smart-screenshots)',
|
|
63
|
+
},
|
|
64
|
+
viewport: {
|
|
65
|
+
type: 'object',
|
|
66
|
+
properties: {
|
|
67
|
+
width: { type: 'number', description: 'Viewport width (default: 1920)' },
|
|
68
|
+
height: { type: 'number', description: 'Viewport height (default: 1080)' },
|
|
69
|
+
},
|
|
70
|
+
description: 'Custom viewport dimensions',
|
|
71
|
+
},
|
|
72
|
+
darkMode: {
|
|
73
|
+
type: 'boolean',
|
|
74
|
+
description: 'Enable dark mode rendering (default: false)',
|
|
75
|
+
},
|
|
76
|
+
deviceScaleFactor: {
|
|
77
|
+
type: 'number',
|
|
78
|
+
description: 'Device scale factor for retina (default: 1, use 2 for retina)',
|
|
79
|
+
},
|
|
80
|
+
includeFullPage: {
|
|
81
|
+
type: 'boolean',
|
|
82
|
+
description: 'Also capture a full-page screenshot (default: false)',
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
required: ['url', 'targets'],
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: 'detect_page_features',
|
|
90
|
+
description: `Analyze a webpage and detect all available UI features/sections without taking screenshots.
|
|
91
|
+
|
|
92
|
+
Returns a list of detected features with their names, locations, and sizes.
|
|
93
|
+
Useful for planning which elements to screenshot or for understanding page structure.
|
|
94
|
+
|
|
95
|
+
Detects: Hero, Chat, Booking, Pricing, Contact Form, Navigation, Footer, Gallery, Wizard/Stepper, Testimonials, Services, CTA, Map, Video, Newsletter sections.`,
|
|
96
|
+
annotations: {
|
|
97
|
+
title: 'Detect Page Features',
|
|
98
|
+
readOnlyHint: true,
|
|
99
|
+
destructiveHint: false,
|
|
100
|
+
openWorldHint: true,
|
|
101
|
+
idempotentHint: true,
|
|
102
|
+
},
|
|
103
|
+
inputSchema: {
|
|
104
|
+
type: 'object' as const,
|
|
105
|
+
properties: {
|
|
106
|
+
url: {
|
|
107
|
+
type: 'string',
|
|
108
|
+
description: 'URL of the website to analyze',
|
|
109
|
+
},
|
|
110
|
+
viewport: {
|
|
111
|
+
type: 'object',
|
|
112
|
+
properties: {
|
|
113
|
+
width: { type: 'number' },
|
|
114
|
+
height: { type: 'number' },
|
|
115
|
+
},
|
|
116
|
+
description: 'Viewport dimensions (default: 1920x1080)',
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
required: ['url'],
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
];
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Tool Schemas for TTS & Narrated Video
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const sceneSchema = {
|
|
6
|
+
type: 'object' as const,
|
|
7
|
+
properties: {
|
|
8
|
+
type: {
|
|
9
|
+
type: 'string',
|
|
10
|
+
enum: ['scroll', 'pause', 'hover', 'click', 'type', 'wait'],
|
|
11
|
+
},
|
|
12
|
+
to: { type: ['string', 'number'] },
|
|
13
|
+
duration: { type: 'number' },
|
|
14
|
+
easing: { type: 'string' },
|
|
15
|
+
selector: { type: 'string' },
|
|
16
|
+
text: { type: 'string' },
|
|
17
|
+
waitFor: { type: ['string', 'number'] },
|
|
18
|
+
pauseAfter: { type: 'number' },
|
|
19
|
+
},
|
|
20
|
+
required: ['type'],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const ttsSchemas = [
|
|
24
|
+
// --- Text-to-Speech ---
|
|
25
|
+
{
|
|
26
|
+
name: 'generate_speech',
|
|
27
|
+
description: 'Generate speech audio from text using ElevenLabs (primary) or OpenAI TTS (fallback). Supports German, English, Spanish and 29+ languages. Returns an MP3 file. IMPORTANT: Uses paid APIs — ElevenLabs or OpenAI.',
|
|
28
|
+
annotations: {
|
|
29
|
+
title: 'Generate Speech (TTS)',
|
|
30
|
+
readOnlyHint: false,
|
|
31
|
+
destructiveHint: false,
|
|
32
|
+
openWorldHint: true,
|
|
33
|
+
idempotentHint: true,
|
|
34
|
+
},
|
|
35
|
+
inputSchema: {
|
|
36
|
+
type: 'object' as const,
|
|
37
|
+
properties: {
|
|
38
|
+
text: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
description: 'Text to convert to speech',
|
|
41
|
+
},
|
|
42
|
+
outputPath: {
|
|
43
|
+
type: 'string',
|
|
44
|
+
description: 'Output path for MP3 file (default: ./output/speech-{timestamp}.mp3)',
|
|
45
|
+
},
|
|
46
|
+
provider: {
|
|
47
|
+
type: 'string',
|
|
48
|
+
enum: ['elevenlabs', 'openai'],
|
|
49
|
+
description: 'TTS provider (default: elevenlabs if API key available, otherwise openai)',
|
|
50
|
+
},
|
|
51
|
+
language: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
description: 'Language code: en, de, es, fr, it, etc. (default: en)',
|
|
54
|
+
},
|
|
55
|
+
speed: {
|
|
56
|
+
type: 'number',
|
|
57
|
+
description: 'Speaking speed 0.7-1.2 for ElevenLabs, 0.25-4.0 for OpenAI (default: 1.0)',
|
|
58
|
+
},
|
|
59
|
+
elevenLabsVoice: {
|
|
60
|
+
type: 'string',
|
|
61
|
+
enum: ['rachel', 'sarah', 'emily', 'charlotte', 'alice', 'matilda', 'lily', 'brian', 'adam', 'daniel', 'josh', 'james', 'liam', 'chris', 'george'],
|
|
62
|
+
description: 'ElevenLabs voice (default: adam). Male: adam, brian, daniel, josh, james, liam. Female: rachel, sarah, emily, charlotte.',
|
|
63
|
+
},
|
|
64
|
+
elevenLabsModel: {
|
|
65
|
+
type: 'string',
|
|
66
|
+
enum: ['eleven_multilingual_v2', 'eleven_turbo_v2_5', 'eleven_flash_v2_5'],
|
|
67
|
+
description: 'ElevenLabs model (default: eleven_multilingual_v2 for best quality)',
|
|
68
|
+
},
|
|
69
|
+
openaiVoice: {
|
|
70
|
+
type: 'string',
|
|
71
|
+
enum: ['alloy', 'ash', 'coral', 'echo', 'fable', 'nova', 'onyx', 'sage', 'shimmer'],
|
|
72
|
+
description: 'OpenAI voice (default: onyx). Deep: onyx, echo. Bright: nova, shimmer. Neutral: alloy.',
|
|
73
|
+
},
|
|
74
|
+
openaiModel: {
|
|
75
|
+
type: 'string',
|
|
76
|
+
enum: ['tts-1', 'tts-1-hd'],
|
|
77
|
+
description: 'OpenAI model (default: tts-1-hd for best quality)',
|
|
78
|
+
},
|
|
79
|
+
stability: {
|
|
80
|
+
type: 'number',
|
|
81
|
+
description: 'ElevenLabs voice stability 0-1 (default: 0.5). Lower = more dynamic.',
|
|
82
|
+
},
|
|
83
|
+
similarityBoost: {
|
|
84
|
+
type: 'number',
|
|
85
|
+
description: 'ElevenLabs similarity 0-1 (default: 0.75).',
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
required: ['text'],
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
// --- List Voices ---
|
|
93
|
+
{
|
|
94
|
+
name: 'list_voices',
|
|
95
|
+
description: 'List all available ElevenLabs voices including custom/cloned voices. Requires ELEVENLABS_API_KEY.',
|
|
96
|
+
annotations: {
|
|
97
|
+
title: 'List ElevenLabs Voices',
|
|
98
|
+
readOnlyHint: true,
|
|
99
|
+
destructiveHint: false,
|
|
100
|
+
openWorldHint: true,
|
|
101
|
+
idempotentHint: true,
|
|
102
|
+
},
|
|
103
|
+
inputSchema: {
|
|
104
|
+
type: 'object' as const,
|
|
105
|
+
properties: {},
|
|
106
|
+
required: [],
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
// --- Narrated Video (the killer feature) ---
|
|
111
|
+
{
|
|
112
|
+
name: 'create_narrated_video',
|
|
113
|
+
description: `Create a fully narrated explainer video of a website or app. This is the ultimate tool: provide a URL and a script, and get a professional video with AI voiceover synchronized to the on-screen actions.
|
|
114
|
+
|
|
115
|
+
Flow: Script → TTS → Website Recording (synced to speech durations) → Merge video + audio → Final MP4
|
|
116
|
+
|
|
117
|
+
Each segment has text (what to say) and a scene (what to show). The scene duration is automatically matched to the speech duration.
|
|
118
|
+
|
|
119
|
+
IMPORTANT: Uses paid TTS APIs (ElevenLabs or OpenAI). Always confirm with user before calling.`,
|
|
120
|
+
annotations: {
|
|
121
|
+
title: 'Create Narrated Video',
|
|
122
|
+
readOnlyHint: false,
|
|
123
|
+
destructiveHint: false,
|
|
124
|
+
openWorldHint: true,
|
|
125
|
+
idempotentHint: false,
|
|
126
|
+
},
|
|
127
|
+
inputSchema: {
|
|
128
|
+
type: 'object' as const,
|
|
129
|
+
properties: {
|
|
130
|
+
url: {
|
|
131
|
+
type: 'string',
|
|
132
|
+
description: 'URL of the website/app to record',
|
|
133
|
+
},
|
|
134
|
+
segments: {
|
|
135
|
+
type: 'array',
|
|
136
|
+
items: {
|
|
137
|
+
type: 'object',
|
|
138
|
+
properties: {
|
|
139
|
+
text: {
|
|
140
|
+
type: 'string',
|
|
141
|
+
description: 'Narration text for this segment',
|
|
142
|
+
},
|
|
143
|
+
scene: sceneSchema,
|
|
144
|
+
paddingAfter: {
|
|
145
|
+
type: 'number',
|
|
146
|
+
description: 'Extra pause after speech in seconds (default: 0.5)',
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
required: ['text', 'scene'],
|
|
150
|
+
},
|
|
151
|
+
description: 'Array of narration segments, each with text + scene action',
|
|
152
|
+
},
|
|
153
|
+
outputPath: {
|
|
154
|
+
type: 'string',
|
|
155
|
+
description: 'Output path without extension (default: ./output/narrated-{domain})',
|
|
156
|
+
},
|
|
157
|
+
provider: {
|
|
158
|
+
type: 'string',
|
|
159
|
+
enum: ['elevenlabs', 'openai'],
|
|
160
|
+
description: 'TTS provider (default: elevenlabs)',
|
|
161
|
+
},
|
|
162
|
+
language: {
|
|
163
|
+
type: 'string',
|
|
164
|
+
description: 'Language code (default: en)',
|
|
165
|
+
},
|
|
166
|
+
viewport: {
|
|
167
|
+
type: 'string',
|
|
168
|
+
enum: ['desktop', 'desktop-4k', 'tablet', 'mobile'],
|
|
169
|
+
description: 'Viewport (default: desktop)',
|
|
170
|
+
},
|
|
171
|
+
elevenLabsVoice: {
|
|
172
|
+
type: 'string',
|
|
173
|
+
enum: ['rachel', 'sarah', 'emily', 'charlotte', 'alice', 'matilda', 'lily', 'brian', 'adam', 'daniel', 'josh', 'james', 'liam', 'chris', 'george'],
|
|
174
|
+
description: 'ElevenLabs voice (default: adam)',
|
|
175
|
+
},
|
|
176
|
+
openaiVoice: {
|
|
177
|
+
type: 'string',
|
|
178
|
+
enum: ['alloy', 'ash', 'coral', 'echo', 'fable', 'nova', 'onyx', 'sage', 'shimmer'],
|
|
179
|
+
description: 'OpenAI voice (default: onyx)',
|
|
180
|
+
},
|
|
181
|
+
speed: {
|
|
182
|
+
type: 'number',
|
|
183
|
+
description: 'Speaking speed (default: 1.0)',
|
|
184
|
+
},
|
|
185
|
+
backgroundMusicPath: {
|
|
186
|
+
type: 'string',
|
|
187
|
+
description: 'Optional: path to background music file',
|
|
188
|
+
},
|
|
189
|
+
backgroundMusicVolume: {
|
|
190
|
+
type: 'number',
|
|
191
|
+
description: 'Background music volume 0-1 (default: 0.1)',
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
required: ['url', 'segments'],
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
];
|