Skip to main content
Glama

gimp-mcp

An MCP server that drives GIMP 3 for scripted image editing: crop, resize, aspect-ratio fitting, light colour touch-up, dimension-spec validation, and batch processing across a folder.

Built and verified on Windows with GIMP 3.2.4, using GIMP 3's GObject Introspection Python API (gi.repository.Gimp) rather than the old 2.x Script-Fu interface.


What it is for

Any workflow where images need the same deterministic treatment applied repeatedly and you would rather describe it than click through it:

  • crop a photo to a target aspect ratio, or to the largest centred square

  • resize a folder of images so the longest edge is at most 2000px

  • check whether images meet a size/orientation requirement before publishing

  • apply one crop-and-resize pipeline across a whole shoot in one pass

Related MCP server: gimp-mcp

The one thing that will bite you: EXIF orientation

Photos from phones and many cameras are frequently stored landscape with an EXIF orientation tag telling viewers to rotate them. A photo everyone sees as 3000x4000 portrait may be stored as 4000x3000.

GIMP's non-interactive loader does not apply that tag. A naive "crop to square, centered" therefore crops the wrong axis and produces a sideways image — while still reporting plausible-looking dimensions, so nothing looks obviously broken until you open the output.

Every load in this project goes through load_image(), which calls Gimp.Image.policy_rotate() first, so all geometry — and every dimension this server reports — is in displayed orientation, i.e. what a viewer actually sees. This is covered by a test.


Architecture

Two execution backends, one shared operation runtime:

                    ┌───────────────────────────────┐
  MCP client ──────►│  gimp_mcp/server.py (stdio)   │
                    └───────────┬───────────────────┘
                                │
              ┌─────────────────┴──────────────────┐
              ▼                                    ▼
   HeadlessBackend                        BridgeBackend
   spawns gimp-console-3.exe              TCP 127.0.0.1:50472
   (no running GIMP needed)               (into a running GIMP)
              │                                    │
              ▼                                    ▼
      bootstrap.py                    plug-ins/gimp-mcp-bridge/
              │                                    │
              └──────────────┬─────────────────────┘
                             ▼
              gimp_mcp/gimp_runtime.py
              THE single source of truth for every
              image operation. Both paths share it,
              so batch and live cannot drift apart.

install_plugin.py writes a runtime_path.txt pointer next to the installed plug-in rather than copying gimp_runtime.py, so exactly one copy of the operation code exists on disk.

Backend choice. headless is the default and is what all batch and deterministic work uses — it needs no open GIMP and is the reliable path. bridge is for live work on a document you already have open. Both are verified to produce pixel-identical output.

Why TCP and not D-Bus

Existing live-GIMP-control projects use D-Bus, which does not exist on Windows. A loopback TCP socket achieves the same thing and is cross-platform. It binds 127.0.0.1 only and is never exposed to the network.


Install

Requires Python 3.10+, GIMP 3.x (developed against 3.2.4), and the mcp Python package. 3.9 cannot work — see the note below.

Note on the mcp dependency. This targets the mcp 1.x SDK and is pinned to mcp>=1.0,<2. Version 2.0 removed mcp.server.fastmcp and renamed FastMCP to MCPServer; porting to it is not done yet, and an unpinned install picks up 2.x and fails at import.

That dependency also sets the Python floor: every published mcp requires >=3.10, so this package cannot install on 3.9 whatever its own metadata says. Tested on 3.10.20 and 3.14.6.

pip install -r requirements.txt
python install_plugin.py          # install the bridge plug-in (optional)
python install_plugin.py --list   # show detected GIMP config dirs

The bridge plug-in is only needed for the live control tools. The batch and single-image tools work without installing anything into GIMP.

Plug-in location

install_plugin.py discovers whatever GIMP 3.x config directories actually exist rather than hardcoding a version. On Windows that is:

%APPDATA%\GIMP\3.2\plug-ins\gimp-mcp-bridge\gimp-mcp-bridge.py

