generate_clips
Generate AI clips from a YouTube video. Specify optional start/end times for a segment. Returns project ID for polling or provide callback URL for webhook notification when clips with download URLs are ready.
Instructions
Start AI clip generation from a YouTube video. Returns a JSON object with project_id (string), status ('processing'), poll_url (string), and estimated_minutes (number). Processing is async -- use get_project_status to poll every 10-15 seconds, or provide a callback_url to receive a webhook POST when all clips are exported with download URLs.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Full YouTube video URL (e.g. https://www.youtube.com/watch?v=...) | |
| start_time | No | Start time in seconds to clip only a segment of the video. Omit to process the full video. | |
| end_time | No | End time in seconds to clip only a segment of the video. Omit to process the full video. | |
| callback_url | No | Webhook URL to receive a POST when processing finishes. The payload includes an array of clips sorted by score, each with a download_url. |
Implementation Reference
- src/server.ts:76-113 (handler)The handler function for the generate_clips tool. It calls the lumiclip API POST /clips/generate with url, start_time, end_time, and callback_url, then returns a JSON object with project_id, status, poll_url, estimated_minutes, and a message.
async ({ url, start_time, end_time, callback_url }) => { try { const result = await apiCall(config, "POST", "/clips/generate", { url, start_time, end_time, callback_url, }); return { content: [ { type: "text" as const, text: JSON.stringify( { project_id: result.project_id, status: "processing", poll_url: result.poll_url, estimated_minutes: result.estimated_minutes, message: callback_url ? "Processing started. A webhook will be sent to your callback_url when ready." : "Processing started. Poll with get_project_status every 10-15 seconds until status is 'completed'.", }, null, 2 ), }, ], }; } catch (err: unknown) { const message = err instanceof Error ? err.message : String(err); return { content: [{ type: "text" as const, text: `Error: ${message}` }], isError: true, }; } } ); - src/server.ts:50-68 (schema)Zod schema for generate_clips tool input: url (required), start_time (optional number), end_time (optional number), callback_url (optional string).
{ url: z.string().describe("Full YouTube video URL (e.g. https://www.youtube.com/watch?v=...)"), start_time: z .number() .optional() .describe( "Start time in seconds to clip only a segment of the video. Omit to process the full video." ), end_time: z .number() .optional() .describe("End time in seconds to clip only a segment of the video. Omit to process the full video."), callback_url: z .string() .optional() .describe( "Webhook URL to receive a POST when processing finishes. The payload includes an array of clips sorted by score, each with a download_url." ), }, - src/server.ts:47-113 (registration)Registration of the generate_clips tool via server.tool() on the McpServer instance, including name, description, zod schema, metadata hints, and handler.
server.tool( "generate_clips", "Start AI clip generation from a YouTube video. Returns a JSON object with project_id (string), status ('processing'), poll_url (string), and estimated_minutes (number). Processing is async -- use get_project_status to poll every 10-15 seconds, or provide a callback_url to receive a webhook POST when all clips are exported with download URLs.", { url: z.string().describe("Full YouTube video URL (e.g. https://www.youtube.com/watch?v=...)"), start_time: z .number() .optional() .describe( "Start time in seconds to clip only a segment of the video. Omit to process the full video." ), end_time: z .number() .optional() .describe("End time in seconds to clip only a segment of the video. Omit to process the full video."), callback_url: z .string() .optional() .describe( "Webhook URL to receive a POST when processing finishes. The payload includes an array of clips sorted by score, each with a download_url." ), }, { title: "Generate Clips", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true, }, async ({ url, start_time, end_time, callback_url }) => { try { const result = await apiCall(config, "POST", "/clips/generate", { url, start_time, end_time, callback_url, }); return { content: [ { type: "text" as const, text: JSON.stringify( { project_id: result.project_id, status: "processing", poll_url: result.poll_url, estimated_minutes: result.estimated_minutes, message: callback_url ? "Processing started. A webhook will be sent to your callback_url when ready." : "Processing started. Poll with get_project_status every 10-15 seconds until status is 'completed'.", }, null, 2 ), }, ], }; } catch (err: unknown) { const message = err instanceof Error ? err.message : String(err); return { content: [{ type: "text" as const, text: `Error: ${message}` }], isError: true, }; } } ); - src/http.ts:26-40 (registration)Server card registration of the generate_clips tool in the /.well-known/mcp/server-card.json endpoint, providing name, description, and JSON Schema inputSchema.
{ name: "generate_clips", description: "Start AI clip generation from a YouTube video. Returns {project_id, status, poll_url, estimated_minutes}. Poll with get_project_status every 10-15 seconds, or provide a callback_url for webhook notification.", inputSchema: { type: "object", properties: { url: { type: "string", description: "Full YouTube video URL (e.g. https://www.youtube.com/watch?v=...)" }, start_time: { type: "number", description: "Start time in seconds to clip only a segment. Omit to process the full video." }, end_time: { type: "number", description: "End time in seconds to clip only a segment. Omit to process the full video." }, callback_url: { type: "string", description: "Webhook URL to receive a POST when all clips are ready with download links." }, }, required: ["url"], }, }, - src/server.ts:9-37 (helper)Helper function used by the generate_clips handler to make HTTP requests to the Lumiclip API with authentication.
async function apiCall( config: ApiConfig, method: string, path: string, body?: unknown ) { const base = config.apiBase || "https://api.lumiclip.ai"; const url = `${base}/api/v1${path}`; const res = await fetch(url, { method, headers: { Authorization: `Bearer ${config.apiKey}`, "Content-Type": "application/json", }, ...(body ? { body: JSON.stringify(body) } : {}), }); const data = (await res.json()) as Record<string, unknown>; if (!res.ok) { throw new Error( (data.error as string) || (data.message as string) || `API error ${res.status}` ); } return data; }