wan_pro_text
Generate professional videos from text prompts using FAL AI models, with customizable duration and aspect ratios for various formats.
Instructions
Wan Pro - Professional video effects
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | Yes | Text prompt for video generation | |
| duration | No | ||
| aspect_ratio | No | 16:9 |
Implementation Reference
- src/index.ts:110-118 (registration)Registration of 'wan_pro_text' tool in MODEL_REGISTRY.textToVideo array, defining its id, endpoint, name, and description.textToVideo: [ { id: 'veo3', endpoint: 'fal-ai/veo3', name: 'Veo 3', description: 'Google DeepMind\'s latest with speech and audio' }, { id: 'kling_master_text', endpoint: 'fal-ai/kling-video/v2.1/master/text-to-video', name: 'Kling 2.1 Master', description: 'Premium text-to-video with motion fluidity' }, { id: 'pixverse_text', endpoint: 'fal-ai/pixverse/v4.5/text-to-video', name: 'Pixverse V4.5', description: 'Advanced text-to-video generation' }, { id: 'magi', endpoint: 'fal-ai/magi', name: 'Magi', description: 'Creative video generation' }, { id: 'luma_ray2', endpoint: 'fal-ai/luma-dream-machine/ray-2', name: 'Luma Ray 2', description: 'Latest Luma Dream Machine' }, { id: 'wan_pro_text', endpoint: 'fal-ai/wan-pro/text-to-video', name: 'Wan Pro', description: 'Professional video effects' }, { id: 'vidu_text', endpoint: 'fal-ai/vidu/q1/text-to-video', name: 'Vidu Q1', description: 'High-quality text-to-video' } ],
- src/index.ts:346-393 (schema)Dynamic schema generation for tools, including input schema for textToVideo models like 'wan_pro_text' (prompt, duration, aspect_ratio). Used in tools/list.private generateToolSchema(model: any, category: string) { const baseSchema = { name: model.id, description: `${model.name} - ${model.description}`, inputSchema: { type: 'object', properties: {} as any, required: [] as string[], }, }; if (category === 'imageGeneration') { baseSchema.inputSchema.properties = { prompt: { type: 'string', description: 'Text prompt for image generation' }, image_size: { type: 'string', enum: ['square_hd', 'square', 'portrait_4_3', 'portrait_16_9', 'landscape_4_3', 'landscape_16_9'], default: 'landscape_4_3' }, num_images: { type: 'number', default: 1, minimum: 1, maximum: 4 }, }; baseSchema.inputSchema.required = ['prompt']; // Add model-specific parameters if (model.id.includes('flux') || model.id.includes('stable_diffusion')) { baseSchema.inputSchema.properties.num_inference_steps = { type: 'number', default: 25, minimum: 1, maximum: 50 }; baseSchema.inputSchema.properties.guidance_scale = { type: 'number', default: 3.5, minimum: 1, maximum: 20 }; } if (model.id.includes('stable_diffusion') || model.id === 'ideogram_v3') { baseSchema.inputSchema.properties.negative_prompt = { type: 'string', description: 'Negative prompt' }; } } else if (category === 'textToVideo') { baseSchema.inputSchema.properties = { prompt: { type: 'string', description: 'Text prompt for video generation' }, duration: { type: 'number', default: 5, minimum: 1, maximum: 30 }, aspect_ratio: { type: 'string', enum: ['16:9', '9:16', '1:1', '4:3', '3:4'], default: '16:9' }, }; baseSchema.inputSchema.required = ['prompt']; } else if (category === 'imageToVideo') { baseSchema.inputSchema.properties = { image_url: { type: 'string', description: 'URL of the input image' }, prompt: { type: 'string', description: 'Motion description prompt' }, duration: { type: 'string', enum: ['5', '10'], default: '5', description: 'Video duration in seconds' }, aspect_ratio: { type: 'string', enum: ['16:9', '9:16', '1:1'], default: '16:9' }, negative_prompt: { type: 'string', description: 'What to avoid in the video' }, cfg_scale: { type: 'number', default: 0.5, minimum: 0, maximum: 1, description: 'How closely to follow the prompt' } }; baseSchema.inputSchema.required = ['image_url', 'prompt']; } return baseSchema; }
- src/index.ts:627-675 (handler)Handler function executing the text-to-video logic for 'wan_pro_text', calling fal.subscribe on the endpoint and processing video output.private async handleTextToVideo(args: any, model: any) { const { prompt, duration = 5, aspect_ratio = '16:9' } = args; try { // Configure FAL client lazily with query config override configureFalClient(this.currentQueryConfig); const inputParams: any = { prompt }; if (duration) inputParams.duration = duration; if (aspect_ratio) inputParams.aspect_ratio = aspect_ratio; const result = await fal.subscribe(model.endpoint, { input: inputParams }); const videoData = result.data as FalVideoResult; const videoProcessed = await downloadAndProcessVideo(videoData.video.url, model.id); return { content: [ { type: 'text', text: JSON.stringify({ model: model.name, id: model.id, endpoint: model.endpoint, prompt, video: { url: videoData.video.url, localPath: videoProcessed.localPath, ...(videoProcessed.dataUrl && { dataUrl: videoProcessed.dataUrl }), width: videoData.video.width, height: videoData.video.height, }, metadata: inputParams, download_path: DOWNLOAD_PATH, data_url_settings: { enabled: ENABLE_DATA_URLS, max_size_mb: Math.round(MAX_DATA_URL_SIZE / 1024 / 1024), }, autoopen_settings: { enabled: AUTOOPEN, note: AUTOOPEN ? "Files automatically opened with default application" : "Auto-open disabled" }, }, null, 2), }, ], }; } catch (error) { throw new Error(`${model.name} generation failed: ${error}`); } }
- src/index.ts:456-492 (handler)Tool call dispatcher that routes 'wan_pro_text' calls to handleTextToVideo based on MODEL_REGISTRY lookup.this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { // Handle special tools first if (name === 'list_available_models') { return await this.handleListModels(args); } else if (name === 'execute_custom_model') { return await this.handleCustomModel(args); } const model = getModelById(name); if (!model) { throw new McpError( ErrorCode.MethodNotFound, `Unknown model: ${name}` ); } // Determine category and handle accordingly if (MODEL_REGISTRY.imageGeneration.find(m => m.id === name)) { return await this.handleImageGeneration(args, model); } else if (MODEL_REGISTRY.textToVideo.find(m => m.id === name)) { return await this.handleTextToVideo(args, model); } else if (MODEL_REGISTRY.imageToVideo.find(m => m.id === name)) { return await this.handleImageToVideo(args, model); } throw new McpError( ErrorCode.MethodNotFound, `Unsupported model category for: ${name}` ); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); throw new McpError(ErrorCode.InternalError, errorMessage); } });
- src/index.ts:290-313 (helper)Helper function to download, convert to data URL, and auto-open the generated video file, used by text-to-video handlers.async function downloadAndProcessVideo(videoUrl: string, modelName: string): Promise<any> { const filename = generateFilename('video', modelName); const localPath = await downloadFile(videoUrl, filename); const dataUrl = await urlToDataUrl(videoUrl); // Auto-open the downloaded video if available if (localPath) { await autoOpenFile(localPath); } const result: any = {}; // Only include localPath if download was successful if (localPath) { result.localPath = localPath; } // Only include dataUrl if it was successfully generated if (dataUrl) { result.dataUrl = dataUrl; } return result; }