Note it is the versioned directory (3.2 for GIMP 3.2, not 3.0), and GIMP 3 requires each plug-in to sit in a folder whose name matches the .py file. On Linux and macOS the installer looks in ~/.config/GIMP/3.x/ and ~/Library/Application Support/GIMP/3.x/ respectively.

Register the MCP server

Installing the package provides a gimp-mcp console script, which is the tidiest thing to register because it does not depend on a working directory:

python -m venv .venv
.venv/Scripts/python -m pip install -e .     # .venv/bin/python on Unix
{
  "mcpServers": {
    "gimp": {
      "type": "stdio",
      "command": "/path/to/gimp-mcp/.venv/Scripts/gimp-mcp.exe",
      "args": []
    }
  }
}

With Claude Code, the equivalent one-liner is:

claude mcp add gimp --scope user -- /path/to/gimp-mcp/.venv/Scripts/gimp-mcp.exe

Running the module directly works too, if mcp is importable in that interpreter:

{
  "mcpServers": {
    "gimp": {
      "command": "python",
      "args": ["-m", "gimp_mcp"],
      "cwd": "/path/to/gimp-mcp"
    }
  }
}

Optional environment variables:

Variable

Purpose

GIMP_CONSOLE

Full path to gimp-console-3.exe if it is not auto-detected

GIMP_MCP_BACKEND

headless (default) or bridge

GIMP_MCP_BRIDGE_PORT

Bridge port, default 50472


Tools

Inspection

Tool

Purpose

gimp_status

Check GIMP is reachable; reports both backends. Start here if something is wrong.

inspect_image

Dimensions, layers, orientation. Dimensions are as displayed.

check_image_spec

Validate against a dimension spec; pass/fail with measured dimensions and a plain-language reason.

Single image

Tool

Purpose

crop_image

Exact pixel rectangle. Rejects out-of-bounds rather than silently clamping.

crop_square

Largest square; anchor = center/top/bottom/left/right/corner.

crop_to_aspect

Target ratio (1.0 square, 1.3333 for 4:3, 1.7778 for 16:9), max area.

resize_image

By width, height, or max_edge. Aspect preserved by default.

adjust_image

Brightness/contrast, -1..1, rejected outside rather than clamped.

enhance_image

Gamma shadow-lift, contrast, saturation and a high-pass sharpen in one pass.

fit_to_spec

One shot: fix orientation by cropping, upscale to a minimum, downscale to a maximum, optional touch-up.

process_image

Custom operation pipeline in one pass (one JPEG re-encode).

Batch

Tool

Purpose

batch_process

Arbitrary pipeline over a folder.

batch_fit_to_spec

Conform a whole folder to one dimension spec.

batch_check_image_spec

Read-only audit; triage before editing.

A whole batch runs inside one GIMP invocation. GIMP's console takes several seconds to start, so spawning per file would be slow — measured at ~2.4x cheaper per file for a small folder, and the saving grows with folder size. A file that fails does not abort the run; it lands in errors and the rest continue.

Live control (needs the bridge plug-in)

Tool

Purpose

live_list_images

What is open in the running GIMP.

live_screenshot

Flattened snapshot of the canvas, so you can see and iterate.

live_run_python

Arbitrary Python in the live context; assign to result.

live_stop_bridge

Stop the bridge, leave GIMP open.

Start the bridge in GIMP: Filters > Development > Start MCP Bridge.


Image specifications

check_image_spec, fit_to_spec and their batch equivalents share one spec model. Every constraint is optional — 0 means no limit, and orientation any means no orientation requirement.

Field

Values

min_width, min_height

pixels, 0 for no minimum

max_width, max_height

pixels, 0 for no maximum

orientation

any, square, landscape, portrait, square_or_landscape, square_or_portrait

fit_to_spec satisfies a spec in three ordered steps: crop to correct the orientation, upscale to reach the minimum, downscale to respect the maximum. Constraints already satisfied leave the framing untouched.

// A square image at least 1000x1000, capped at 2000x2000
{ "orientation": "square", "min_width": 1000, "min_height": 1000,
  "max_width": 2000, "max_height": 2000 }

