# Aseprite Agent MCP (pypi · aseprite-agent-mcp)

Create and verify pixel-art assets with atomic Aseprite edits and Phaser export.

- Trust score: 83/100 (high trust)
- Change this week: +4
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-11-05

> **Recent critical change**: GHSA-6q48-6c7w-9gw2 affects this package (2026-10-21). See the changelog below before you install this server.

## Components

- pypi · `aseprite-agent-mcp`: 83/100 (this document), [markdown](https://verifymcp.io/servers/sarutobisasuke8-aseprite-agent-mcp/aseprite-agent-mcp.md), [page](https://verifymcp.io/servers/sarutobisasuke8-aseprite-agent-mcp/aseprite-agent-mcp)

## Channel facts

- Registry: `pypi`
- Package: `aseprite-agent-mcp`
- Version: `0.3.0`
- 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-11-05.

- **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 29 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 100/100
  - Source repository is publicly reachable at the declared URL.
  - Cryptographically verified build provenance (signed, bound to SarutobiSasuke8/aseprite-agent-mcp).
  - Clear OSI-approved license (MIT).
  - Actively maintained (last published 19 days ago).
  - Publishes a security disclosure policy (SECURITY.md).
- **Schema Quality & AI Usability**: 53/100
  - AI-judged instruction clarity (good).
  - Context-footprint check failed: tool/resource definitions use about 6720 tokens (~160/item across 42 items; 42 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 67/100
  - Stability observed for 20 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **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 2 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "remove_frame" implies "remove" and declares no destructiveHint at all, which the MCP spec reads as destructive by default.
  - An AI judge read all 43 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.

## Install

### How do I install the Aseprite Agent MCP server?

Aseprite Agent MCP runs locally as a PyPI package, launched with uvx aseprite-agent-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 sarutobisasuke8-aseprite-agent-mcp -- uvx aseprite-agent-mcp
```

### Cursor

```json
{
  "mcpServers": {
    "sarutobisasuke8-aseprite-agent-mcp": {
      "command": "uvx",
      "args": [
        "aseprite-agent-mcp"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "sarutobisasuke8-aseprite-agent-mcp": {
      "command": "uvx",
      "args": [
        "aseprite-agent-mcp"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add sarutobisasuke8-aseprite-agent-mcp -- uvx aseprite-agent-mcp
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "sarutobisasuke8-aseprite-agent-mcp": {
      "type": "local",
      "command": [
        "uvx",
        "aseprite-agent-mcp"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add sarutobisasuke8-aseprite-agent-mcp --command uvx --arg aseprite-agent-mcp
```

### Hermes

```yaml
mcp_servers:
  sarutobisasuke8-aseprite-agent-mcp:
    command: "uvx"
    args: ["aseprite-agent-mcp"]
```

### Netclaw

```json
{
  "McpServers": {
    "sarutobisasuke8-aseprite-agent-mcp": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "aseprite-agent-mcp"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add sarutobisasuke8-aseprite-agent-mcp -t stdio -c uvx -a aseprite-agent-mcp
```

### Other

```json
{
  "mcpServers": {
    "sarutobisasuke8-aseprite-agent-mcp": {
      "command": "uvx",
      "args": [
        "aseprite-agent-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-11-05 (score 83, +1)

No change was recorded against any check on this day. Stability & Change Management went from 63 to 67. That category is still filling its 30-day observation window: 19 days of observed history at the previous scan, 20 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-11-03 (score 82, +1)

No change was recorded against any check on this day. Stability & Change Management went from 57 to 60. That category is still filling its 30-day observation window: 17 days of observed history at the previous scan, 18 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-11-01 (score 81, +1)

No change was recorded against any check on this day. Stability & Change Management went from 50 to 53. That category is still filling its 30-day observation window: 15 days of observed history at the previous scan, 16 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-30 (score 80, +1)

No change was recorded against any check on this day. Stability & Change Management went from 43 to 47. That category is still filling its 30-day observation window: 13 days of observed history at the previous scan, 14 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-27 (score 79, +1)

No change was recorded against any check on this day. Stability & Change Management went from 33 to 37. That category is still filling its 30-day observation window: 10 days of observed history at the previous scan, 11 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-25 (score 78, +1)

No change was recorded against any check on this day. Stability & Change Management went from 27 to 30. That category is still filling its 30-day observation window: 8 days of observed history at the previous scan, 9 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-23 (score 77, +1)

No change was recorded against any check on this day. Stability & Change Management went from 20 to 23. That category is still filling its 30-day observation window: 6 days of observed history at the previous scan, 7 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-22 (score 76, +76)

- [security improvement] GHSA-6q48-6c7w-9gw2 no longer affects this package
- [security improvement] Known CVEs: fail → pass
- [functional improvement] Score status: failed → scored

## MCP tools (42)

### `apply_operations` (~834 tokens)

Apply a list of edit operations to a sprite in one atomic, single-process batch. If any op fails, the whole batch is rolled back, nothing is saved, and the error names the failing op index. dry_run=true checks the list without launching Aseprite (shape only; a missing layer still fails on a real run). Returns a workflow_manifest.v1 with a per-op operations list.

Each operation is {"op": "<name>", "args": {...}}. Ops run in order against the same open sprite, so later ops see earlier ones (add a layer, then draw on it). Coordinates are pixels from the top-left (0,0); frames are 1-based and must exist; layer is a name or 1-based index and defaults to the top layer; durations are milliseconds. '?' marks an optional arg.
\- add_layer(name:str, opacity?:int, blend_mode?:str, visible?:bool): new layer on top
\- rename_layer(layer:str, new_name:str): rename a layer
\- set_layer_visible(layer:str, visible:bool): show or hide a layer
\- set_layer_opacity(layer:str, opacity:int): layer opacity 0-255
\- remove_layer(layer:str): delete a layer (not the last one)
\- add_frame(duration_ms?:int, copy_from?:int): append a frame (copy_from copies an existing frame)
\- duplicate_frame(frame:int): insert a copy of a frame after it
\- set_frame_duration(frame:int, duration_ms:int): frame duration in milliseconds
\- add_tag(name:str, from:int, to:int, direction?:str, color?:color): animation tag over frames from..to (direction forward|reverse|pingpong)
\- remove_tag(name:str): delete a tag by name
\- set_pixel(layer?:str, frame?:int, x:int, y:int, color:color): one pixel
\- draw_line(layer?:str, frame?:int, x1:int, y1:int, x2:int, y2:int, color:color): 1px line between two points
\- draw_rectangle(layer?:str, frame?:int, x:int, y:int, width:int, height:int, color:color): rectangle outline
\- fill_rectangle(layer?:str, frame?:int, x:int, y:int, width:int, height:int, color:color): filled rectangle
\- draw_ellipse(layer?:str, frame?:int, cx:int, cy:int, rx:int, ry:int, color:color): ellipse outline
\-…

Input parameters:

- `dry_run` (boolean)
- `filename` (string, required)
- `operations` (array, required)

### `export_onion_skin` (~170 tokens)

Export a frame with neighbouring frames ghosted behind it (onion skin).

Args:
    frame: The in-focus frame (drawn fully opaque), 1-based.
    previous, next: How many earlier/later frames to ghost.
    ghost_opacity: Max opacity (0-255) of the nearest ghost; further frames fade.
    scale: Integer upscaling factor for the output PNG.
    overwrite: Replace an existing output file. Editable .ase/.aseprite masters are never replaced.

Input parameters:

- `filename` (string, required)
- `frame` (integer, required)
- `ghost_opacity` (integer)
- `next` (integer)
- `output` (string, required)
- `overwrite` (boolean)
- `previous` (integer)
- `scale` (integer)

### `get_sprite_info` (~56 tokens)

Return structured info about a sprite: size, colour mode, frames (with
durations), the full layer tree (names, opacity, blend mode, visibility),
animation tags, and palette size.

Input parameters:

- `filename` (string, required)

### `render_preview` (~78 tokens)

Render a single frame to a PNG and return it as an image you can view.

Use this to *see* your work. frame is 1-based; scale enlarges small sprites
(default 8x) so individual pixels are visible.

Input parameters:

- `filename` (string, required)
- `frame` (integer)
- `scale` (integer)

### `get_pixels` (~103 tokens)

Read the composited (all visible layers) pixel colours of a region.

Returns rows of "#RRGGBBAA" hex strings. The region is capped at 64x64
(4096 pixels) per call to keep responses small — read in tiles for bigger areas.

Input parameters:

- `filename` (string, required)
- `frame` (integer)
- `height`
- `width`
- `x` (integer)
- `y` (integer)

### `list_sprites` (~18 tokens)

List sprite/image files in the workspace directory.

### `get_palette` (~33 tokens)

Return the sprite's palette as a list of "#RRGGBBAA" colours.

Input parameters:

- `filename` (string, required)

### `set_palette` (~59 tokens)

Replace the entire palette with the given list of colours.

colors: list of colour strings, e.g. ["#000000", "#ffffff", "255,0,0"].

Input parameters:

- `colors` (array, required)
- `filename` (string, required)

### `load_palette` (~48 tokens)

Load a palette from a file (.gpl, .pal, .aseprite, .png, ...) and apply it.

Input parameters:

- `filename` (string, required)
- `palette_file` (string, required)

### `set_cel_position` (~61 tokens)

Move a cel's image to position (x, y) within the canvas.

Input parameters:

- `filename` (string, required)
- `frame` (integer, required)
- `layer` (string, required)
- `x` (integer, required)
- `y` (integer, required)

### `copy_cel` (~58 tokens)

Copy a cel's image (and position) from one frame to another on the same layer.

Input parameters:

- `filename` (string, required)
- `from_frame` (integer, required)
- `layer` (string, required)
- `to_frame` (integer, required)

### `draw_pixels` (~130 tokens)

Plot individual pixels.

Args:
    pixels: List of {"x": int, "y": int, "color": "#hex"?}. If a pixel omits
        "color", the shared `color` argument is used.
    color: Default colour for pixels that don't specify their own.
    layer: Target layer name or 1-based index (default: top layer).
    frame: Target frame, 1-based (default 1).

Input parameters:

- `color`
- `filename` (string, required)
- `frame` (integer)
- `layer`
- `pixels` (array, required)

### `draw_line` (~159 tokens)

Draw a straight line from (x1,y1) to (x2,y2).

Args:
    pixel_perfect: Remove L-shaped corner pixels for a clean 1px pixel-art line.
    antialias: Smooth (Xiaolin Wu) line with alpha blending — RGB sprites only;
        ignored on indexed/gray. Takes precedence over pixel_perfect.

Input parameters:

- `antialias` (boolean)
- `color` (string, required)
- `filename` (string, required)
- `frame` (integer)
- `layer`
- `pixel_perfect` (boolean)
- `x1` (integer, required)
- `x2` (integer, required)
- `y1` (integer, required)
- `y2` (integer, required)

### `draw_rectangle` (~86 tokens)

Draw a rectangle. filled=False draws a 1px outline, True fills it.

Input parameters:

- `color` (string, required)
- `filename` (string, required)
- `filled` (boolean)
- `frame` (integer)
- `height` (integer, required)
- `layer`
- `width` (integer, required)
- `x` (integer, required)
- `y` (integer, required)

### `fill_area` (~76 tokens)

Flood fill (paint bucket): replace the contiguous region of matching
colour starting at (x,y) on the target layer with `color`.

Input parameters:

- `color` (string, required)
- `filename` (string, required)
- `frame` (integer)
- `layer`
- `x` (integer, required)
- `y` (integer, required)

### `replace_color` (~79 tokens)

Replace every pixel matching `from_color` (within `tolerance` per channel)
with `to_color`, on the chosen layer + frame.

Input parameters:

- `filename` (string, required)
- `frame` (integer)
- `from_color` (string, required)
- `layer`
- `to_color` (string, required)
- `tolerance` (integer)

### `add_frame` (~87 tokens)

Append a new frame to the animation.

Args:
    duration_ms: Frame duration in milliseconds (default 100).
    copy_from: If given (1-based), duplicate the content of that frame;
        otherwise the new frame is empty.

Returns the new frame number and updated frame count.

Input parameters:

- `copy_from`
- `duration_ms` (integer)
- `filename` (string, required)

### `remove_frame` (~38 tokens)

Delete a frame (1-based). The sprite must have more than one frame.

Input parameters:

- `filename` (string, required)
- `frame` (integer, required)

### `set_frame_duration` (~44 tokens)

Set a single frame's duration in milliseconds (1-based frame).

Input parameters:

- `duration_ms` (integer, required)
- `filename` (string, required)
- `frame` (integer, required)

### `add_layer` (~154 tokens)

Add a new (empty) normal layer on top of the stack.

Args:
    name: Layer name.
    group: Optional name of an existing group layer to nest the new layer in.
    opacity: 0-255.
    blend_mode: normal, multiply, screen, overlay, darken, lighten,
        color_dodge, color_burn, hard_light, soft_light, difference,
        exclusion, hue, saturation, color, luminosity, addition, subtract, divide.
    visible: Initial visibility.

Input parameters:

- `blend_mode` (string)
- `filename` (string, required)
- `group`
- `name` (string, required)
- `opacity` (integer)
- `visible` (boolean)

### `rename_layer` (~34 tokens)

Rename a layer.

Input parameters:

- `filename` (string, required)
- `layer` (string, required)
- `new_name` (string, required)

### `set_layer_properties` (~64 tokens)

Update one or more layer properties. Only the arguments you pass are changed.

Input parameters:

- `blend_mode`
- `editable`
- `filename` (string, required)
- `layer` (string, required)
- `name`
- `opacity`
- `visible`

### `create_sprite` (~179 tokens)

Create a new sprite file and save it.

Args:
    filename: Output path. Relative paths go in the workspace. Use a
        .aseprite/.ase extension to keep layers & frames editable.
    width, height: Canvas size in pixels (1-65535).
    color_mode: "rgb" (default), "indexed", or "gray".
    background: Optional fill colour for the first layer (e.g. "#1d2b53").
        Omit for a transparent canvas.
    overwrite: Replace `filename` if it already exists (default False = no-clobber).

Returns the new sprite's structured info.

Input parameters:

- `background`
- `color_mode` (string)
- `filename` (string, required)
- `height` (integer, required)
- `overwrite` (boolean)
- `width` (integer, required)

### `save_sprite_as` (~101 tokens)

Save a copy of a sprite under a new path (optionally flattened).

The original file is left untouched. Useful for exporting an editable
.aseprite to another .aseprite, or snapshotting a version.

overwrite: Replace `new_filename` if it already exists (default False = no-clobber).

Input parameters:

- `filename` (string, required)
- `flatten` (boolean)
- `new_filename` (string, required)
- `overwrite` (boolean)

### `add_tag` (~99 tokens)

Create an animation tag spanning frames [from_frame, to_frame] (1-based).

direction: "forward" (default), "reverse", "pingpong", or "pingpong_reverse".
color: optional tag colour (shown in the timeline).

Input parameters:

- `color`
- `direction` (string)
- `filename` (string, required)
- `from_frame` (integer, required)
- `name` (string, required)
- `to_frame` (integer, required)

### `remove_tag` (~29 tokens)

Delete an animation tag by name.

Input parameters:

- `filename` (string, required)
- `name` (string, required)

### `set_tag` (~88 tokens)

Update an existing tag. Only the arguments you pass are changed.

Note: changing from_frame/to_frame recreates the tag in place to update its
range reliably across Aseprite versions.

Input parameters:

- `color`
- `direction`
- `filename` (string, required)
- `from_frame`
- `name` (string, required)
- `new_name`
- `to_frame`

### `mirror_layer` (~132 tokens)

Mirror one half of a layer onto the other (build symmetric artwork).

Args:
    direction: "horizontal" (reflect left<->right) or "vertical" (top<->bottom).
    source_side: which half is copied: "first" (left/top) or "second" (right/bottom).
    axis: mirror line position (x for horizontal, y for vertical); default = centre.

Input parameters:

- `axis`
- `direction` (string)
- `filename` (string, required)
- `frame` (integer)
- `layer` (string, required)
- `source_side` (string)

### `draw_symmetric_pixels` (~110 tokens)

Plot pixels together with their mirror image(s).

mode: "horizontal" (mirror across vertical axis_x), "vertical" (across axis_y),
or "both" (4-way radial symmetry). Axes default to the canvas centre.

Input parameters:

- `axis_x`
- `axis_y`
- `color` (string, required)
- `filename` (string, required)
- `frame` (integer)
- `layer`
- `mode` (string)
- `pixels` (array, required)

### `draw_pixel_rows` (~303 tokens)

Draw a block of pixel art in one call, like a text-art bitmap.

Each string in `rows` is one pixel row; each character is looked up in `key`
and painted at (x + column, y + row), with (0,0) the top-left of the canvas.
'.' and ' ' are left untouched unless `key` defines them. Any other character
missing from `key` is an error, so typos never paint silently.

Example: rows=["..oo..", ".oxxo.", "..oo.."], key={"o": "#203040", "x": "#f0c060"}.

Args:
    rows: Up to 256 strings of up to 256 characters each.
    key: Single character -> colour ("#RRGGBB", "#RRGGBBAA", "r,g,b", "index:N", a name).
        Map a character to "transparent" to erase pixels.
    layer: Layer name or 1-based index (default: top layer).
    frame: 1-based frame; it must already exist.
    clear: Erase the whole cel before drawing (use for full-frame redraws).

Input parameters:

- `clear` (boolean)
- `filename` (string, required)
- `frame` (integer)
- `key` (object, required)
- `layer`
- `rows` (array, required)
- `x` (integer)
- `y` (integer)

### `derive_mirrored_tag` (~189 tokens)

Create a new animation tag by mirroring an existing one (e.g. walk_left from walk_right).

Copies every frame of `source_tag` to new frames at the end of the sprite,
flips every layer's cel along `axis`, keeps each frame's duration, and tags
the new frames `new_tag` with the source tag's playback direction. Other tags
keep their exact ranges. Asymmetric details (a sword hand, a logo) flip too,
so review the result with ase_preview_animation.

Args:
    source_tag: Existing tag to mirror.
    new_tag: Name for the new tag; must not exist yet.
    axis: "horizontal" (left/right) or "vertical" (up/down).

Input parameters:

- `axis` (string)
- `filename` (string, required)
- `new_tag` (string, required)
- `source_tag` (string, required)

### `copy_frames_from` (~229 tokens)

Append frames from another sprite file, flattened onto one layer of this sprite.

Use it to start every character from a shared base body or animation. The
source frames are composited (all visible layers) and placed on `layer` of
\`filename`, keeping each frame's duration. If this sprite has a single empty
frame (a fresh file), the first copied frame fills it instead of leaving a
blank frame in front.

Args:
    source: The .aseprite file to copy from (same width, height and colour mode).
    source_tag: Copy this tag's frames. Or give from_frame/to_frame (1-based,
        inclusive). With neither, every frame is copied.
    layer: Destination layer name or 1-based index (default: top layer).
    new_tag: Optionally tag the copied frames with this name (must not exist yet).

Input parameters:

- `filename` (string, required)
- `from_frame`
- `layer`
- `new_tag`
- `source` (string, required)
- `source_tag`
- `to_frame`

### `recolor_sprite` (~239 tokens)

Replace colours across every layer, frame and palette entry of a sprite.

Use it to turn one character template into another (new shirt, hair, skin).
Each source colour is matched per channel within `tolerance` and replaced by
its target; every pixel is mapped once from its original value, so swaps such
as A->B and B->A work. With `output`, the recoloured sprite is saved as a new
file and the original is left untouched.

Args:
    mapping: Source colour -> target colour, e.g. {"#3060c0": "#c03030"}.
    output: Optional new .aseprite path. Without it the sprite is edited in place.
    tolerance: Per-channel match tolerance 0-255 (default exact).
    overwrite: Allow `output` to replace an existing file.

Returns per-colour pixel counts; a source colour with zero matches is listed
under `unmatched` so a typo is visible.

Input parameters:

- `filename` (string, required)
- `mapping` (object, required)
- `output`
- `overwrite` (boolean)
- `tolerance` (integer)

### `import_generated_image` (~202 tokens)

Clean one PNG into a binary-alpha pixel grid, palette and editable master.

background is an explicit #RRGGBB border-connected colour key, not semantic
segmentation. outline adds a 1px eight-neighbour border, clipped at the cell
edge, and may add one palette colour. N colours excludes transparency.
New output directory only. Returns a nearest-neighbour preview for review.
width/height support 1..256px grids. palette_first snaps the source to one
shared palette before sampling, useful with majority on generated shading.

Input parameters:

- `alpha_threshold` (integer)
- `background`
- `background_tolerance` (integer)
- `colours` (integer)
- `filename` (string, required)
- `height` (integer)
- `method` (string)
- `outline`
- `output_directory` (string, required)
- `palette`
- `palette_first` (boolean)
- `width` (integer)

### `assemble_animation` (~253 tokens)

Clean 1..128 ordered PNG poses with one palette; save master, sheet and JSON.

Bounding-box mode uses one shared scale, bottom-centres silhouettes and leaves
an outline margin. Anchor mode scales same-size canvases and translates each
source [x,y] to (width//2,height-2), refusing clipping. No pose synthesis is
implied: inspect the preview for identity, timing and motion coherence.
Output is atomically published only after master and PNG pixel verification.
Use height=128 and colours=32..48 for detailed sprites. palette_first snaps
one shared source palette before sampling; defaults retain the prior pipeline.

Input parameters:

- `alignment` (string)
- `alpha_threshold` (integer)
- `anchors`
- `background`
- `background_tolerance` (integer)
- `colours` (integer)
- `duration_ms` (integer)
- `durations_ms`
- `filenames` (array, required)
- `height` (integer)
- `method` (string)
- `outline`
- `output_directory` (string, required)
- `palette`
- `palette_first` (boolean)
- `tag` (string)
- `width` (integer)

### `health_check` (~73 tokens)

Run a self-test of the server and its Aseprite integration.

Returns whether Aseprite was found, its version, the resolved workspace, the
number of registered tools, and whether a real create-sprite + export-PNG
round-trip succeeds. `ok` is True only if the full round-trip works.

### `flip_sprite` (~36 tokens)

Flip the entire sprite. direction: "horizontal" or "vertical".

Input parameters:

- `direction` (string)
- `filename` (string, required)

### `ase_validate_asset_contract` (~114 tokens)

Reopen a native master and check every frame against a contract.

Checks frame count, cell size, that each row's tag covers exactly its frames in
order with the expected playback, binary alpha, palette membership, empty frames,
and optional per-row foot/centre drift. Unknown contract fields are rejected.
Rows are laid out in contract order starting at frame 1. Passing proves geometry
and colours, not art quality: still review with ase_preview_animation.

Input parameters:

- `contract` (required)
- `filename` (string, required)

### `ase_apply_and_preview` (~814 tokens)

Atomically apply typed batch operations to a native master, then return the result and a nearest-neighbour PNG of `frame` at `scale` (1-16). Save succeeds before the preview; a preview failure is reported as saved, not rolled back.

Each operation is {"op": "<name>", "args": {...}}. Ops run in order against the same open sprite, so later ops see earlier ones (add a layer, then draw on it). Coordinates are pixels from the top-left (0,0); frames are 1-based and must exist; layer is a name or 1-based index and defaults to the top layer; durations are milliseconds. '?' marks an optional arg.
\- add_layer(name:str, opacity?:int, blend_mode?:str, visible?:bool): new layer on top
\- rename_layer(layer:str, new_name:str): rename a layer
\- set_layer_visible(layer:str, visible:bool): show or hide a layer
\- set_layer_opacity(layer:str, opacity:int): layer opacity 0-255
\- remove_layer(layer:str): delete a layer (not the last one)
\- add_frame(duration_ms?:int, copy_from?:int): append a frame (copy_from copies an existing frame)
\- duplicate_frame(frame:int): insert a copy of a frame after it
\- set_frame_duration(frame:int, duration_ms:int): frame duration in milliseconds
\- add_tag(name:str, from:int, to:int, direction?:str, color?:color): animation tag over frames from..to (direction forward|reverse|pingpong)
\- remove_tag(name:str): delete a tag by name
\- set_pixel(layer?:str, frame?:int, x:int, y:int, color:color): one pixel
\- draw_line(layer?:str, frame?:int, x1:int, y1:int, x2:int, y2:int, color:color): 1px line between two points
\- draw_rectangle(layer?:str, frame?:int, x:int, y:int, width:int, height:int, color:color): rectangle outline
\- fill_rectangle(layer?:str, frame?:int, x:int, y:int, width:int, height:int, color:color): filled rectangle
\- draw_ellipse(layer?:str, frame?:int, cx:int, cy:int, rx:int, ry:int, color:color): ellipse outline
\- fill_ellipse(layer?:str, frame?:int, cx:int, cy:int, rx:int, ry:int, color:color): filled ellipse
\- fill_layer(layer?:str, frame?:int…

Input parameters:

- `filename` (string, required)
- `frame` (integer)
- `operations` (array, required)
- `scale` (integer)

### `ase_preview_animation` (~188 tokens)

Return a labelled contact sheet of every frame, scaled with nearest-neighbour.

With by_tag (default) each tag gets its own row, labelled with its name, frame
range, playback and the frame numbers; untagged frames share a final row. The
background is a checkerboard so transparency is visible, or any colour.
Also returns the sprite info (frame timing in seconds, tags). This is a review
sheet, not proof that the motion reads well.

Args:
    scale: 1-16 pixel magnification.
    background: "checker" (default), a colour such as "#202020", or null for transparent.
    by_tag: One row per tag (True) or a plain 8-column grid (False).

Input parameters:

- `background`
- `by_tag` (boolean)
- `filename` (string, required)
- `scale` (integer)

### `ase_export_phaser` (~157 tokens)

Validate a native master and export a Phaser bundle directory.

Writes sheet.png (one row per contract row), a Phaser hash atlas, animations.json
(per-frame timing, repeat and yoyo from the contract), qa.json, contract.json and
loader.js. The master and the written PNG are reopened and every RGBA pixel is
compared before publishing. Animations are named "<contract name>:<row tag>".
An existing directory is only replaced with replace=true, and only if it is a
previous bundle; the swap is a rename, so a failed export leaves the old one intact.

Input parameters:

- `contract` (required)
- `filename` (string, required)
- `output_directory` (string, required)
- `replace` (boolean)

### `ase_export_cast_atlas` (~137 tokens)

Validate several character masters and export them as ONE Phaser atlas.

Each member is validated against its own contract; if any fails, nothing is
written and every failure is returned. Characters are stacked as row blocks in
one sheet.png. Atlas frames are "<character>/<tag>_<nn>" and animations are
"<character>:<tag>", all under the atlas key `name`. Every frame of every master
is reopened and compared pixel-for-pixel with the written sheet before publishing.

Input parameters:

- `members` (array, required)
- `name` (string, required)
- `output_directory` (string, required)
- `replace` (boolean)

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/sarutobisasuke8-aseprite-agent-mcp/aseprite-agent-mcp#diagnostics

## Score history

- 2026-11-05: 83
- 2026-11-04: 82
- 2026-11-03: 82
- 2026-11-02: 81
- 2026-11-01: 81
- 2026-10-31: 80
- 2026-10-30: 80
- 2026-10-29: 79
- 2026-10-28: 79
- 2026-10-27: 79
- 2026-10-26: 78
- 2026-10-25: 78
- 2026-10-24: 77
- 2026-10-23: 77
- 2026-10-22: 76
- 2026-10-21: 0
- 2026-10-20: 75
- 2026-10-19: 75
- 2026-10-18: 74
- 2026-10-17: 74
- 2026-10-16: 58

## Common questions

### What is the Aseprite Agent MCP server?

Aseprite Agent MCP is listed in the public MCP registry as io.github.SarutobiSasuke8/aseprite-agent-mcp. Create and verify pixel-art assets with atomic Aseprite edits and Phaser export. This page covers its PyPI package (aseprite-agent-mcp).

### Is the Aseprite Agent MCP server safe to use?

Aseprite Agent MCP scores 83 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 5 November 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 Aseprite Agent MCP server expose?

Aseprite Agent MCP exposes 42 tools: apply_operations, export_onion_skin, get_sprite_info, render_preview, get_pixels, and 37 more. Their descriptions and schemas cost roughly 6,141 tokens of context every time the server is loaded.

### Is the Aseprite Agent MCP server still maintained?

Aseprite Agent MCP is still listed as active in the MCP registry. We last reached this channel on 5 November 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 Aseprite Agent MCP server under?

Aseprite Agent 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/aseprite-agent-mcp/
- Socket report: https://socket.dev/pypi/package/aseprite-agent-mcp
- Repository: https://github.com/SarutobiSasuke8/aseprite-agent-mcp
- Website: https://pypi.org/project/aseprite-agent-mcp/
- Changelog RSS feed: https://verifymcp.io/servers/sarutobisasuke8-aseprite-agent-mcp/aseprite-agent-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/sarutobisasuke8-aseprite-agent-mcp/aseprite-agent-mcp.json
- HTML version of this page: https://verifymcp.io/servers/sarutobisasuke8-aseprite-agent-mcp/aseprite-agent-mcp
