generate_image
Create custom images based on text prompts using AI-powered tools. Specify aspect ratios, generate multiple images, and save outputs with defined file paths for seamless integration into projects.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| aspectRatio | No | Aspect ratio of the image | |
| n | No | Number of images to generate (1-9) | |
| outputFile | Yes | Absolute path to save the generated image file. The directory must already exist. When generating multiple images (n>1), files will be named with sequential numbers (e.g., 'image-1.jpg', 'image-2.jpg') | |
| prompt | Yes | Description of the image to generate | |
| subjectReference | No | Path to a local image file or a public URL for character reference image |
Implementation Reference
- src/services/image-service.ts:47-65 (handler)Core handler function that executes the image generation: constructs API payload, sends request to Minimax, processes response, downloads/saves images to files.async generateImage(params: ImageGenerationParams): Promise<ImageGenerationResult> { try { // Build API payload (MCP handles validation) const payload = this.buildPayload(params); // Make API request const response = await this.post(API_CONFIG.ENDPOINTS.IMAGE_GENERATION, payload) as ImageGenerationResponse; // Process response return await this.processImageResponse(response, params); } catch (error: any) { const processedError = ErrorHandler.handleAPIError(error); ErrorHandler.logError(processedError, { service: 'image', params }); // Throw the error so task manager can properly mark it as failed throw processedError; } }
- src/config/schemas.ts:31-69 (schema)Zod schema defining input parameters for image generation tool (ImageGenerationParams). Used for validation.export const imageGenerationSchema = z.object({ prompt: z.string() .min(1, 'Prompt is required') .max(CONSTRAINTS.IMAGE.PROMPT_MAX_LENGTH, `Prompt must not exceed ${CONSTRAINTS.IMAGE.PROMPT_MAX_LENGTH} characters`), outputFile: filePathSchema.describe('Absolute path for generated image'), aspectRatio: z.enum(CONSTRAINTS.IMAGE.ASPECT_RATIOS as readonly [AspectRatio, ...AspectRatio[]]) .default('1:1' as AspectRatio) .describe(`Aspect ratio for the image. Options: ${CONSTRAINTS.IMAGE.ASPECT_RATIOS.join(', ')}`), customSize: z.object({ width: z.number() .min(CONSTRAINTS.IMAGE.MIN_DIMENSION) .max(CONSTRAINTS.IMAGE.MAX_DIMENSION) .multipleOf(CONSTRAINTS.IMAGE.DIMENSION_STEP), height: z.number() .min(CONSTRAINTS.IMAGE.MIN_DIMENSION) .max(CONSTRAINTS.IMAGE.MAX_DIMENSION) .multipleOf(CONSTRAINTS.IMAGE.DIMENSION_STEP) }).optional().describe('Custom image dimensions (width x height in pixels). Range: 512-2048, must be multiples of 8. Total resolution should stay under 2M pixels. Only supported with image-01 model (cannot be used with style parameter). When both customSize and aspectRatio are set, aspectRatio takes precedence'), seed: positiveIntSchema.optional().describe('Random seed for reproducible results'), subjectReference: z.string().optional().describe('File path to a portrait image for maintaining facial characteristics in generated images. Only supported with image-01 model (cannot be used with style parameter). Provide a clear frontal face photo for best results. Supports local file paths and URLs. Max 10MB, formats: jpg, jpeg, png'), style: z.object({ style_type: z.enum(CONSTRAINTS.IMAGE.STYLE_TYPES as readonly [StyleType, ...StyleType[]]) .describe(`Art style type. Options: ${CONSTRAINTS.IMAGE.STYLE_TYPES.join(', ')}`), style_weight: z.number() .min(CONSTRAINTS.IMAGE.STYLE_WEIGHT_MIN, 'Style weight must be greater than 0') .max(CONSTRAINTS.IMAGE.STYLE_WEIGHT_MAX, 'Style weight must not exceed 1') .default(0.8) .describe('Style control weight (0-1]. Higher values apply stronger style effects. Default: 0.8') }).optional().describe('Art style control settings. Uses image-01-live model which does not support customSize or subjectReference parameters. Cannot be combined with customSize or subjectReference'), });
- src/index.ts:57-87 (registration)MCP tool registration for image generation (named 'submit_image_generation'). Validates params, submits async task that calls generateImage, returns taskId.server.registerTool( "submit_image_generation", { title: "Submit Image Generation Task", description: "Generate images asynchronously. RECOMMENDED: Submit multiple tasks in batch to saturate rate limits, then call task_barrier once to wait for all completions. Returns task ID only - actual files available after task_barrier.", inputSchema: imageGenerationSchema.shape }, async (params: unknown): Promise<ToolResponse> => { try { const validatedParams = validateImageParams(params); const { taskId } = await taskManager.submitImageTask(async () => { return await imageService.generateImage(validatedParams); }); return { content: [{ type: "text", text: `Task ${taskId} submitted` }] }; } catch (error: any) { ErrorHandler.logError(error, { tool: 'submit_image_generation', params }); return { content: [{ type: "text", text: `❌ Failed to submit image generation task: ${ErrorHandler.formatErrorForUser(error)}` }] }; } } );
- Helper function to process API response: handles URL/base64 images, downloads/saves to files, handles errors, returns file paths.private async processImageResponse(response: ImageGenerationResponse, params: ImageGenerationParams): Promise<ImageGenerationResult> { // Handle both URL and base64 responses const imageUrls = response.data?.image_urls || []; const imageBase64 = response.data?.image_base64 || []; if (!imageUrls.length && !imageBase64.length) { throw new Error('No images generated in API response'); } // Download and save images const savedFiles: string[] = []; const errors: string[] = []; const imageSources = imageUrls.length ? imageUrls : imageBase64; for (let i = 0; i < imageSources.length; i++) { try { const filename = FileHandler.generateUniqueFilename(params.outputFile, i, imageSources.length); if (imageBase64.length && !imageUrls.length) { // Save base64 image await FileHandler.saveBase64Image(imageBase64[i]!, filename); } else { // Download from URL await FileHandler.downloadFile(imageSources[i]!, filename); } savedFiles.push(filename); } catch (error: any) { errors.push(`Image ${i + 1}: ${error.message}`); } } if (savedFiles.length === 0) { throw new Error(`Failed to save any images: ${errors.join('; ')}`); } // Use the actual model that was used const modelUsed = params.style ? 'image-01-live' : 'image-01'; const result: ImageGenerationResult = { files: savedFiles, count: savedFiles.length, model: modelUsed, prompt: params.prompt }; if (errors.length > 0) { result.warnings = errors; } return result; }
- src/services/image-service.ts:67-118 (helper)Helper function to construct the API payload for Minimax image generation based on input params, handling model selection and parameters.private buildPayload(params: ImageGenerationParams): ImageGenerationPayload { const imageDefaults = DEFAULTS.IMAGE as any; // Choose model based on whether style is provided const model = params.style ? 'image-01-live' : 'image-01'; const payload: ImageGenerationPayload = { model: model, prompt: params.prompt, n: 1, prompt_optimizer: true, // Always optimize prompts response_format: 'url' // Always use URL since we save to file }; // Handle sizing parameters (conflict-free approach) if (params.customSize) { payload.width = params.customSize.width; payload.height = params.customSize.height; } else { payload.aspect_ratio = params.aspectRatio || imageDefaults.aspectRatio; } // Add optional parameters if (params.seed !== undefined) { payload.seed = params.seed; } // Model-specific parameter handling if (model === 'image-01') { // Add subject reference for image-01 model // MCP Server Bridge: Convert user-friendly file path to API format if (params.subjectReference) { // TODO: Convert file path/URL to base64 or ensure URL is accessible // For now, pass through assuming it's already in correct format payload.subject_reference = [{ type: 'character', image_file: params.subjectReference }]; } } else if (model === 'image-01-live') { // Add style settings for image-01-live model if (params.style) { payload.style = { style_type: params.style.style_type, style_weight: params.style.style_weight || 0.8 }; } } return payload; }