Enhancement

enhance_image applies, in this order and each skippable at its no-op value:

Parameter

Effect

Off at

gamma

lifts midtones and shadows via levels, black and white points untouched so nothing clips

1.0

contrast

GIMP 3 native -1..1

0.0

saturation

-100..100

0.0

sharpen

high-pass sharpen blended back at this percent opacity

0.0

sharpen_radius

blur radius in px for the high pass

default 8

The sharpen is a frequency-separation high pass — duplicate, blur, grain-extract to isolate the high frequencies, grain-merge back at low opacity — not an unsharp mask, which haloes around high-contrast edges.

Contrast does not mean what it meant in GIMP 2.x

GIMP 3 runs brightness-contrast in linear light; GIMP 2.x ran it on sRGB values. The same nominal number is therefore much stronger here. Measured on a real photo against the 2.x transfer curve:

GIMP 2.x "+12"  ->  slope 1.161 on sRGB   (the intended result)
passing 12/127 = 0.094 to GIMP 3          ~4x too strong, visibly crushes shadows
contrast = 0.020 in GIMP 3                closest match to the intended curve

sharpen_radius has the same trap: GIMP 3 dropped plug-in-gauss, and gegl:gaussian-blur takes a standard deviation, not a radius. A radius is converted using GIMP's legacy formula (radius 8 → std-dev ≈ 2.40) and the applied value is reported back so it can be checked.

Calibrate against output, not against a remapped number.

Colour adjustment: range, and what it actually does

adjust_image and enhance_image's contrast both run -1.0..1.0 — GIMP 3's real range for this operation — and reject values outside it rather than clamping. They wrap the same GIMP call, so they deliberately share one range; an earlier version capped adjust_image at ±0.5 and described that as "the native range", which was simply wrong and made two tools behave differently for no stated reason.

Useful values are far smaller than the limits. GIMP 3 applies this in linear light, so anything much past ±0.1 visibly changes the character of a photo — see Enhancement for the measured comparison against GIMP 2.x. Keep adjustments small when the image needs to represent a real subject faithfully.

There is intentionally no "auto enhance" that guesses at settings.


Verification

Run the suite:

python -m pytest tests/ -v

Tests that need real images are skipped unless you point them at some:

export GIMP_MCP_TEST_IMAGE=/path/to/photo.jpg          # ideally EXIF-rotated
export GIMP_MCP_TEST_REFERENCE=/path/to/photo-square.jpg

GIMP_MCP_TEST_REFERENCE should be an independently produced centred square crop of GIMP_MCP_TEST_IMAGE — cropped by hand in GIMP, for example. The headline test asserts that crop_square reproduces that reference, rather than merely running without error.

On the reference photo used during development (a 4000x3000 JPEG with EXIF orientation 6, displaying as 3000x4000):

crop_square vs hand-made reference : mean abs diff 0.236, max 18, outliers 0.0014%
same crop via the bridge backend   : mean abs diff 0.236, max 18, outliers 0.0014%

That residual is JPEG re-encode noise — re-encoding alone gives ~0.5 mean — not a geometry difference, and both backends agree exactly.

The suite also covers displayed-orientation reporting, orientation and minimum-size specs, out-of-bounds crops being rejected, out-of-range adjustments being rejected, brightness moving pixels the right way, chained pipelines, aspect-ratio cropping, batch across a folder, the read-only audit, clear errors for missing files, and a full pass over the real MCP stdio protocol.


Troubleshooting

gimp-console not found — set GIMP_CONSOLE to the full path of gimp-console-3.exe.

Bridge tools fail with "Could not reach the GIMP bridge" — GIMP is not open, or the bridge was not started. Run Filters > Development > Start MCP Bridge. gimp_status shows both backends at once.

The menu item is missing after installing — restart GIMP; it only scans plug-ins at startup. Confirm the layout is plug-ins/gimp-mcp-bridge/gimp-mcp-bridge.py (the folder name must match the file name).

