# GIMP Studio MCP (pypi · twelvetake-gimp-studio-mcp)

Lets an AI assistant edit images in GIMP 3, including print and DTF transfer prep.

- Trust score: 76/100 (medium)
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-10-04

## Components

- pypi · `twelvetake-gimp-studio-mcp`: 76/100 (this document), [markdown](https://verifymcp.io/servers/com-twelvetake-gimp-studio-mcp/twelvetake-gimp-studio-mcp.md), [page](https://verifymcp.io/servers/com-twelvetake-gimp-studio-mcp/twelvetake-gimp-studio-mcp)

## Channel facts

- Registry: `pypi`
- Package: `twelvetake-gimp-studio-mcp`
- Version: `0.3.4`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-10-04.

- **Supply Chain Security**: 100/100
  - No malware found by supply-chain analysis.
  - No known CVEs affecting this package version or its production dependencies.
  - Runs hatchling.build at install time, a recognised build step with no custom scripting around it.
  - 0 of 28 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 100/100
  - Source repository is publicly reachable at the declared URL.
  - Cryptographically verified build provenance (signed, bound to TwelveTake-Studios/gimp-studio-mcp).
  - Clear OSI-approved license (MIT).
  - Actively maintained (last published 4 days ago).
  - Publishes a security disclosure policy (SECURITY.md).
- **Schema Quality & AI Usability**: 69/100
  - AI-judged instruction clarity (good).
  - Tool/resource definitions use about 9684 tokens (~81/item across 119 items; 119 tools + 0 resources), lean.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 0/100
  - Stability not yet verified: not enough scan history yet (needs a 30-day window).
- **Tool Coverage**: 67/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 0% of tool parameters carry a description.
- **Tool Safety**: 75/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - 0 of 6 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "gimp_exec" implies "exec" and declares no destructiveHint at all, which the MCP spec reads as destructive by default.
  - An AI judge read all 120 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

**Unverified: 1 category.** A category scored 0 because we could not verify it: a data source with nothing on this package, evidence we could not reach, or a check we could not run. We only credit what we can confirm.

## Install

### How do I install the GIMP Studio MCP server?

GIMP Studio MCP runs locally as a PyPI package, launched with uvx twelvetake-gimp-studio-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add com-twelvetake-gimp-studio-mcp -- uvx twelvetake-gimp-studio-mcp
```

### Cursor

```json
{
  "mcpServers": {
    "com-twelvetake-gimp-studio-mcp": {
      "command": "uvx",
      "args": [
        "twelvetake-gimp-studio-mcp"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "com-twelvetake-gimp-studio-mcp": {
      "command": "uvx",
      "args": [
        "twelvetake-gimp-studio-mcp"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add com-twelvetake-gimp-studio-mcp -- uvx twelvetake-gimp-studio-mcp
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "com-twelvetake-gimp-studio-mcp": {
      "type": "local",
      "command": [
        "uvx",
        "twelvetake-gimp-studio-mcp"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add com-twelvetake-gimp-studio-mcp --command uvx --arg twelvetake-gimp-studio-mcp
```

### Hermes

```yaml
mcp_servers:
  com-twelvetake-gimp-studio-mcp:
    command: "uvx"
    args: ["twelvetake-gimp-studio-mcp"]
```

### Netclaw

```json
{
  "McpServers": {
    "com-twelvetake-gimp-studio-mcp": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "twelvetake-gimp-studio-mcp"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add com-twelvetake-gimp-studio-mcp -t stdio -c uvx -a twelvetake-gimp-studio-mcp
```

### Other

```json
{
  "mcpServers": {
    "com-twelvetake-gimp-studio-mcp": {
      "command": "uvx",
      "args": [
        "twelvetake-gimp-studio-mcp"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-09-30 (score 76, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-09-29 (score 61)

First indexed and scored.

## MCP tools (119)

### `status` (~35 tokens)

GIMP/bridge health: GIMP version, bridge version, mode, open-image count,
and the names seeded into the persistent namespace.

### `list_images` (~25 tokens)

List open images: id, name (basename), width, height, dirty flag.

### `set_active_image` (~25 tokens)

Set the working image by integer id or basename string.

Input parameters:

- `image` (required)

### `gimp_exec` (~143 tokens)

Raw escape hatch: run Python inside GIMP.

Returns the structured envelope {ok, result, stdout, warnings, error}; stdout
is preserved even on error. Set a top-level `_result` for structured output.
The persistent namespace has Gimp/Gegl/Gio/GLib/GObject/Babl, `pdb`,
\`find_image(spec)`, and `compat` (color/read_pixel/color_to_alpha/...).

Runs arbitrary host code by design (same trust boundary as the local user);
set GIMP_MCP_NO_EXEC=1 to skip registering this tool. See SECURITY.md.

Input parameters:

- `code` (string, required)
- `undo_group` (boolean)

### `reset_namespace` (~90 tokens)

Reset the persistent namespace.

scope='soft' (default): clear user-defined vars and re-seed the baseline;
the canvas/open images are untouched.
scope='scratch' (guarded HARD reset): soft + delete only bridge-created
scratch images (checkpoint snapshots tagged in `_gimpmcp_scratch`); never
touches user-opened or agent working images.

Input parameters:

- `scope` (string)

### `get_metadata` (~110 tokens)

Metadata for an OPEN image: pixel width/height, resolution
[x_dpi, y_dpi], base type, precision, file path, dirty flag, and per-layer
info (size, opacity, visible, has_alpha). `image` = id/basename, or omit for
the active image. To inspect a file ON DISK (e.g. verify an export's pixels /
DPI), open_image it first, then call this on the returned id.

Input parameters:

- `image`

### `new_image` (~61 tokens)

Create a new RGBA image. fill: white|transparent|background|foreground.
Returns the new image id + size.

Input parameters:

- `fill` (string)
- `height` (integer, required)
- `name` (string)
- `width` (integer, required)

### `open_image` (~33 tokens)

Open an image file (any format GIMP loads). Returns new image id + size.

Input parameters:

- `path` (string, required)

### `export_image` (~182 tokens)

Export an image to a file (format by extension: png/jpg/tiff/webp/...).
Works on a COPY — the source image is never modified.

ALPHA-SAFE: transparency is PRESERVED by default for formats that support it
(png/tiff/webp/tga/gif) and only flattened for formats that can't hold alpha
(jpg/bmp) — so a transparent cutout isn't silently ruined. `flatten=True`
forces a flattened opaque export; `flatten=False` forces keep-alpha (merge
visible, no flatten). For DTF PNGs prefer `export_dtf_png` (also tags DPI).
Returns {saved, format, flattened, alpha (kept in the file?), had_alpha,
warning (set when alpha had to be dropped)}.

Input parameters:

- `flatten`
- `image`
- `path` (string, required)

### `create_layer` (~83 tokens)

Create a new transparent RGBA layer (default sized to the image) and
insert it at `position` (0=top) under optional `parent` group.

Input parameters:

- `height`
- `image`
- `name` (string, required)
- `opacity` (number)
- `parent`
- `position` (integer)
- `width`

### `layer_from_file` (~70 tokens)

Load an image file as a new layer in the image and insert it (top by
default). Optional `name`/`parent`/`position`.

Input parameters:

- `image`
- `name`
- `parent`
- `path` (string, required)
- `position` (integer)

### `duplicate_layer` (~50 tokens)

Duplicate a layer; the copy is inserted just above the original.
\`layer` = id/name, or omit for the active layer.

Input parameters:

- `image`
- `layer`
- `name`

### `delete_layer` (~37 tokens)

Remove a layer from the image. `layer` = id/name, or omit for active.

Input parameters:

- `image`
- `layer`

### `reorder_layer` (~59 tokens)

Move a layer to absolute `position` (0=top) within its parent, or into
a different `parent` group when given.

Input parameters:

- `image`
- `layer`
- `parent`
- `position` (integer)

### `set_opacity` (~37 tokens)

Set a layer's opacity (0-100 float).

Input parameters:

- `image`
- `layer`
- `opacity` (number, required)

### `set_blend_mode` (~59 tokens)

Set a layer's blend mode (NORMAL, MULTIPLY, SCREEN, OVERLAY, ...).
Case/sep insensitive; unknown names fall back to NORMAL.

Input parameters:

- `image`
- `layer`
- `mode` (string, required)

### `set_visible` (~31 tokens)

Show/hide a layer.

Input parameters:

- `image`
- `layer`
- `visible` (boolean, required)

### `rename_layer` (~29 tokens)

Rename a layer.

Input parameters:

- `image`
- `layer`
- `name` (string, required)

### `merge_down` (~45 tokens)

Merge a layer down into the one below it (EXPAND_AS_NECESSARY).
Destructive. Returns the resulting merged layer.

Input parameters:

- `image`
- `layer`

### `flatten` (~23 tokens)

Flatten the image to a single layer. Destructive.

Input parameters:

- `image`

### `group_create` (~52 tokens)

Create an empty layer group, inserted at `position` (0=top) under
optional `parent`.

Input parameters:

- `image`
- `name`
- `parent`
- `position` (integer)

### `group_add` (~47 tokens)

Move an existing layer into a layer group at `position` (0=top).

Input parameters:

- `group`
- `image`
- `layer`
- `position` (integer)

### `group_ungroup` (~51 tokens)

Dissolve a layer group: lift its children to the group's parent (in
order) and remove the empty group. Destructive to the group structure.

Input parameters:

- `group`
- `image`

### `move_layer` (~44 tokens)

Move a layer to absolute canvas offsets (x, y).

Input parameters:

- `image`
- `layer`
- `x` (integer, required)
- `y` (integer, required)

### `offset_layer` (~49 tokens)

Offset a layer by a relative delta (dx, dy) from its current position.

Input parameters:

- `dx` (integer)
- `dy` (integer)
- `image`
- `layer`

### `offset_content` (~126 tokens)

Roll a layer's PIXEL CONTENT by (dx, dy) — distinct from offset_layer, which
repositions the layer on the canvas. wrap=True wraps edges around (use it to
seam-check a tileable texture); wrap=False fills the vacated strip per
fill: transparent|color (color uses the `color` name/hex, default clear).

Input parameters:

- `color`
- `dx` (integer)
- `dy` (integer)
- `fill` (string)
- `image`
- `layer`
- `wrap` (boolean)

### `seam_check` (~100 tokens)

Wrap-offset a layer's content by half its size so a tileable texture's seams
land in the middle for inspection (pair with get_bitmap). axis: both|x|y.
Destructive — undo to revert (re-running the same axis restores only when that
dimension is even; for odd sizes floor(w/2) applied twice lands 1px off).

Input parameters:

- `axis` (string)
- `image`
- `layer`

### `add_mask` (~126 tokens)

Add a layer mask. mask_type: white|black|alpha|alpha-transfer|
selection|copy|channel. Omit `layer` for the selected/top layer.
For mask_type='channel' pass `channel` (id/name) as the source, or have a
channel already selected; with neither, channel masks return
supported=False (GIMP 3.0.4 create_mask(CHANNEL) needs a selected
channel and exposes no source-channel parameter).

Input parameters:

- `channel`
- `image`
- `layer`
- `mask_type` (string)

### `apply_mask` (~36 tokens)

Merge the layer's mask into its alpha (destructive). No-op if no mask.

Input parameters:

- `image`
- `layer`

### `remove_mask` (~31 tokens)

Discard the layer's mask without applying it (destructive).

Input parameters:

- `image`
- `layer`

### `add_alpha` (~30 tokens)

Add an alpha channel to the layer if it lacks one.

Input parameters:

- `image`
- `layer`

### `lock_alpha` (~38 tokens)

Lock (or unlock) the layer's alpha channel against painting.

Input parameters:

- `image`
- `layer`
- `locked` (boolean)

### `luminance_to_alpha` (~93 tokens)

Map luminance to transparency per-pixel (destructive): default makes
dark pixels transparent and bright pixels opaque (white-art-on-black);
invert=True makes bright pixels transparent (knock out white/highlights).
Computed directly over the layer buffer (no dedicated GEGL op exists in
GIMP 3.0.4).

Input parameters:

- `image`
- `invert` (boolean)
- `layer`

### `color_to_alpha` (~194 tokens)

SOFT knockout: remove a color to transparency with graded alpha
(destructive; gegl:color-to-alpha). color: name/#rrggbb. The colour is
subtracted from every pixel that contains it, so edges and matching interior
tones fade smoothly — great for feathered/anti-aliased backgrounds (e.g. a
clean black knockout from #000000 at threshold ~0.15-0.20). Higher
\`transparency_threshold` (0-1) removes a wider band of near-target colours;
\`opacity_threshold` (0-1) sets where fully-opaque begins. For a CRISP,
hard-edged cut (select-by-colour + delete, no fade) use `cutout_color`.

Input parameters:

- `color` (string)
- `image`
- `layer`
- `opacity_threshold` (number)
- `transparency_threshold` (number)

### `cutout_color` (~290 tokens)

HARD knockout: select a colour and DELETE it to transparency — the crisp,
predictable cutout (the tool form of by-hand 'add alpha -> select by colour ->
delete'). Auto-adds alpha. WYSIWYG: no auto-mode, no defringe, no alpha-clean.

Colour to remove: explicit `color` (name/#hex/rgb) OR a `sample_xy=[x,y]`
eyedropper (one is required). `threshold` (0-1, default 0.15) = colour-match
tolerance. `contiguous=True` removes only the edge-connected region (keeps
interior areas that reuse the colour); seeds from `sample_xy` if given, else
the nearest-matching corner. `antialias` (default on) smooths the cut edge;
\`feather` softens it further. For a soft/graded knockout use `color_to_alpha`.

Returns the colour used, `cleared`, `content_bbox` as `[x1,y1,x2,y2]` (or null),
and canonical `layer`/`image` ids.

Input parameters:

- `antialias` (boolean)
- `color`
- `contiguous` (boolean)
- `feather` (number)
- `image`
- `layer`
- `sample_xy`
- `threshold` (number)

### `threshold_alpha` (~50 tokens)

Binarize the alpha channel at `value` (0..1) for a clean print edge
(destructive).

Input parameters:

- `image`
- `layer`
- `value` (number)

### `select_rect` (~67 tokens)

Rectangular selection. op: replace|add|subtract|intersect.
Returns selection bounds.

Input parameters:

- `h` (integer, required)
- `image`
- `op` (string)
- `w` (integer, required)
- `x` (integer, required)
- `y` (integer, required)

### `select_ellipse` (~74 tokens)

Elliptical selection inscribed in the x,y,w,h box. op:
replace|add|subtract|intersect.

Input parameters:

- `h` (integer, required)
- `image`
- `op` (string)
- `w` (integer, required)
- `x` (integer, required)
- `y` (integer, required)

### `select_by_color` (~76 tokens)

Select all pixels matching a color (name/#rrggbb/(r,g,b[,a])) within
threshold (0..1). op: replace|add|subtract|intersect.

Input parameters:

- `color` (required)
- `image`
- `layer`
- `op` (string)
- `threshold` (number)

### `fuzzy_select` (~78 tokens)

Contiguous color (magic-wand) selection seeded at x,y within threshold
(0..1). op: replace|add|subtract|intersect.

Input parameters:

- `image`
- `layer`
- `op` (string)
- `threshold` (number)
- `x` (integer, required)
- `y` (integer, required)

### `select_all` (~19 tokens)

Select the entire image canvas.

Input parameters:

- `image`

### `select_none` (~20 tokens)

Clear the selection (select nothing).

Input parameters:

- `image`

### `select_invert` (~20 tokens)

Invert the current selection.

Input parameters:

- `image`

### `select_grow` (~31 tokens)

Grow the selection outward by `steps` pixels.

Input parameters:

- `image`
- `steps` (integer, required)

### `select_shrink` (~32 tokens)

Shrink the selection inward by `steps` pixels.

Input parameters:

- `image`
- `steps` (integer, required)

### `select_feather` (~35 tokens)

Feather (soften) the selection edge by `radius` pixels.

Input parameters:

- `image`
- `radius` (number, required)

### `select_border` (~33 tokens)

Replace the selection with a border band `radius` pixels wide.

Input parameters:

- `image`
- `radius` (integer, required)

### `selection_to_channel` (~33 tokens)

Save the current selection to a new channel. Returns the channel id.

Input parameters:

- `image`
- `name`

### `select_from_alpha` (~59 tokens)

Select from a layer's alpha (opaque pixels). layer = id/name or omit for
the active drawable. op: replace|add|subtract|intersect.

Input parameters:

- `image`
- `layer`
- `op` (string)

### `select_from_path` (~85 tokens)

Select the region enclosed by a path. path = id/name or omit for the
active path. op: replace|add|subtract|intersect. If the image has no
paths and none is named, returns {"supported": false} (nothing to do)
rather than erroring.

Input parameters:

- `image`
- `op` (string)
- `path`

### `foreground_select` (~473 tokens)

Edge-aware SUBJECT selection via SIOX/matting
(gimp-drawable-foreground-extract). Refines a ROUGH hint into a clean
foreground selection — good for hair/soft/complex edges and backgrounds that
AREN'T a flat colour (where cutout_color / select_by_color fail). It is
SEMI-automatic: it needs a rough hint and does NOT auto-detect the subject.

Rough hint: pass a bounding box `x, y, w, h` roughly around the subject, OR
make a rough selection first and omit the box. `band` = px the hint is grown /
shrunk to form the 'unknown' boundary ring the matting solves (so the ring is
\~2*band wide; default auto from the region size; larger = more slack for an
imprecise hint). Internally builds a trimap (shrink→foreground / grow→background
/ the ring between→unknown), runs matting, and REPLACES the selection with the
refined matte.

KNOWN LIMITATION — the hint must roughly FIT the subject's shape. Everything
inside the shrunk hint is treated as definite foreground, so if the subject does
NOT fill its box (an irregular shape, or several subjects with background showing
between them), that interior background is KEPT and only the edge band is refined.
A rectangular box works when the subject fills it; for an irregular subject give a
rough OUTLINE *selection* (omit the box) instead. This is an edge REFINER, not a
subject detector — for cutting a subject out of a busy scene (e.g. people in a
crowd) use an external model (rembg/u²-net; not built in). A subject running to
the image edge may also lose a thin strip there. On failure the incoming selection
is restored and no scratch channel is left behind.

Follow with `select_invert` + `cutout_color`/clear to knock out the background.
Returns {bounds, band, hint, fg_core_empty, selection_empty, layer, image}.

Input parameters:

- `band`
- `h`
- `image`
- `layer`
- `w`
- `x`
- `y`

### `set_fg` (~34 tokens)

Set the foreground color. color = name|'#rrggbb'|(r,g,b[,a]).

Input parameters:

- `color` (required)

### `set_bg` (~34 tokens)

Set the background color. color = name|'#rrggbb'|(r,g,b[,a]).

Input parameters:

- `color` (required)

### `set_brush` (~35 tokens)

Set the active paint brush by name (e.g. '2. Hardness 050').

Input parameters:

- `name` (string, required)

### `set_paint_opacity` (~28 tokens)

Set the paint/context opacity (0-100).

Input parameters:

- `opacity` (number, required)

### `fill` (~55 tokens)

Fill the whole drawable. fill_type: foreground|background|white|
transparent|pattern. `layer`/`image` optional (default active).

Input parameters:

- `fill_type` (string)
- `image`
- `layer`

### `bucket_fill` (~81 tokens)

Flood-fill from seed point (x, y) with `color` (or current fg).
mode = layer-mode name (e.g. 'normal', 'multiply').

Input parameters:

- `color`
- `image`
- `layer`
- `mode`
- `opacity`
- `x` (number, required)
- `y` (number, required)

### `gradient` (~109 tokens)

Draw a gradient from (x1,y1) to (x2,y2). `gradient` = named gradient
(else fg->bg). gradient_type: linear|bilinear|radial|conical-symmetric|...

Input parameters:

- `gradient`
- `gradient_type` (string)
- `image`
- `layer`
- `x1` (number, required)
- `x2` (number, required)
- `y1` (number, required)
- `y2` (number, required)

### `stroke_selection` (~52 tokens)

Stroke the active selection's outline with `color`/`line_width`
(current fg/line width if omitted).

Input parameters:

- `color`
- `image`
- `layer`
- `line_width`

### `pencil` (~57 tokens)

Hard-edged pencil stroke. points = flat [x1,y1,x2,y2,...]. Uses `color`
or current fg.

Input parameters:

- `color`
- `image`
- `layer`
- `points` (array, required)

### `paintbrush` (~77 tokens)

Soft paintbrush stroke. points = flat [x1,y1,x2,y2,...]. Optional
\`brush` name + `size`; uses `color` or current fg.

Input parameters:

- `brush`
- `color`
- `image`
- `layer`
- `points` (array, required)
- `size`

### `create_text_layer` (~108 tokens)

Create a text layer. font=name (else context font); size in px; color by
name/#hex/(r,g,b); justify=left|right|center|fill; x/y = position offsets.

Input parameters:

- `color`
- `font`
- `image`
- `justify`
- `letter_spacing`
- `line_spacing`
- `size` (number)
- `text` (string, required)
- `x`
- `y`

### `set_text_props` (~97 tokens)

Mutate any subset of an existing text layer's properties (omitted args are
left unchanged). `layer` = id/name of a text layer.

Input parameters:

- `color`
- `font`
- `image`
- `justify`
- `layer` (required)
- `letter_spacing`
- `line_spacing`
- `size`
- `text`
- `x`
- `y`

### `outline_text` (~65 tokens)

Add an outline beneath a text layer: alpha->selection, grow by `radius`,
fill onto a new layer in `color`. Destructive (adds a layer).

Input parameters:

- `color` (string)
- `image`
- `layer` (required)
- `radius` (integer)

### `check_fonts` (~27 tokens)

Report availability of each font name -> {name: bool}.

Input parameters:

- `fonts` (array, required)

### `substitute_font` (~51 tokens)

Best-effort font-substitution report: whether `old` is missing and `new`
is present (does not mutate global GIMP config).

Input parameters:

- `new` (string, required)
- `old` (string, required)

### `levels` (~137 tokens)

Adjust levels on a drawable. channel: value|red|green|blue|alpha.
Inputs/outputs are 0.0-1.0 floats in LINEAR light, not the 0-255 sRGB values
color_at reports: a pixel color_at reads as 200 sits at about 0.58 here.
gamma is the midtone exponent.

Input parameters:

- `channel` (string)
- `gamma` (number)
- `high_in` (number)
- `high_out` (number)
- `image`
- `layer`
- `low_in` (number)
- `low_out` (number)

### `curves` (~94 tokens)

Apply a spline curve. `points` = flat [x0,y0,x1,y1,...] control points
in 0.0-1.0, in LINEAR light like levels (not the sRGB values color_at
reports). channel: value|red|green|blue|alpha.

Input parameters:

- `channel` (string)
- `image`
- `layer`
- `points` (array, required)

### `brightness_contrast` (~54 tokens)

Adjust brightness and contrast. Each ranges -1.0..1.0 (0 = no change).

Input parameters:

- `brightness` (number)
- `contrast` (number)
- `image`
- `layer`

### `hue_saturation` (~100 tokens)

Adjust hue/lightness/saturation. range: all|red|yellow|green|cyan|blue|
magenta. hue -180..180, lightness/saturation -100..100, overlap 0..100.

Input parameters:

- `hue` (number)
- `image`
- `layer`
- `lightness` (number)
- `overlap` (number)
- `range` (string)
- `saturation` (number)

### `color_balance` (~91 tokens)

Shift color balance for a tonal range: shadows|midtones|highlights.
Each channel pair is -100..100; preserve_lum keeps luminosity.

Input parameters:

- `cyan_red` (number)
- `image`
- `layer`
- `magenta_green` (number)
- `preserve_lum` (boolean)
- `range` (string)
- `yellow_blue` (number)

### `desaturate` (~48 tokens)

Convert to grayscale values in place. mode: luminance|luma|lightness|
average|value.

Input parameters:

- `image`
- `layer`
- `mode` (string)

### `invert` (~40 tokens)

Invert colors. linear=True inverts in linear light, else perceptual.

Input parameters:

- `image`
- `layer`
- `linear` (boolean)

### `posterize` (~39 tokens)

Reduce each channel to `levels` discrete tones (2..255).

Input parameters:

- `image`
- `layer`
- `levels` (integer, required)

### `threshold` (~101 tokens)

Black/white threshold: pixels in [low, high] -> white, else black.
low/high are 0.0-1.0 on the same sRGB scale as color_at (divide its 0-255
values by 255). channel: value|red|green|blue|alpha.

Input parameters:

- `channel` (string)
- `high` (number)
- `image`
- `layer`
- `low` (number)

### `normalize` (~91 tokens)

Auto-stretch tones to fill the full 0-255 range (like Colors > Auto >
Stretch Contrast). keep_colors=False (default) stretches each channel
independently — maximum contrast, but may shift colour balance; keep_colors=True
stretches all channels uniformly to preserve hue (gegl:stretch-contrast).

Input parameters:

- `image`
- `keep_colors` (boolean)
- `layer`

### `apply_filter` (~85 tokens)

Apply any GEGL operation to a layer (destructive merge).
\`op` = full op name e.g. 'gegl:pixelize'. `params` = {property: value}
(underscores become hyphens; color-like values auto-coerced).

Input parameters:

- `image`
- `layer`
- `op` (string, required)
- `params`

### `gaussian_blur` (~57 tokens)

Gaussian blur a layer (gegl:gaussian-blur). std_dev_x/y in pixels.

Input parameters:

- `image`
- `layer`
- `std_dev_x` (number)
- `std_dev_y` (number)

### `unsharp_mask` (~62 tokens)

Sharpen a layer via unsharp mask (gegl:unsharp-mask). std_dev = blur
radius, scale = sharpen strength.

Input parameters:

- `image`
- `layer`
- `scale` (number)
- `std_dev` (number)

### `drop_shadow` (~187 tokens)

Add a drop shadow to a layer (gegl:dropshadow). x/y = offset, blur =
shadow radius, grow = shadow expansion, color = name/'#rrggbb'/(r,g,b).

NOTE: gegl:dropshadow ENLARGES the target layer and shifts its offsets so
the soft shadow has room to render (verified on GIMP 3.0.4: a 64x48 layer
at (0,0) became 116x100 at (-20,-20)). The layer may therefore extend
beyond the canvas; flatten or crop afterward if you need it clipped.

Input parameters:

- `blur` (number)
- `color` (string)
- `grow` (number)
- `image`
- `layer`
- `opacity` (number)
- `x` (number)
- `y` (number)

### `print_geometry` (~74 tokens)

Set print resolution (dpi) and/or scale to a physical size in inches.
Pass width_in and/or height_in to scale (aspect preserved if one given).
Reports current inches @ dpi and warns on upscaling.

Input parameters:

- `dpi`
- `height_in`
- `image`
- `width_in`

### `trim_to_content` (~51 tokens)

Autocrop the image to the artwork's alpha bounding box, plus optional
padding (px). Removes empty transparent margins.

Input parameters:

- `image`
- `layer`
- `padding` (integer)

### `white_underbase` (~73 tokens)

Core DTF op: create a white-ink layer BELOW the art, filled to the
art's alpha shrunk inward by `choke` px at `opacity`. Returns new layer id.

Input parameters:

- `choke` (integer)
- `image`
- `layer`
- `opacity` (number)

### `edge_choke` (~56 tokens)

Pull the art's effective alpha edge inward by `pixels` (trims a thin
rim — useful before underbase or to remove fringing).

Input parameters:

- `image`
- `layer`
- `pixels` (integer)

### `edge_spread` (~73 tokens)

Grow (dilate) the art's alpha edge outward by `pixels`, fattening the
artwork and carrying the edge colour into the grown ring (morphological
alpha dilate via gegl:median-blur).

Input parameters:

- `image`
- `layer`
- `pixels` (integer)

### `knockout_background` (~636 tokens)

One-click DTF background / shirt-colour knockout. Auto-adds an alpha
channel if the source is flat (no need to call add_alpha first).

For a dead-simple crisp cutout of ONE flat colour, prefer `cutout_color`
(hard) or `color_to_alpha` (soft) — this tool adds garment-aware
auto-technique + presets on top.

Colour to remove, by priority: explicit `color` (name/#hex) > `shirt=`
garment preset (see list_shirt_presets) > `sample_xy=[x,y]` eyedropper >
AUTO-DETECT from the image edges. (A `shirt=` preset still supplies the
technique + tolerance defaults even when an explicit `color` overrides
its hue.)

\`mode='auto'` snaps the resolved colour to the nearest garment preset and
inherits its technique (e.g. red -> hard, so reds in the art aren't eaten;
black -> subtract, since on a black shirt black shows through); with no
preset table it falls back to a luma rule (dark -> subtract / light ->
hard). Override with 'hard'/'subtract' (case-insensitive). `tolerance` =
match aggressiveness (default 0.15; a `shirt` preset supplies its own).
\`contiguous=True` (BOTH modes) removes only the border-connected region,
so areas of the background colour ENCLOSED by artwork survive. Leave it
off (default) when those enclosed areas are letter counters (the hole in
an O) or donut holes — background that must knock out so the garment shows
through. Turn it ON when they are interior ARTWORK in the garment colour
(black linework on a black shirt). Colour cannot distinguish the two, so
when a non-contiguous run clears enclosed regions the result reports
\`enclosed_bbox` + a `warning` telling you to re-run with contiguous=True
if that was art. `feather` softens the cut.
\`defringe` (default OFF) trims a 1px halo but ERODES the art edge — enable
only if you actually see a fringe. `clean` (default OFF) binarizes/denoises
the alpha for film but HARDENS soft/anti-aliased edges — enable for crisp
film output, leave off to preserve a clean subtract/feathered result.

Returns the colour used, effective `…

Input parameters:

- `clean` (boolean)
- `color`
- `contiguous`
- `defringe` (boolean)
- `feather` (number)
- `image`
- `layer`
- `mode` (string)
- `sample_xy`
- `shirt`
- `tolerance`

### `list_shirt_presets` (~42 tokens)

List the built-in garment / shirt-colour presets for
knockout_background(shirt=...) — name, display, hex, technique, tolerance.

### `clean_for_dtf` (~132 tokens)

Binarize the ALPHA channel at `threshold` (0-1, default 0.5): pixels
below it -> fully transparent (drops faint dust/noise), at/above -> fully
opaque (crisp ink edges for film). RGB is untouched. NOTE: this HARDENS every
soft/anti-aliased edge and drops intentional low-alpha interior detail
(faint gradients / highlights) below the threshold — skip it, or lower the
threshold, when the art has soft edges worth keeping.

Input parameters:

- `image`
- `layer`
- `threshold` (number)

### `despill` (~55 tokens)

Reduce edge color spill left over from a knockout (best-effort
approximation; flag if results are off).

Input parameters:

- `amount` (number)
- `color` (string)
- `image`
- `layer`

### `halftone_separation` (~73 tokens)

Apply a newsprint halftone screen. PREVIEW/APPROXIMATION ONLY — this is
a visual halftone, NOT registration-accurate channel film separations.

Input parameters:

- `angle` (number)
- `cell_size` (number)
- `image`
- `layer`

### `gang_sheet` (~103 tokens)

Lay out multiple design files on a print sheet via a left-to-right /
top-to-bottom shelf packer (gutter between items), growing height as
needed, then export a transparent PNG. Returns {placed, sheet_px, out_path}.

Input parameters:

- `dpi` (number)
- `files` (array, required)
- `gutter_in` (number)
- `out_path` (string, required)
- `rotate` (boolean)
- `sheet_width_in` (number)

### `bleed_and_safe` (~59 tokens)

Add a bleed margin (resize canvas by bleed_in on each side) and report
the inner safe-area rect (inset by safe_in).

Input parameters:

- `bleed_in` (number)
- `image`
- `safe_in` (number)

### `export_dtf_png` (~149 tokens)

Export a transparent, print-ready PNG. PRESERVES ALPHA — merges visible
layers WITHOUT flattening (flattening would drop alpha and ruin the DTF
transfer). DPI: if `dpi` is given the file is tagged at it; if OMITTED the
file inherits the image's CURRENT resolution (e.g. whatever `print_geometry`
set). This only writes the DPI tag — it never resamples pixels, so set the
physical print size with `print_geometry` FIRST, then export. Works on a
duplicate (source untouched); returns the saved path and the DPI tag written.

Input parameters:

- `dpi`
- `image`
- `path` (string, required)

### `get_profile` (~45 tokens)

Read the image's embedded ICC profile label (None = built-in sRGB).
\`image` = id/basename, or omit for the active image.

Input parameters:

- `image`

### `assign_profile` (~56 tokens)

Tag the image with an ICC profile WITHOUT converting pixels (assign).
\`icc_path` = path to a .icc/.icm file. RGB/working-space use.

Input parameters:

- `icc_path` (string, required)
- `image`

### `convert_profile` (~77 tokens)

Convert pixels into the target ICC working space (RGB/working-space only).
intent: perceptual|relative-colorimetric|saturation|absolute-colorimetric.
bpc = black-point compensation.

Input parameters:

- `bpc` (boolean)
- `icc_path` (string, required)
- `image`
- `intent` (string)

### `soft_proof` (~86 tokens)

NOT SUPPORTED: soft-proofing is a VIEW-only display simulation in GIMP
3.x, not a scriptable pixel operation — this ALWAYS fails. Returns
ok=false with {supported: false, note}; no pixels are changed. Use
convert_profile to bake the conversion instead.

Input parameters:

- `icc_path`
- `image`
- `intent` (string)

### `to_grayscale` (~26 tokens)

Convert the image to GRAYSCALE mode (destructive).

Input parameters:

- `image`

### `to_rgb` (~23 tokens)

Convert the image to RGB mode (destructive).

Input parameters:

- `image`

### `list_profiles` (~55 tokens)

NOT SUPPORTED: the libgimp API cannot enumerate installed ICC profiles —
this ALWAYS fails. Returns ok=false with {supported: false, note}. Pass
explicit .icc paths instead; get_profile reads an image's own profile.

### `get_bitmap` (~197 tokens)

THE vision tool: render a scaled/cropped/composited COPY and return it as a
VIEWABLE image (an MCP image block you can actually see) plus size metadata.
region=[x,y,w,h] crops first; background (name/hex) flattens over an opaque
colour (else alpha is kept); the longest side is scaled to <= max_dim (clamped
1..4096). If the encoded image would exceed max_bytes (~4 MB default) it is
auto-downscaled to fit your context. Pass save_to=<abs path> to write the
render to disk and get the path back instead of an inline image — use this for
previews too large to view inline.

Input parameters:

- `background`
- `fmt` (string)
- `image`
- `max_bytes` (integer)
- `max_dim` (integer)
- `region`
- `save_to`

### `read_region` (~84 tokens)

Structured 2D grid of [r,g,b,a] pixels for a rectangle. Capped at w*h<=4096
(raises if larger — use get_bitmap for big areas).

Input parameters:

- `h` (integer, required)
- `image`
- `layer`
- `w` (integer, required)
- `x` (integer, required)
- `y` (integer, required)

### `color_at` (~50 tokens)

Sample one pixel: returns {rgba:[r,g,b,a]} (0-255).

Input parameters:

- `image`
- `layer`
- `x` (integer, required)
- `y` (integer, required)

### `histogram` (~160 tokens)

Channel statistics (value|red|green|blue|alpha|luminance).

space='perceptual' (default) computes the stats from the drawable's own pixels
in the same 0-255 sRGB values as color_at/get_bitmap, returning mean, std_dev,
median, min, max (all 0-255) plus pixels/count. space='gimp' returns GIMP's
native PDB histogram (mean/std_dev/median/percentile, no min/max).
Very large drawables are point-sampled at reduced resolution (min/max are from
the sample, flagged by `sampled`).

Input parameters:

- `channel` (string)
- `image`
- `layer`
- `space` (string)

### `list_gegl_ops` (~27 tokens)

List available GEGL operation names, optionally filtered by substring.

Input parameters:

- `filter`

### `describe_op` (~31 tokens)

Introspect a GEGL op: categories, description, and its properties.

Input parameters:

- `op` (string, required)

### `list_procedures` (~26 tokens)

List PDB procedure names, optionally filtered by substring.

Input parameters:

- `filter`

### `list_fonts` (~23 tokens)

List installed font names, optionally filtered by substring.

Input parameters:

- `filter`

### `list_brushes` (~24 tokens)

List brush names, optionally filtered by substring.

Input parameters:

- `filter`

### `list_patterns` (~22 tokens)

List pattern names, optionally filtered by substring.

Input parameters:

- `filter`

### `list_gradients` (~23 tokens)

List gradient names, optionally filtered by substring.

Input parameters:

- `filter`

### `list_palettes` (~23 tokens)

List palette names, optionally filtered by substring.

Input parameters:

- `filter`

### `checkpoint` (~53 tokens)

Snapshot an image (a real duplicate) so you can restore() it later.
Returns a numeric checkpoint_id. `image` = id/basename, or omit for active.

Input parameters:

- `image`
- `label`

### `restore` (~52 tokens)

Roll an image back to a checkpoint by rebuilding its layer stack from the
snapshot. The checkpoint stays usable. `image` = which image to restore into.

Input parameters:

- `checkpoint_id` (integer, required)
- `image`

### `list_checkpoints` (~25 tokens)

List live checkpoints: id, snapshot image_id, and whether it's still valid.

### `undo_group_begin` (~51 tokens)

Begin an undo group on an image: subsequent edits collapse into one undo
step. Pair with undo_group_end. `image` = id/basename, or omit for active.

Input parameters:

- `image`

### `undo_group_end` (~27 tokens)

End the undo group started by undo_group_begin on this image.

Input parameters:

- `image`

### `undo` (~62 tokens)

Undo the last operation — only if GIMP exposes scriptable undo, which
GIMP 3.x does NOT (undo is interactive), so this returns ok=false with
{supported: false} and rolls nothing back. Use checkpoint()/restore().

Input parameters:

- `image`

### `redo` (~62 tokens)

Redo the last undone operation — only if GIMP exposes scriptable redo,
which GIMP 3.x does NOT, so this returns ok=false with {supported: false}
and redoes nothing. Use checkpoint()/restore() for reliable rollback.

Input parameters:

- `image`

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/com-twelvetake-gimp-studio-mcp/twelvetake-gimp-studio-mcp#diagnostics

## Score history

- 2026-10-04: 76
- 2026-10-03: 76
- 2026-10-02: 76
- 2026-10-01: 76
- 2026-09-30: 76
- 2026-09-29: 61

## Common questions

### What is the GIMP Studio MCP server?

GIMP Studio MCP is listed in the public MCP registry as com.twelvetake/gimp-studio-mcp. Lets an AI assistant edit images in GIMP 3, including print and DTF transfer prep. This page covers its PyPI package (twelvetake-gimp-studio-mcp).

### Is the GIMP Studio MCP server safe to use?

GIMP Studio MCP scores 76 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 4 October 2026. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the GIMP Studio MCP server expose?

GIMP Studio MCP exposes 119 tools: status, list_images, set_active_image, gimp_exec, reset_namespace, and 114 more. Their descriptions and schemas cost roughly 8,781 tokens of context every time the server is loaded.

### Is the GIMP Studio MCP server still maintained?

GIMP Studio MCP is still listed as active in the MCP registry. We last reached this channel on 4 October 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

### What licence is the GIMP Studio MCP server under?

GIMP Studio MCP declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.

## Links

- PyPI project: https://pypi.org/project/twelvetake-gimp-studio-mcp/
- Socket report: https://socket.dev/pypi/package/twelvetake-gimp-studio-mcp
- Repository: https://github.com/TwelveTake-Studios/gimp-studio-mcp
- Website: https://twelvetake.com/tools/gimp-studio-mcp/
- Changelog RSS feed: https://verifymcp.io/servers/com-twelvetake-gimp-studio-mcp/twelvetake-gimp-studio-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/com-twelvetake-gimp-studio-mcp/twelvetake-gimp-studio-mcp.json
- HTML version of this page: https://verifymcp.io/servers/com-twelvetake-gimp-studio-mcp/twelvetake-gimp-studio-mcp
