Skip to main content
Glama
elhombrejd

BFL MCP Server

by elhombrejd

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
NameRequiredDescriptionDefault
promptYesText description of the image to generate
aspect_ratioNoAspect ratio of the image (e.g., "1:1", "16:9", "9:16")1:1
seedNoSeed for reproducible generation
safety_toleranceNoSafety tolerance level (0-6)
output_formatNoOutput image formatjpeg

Implementation Reference

  • 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.`, }, ], }; }
  • 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'], }, },
  • 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'; }
  • 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); }
Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/elhombrejd/bfl_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server