Diagnosing the plug-in — a GIMP plug-in is a separate process whose stderr is invisible when GIMP runs as a GUI app on Windows. The bridge writes to bridge.log next to the installed plug-in.

A colour-profile dialog blocks GIMP on startup when opening an image with an embedded profile in GUI mode. It does not appear in headless mode, which is another reason batch work uses the headless backend.

Batch timed out — the default is 600s for the whole run; very large folders may need more.


Testing

python -m pytest tests/ -q                      # everything
python -m pytest tests/ -q -k "not live"        # skip the slow bridge tests
GIMP_MCP_SKIP_LIVE=1 python -m pytest tests/    # same, via the env var

Most tests drive real GIMP, which is the point — they are slow because they are not mocking the thing under test. Those needing sample images skip unless GIMP_MCP_TEST_IMAGE / GIMP_MCP_TEST_REFERENCE are set (see conftest.py).

tests/test_live_bridge.py covers the four live_* tools by starting a bridge itself. It hosts the plug-in under gimp-console, not the GUI: plug-ins run there just the same, so the fixture needs no window, no desktop session and no window manager, starts in ~2s instead of ~10, and cannot be blocked by the colour-profile dialog a GUI GIMP raises for a photo with an embedded profile. It binds a non-default port (50573, and 50574 for the teardown test) so it never collides with a bridge you have running on 50472, and it tears the process down afterwards — verified across repeated runs to leave no stray process and no open port.

Known limitations

  • The live_* tests need a real GIMP and are the slow part of the suite. tests/test_live_bridge.py starts a bridge itself and covers all four tools, but it costs ~33s and depends on GIMP being installed with the plug-in in place. It skips with a reason — never hangs — when GIMP is missing, the plug-in is not installed, its port is taken, or the bridge does not answer in time. GIMP_MCP_SKIP_LIVE=1 skips it outright.

  • The bridge executes arbitrary Python by design. It is loopback-only and started manually rather than automatically, but anything that can reach localhost on the machine can drive GIMP while it is running. Stop it when not in use.

  • Bridge start blocks its own plug-in process — that is what keeps it alive. It does not freeze GIMP's UI, but GIMP shows the plug-in as running.

  • The GUI menu item itself is not automated-test covered. The procedure it invokes is verified; the click path is not.

  • Only Windows is verified. The code paths are cross-platform and the installer handles Linux/macOS config directories, but neither has been tested.

  • The mcp 2.x SDK is not supported yet -- see the note under Install.

  • Python 3.10 is the floor, and 3.9 is impossible. Not a style preference: the mcp SDK has required >=3.10 in every version ever published (0.9.1 through 2.1.x), so on 3.9 the sole runtime dependency does not resolve and the package cannot be installed at all. The floor was briefly advertised as >=3.9, which promised something that could never work. It is now >=3.10, verified by running the full suite on 3.10.20 (39 passed), and tests/test_packaging.py checks the declared floor against the installed mcp's own metadata so the two cannot drift apart again.

  • No AI background removal or style transfer. Some comparable projects advertise these without a working implementation behind them; they are deliberately not claimed here.

Notes on prior art

The split between a GIMP-side plug-in exposing a bridge and a standalone MCP server process that connects to it as a client is a natural shape for this problem and is used by other GIMP MCP projects. Batch processing and preset-style pipelines are common to several. Live-canvas control exists elsewhere via D-Bus, replaced here with loopback TCP for Windows support. No code was copied from any of them; the Windows specifics — the real plug-in path, the plug-in process lifetime, the run-callback signature, and the EXIF behaviour — were established directly against GIMP 3.2.4.

License

MIT — see LICENSE.

Available Tools

18 tools
adjust_imageA

Brightness/contrast touch-up.

Both values run -1.0..1.0 -- GIMP 3's real range for this operation -- and are rejected outside it rather than clamped. enhance_image uses the same range for contrast; they wrap the same GIMP call.

Useful values are far smaller than the limits. GIMP 3 applies this in linear light, so it bites harder than the same number did in GIMP 2.x, and anything much past +/-0.1 visibly changes the character of a photo. Keep adjustments small when the image needs to represent a real subject faithfully.

