Image Generation MCP
Generate and edit images using Gemini "nano banana" (gemini-3-pro-image-preview), OpenAI GPT Image, and fal.ai Flux (text-to-image and image-to-image).
Model aliases: "nano banana" / "nano-banana" → gemini-3-pro-image-preview
When to Use
- Creating AI-generated images from text prompts
- Editing existing images with AI instructions
- Generating UI mockups, illustrations, or concept art
- Creating marketing images or visual assets
- Image-to-image transformations
- Batch generating multiple images cost-efficiently
When NOT to Use
- Taking screenshots of websites (use Playwright)
- Exporting designs from Figma (use Figma MCP)
- Visual regression testing (use image-diff)
- Photo editing that requires precise control (use dedicated tools)
Architecture
+------------------+ stdin/stdout +------------------+
| Claude Code | <---- JSON-RPC -----> | Image Gen MCP |
| (tool-proxy) | | (subprocess) |
+------------------+ +------------------+
|
+-------------+-------------+
v HTTPS v HTTPS v HTTPS
+------------+ +------------+ +-----------+
| Gemini API | | OpenAI API | | fal.ai |
+------------+ +------------+ +-----------+
Authentication
Set at least one provider API key:
# Google Gemini (default — best general quality)
GEMINI_API_KEY=your_api_key_here
# OpenAI GPT Image (auto-selected for text-heavy images)
OPENAI_API_KEY=sk-...
# fal.ai Flux (auto-selected for batch generation, cheapest)
FAL_KEY=your_fal_key_here
Gemini key: https://aistudio.google.com/app/apikey OpenAI key: https://platform.openai.com/api-keys fal.ai key: https://fal.ai/dashboard/keys
Available Tools (17 tools)
Generation
- generate_image — Create image from text prompt with aspect ratio control
- batch_generate_images — Generate multiple images from prompts or templates
- edit_image — Modify existing image using AI instructions
- generate_with_references — Generate with style, character, and object references
Element and Background Editing
- remove_element / add_element / replace_element — Targeted image edits
- remove_background / replace_background — Subject isolation and background swaps
Specs and Sessions
- generate_from_spec — Generate from a JSON image spec
- save_spec / load_spec / list_specs — Persist reusable specs
- get_generation_job — Inspect persisted job status, events, and result
- start_session / refine_image / end_session — Multi-turn refinement
Jobs and Streaming Progress
Provider-backed tools such as generate_image, edit_image, and
batch_generate_images create a persisted job record and return job_id in the
final result. Job records are stored under IMAGE_GENERATION_STATE_DIR when set,
otherwise under the platform state directory ($XDG_STATE_HOME/image-generation
or ~/.local/state/image-generation).
The Python API accepts an optional event sink:
from image_generation.image_generation_session import ImageGenerationSession
def handle_event(event):
print(event.to_dict())
session = ImageGenerationSession(interactive=False, event_sink=handle_event)
session.call_tool("generate_image", {"prompt": "A clean product photo"})
The tool-proxy adapter maps these events to structured stderr stream chunks, so
compatible clients can show progress while the blocking tool call is running.
Use get_generation_job with the returned job_id to inspect the durable event
history after completion.
Model Options and Costs
| Model | Alias | Provider | Cost/Image | Best For |
|---|---|---|---|---|
gemini-3-pro-image-preview |
nano-banana | Gemini | ~$0.04 | Default. Multi-reference, iterative editing, general quality |
flux-schnell |
fal.ai | ~$0.003 | Batch, product images, cheapest | |
flux-pro |
fal.ai | ~$0.05 | Higher quality fal.ai generation | |
chatgpt-image-latest |
OpenAI | ~$0.08 | Highest quality, best text rendering | |
gpt-image-1 |
OpenAI | ~$0.04 | Good quality | |
gpt-image-1-mini |
OpenAI | ~$0.02 | Fastest OpenAI option |
Smart Routing
When no explicit model is provided, the router picks the best provider
automatically using this priority:
- Explicit model — always wins
- Explicit use_case — routes to a known-good provider
- Prompt analysis — detects text-heavy prompts and routes to OpenAI
- Batch context — batch_generate_images defaults to flux-schnell
- Default — single generations default to nano-banana (Gemini)
use_case Routing
| use_case | Routed To | Rationale |
|---|---|---|
batch |
flux-schnell |
Cheapest per-image cost |
product |
flux-schnell |
Fast, cost-efficient |
quality |
gemini-3-pro-image-preview |
Best multi-reference support |
text |
chatgpt-image-latest |
Best text rendering |
| (unspecified) | gemini-3-pro-image-preview |
Best general quality |
Automatic Text Detection
The router analyzes the prompt for signals that the image needs readable text
rendered in it (e.g. "with the text", "that says", "typography", "poster",
"business card"). When detected, it auto-routes to chatgpt-image-latest which has
the best text rendering of any model.
Routing Metadata
Every response includes routing_reason explaining why a model was chosen:
"explicit"— user specified the model"use_case=quality"— routed by use_case"text_detected: 'with the text'"— prompt text analysis"batch_default"— batch context"default_quality"— no signals, used nano-banana
When to Ask the User
IMPORTANT for calling agents: If the user's request is ambiguous about quality expectations, ask before generating. Specifically:
- User asks for a "poster" or "banner" without specifying text content → ask if it needs text rendered in it (OpenAI) or is purely visual (Gemini)
- User asks for "logo" → ask if text/wordmark is needed (OpenAI) or it's an icon/symbol only (Gemini)
- User says "quick image" or "just a rough idea" → suggest flux-schnell to save cost, but confirm
- User doesn't specify quality expectations for a non-trivial image → default to nano-banana but mention the choice
Do NOT ask when:
- The prompt clearly describes a visual scene with no text → use nano-banana
- The prompt explicitly mentions text to render → use chatgpt-image-latest
- The user specified a model or use_case → honor it
- It's a batch operation → use flux-schnell
An explicit model parameter always overrides automatic routing.
Usage
Session Script
image-generation
Generate Image
session.call_tool("generate_image", {
"prompt": "A minimalist logo for a tech startup, blue and white colors",
"aspect_ratio": "1:1",
"output_dir": "./generated-images",
"goal": "logo" # Creates logo_01.jpg, logo_02.jpg, etc.
})
Smart Routing Examples
# Auto-routes to nano-banana (default quality)
session.call_tool("generate_image", {
"prompt": "Detailed illustration of a fantasy castle",
})
# routing_reason: "default_quality"
# Auto-detects text rendering → routes to OpenAI
session.call_tool("generate_image", {
"prompt": "A poster with the text 'HELLO WORLD' in bold",
})
# routing_reason: "text_detected: 'with the text'"
# Explicit use_case override
session.call_tool("generate_image", {
"prompt": "Product photo of a coffee mug",
"use_case": "product"
})
# routing_reason: "use_case=product"
Batch Generate Images
# From a list of prompts
session.call_tool("batch_generate_images", {
"prompts": [
"A red sports car",
"A blue sedan",
"A green SUV"
],
"output_dir": "./car-images"
})
# From a template with variables
session.call_tool("batch_generate_images", {
"prompt_template": "A photo of a {plant_name} in a {pot_style} pot",
"variables": [
{"plant_name": "cactus", "pot_style": "terracotta"},
{"plant_name": "fern", "pot_style": "ceramic"},
{"plant_name": "succulent", "pot_style": "modern"}
],
"output_dir": "./plant-images"
})
# Returns manifest: [{"prompt": "...", "file": "/path/to/image.png", "model": "flux-schnell", "provider": "fal"}, ...]
Edit Image
session.call_tool("edit_image", {
"prompt": "Change the background to a sunset beach",
"image_path": "./original.jpg",
"output_dir": "./edited-images",
"goal": "sunset-version"
})
Parameters
generate_image
| Parameter | Required | Description |
|---|---|---|
| prompt | Yes | Text description of desired image |
| reference_image | No | Single reference image path for style guidance |
| thought_signatures | No | Path to .sig file or array of signatures for reproducible variations |
| aspect_ratio | No | "1:1", "16:9", "9:16", "4:3", "3:4", "2:3", "3:2", "21:9" |
| image_size | No | "1K", "2K", "4K" (Gemini); mapped to quality for OpenAI |
| output_dir | No | Directory for output files |
| goal | No | Name prefix for auto-incrementing filenames |
| model | No | See Model Options table above |
| use_case | No | Routing hint: batch, product, quality, text |
batch_generate_images
| Parameter | Required | Description |
|---|---|---|
| prompts | No* | List of prompt strings |
| prompt_template | No* | Template with {variable} placeholders |
| variables | No* | List of dicts for template substitution |
| model | No | Model name (defaults to flux-schnell) |
| output_dir | No | Directory for output files |
| use_case | No | Routing hint for auto model selection |
* Either prompts or both prompt_template and variables must be provided.
edit_image
| Parameter | Required | Description |
|---|---|---|
| prompt | Yes | Instructions for how to edit the image |
| image_path | Yes | Path to input image |
| thought_signatures | No | Path to .sig file or array of signatures for reproducible variations |
| image_size | No | "1K", "2K", "4K" |
| output_dir | No | Directory for output files |
| goal | No | Name prefix for auto-incrementing filenames |
| model | No | gemini-3-pro-image-preview (default), chatgpt-image-latest, gpt-image-1, gpt-image-1-mini |
Thought Signatures
Thought signatures enable reproducible variations of generated images. When
you generate an image, a .sig sidecar file is saved alongside the image
containing base64-encoded tokens that capture the model's internal state.
To create variations:
- Generate an initial image — a
.sigfile is saved (e.g.,car-original_01.sig) - Pass that file path to subsequent generations with a modified prompt
- The model will maintain consistency while applying your changes
# Initial generation - saves car-original_01.jpg and car-original_01.sig
result1 = session.call_tool("generate_image", {
"prompt": "A red sports car in a city",
"goal": "car-original"
})
sig_file = result1.get("thought_signatures_file")
# Variation with same "thought"
result2 = session.call_tool("generate_image", {
"prompt": "A blue sports car in a city",
"thought_signatures": sig_file,
"goal": "car-blue"
})
Output Files
Images are saved with auto-incrementing filenames:
- With goal:
{goal}_01.jpg,{goal}_02.jpg, etc. - Without goal:
image_01.jpg,image_02.jpg, etc.
A .sig sidecar file is saved alongside each image containing thought
signatures for reproducible variations.
Limitations
- Requires at least one valid API key (Gemini, OpenAI, or fal.ai)
- Subject to each provider's content policies
- Image quality depends on prompt specificity
- Edit quality depends on source image and instruction clarity
- fal.ai Flux models do not support image editing (generate only)
- Batch concurrency limited to 5 parallel requests
Best Practices
- Be specific in prompts: "A watercolor painting of a serene mountain lake at dawn, soft pastel colors" beats "a lake"
- Use goal names: Helps organize multiple generations
- Iterate: Generate multiple versions and refine prompts based on results
- For edits: Reference specific elements you want changed
- For batch: Batch defaults to
flux-schnell(~$0.003/image) automatically - Trust the router: The router auto-detects text-heavy prompts (OpenAI)
and defaults to nano-banana (Gemini) for everything else. Only set
modeloruse_casewhen you need to override - Ask when ambiguous: If the user hasn't specified quality expectations and it's unclear whether text needs to be rendered, ask before generating
Release files for dungle-scrubs-image-generation 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dungle_scrubs_image_generation-0.1.0.tar.gz | 88.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dungle_scrubs_image_generation-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 120.2 kB
Release files / dungle_scrubs_image_generation-0.1.0.tar.gz
| Download URL | dungle_scrubs_image_generation-0.1.0.tar.gz |
|---|---|
| Size | 88.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
52c14233c6cef4c5d38924cb9c3f2e1f9b27771e9184f522fcf07d92e57ba812
|
|
BLAKE2b-256 checksum How to use checksums |
dffdc5a848ac417b2e42518ed26d89fb5b09d7872e945a1dbdf5bbd9a42d780f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.
Transparency logRelease files / dungle_scrubs_image_generation-0.1.0-py3-none-any.whl
| Download URL | dungle_scrubs_image_generation-0.1.0-py3-none-any.whl |
|---|---|
| Size | 32.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
607eeef053f013e899a1a61257597f70bcd193ae8d73972accacef322a0a010c
|
|
BLAKE2b-256 checksum How to use checksums |
ddded694c55e88aba9226f880a321cbbac5da56fdc5a257b1ce62e10d7b7cf33
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.
Transparency log