Skip to main content
Glama

flux_generate

Generate images from text prompts using FLUX AI models, save files to specified directories, and apply variations, inpainting, or edge-guided creation.

Instructions

Generate an image with a FLUX model via Replicate and save files to download_path

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
promptYesText prompt describing the image
download_pathYesDirectory to save generated images
modelNoFLUX model to useblack-forest-labs/flux-1.1-pro-ultra
image_pathNoLocal path or URL to input image (for image-accepting models)
mask_pathNoLocal path or URL to mask for inpainting (Fill model)
aspect_ratioNoAspect ratio (e.g., '1:1', '16:9', '3:4')
seedNoRandom seed for reproducibility
rawNoEnable raw realism mode (Ultra model)
num_outputsNoNumber of images to generate
output_qualityNoQuality setting (model-dependent)
go_fastNoSpeed vs quality tradeoff
strengthNoVariation strength (Redux model)
num_inference_stepsNoInference steps (Fill model)
guidanceNoGuidance scale (Fill model)
output_formatNoOutput image format (png, jpeg, or webp)png

Implementation Reference

  • The core handler for the 'flux_generate' tool. It validates inputs, runs the specified FLUX model on Replicate, downloads the generated image(s) to a secure download path, and returns the file paths and URLs.
    if (name === "flux_generate") {
      try {
        const apiToken = process.env.REPLICATE_API_TOKEN;
        if (!apiToken) {
          throw new Error("REPLICATE_API_TOKEN environment variable is not set");
        }
    
        const replicate = new Replicate({ auth: apiToken });
    
        const modelId = args.model || "black-forest-labs/flux-1.1-pro-ultra";
        const meta = FLUX_MODELS[modelId];
    
        if (!meta) {
          throw new Error(`Unknown model: ${modelId}`);
        }
    
        // Build input
        const input = { prompt: args.prompt };
    
        // Set output format (default to png for better compatibility)
        const outputFormat = args.output_format || "png";
        input.output_format = outputFormat;
    
        // Add optional parameters if they exist for this model
        const optionalParams = [
          "aspect_ratio",
          "seed",
          "raw",
          "num_outputs",
          "output_quality",
          "go_fast",
          "strength",
          "num_inference_steps",
          "guidance",
        ];
    
        for (const param of optionalParams) {
          if (args[param] !== undefined && meta.inputs[param]) {
            input[param] = args[param];
          }
        }
    
        // Handle image input for models that accept it
        if (meta.accepts_image) {
          if (!args.image_path) {
            throw new Error(`Model ${modelId} requires image_path`);
          }
          // Validate image_path to prevent SSRF
          // Only allow HTTPS URLs or local file paths (Replicate will handle validation)
          if (args.image_path.startsWith("http://")) {
            throw new Error("HTTP URLs not allowed for security reasons. Use HTTPS.");
          }
          input.image = args.image_path;
        }
    
        // Handle mask for Fill model
        if (modelId.endsWith("/flux-fill-pro") && args.mask_path) {
          // Same validation for mask paths
          if (args.mask_path.startsWith("http://")) {
            throw new Error("HTTP URLs not allowed for security reasons. Use HTTPS.");
          }
          input.mask = args.mask_path;
        }
    
        // Run the model
        const output = await replicate.run(modelId, { input });
    
        // Download results - VALIDATE PATH FIRST
        const downloadPath = validateDownloadPath(args.download_path);
        await fs.mkdir(downloadPath, { recursive: true });
    
        const timestamp = new Date()
          .toISOString()
          .replace(/[:.]/g, "-")
          .slice(0, 19);
        const baseName = `${meta.display.replace(/[^a-z0-9]/gi, "").toLowerCase()}_${timestamp}`;
    
        const savedFiles = [];
        const urls = Array.isArray(output) ? output : [output];
    
        for (let i = 0; i < urls.length; i++) {
          const urlObj = urls[i];
          // Convert to string if it's a URL object
          const url = typeof urlObj === 'string' ? urlObj : String(urlObj);
    
          // Use the requested output format for file extension
          const ext = outputFormat === "jpeg" ? ".jpg" : `.${outputFormat}`;
          const filepath = path.join(downloadPath, `${baseName}_${i + 1}${ext}`);
    
          await downloadFile(url, filepath);
          savedFiles.push(filepath);
        }
    
        return {
          content: [
            {
              type: "text",
              text: JSON.stringify(
                {
                  model: modelId,
                  saved: savedFiles,
                  urls: urls,
                },
                null,
                2
              ),
            },
          ],
        };
      } catch (error) {
        // Sanitize error message to avoid leaking sensitive information
        let safeMessage = "An error occurred while generating the image.";
    
        // Only expose safe, user-actionable error messages
        if (error.message.includes("REPLICATE_API_TOKEN")) {
          safeMessage = "API token is not configured. Please set REPLICATE_API_TOKEN.";
        } else if (error.message.includes("Unknown model")) {
          safeMessage = error.message; // Safe to expose model validation errors
        } else if (error.message.includes("requires image_path")) {
          safeMessage = error.message; // Safe to expose parameter validation errors
        } else if (error.message.includes("Download path must be")) {
          safeMessage = "Invalid download path. Path must be within home directory or /tmp.";
        } else if (error.message.includes("HTTP URLs not allowed")) {
          safeMessage = "Only HTTPS URLs are allowed for security reasons.";
        } else if (error.message.includes("NSFW")) {
          safeMessage = "Content was flagged by safety filters. Please try a different prompt.";
        } else if (error.message.includes("Only Replicate CDN")) {
          safeMessage = "Invalid image source. Only Replicate CDN URLs are allowed.";
        }
    
        // Log full error server-side for debugging (not sent to client)
        console.error("FLUX MCP Error:", error);
    
        return {
          content: [
            {
              type: "text",
              text: `Error: ${safeMessage}`,
            },
          ],
          isError: true,
        };
      }
    }
  • index.js:214-288 (registration)
    Registration of the 'flux_generate' tool in the ListTools response, including name, description, and detailed input schema with properties, enums, defaults, and requirements.
    {
      name: "flux_generate",
      description:
        "Generate an image with a FLUX model via Replicate and save files to download_path",
      inputSchema: {
        type: "object",
        properties: {
          prompt: {
            type: "string",
            description: "Text prompt describing the image",
          },
          download_path: {
            type: "string",
            description: "Directory to save generated images",
          },
          model: {
            type: "string",
            description: "FLUX model to use",
            enum: Object.keys(FLUX_MODELS),
            default: "black-forest-labs/flux-1.1-pro-ultra",
          },
          image_path: {
            type: "string",
            description: "Local path or URL to input image (for image-accepting models)",
          },
          mask_path: {
            type: "string",
            description: "Local path or URL to mask for inpainting (Fill model)",
          },
          aspect_ratio: {
            type: "string",
            description: "Aspect ratio (e.g., '1:1', '16:9', '3:4')",
          },
          seed: {
            type: "number",
            description: "Random seed for reproducibility",
          },
          raw: {
            type: "boolean",
            description: "Enable raw realism mode (Ultra model)",
          },
          num_outputs: {
            type: "number",
            description: "Number of images to generate",
          },
          output_quality: {
            type: "number",
            description: "Quality setting (model-dependent)",
          },
          go_fast: {
            type: "boolean",
            description: "Speed vs quality tradeoff",
          },
          strength: {
            type: "number",
            description: "Variation strength (Redux model)",
          },
          num_inference_steps: {
            type: "number",
            description: "Inference steps (Fill model)",
          },
          guidance: {
            type: "number",
            description: "Guidance scale (Fill model)",
          },
          output_format: {
            type: "string",
            description: "Output image format (png, jpeg, or webp)",
            enum: ["png", "jpeg", "webp"],
            default: "png",
          },
        },
        required: ["prompt", "download_path"],
      },
    },
  • FLUX_MODELS configuration object defining all supported models, their display names, kinds, notes, input schemas, and whether they accept images. Used by flux_generate for validation and metadata.
    const FLUX_MODELS = {
      "black-forest-labs/flux-1.1-pro-ultra": {
        display: "FLUX1.1 Pro Ultra",
        kind: "text-to-image",
        notes: [
          "Highest quality, up to ~4MP; 'raw' mode for realism.",
          "Use when you need best composition/large output.",
        ],
        inputs: {
          prompt: { required: true, type: "string" },
          raw: { required: false, type: "boolean" },
          aspect_ratio: { required: false, type: "string" },
          seed: { required: false, type: "integer" },
          output_quality: { required: false, type: "number" },
          go_fast: { required: false, type: "boolean" },
        },
        accepts_image: false,
      },
      "black-forest-labs/flux-pro": {
        display: "FLUX1.1 Pro",
        kind: "text-to-image",
        notes: [
          "Fast, reliable, commercial-grade default when Ultra not required.",
        ],
        inputs: {
          prompt: { required: true, type: "string" },
          aspect_ratio: { required: false, type: "string" },
          seed: { required: false, type: "integer" },
        },
        accepts_image: false,
      },
      "black-forest-labs/flux-redux-dev": {
        display: "FLUX.1 Redux [dev]",
        kind: "image-variation",
        notes: [
          "Variations/restyling while preserving key elements; mix image + text.",
        ],
        inputs: {
          image: { required: true, type: "file_or_url" },
          prompt: { required: true, type: "string" },
          strength: { required: false, type: "number" },
          seed: { required: false, type: "integer" },
          num_outputs: { required: false, type: "integer" },
        },
        accepts_image: true,
      },
      "black-forest-labs/flux-fill-pro": {
        display: "FLUX.1 Fill [pro]",
        kind: "inpainting/outpainting",
        notes: ["Professional in/outpainting; provide mask for areas to change."],
        inputs: {
          image: { required: true, type: "file_or_url" },
          mask: { required: false, type: "file_or_url" },
          prompt: { required: true, type: "string" },
          num_inference_steps: { required: false, type: "integer" },
          guidance: { required: false, type: "number" },
          seed: { required: false, type: "integer" },
        },
        accepts_image: true,
      },
      "black-forest-labs/flux-depth-dev": {
        display: "FLUX.1 Depth [dev]",
        kind: "depth-guided editing",
        notes: [
          "Structure-preserving edits/style transfer using depth; supply an image.",
        ],
        inputs: {
          image: { required: true, type: "file_or_url" },
          prompt: { required: true, type: "string" },
          seed: { required: false, type: "integer" },
        },
        accepts_image: true,
      },
      "black-forest-labs/flux-canny-pro": {
        display: "FLUX.1 Canny [pro]",
        kind: "edge-guided generation",
        notes: [
          "Control structure/composition with edges; ideal for sketches/wireframes → detailed images.",
        ],
        inputs: {
          image: { required: true, type: "file_or_url" },
          prompt: { required: true, type: "string" },
          seed: { required: false, type: "integer" },
        },
        accepts_image: true,
      },
    };
  • validateDownloadPath helper function used by flux_generate to securely validate and normalize the download directory path, preventing directory traversal attacks.
    function validateDownloadPath(userPath) {
      // Expand ~ to home directory
      const expandedPath = userPath.replace(/^~/, process.env.HOME || "");
    
      // Resolve to absolute path and normalize
      const absolutePath = path.resolve(expandedPath);
    
      // Security check: Ensure path doesn't escape to parent directories
      const homePath = process.env.HOME || "";
      const allowedPaths = [
        homePath,
        "/tmp",
        path.join(process.cwd(), "downloads"),
      ];
    
      // Check if the resolved path is within allowed directories
      const isAllowed = allowedPaths.some(allowedPath => {
        return absolutePath.startsWith(path.resolve(allowedPath));
      });
    
      if (!isAllowed) {
        throw new Error(`Download path must be within home directory, /tmp, or project downloads folder. Got: ${absolutePath}`);
      }
    
      return absolutePath;
    }
  • downloadFile helper function used by flux_generate to securely download generated images from Replicate CDN URLs to local paths.
    async function downloadFile(url, filepath) {
      // Validate URL before downloading
      validateReplicateUrl(url);
    
      return new Promise((resolve, reject) => {
        const file = fsSync.createWriteStream(filepath);
    
        https
          .get(url, (response) => {
            // Check for redirects to non-Replicate domains
            if (response.statusCode === 301 || response.statusCode === 302) {
              const redirectUrl = response.headers.location;
              try {
                validateReplicateUrl(redirectUrl);
              } catch (error) {
                file.close();
                fsSync.unlink(filepath, () => {});
                reject(new Error("Redirect to unsafe domain detected"));
                return;
              }
            }
    
            response.pipe(file);
            file.on("finish", () => {
              file.close(resolve);
            });
          })
          .on("error", (err) => {
            fsSync.unlink(filepath, () => {});
            reject(err);
          });
      });
    }
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/kmaurinjones/flux-mcp'

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