Inputs: input_path (required), output_path (required), backend, quality, +2 more. Returns: result

batch_check_image_specA

Audit a folder: which images already satisfy a specification.

Read-only; writes nothing. Use it to triage a folder before editing.

Inputs: input_dir (required), backend, pattern, max_width, +5 more. Returns: result

batch_fit_to_specC

Make every image in a folder satisfy one dimension specification.

The common bulk case: point it at a folder of photos and get conforming copies, with each file's final dimensions and pass/fail reported.

Inputs: input_dir (required), output_dir (required), anchor, suffix, +9 more. Returns: result

batch_processA

Apply the same operations to every image in a folder.

All files are handled inside a single GIMP session, so a large folder costs one GIMP startup rather than one per file. A file that fails does not abort the run: it is reported in errors and the rest continue.

operations is a JSON list, same format as process_image. Set suffix to e.g. "_out" to avoid overwriting, and output_format to "jpg"/"png" to convert.

Inputs: input_dir (required), operations (required), output_dir (required), suffix, +5 more. Returns: result

check_image_specA

Check an image against a dimension specification.

Every constraint is optional: 0 means "no limit", and orientation "any" means no orientation requirement. Valid orientation values are: any, square, landscape, portrait, square_or_landscape, square_or_portrait.

Returns pass/fail with the actual measured dimensions and a plain-language reason for each failure. Useful for validating images against a publishing platform's requirements, a print size, or an asset pipeline's conventions before spending time editing.

Inputs: path (required), backend, max_width, min_width, +3 more. Returns: result

crop_imageB

Crop to an exact pixel rectangle.

x/y are the top-left offset in DISPLAYED orientation. Fails clearly if the rectangle falls outside the image rather than silently clamping.

Inputs: width (required), height (required), input_path (required), output_path (required), +4 more. Returns: result

crop_squareB

Crop to the largest possible square.

anchor picks which part of the frame to keep: center (default), top, bottom, left, right, or a corner such as topleft.

Inputs: input_path (required), output_path (required), anchor, backend, +1 more. Returns: result

crop_to_aspectB

Crop to a target aspect ratio (width/height), keeping maximum area.

Use 1.0 for square, 1.3333 for 4:3, 1.5 for 3:2, 1.7778 for 16:9.

Inputs: ratio (required), input_path (required), output_path (required), anchor, +2 more. Returns: result

enhance_imageA

Tone and detail enhancement in one pass.

gamma lifts midtones and shadows via levels, leaving the black and white points alone so nothing clips. 1.0 = off. contrast GIMP 3 native -1..1. 0 = off. saturation -100..100. 0 = off. sharpen high-pass sharpen blended back at this percent opacity, 0 = off. Preferred over unsharp mask, which haloes. sharpen_radius blur radius in pixels for the high pass (default 8).

Contrast bites harder than the same nominal value did in GIMP 2.x, because GIMP 3 runs the operation in linear light: 2.x's "+12" is roughly 0.020 here, not 0.094. Calibrate against output rather than remapping an old number.

Inputs: input_path (required), output_path (required), gamma, backend, +5 more. Returns: result

fit_to_specA

Transform an image until it satisfies a dimension specification.

Crops to fix the orientation if required, upscales to reach a minimum size, downscales to respect a maximum, and optionally applies a light touch-up -- all in one pass, so the JPEG is re-encoded only once. Images already satisfying a constraint keep their framing.

Example: to produce a square image at least 1000x1000, pass orientation="square" with min_width=1000 and min_height=1000.

Inputs: input_path (required), output_path (required), anchor, backend, +9 more. Returns: result

gimp_statusA

Check that GIMP is reachable and report its version.

Use this first if anything seems wrong. Reports both the headless backend and whether the live bridge plug-in is running inside an open GIMP.

Inputs: backend. Returns: result

inspect_imageB

Report an image's dimensions, layers, and orientation.

Dimensions are reported as DISPLAYED (EXIF orientation applied), which is what a viewer sees -- not necessarily how the pixels are stored.

