generate_image
Create custom images from text descriptions using the FLUX.1 Kontext model. Specify aspect ratio, format, and safety settings for tailored visual content generation.
Instructions
Generate an image using FLUX.1 Kontext model based on a text prompt
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | Yes | Text description of the image to generate | |
| aspect_ratio | No | Aspect ratio of the image (e.g., "1:1", "16:9", "9:16") | 1:1 |
| seed | No | Seed for reproducible generation | |
| safety_tolerance | No | Safety tolerance level (0-6) | |
| output_format | No | Output image format | jpeg |
Implementation Reference
- src/index.ts:139-156 (handler)MCP tool handler for 'generate_image': parses arguments, calls bflClient.generateImage, and returns the image URL in response.case 'generate_image': { const imageUrl = await bflClient.generateImage({ prompt: args.prompt as string, aspect_ratio: args.aspect_ratio as string | undefined, seed: args.seed as number | undefined, safety_tolerance: args.safety_tolerance as number | undefined, output_format: args.output_format as 'jpeg' | 'png' | undefined, }); return { content: [ { type: 'text', text: `Image generated successfully! URL: ${imageUrl}\n\nNote: The URL is valid for 10 minutes.`, }, ], }; }
- src/bfl-client.ts:101-132 (helper)Core implementation of image generation: submits POST request to BFL API /v1/flux-kontext-pro and polls for completion.async generateImage(request: GenerateImageRequest): Promise<string> { try { // Step 1: Submit generation request const response = await this.makeRequest('/v1/flux-kontext-pro', { prompt: request.prompt, aspect_ratio: request.aspect_ratio || '1:1', seed: request.seed, safety_tolerance: request.safety_tolerance, output_format: request.output_format || 'jpeg', }); if (!response.id) { throw new Error('No request ID received from BFL API'); } // Log the polling URL if provided if (response.polling_url) { console.log(`[BFL] Using polling URL: ${response.polling_url}`); } // Step 2: Poll for result const result = await this.pollForResult(response.id, response.polling_url); if (!result.result?.sample) { throw new Error('No image URL in response'); } return result.result.sample; } catch (error) { throw new Error(`Image generation failed: ${error instanceof Error ? error.message : 'Unknown error'}`); } }
- src/index.ts:38-72 (registration)Registration of the 'generate_image' tool in the tools list, including name, description, and detailed inputSchema.{ name: 'generate_image', description: 'Generate an image using FLUX.1 Kontext model based on a text prompt', inputSchema: { type: 'object', properties: { prompt: { type: 'string', description: 'Text description of the image to generate', }, aspect_ratio: { type: 'string', description: 'Aspect ratio of the image (e.g., "1:1", "16:9", "9:16")', default: '1:1', }, seed: { type: 'number', description: 'Seed for reproducible generation', }, safety_tolerance: { type: 'number', description: 'Safety tolerance level (0-6)', minimum: 0, maximum: 6, }, output_format: { type: 'string', enum: ['jpeg', 'png'], description: 'Output image format', default: 'jpeg', }, }, required: ['prompt'], }, },
- src/types.ts:6-12 (schema)TypeScript type definition for GenerateImageRequest, matching the tool's input schema.export interface GenerateImageRequest { prompt: string; aspect_ratio?: string; seed?: number; safety_tolerance?: number; output_format?: 'jpeg' | 'png'; }
- src/bfl-client.ts:29-99 (helper)Helper function to poll the BFL API for generation completion with retry logic and timeout.private async pollForResult(requestId: string, pollingUrl?: string): Promise<BFLApiResponse> { const maxAttempts = 20; // 1 minute with 3-second intervals const pollInterval = 3000; console.log(`[BFL] Starting polling for request ${requestId} (max ${maxAttempts} attempts, ${pollInterval/1000}s intervals)`); for (let attempt = 0; attempt < maxAttempts; attempt++) { try { console.log(`[BFL] Polling attempt ${attempt + 1}/${maxAttempts} for ${requestId}`); // Use polling URL if provided, otherwise construct from base URL const url = pollingUrl || `${this.baseUrl}/v1/get_result?id=${requestId}`; const response = await fetch(url, { headers: { 'x-key': this.config.apiKey, }, }); if (!response.ok) { const errorMsg = `Poll error: ${response.status} - ${response.statusText}`; console.log(`[BFL] ${errorMsg}`); // Don't retry on client errors (4xx) if (response.status >= 400 && response.status < 500) { throw new Error(errorMsg); } throw new Error(errorMsg); } const result: PollResponse = await response.json(); console.log(`[BFL] Status: ${result.status}`); if (result.status === 'Ready') { console.log(`[BFL] ✅ Image generation completed for ${requestId}`); return result; } else if (result.status === 'Error') { const errorMsg = `Generation failed: ${result.error || 'Unknown error'}`; console.log(`[BFL] ❌ ${errorMsg}`); throw new Error(errorMsg); } else if (result.status === 'Processing' || result.status === 'Pending') { console.log(`[BFL] ⏳ Still ${result.status.toLowerCase()}, waiting ${pollInterval/1000}s...`); } // Wait before next poll (only if not last attempt) if (attempt < maxAttempts - 1) { await new Promise(resolve => setTimeout(resolve, pollInterval)); } } catch (error) { console.log(`[BFL] Error on attempt ${attempt + 1}: ${error instanceof Error ? error.message : 'Unknown error'}`); if (attempt === maxAttempts - 1) { console.log(`[BFL] ❌ Final attempt failed, giving up`); throw error; } // For network errors, wait before retry if (error instanceof Error && !error.message.includes('Poll error: 4')) { console.log(`[BFL] Retrying in ${pollInterval/1000}s...`); await new Promise(resolve => setTimeout(resolve, pollInterval)); } else { // Don't retry 4xx errors throw error; } } } const timeoutMsg = `Timeout: Image generation exceeded ${maxAttempts * pollInterval / 1000}s limit`; console.log(`[BFL] ❌ ${timeoutMsg}`); throw new Error(timeoutMsg); }