Skip to main content
Glama

codex-image-mcp

An MCP server that generates images (game sprites, concept art, icons) with your ChatGPT plan through the official Codex CLI. It needs no API key and has no per-image billing: each image counts against your plan's Codex usage limits.

It runs codex exec headless and lets Codex's built-in image tool (gpt-image) draw. Then it picks up the PNG Codex saves under $CODEX_HOME/generated_images/<thread>/ and writes it where you asked. Optionally it keys out a flat background, trims and downscales the image for sprites.

Unofficial. It only drives the Codex CLI you installed and signed in to; it never reads or sends your tokens anywhere. Codex behaviour can change between versions.

Requirements

  • Codex CLI on PATH (or set CODEX_BIN), signed in with a paid ChatGPT plan (Plus, Pro, Business...). The image tool is not offered on free accounts.

  • uv (or any Python ≥ 3.10 environment).

Sign in with a device code if you have no browser on the machine:

codex login --device-auth

Related MCP server: codex-image

Install

Claude Code:

claude mcp add -s user codex-image -- uvx --from git+https://github.com/JuanCG13/codex-image-mcp codex-image-mcp

Any other MCP client (stdio):

{
  "mcpServers": {
    "codex-image": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/JuanCG13/codex-image-mcp", "codex-image-mcp"]
    }
  }
}

Tools

Tool

What it does

generate_image

One image to output_path (.png). Accepts reference_images to follow a character design or palette.

generate_images

Several jobs in parallel (concurrency, default 3), for example every pose of a sprite set. One result per job, in order.

edit_image

Changes only a region (box or mask_path) of an existing image. Everything outside it stays pixel-identical.

normalize_frames

Makes generated frames one consistent set: same body size, feet baseline and palette as a reference. Local and instant.

login_status

Whether Codex is signed in, and the plan (plus, pro...).

start_device_login

Starts codex login --device-auth and returns the URL and one-time code.

Shared options:

  • chroma_key (e.g. "#FF00FF"): makes that flat background transparent. gpt-image cannot output transparency, so ask for exactly that background colour in the prompt.

  • tolerance (default 60): RGB distance counted as background.

  • trim: crops the image to the subject.

  • max_size: downscales with nearest neighbour so the longest side fits, which keeps pixel art crisp.

  • overwrite: existing files are kept unless this is true.

  • reasoning_effort (default low): how long Codex thinks before calling the tool.

The untouched original stays at raw_path in the result. Each result also reports width, height and Codex token usage.

Example: a sprite

{
  "prompt": "Side-view pixel-art sprite of a stocky coal miner mid pickaxe swing, 16-bit style, full body, centered, on a flat pure magenta (#FF00FF) background",
  "output_path": "/abs/path/assets/miner_swing.png",
  "chroma_key": "#FF00FF",
  "trim": true,
  "max_size": 96
}

Editing a region

Codex's built-in image tool has no mask: every edit redraws the whole picture, so the parts you wanted kept drift (proportions, colours, details). edit_image makes edits safe:

  1. It sends Codex the original (upscaled when small, transparent areas shown on background) and a black-and-white mask of the region, and asks for that change only.

  2. It searches the scale and offset that best overlay the result on the original outside the region, so a re-framed or resized result still lines up.

  3. It copies only the region's pixels from the result. Outside the region the output is the original, byte for byte, alpha included. Inside, the background colour is keyed back to transparency when the original had any.

{
  "image_path": "/abs/path/assets/miner.png",
  "prompt": "Give the miner a red helmet lamp",
  "box": [20, 0, 60, 24],
  "output_path": "/abs/path/assets/miner_lamp.png"
}

The result includes alignment (scale: generated px per original px, origin, error: the mean RGB difference outside the region) and a warning when the result matched poorly.

Making frames a consistent set