Inputs: path (required), backend. Returns: result

live_list_imagesA

List the images currently open in the running GIMP.

Requires the bridge plug-in (Filters > Development > Start MCP Bridge).

Inputs: no named parameters. Returns: result

live_run_pythonA

Execute Python inside the running GIMP and return result.

The Gimp module and every operation helper are already in scope. Assign to a variable named result to return a value. Escape hatch for anything the typed tools above do not cover; requires the bridge plug-in.

Inputs: code (required). Returns: result

live_screenshotA

Save a flattened snapshot of an image open in the running GIMP.

Lets you see the current state of a document you are editing live, then iterate on it. Requires the bridge plug-in.

Inputs: output_path (required), max_edge, image_index. Returns: result

live_stop_bridgeA

Stop the bridge inside the running GIMP, leaving GIMP itself open.

Inputs: no named parameters. Returns: result

process_imageA

Apply a custom sequence of operations in one pass.

operations is a JSON list, e.g. [{"op":"crop_square","anchor":"center"}, {"op":"resize","max_edge":2000}, {"op":"adjust","brightness":0.05}]

Available ops: crop, crop_square, crop_aspect, resize, adjust, autocrop, flatten, fit_spec, enhance. Running them as one pipeline re-encodes the JPEG only once, which avoids stacking compression artefacts.

The optional spec arguments are checked against the FINAL result and reported under spec, so a pipeline that both reshapes and edits an image can be validated without a second pass over it.

Inputs: input_path (required), operations (required), output_path (required), backend, +6 more. Returns: result

resize_imageA

Resize an image.

Give width, height, both, or max_edge (longest side, aspect preserved). With preserve_aspect and both dimensions, the image is fitted inside the box rather than distorted.

Inputs: input_path (required), output_path (required), width, height, +4 more. Returns: result

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A3.5/5.0

    Scored across 18 tools

    Disambiguation3/5

    Several tools overlap in purpose: adjust_image and enhance_image share the same contrast call, and process_image/batch_process can reproduce the effects of most individual editing tools. The descriptions generally clarify scope, but an agent could easily hesitate between a dedicated single-op tool and its pipeline equivalent.

    Naming Consistency4/5

    Most tools follow a clear verb_object snake_case pattern such as crop_image, resize_image, inspect_image, and batch_check_image_spec. The batch_ and live_ prefixes are applied consistently, with only gimp_status and fit_to_spec deviating slightly from the otherwise predictable pattern.

    Tool Count4/5

    At 18 tools the server is slightly above the ideal 3-15 range, but the count is justified by the distinct clusters: single-image operations, spec checking/fitting, batch variants, and live GIMP bridge tools. The single/batch pairs add surface area but each serves a real workload.

    Completeness4/5

    The toolset covers the core image pipeline well: inspect, validate, crop, resize, adjust, enhance, process in one pass, and batch over folders. Obvious gaps like rotation or flipping are absent, but live_run_python and process_image provide workarounds for most missing operations.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables AI agents to perform GIMP-style image operations such as open, resize, crop, flip, rotate, blur, desaturate, text overlay, export, and batch processing via MCP tools, supporting both mock (Pillow) and live GIMP backends.
      2
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI agents to control GIMP for image editing tasks such as opening, resizing, filtering, exporting, and batch processing images through Python-Fu scripting.
      33 npm
      MIT
    • A
      license
      B
      quality
      D
      maintenance
      Enables controlling GIMP 3 locally through natural language, providing tools for image editing, layer management, selections, and PDB procedure invocation. Keeps all images and files on the user's machine with a local-first, secure design.
      40
      1
      GPL 3.0
    • A
      license
      B
      quality
      B
      maintenance
      Enables AI agents to operate GIMP 3 end-to-end: open and inspect images, call every PDB procedure, apply GEGL filters destructively or as layer effects, measure pixels, render before/after/diff comparisons, cut out subjects with AI segmentation, and run multi-step recipes across folders.
      32
      76 PyPI
      5
      Apache 2.0