Install
$ agentstack add mcp-malloythedev-aseprite-mcp ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Aseprite MCP
[](https://github.com/MalloyTheDev/aseprite-mcp/actions/workflows/ci.yml) [](LICENSE) [](https://www.python.org/) [](https://modelcontextprotocol.io)
This slime was drawn, shaded, outlined, and animated entirely through MCP tool calls — no manual pixel-pushing.
An extensive Model Context Protocol server that lets an AI agent (Claude Code, Claude Desktop, or any MCP client) create and edit Aseprite sprites — draw pixel art, build animations, manage layers/frames/tags/palettes, and export to PNG/GIF/sprite sheets — all headlessly.
📖 Full tool reference: [docs/TOOLS.md](docs/TOOLS.md) — every tool with its parameters.
It works by generating Lua scripts and running them through Aseprite's batch mode (aseprite -b --script ...), plus the Aseprite CLI for exports. Every operation opens a real .aseprite file, edits it, and saves — so your files stay fully editable in the Aseprite GUI.
- 108 tools — including high-level workflow tools that scaffold and validate whole
assets in one call, and a batch op-runner that applies many edits atomically in a single Aseprite process — across sprites, layers, frames, cels, drawing (incl. pixel-perfect & anti-aliased modes), custom brushes & symmetry, palettes (extract/sort/ramps), animation tags, slices/9-patch, effects (gradients/outline/drop-shadow/colour adjustments), text rendering, tilemaps, image stamping, reference/rotoscope layers, transforms, rich export (per-layer/per-tag, sprite sheets, onion-skin), a GUI companion view, and a health_check self-test.
- Sandboxed file access — by default the file capability is scoped to the workspace
(relative paths only; absolute/.. paths rejected unless you opt in).
- No-clobber by default — output-writing tools refuse to overwrite an existing file;
pass overwrite=True to replace it intentionally.
- Structured results — every tool returns JSON describing the updated sprite.
render_previewreturns a PNG so the agent can see its work and self-correct.- Deterministic, stateless, robust — each call is an isolated, headless Aseprite run.
Showcase
Everything below was produced entirely through MCP tool calls — no manual pixel-pushing.
🟢 Easy — one call scaffolds usable pixel art
createrpgitem_sheet lays out named item slices in one call; filled here with the drawing tools — heart / coin / potion / sword, each its own export-ready slice.
🟡 Medium — animation & tag generation
make8directionwalktemplate generates the frames and one animation tag per direction (N / NE / E / SE / S / SW / W / NW) — ready to draw the walk cycle into.
🔴 Hard — the full pipeline: create → animate → validate → export
One agent run: createcharactersprite → draw → make4frameidleanimation → validatespriteforgameexport → exportgameasset_bundle.
validate_sprite_for_game_export → passed ✅ (width, height, color_mode, min_frames, required_tags)
export_game_asset_bundle → hero.png · hero.gif · hero_sheet.png (+JSON) · hero_idle.gif · manifest.json
More examples
A bouncing slime, a skeleton, a tilemap scene from 4 painted tiles, and a hue-shifted generate_ramp palette.
Requirements
- Aseprite 1.3+ (the scripting API). The Steam and standalone builds both work.
- Python 3.10+
- uv (recommended) — or any PEP 517 installer.
Install
git clone https://github.com/MalloyTheDev/aseprite-mcp.git
cd aseprite-mcp
uv sync
That creates a virtual environment and installs the aseprite-mcp package and its dependencies. Verify it can find Aseprite and run the test suite (tests auto-skip if Aseprite isn't found):
uv run pytest
Configuration
Everything is configurable via environment variables (all optional):
| Variable | Purpose | Default | | --- | --- | --- | | ASEPRITE_PATH | Full path to Aseprite.exe / aseprite. | Auto-detected (Steam, standalone, PATH). | | ASEPRITE_MCP_WORKSPACE | Folder where relative sprite paths are resolved. | /workspace | | ASEPRITE_MCP_TIMEOUT | Per-operation timeout in seconds. | 90 | | ASEPRITE_MCP_ALLOW_ABSOLUTE | Allow absolute / workspace-escaping paths (1/true to enable). | off (sandboxed) |
On this machine Aseprite was detected at C:\Program Files (x86)\Steam\steamapps\common\Aseprite\Aseprite.exe, so ASEPRITE_PATH is not strictly required — but setting it explicitly is the most reliable.
Register with an MCP client
Replace /ABSOLUTE/PATH/TO/aseprite-mcp below with the absolute path to your clone.
Claude Code (CLI)
claude mcp add aseprite -- uv --directory /ABSOLUTE/PATH/TO/aseprite-mcp run aseprite-mcp
To set the Aseprite path explicitly (recommended if auto-detection fails):
claude mcp add aseprite \
--env ASEPRITE_PATH="/path/to/Aseprite.exe" \
-- uv --directory /ABSOLUTE/PATH/TO/aseprite-mcp run aseprite-mcp
Claude Desktop / generic MCP client (JSON)
Add this to your client's MCP server config (e.g. claude_desktop_config.json). A ready-to-copy template lives in [mcp-config.example.json](mcp-config.example.json) (Windows-style paths shown — adjust for your OS):
{
"mcpServers": {
"aseprite": {
"command": "uv",
"args": ["--directory", "C:\\path\\to\\aseprite-mcp", "run", "aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Aseprite\\Aseprite.exe",
"ASEPRITE_MCP_WORKSPACE": "C:\\path\\to\\aseprite-mcp\\workspace"
}
}
}
}
Restart the client; the aseprite server and its 108 tools will be available. Ask the agent to run health_check to confirm Aseprite is wired up correctly.
High-level workflows
Beyond the low-level tools, a few workflow tools scaffold a whole asset in one call and return a manifest (created files, paths, frames, tags, dimensions, and suggested next steps) so an agent can keep going. They compose the low-level tools — deterministic scaffolding, no AI generation.
| Tool | Description | | --- | --- | | create_character_sprite | Transparent canvas + body/details layers + a generated shading ramp + an outlined placeholder. | | make_4_frame_idle_animation | Turn a 1-frame sprite into a 4-frame idle "bob" loop with a tag. | | create_tileset_project | Canvas + tilemap layer + a starter tileset (grass/dirt/water/stone, or your own). | | create_icon_set | Grid sheet of icon cells, each a placeholder inside a named slice (icon_0, …). | | create_rpg_item_sheet | Grid sheet with a named slice per item (sword/shield/potion/…). | | make_8_direction_walk_template | 8-direction walk template — frames + one tag per direction (N/NE/E/…). | | export_game_asset_bundle | PNG + animated GIF + sprite sheet (+ JSON) + per-tag GIFs + manifest.json. | | export_godot_spriteframes | Godot 4 SpriteFrames resource (.tres) + packed sheet — one animation per tag, timed from frame durations. | | export_slice_metadata | Engine-agnostic _slices.json — hitbox/hurtbox/collision/attach/9-slice/pivot from slice names or JSON data. | | validate_sprite_for_game_export | Check a sprite is game-ready (dimensions/tile multiple, colour mode, frames, required tags, transparency, palette budget, exports exist) → pass/fail report. | | validate_asset_spec / plan_asset_spec / build_asset_from_spec | Describe an asset once (aseprite_mcp.asset_spec.v1), then validate it, dry-run the plan, or build it (structure only — canvas/layers/frames/tags/slices/palette + exports; you draw the art). |
> "Make me an idle-animated hero and a game-ready bundle."
create_character_sprite("hero", 32, 32, base_color="#3878c8")— layers + palette + placeholder.- Draw the character on the
body/detailslayers (low-level tools). make_4_frame_idle_animation("hero.aseprite")— 4-frame loop taggedidle.validate_sprite_for_game_export("hero.aseprite", expected_width=32, required_tags=["idle"])— confirm it's game-ready.export_game_asset_bundle("hero.aseprite", scale=8)— PNG/GIF/sheet+JSON/manifest inhero_bundle/.
Workflow manifest contract
Every workflow tool returns a standardized workflow_manifest.v1 object (defined in [core/manifest.py](src/aseprite_mcp/core/manifest.py)) so the asset layer stays consistent as it grows. Always present: ok, schema_version, kind, created_files[], suggested_next_actions[], warnings[]. Included when relevant: sprite{}, exports[], palette{}, animation{}, tilemap{}. File/export entries are {role, path, format, metadata_path?}.
{
"ok": true,
"schema_version": "workflow_manifest.v1",
"kind": "character_sprite",
"sprite": { "path": "...", "width": 32, "height": 32, "color_mode": "rgb",
"frames": 1, "layers": ["body", "details"], "tags": [] },
"created_files": [ { "role": "source_sprite", "path": "...", "format": "aseprite" } ],
"palette": { "colors": ["#1b1f2a", "..."], "count": 5 },
"suggested_next_actions": ["Draw the character on the 'body' layer", "..."],
"warnings": []
}
Batch operations
apply_operations applies a list of edits to one sprite in a single Aseprite process, atomically — open once → run every op inside one transaction → save only if all succeed. This collapses multi-launch agent flows (add layer → draw → add frame → tag) into one fast, all-or-nothing call. Pass dry_run=true to validate the op list without launching Aseprite.
apply_operations("hero.aseprite", [
{"op": "add_layer", "args": {"name": "fg"}},
{"op": "fill_layer", "args": {"layer": "fg", "color": "#1d2b53"}},
{"op": "draw_rectangle", "args": {"layer": "fg", "x": 2, "y": 2, "width": 12, "height": 8, "color": "#ff004d"}},
{"op": "add_frame", "args": {"copy_from": 1, "duration_ms": 120}},
{"op": "add_tag", "args": {"name": "idle", "from": 1, "to": 2}}
])
If any op fails, the whole batch rolls back and the error names the failing op index. v1 ops: layer add/rename/visible/opacity/remove · frame add/duplicate/duration · tag add/remove · draw setpixel/line/rectangle/fillrectangle/ellipse/fillellipse/filllayer/clearlayer · slice add/remove · replacecolor.
Tool catalogue
Relative filenames resolve inside the workspace (absolute paths require ASEPRITE_MCP_ALLOW_ABSOLUTE=1 — see [Security](#security)). Frames and palette-aware operations are 1-based for frames, 0-based for palette indices. Colours accept #RRGGBB, #RRGGBBAA, r,g,b, r,g,b,a, index:N, or a name (black, white, red, green, blue, yellow, cyan, magenta, transparent, …).
Sprite lifecycle
| Tool | Description | | --- | --- | | create_sprite | Create & save a new sprite (rgb/indexed/gray, optional background). | | save_sprite_as | Save a copy under a new path (optionally flattened). | | set_color_mode | Convert between rgb / indexed / gray (with dithering). | | resize_canvas | Change canvas size without scaling art (top_left / center). | | crop_sprite | Crop the canvas to a rectangle. | | scale_sprite | Scale the whole sprite (by factor or to dimensions; nearest/bilinear). | | flatten_sprite | Flatten all layers into one. | | trim_sprite | Auto-crop the canvas to non-transparent content. | | convert_layer_to_background · convert_background_to_layer | Toggle the opaque Background layer. |
Inspection & preview
| Tool | Description | | --- | --- | | get_sprite_info | Full structured state: size, mode, frames, layer tree, tags, palette. | | render_preview | Render a frame to a PNG image you can view (scaled). | | get_pixels | Read composited pixel colours of a region (≤ 64×64 per call). | | list_sprites | List sprite/image files in the workspace. |
Layers
| Tool | Description | | --- | --- | | add_layer | Add a layer (optional group, opacity, blend mode, visibility). | | add_group_layer | Add a group layer. | | remove_layer · rename_layer | Delete / rename a layer. | | set_layer_properties | Update opacity, blend mode, visibility, editability, name. | | move_layer | Reorder a layer (1-based stack index, 1 = bottom). | | duplicate_layer · merge_layer_down | Duplicate / merge a layer down. |
Frames (animation)
| Tool | Description | | --- | --- | | add_frame | Append a frame (empty, or a copy of another). | | duplicate_frame · remove_frame | Duplicate / delete a frame. | | set_frame_duration · set_all_frame_durations | Set per-frame / uniform durations (ms). |
Cels (a layer's image at a frame)
| Tool | Description | | --- | --- | | get_cel | Inspect a cel (exists, position, bounds, opacity). | | set_cel_position · set_cel_opacity | Move / fade a cel. | | copy_cel · delete_cel | Copy a cel between frames / delete it. |
Animation tags
| Tool | Description | | --- | --- | | add_tag | Tag a frame range with a name, direction, colour. | | set_tag · remove_tag | Edit / delete a tag. |
Drawing
| Tool | Description | | --- | --- | | draw_pixels | Plot individual pixels (per-pixel or shared colour). | | draw_line · draw_polyline | Line / connected segments; pixel_perfect & antialias options. | | draw_curve | Quadratic Bézier curve. | | draw_rectangle · draw_ellipse | Outline or filled rectangle / ellipse; ellipse has antialias. | | fill_area | Flood fill (paint bucket) from a point. | | fill_layer · clear_layer | Fill the whole cel / erase it to transparent. |
Brushes & symmetry
| Tool | Description | | --- | --- | | draw_brush | Stamp a custom brush shape (ASCII mask) at many points. | | stamp_pattern | Tile an image/sprite across a region (with spacing, opacity, blend). | | mirror_layer | Reflect one half of a layer onto the other (build symmetric art). | | draw_symmetric_pixels | Plot pixels with horizontal/vertical/4-way mirroring. |
Slices (named regions / 9-patch)
| Tool | Description | | --- | --- | | add_slice · set_slice · remove_slice · list_slices | Manage slices with optional 9-patch center, pivot, colour, and data. |
Effects & colour adjustments
| Tool | Description | | --- | --- | | fill_gradient | Linear/radial gradient, multi-stop, optional Bayer dithering. | | fill_checkerboard | Two-colour checkerboard pattern. | | add_outline | Pixel outline around art (outside/inside, 4/8-connectivity, thickness). | | add_drop_shadow | Hard drop shadow on a new layer beneath the art. | | replace_color | Swap a colour (with per-channel tolerance). | | invert_colors | Invert RGB (alpha preserved). | | adjust_brightness_contrast · adjust_hue_saturation · desaturate | Colour grading. |
Text
| Tool | Description | | --- | --- | | draw_text | Render text (built-in bitmap font or a TrueType file) as crisp pixels. |
Tilemaps (Aseprite 1.3+)
| Tool | Description | | --- | --- | | create_tilemap_layer | Create a tilemap layer with a tile size + empty grid. | | add_tile · fill_tile · paint_tile_pixels | Define/draw the tileset artwork. | | set_tile · set_tiles · fill_tilemap | Place tiles on the grid. | | get_tilemap | Read the grid of tile indices. |
Image stamping
| Tool | Description | | --- | --- | | stamp_file | Composite another image/sprite file onto a layer (opacity, blend mode). | | draw_image_base64 | Composite an inline base64 image onto a layer. |
Palette
| Tool | Description | | --- | --- | | get_palette · set_palette | Read / replace the whole palette. | | set_palette_color · add_palette_color · resize_palette | Edit individual entries / size. | | load_palette | Load a palette from .gpl/`
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: MalloyTheDev
- Source: MalloyTheDev/aseprite-mcp
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.