Each generation is independent, so frames of one animation come back at different sizes and positions, with slightly different colours. normalize_frames fixes that deterministically:

  • Scale: every frame is resized so the character's body area matches the reference's. Area, unlike height, barely changes when the character crouches, leans or lunges. Thin parts such as a pick handle (under ~4% of the figure's size) are left out of the measure.

  • Anchor: frames are placed on one shared canvas with the same feet baseline and the same centre, taken from the feet rows. The result reports that anchor point for the sprite offset.

  • Palette: colours snap to up to palette_size (default 32) of the reference's own colours. They are picked farthest-first from the most common colour, so a small lamp glow or eye highlight wins a place over many near-identical shades. 0 keeps the generated colours. Alpha becomes fully opaque or transparent.

{
  "frame_paths": ["/abs/gen/windup.png", "/abs/gen/strike.png"],
  "reference_path": "/abs/path/assets/miner_idle.png",
  "output_dir": "/abs/path/assets/miner_combat"
}

Cost and speed

  • About 30–60 s per image. generate_images runs them in parallel.

  • Each run sends Codex's own context: its system prompt, your global ~/.codex/AGENTS.md and the skills list. Most of it is cached between runs. A large global AGENTS.md makes every image more expensive.

  • The server runs Codex with --ignore-user-config and with apps, plugins, the browser and multi-agent turned off, so the request goes straight to the image tool and a model pinned in your config cannot break it.

Development

uv run --with pillow python -m unittest discover -s tests

The tests use tests/fake_codex.py in place of the real CLI, so they spend no quota.

License

MIT

Available Tools

6 tools
edit_imageA

Edit only one region of an image; every pixel outside it stays identical to the original.

Pass exactly one region:

  • box: [x0, y0, x1, y1] in the image's pixels (x1, y1 exclusive).

  • mask_path: a PNG the same size as the image; white (or opaque white) pixels may change. Codex redraws the picture from the original and the mask (~30-60 s, plan usage limits); the result is aligned back onto the original and only the region's pixels are taken. background: flat colour a transparent original is shown on; inside the region that colour is keyed back to transparency (tolerance = RGB distance). The result reports alignment (scale, origin, error) and a warning when the match is poor; the full generated image stays at raw_path.

Inputs: prompt (required), image_path (required), output_path (required), box, +6 more.

generate_imageB

Generate one image with Codex's built-in image tool on the signed-in ChatGPT plan.

Takes ~30-60 s and counts against the plan's Codex usage limits. output_path: absolute path ending in .png; existing files are kept unless overwrite=true. reference_images: local image paths Codex should follow for design, palette or style. reasoning_effort: Codex effort before calling the tool ("low" is fastest).

Inputs: prompt (required), output_path (required), trim, max_size, +6 more.

generate_imagesB

Generate several images in parallel (e.g. every pose of a sprite set).

jobs: list of {"prompt", "output_path", optional "reference_images" and any per-job override of the shared options}. concurrency: parallel Codex runs (default 3; higher may hit rate limits). Returns one result per job in order; failed jobs carry "error".

Inputs: jobs (required), trim, max_size, overwrite, +4 more. Returns: result

login_statusA

Report whether Codex is signed in and which ChatGPT plan it uses (plus, pro, ...).

Inputs: no named parameters.

normalize_framesA

Turn separately generated frames into one consistent sprite set (no Codex call, instant).

Frames need a transparent background (generate them with chroma_key). Each frame is scaled so the character's body area (ignoring thin parts like a pick handle) matches reference_path, which keeps the same size whether the pose stands, crouches or lunges. Frames are anchored on a shared feet baseline and centre on one canvas, given hard alpha, and snapped to up to palette_size of the reference's own colours (0 keeps the generated colours). Writes <output_dir>/.png and returns each frame's scale and body height, the shared canvas size and the anchor (feet point) for the engine's sprite offset.

Inputs: output_dir (required), frame_paths (required), reference_path (required), padding, +2 more.

start_device_loginA

Start a ChatGPT device-code login for Codex and return the URL and one-time code.

The user opens the URL, enters the code and approves; then call login_status to confirm.

Inputs: no named parameters.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

    TDQS

    A3.6/5.0

    Scored across 6 tools

    Disambiguation4/5

    Each tool targets a distinct action: single generation, batch generation, region edit, frame normalization, and two login operations. The only near-pair is generate_image vs generate_images, but the singular/plural framing plus the jobs/concurrency description make the boundary clear. login_status vs start_device_login is also cleanly separated by status-vs-initiate semantics.

    Naming Consistency4/5

    Consistent snake_case with verb_noun ordering (generate_image, edit_image, normalize_frames, start_device_login). The one minor deviation is login_status, which is noun-only rather than a verb form like check_login_status, but it stays readable and predictable.

    Tool Count5/5

    Six tools is well-scoped for an image generation/editing server: generation, batching, editing, post-processing, and login are each covered once. No tool feels redundant or padded.

    Completeness3/5

    The core lifecycle (login, generate, batch generate, edit, normalize frames) is covered, but normalize_frames' description tells users to 'generate them with chroma_key' — a tool that does not exist in this set, leaving a dead end for transparency generation. There is also no way to inspect an existing image or verify plan usage despite usage limits being emphasized throughout.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers