Submit Image Generation Task
submit_image_generationAsynchronous image generation: submit a prompt and output path to create images with customizable aspect ratio, size, style, or subject reference. Returns a task ID for batch processing; call task_barrier for final results.
Instructions
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.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | Yes | ||
| outputFile | Yes | Absolute path for generated image | |
| aspectRatio | No | Aspect ratio for the image. Options: 1:1, 16:9, 4:3, 3:2, 2:3, 3:4, 9:16, 21:9 | 1:1 |
| customSize | No | 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 | No | Random seed for reproducible results | |
| subjectReference | No | 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 | No | Art style control settings. Uses image-01-live model which does not support customSize or subjectReference parameters. Cannot be combined with customSize or subjectReference |
Implementation Reference
- src/index.ts:57-87 (handler)The main handler for 'submit_image_generation'. It registers the tool via server.registerTool, validates parameters using validateImageParams, submits the task via taskManager.submitImageTask which calls imageService.generateImage, and returns the task ID. On error, it logs via ErrorHandler and returns a user-friendly error message.
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)}` }] }; } } ); - src/config/schemas.ts:31-69 (schema)Input schema definition (imageGenerationSchema) using Zod. Defines the expected parameters: prompt, outputFile, aspectRatio, customSize, seed, subjectReference, and style. Used as inputSchema on line 62 of the registration.
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/config/schemas.ts:311-336 (helper)Validation function (validateImageParams) that parses and validates the input parameters using the Zod schema, including custom logic to ensure incompatible parameters (style vs customSize/subjectReference) are rejected.
export function validateImageParams(params: unknown): ImageGenerationParams { try { const parsed = imageGenerationSchema.parse(params); // Manual validation for incompatible parameter combinations const hasStyle = !!parsed.style; const hasCustomSize = !!parsed.customSize; const hasSubjectReference = !!parsed.subjectReference; if (hasStyle && hasCustomSize) { throw new Error('Style parameter (image-01-live model) cannot be combined with customSize (image-01 model feature)'); } if (hasStyle && hasSubjectReference) { throw new Error('Style parameter (image-01-live model) cannot be combined with subjectReference (image-01 model feature)'); } return parsed; } catch (error) { if (error instanceof z.ZodError) { const messages = error.errors.map(e => `${e.path.join('.')}: ${e.message}`); throw new Error(`Validation failed: ${messages.join(', ')}`); } throw error; } } - src/index.ts:57-87 (registration)The registration line itself is part of the handler block: server.registerTool('submit_image_generation', ...) on line 57-87 registers the tool with the MCP server.
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)}` }] }; } } ); - src/services/image-service.ts:47-65 (helper)ImageGenerationService.generateImage — the core logic that builds the API payload, makes the request to the Minimax API, processes the response (downloads/saves images), and returns the result. Called by the handler via taskManager.submitImageTask.
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; } }