An MCP (Model Context Protocol) server that bridges LLMs to Aseprite for programmatic pixel art creation. Supports both CLI batch mode and real-time WebSocket drawing.
- Sprite Management: Create, export, copy, and inspect sprites
- Drawing Tools: Pixels, lines, rectangles, circles, polygons, paths, flood fill, and gradients
- Animation: Frame and cel management, tweening (linear and eased), oscillation, opacity animation, and propagation
- Layer Operations: Add, set, show/hide, set opacity, and copy layers between sprites
- Palette Management: Read/write palettes, remap colors across cel ranges
- Pixel Reading: Sample individual pixels or rectangular regions
- Transforms: Flip, rotate, resize, and crop sprites
- Quality Assurance: Validate scenes, audit for overlaps and out-of-range activity, sanitize animations
- Spritesheet Export: Generate spritesheets with JSON atlas metadata
- Real-time Drawing: WebSocket bridge for interactive pixel manipulation
- Custom Lua Scripts: Execute arbitrary Lua scripts in Aseprite
- Preview Server: HTTP server for browser preview of exported sprites
- Built-in Palettes: Dawnbringer32 and PICO-8 palettes included
- Pixel Art Prompts: Guided prompt template for LLM-driven asset generation
No clone, no install. Just add this to your MCP config:
{
"command": "uvx",
"args": ["aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/path/to/aseprite"
}
}uvx downloads and runs aseprite-mcp on demand. See the Integration Guide for full config snippets per tool.
Not on PyPI yet? Use the Git fallback:
{ "command": "uvx", "args": ["--from", "git+https://github.com/anhnht/aseprite-mcp-python", "aseprite-mcp"], "env": { "ASEPRITE_PATH": "/path/to/aseprite" } }
pipx install aseprite-mcpThen reference the aseprite-mcp binary directly in your MCP config:
{
"command": "aseprite-mcp",
"env": {
"ASEPRITE_PATH": "/path/to/aseprite"
}
}Not on PyPI yet? Install from Git:
pipx install git+https://github.com/anhnht/aseprite-mcp-python
git clone https://github.com/anhnht/aseprite-mcp-python && cd aseprite-mcp-python
uv sync
uv run aseprite-mcpdocker compose up -d # HTTP mode on :8080, WS on :8765
docker compose run --rm aseprite-mcp stdio # stdio modeSet the path to your Aseprite binary via environment variable:
export ASEPRITE_PATH=/path/to/asepriteOr pass it as a CLI argument (--aseprite-path).
Output directory for generated assets (sprites, PNGs, spritesheets):
export ASEPRITE_OUTPUT_DIR=generated_assets # default: generated_assets/ in CWDOr use --output-dir /path/to/assets CLI flag. The directory is auto-created on first use.
Optional WebSocket settings:
export ASEPRITE_WS_HOST=127.0.0.1 # default
export ASEPRITE_WS_PORT=8765 # defaultaseprite-mcp --transport stdioaseprite-mcp --transport streamable-http --port 9090--transport {stdio,streamable-http} Transport protocol (default: stdio)
--port PORT HTTP port for streamable-http (default: 8080)
--aseprite-path PATH Path to Aseprite binary
--ws-port PORT WebSocket port for bridge (default: 8765)
--output-dir PATH Directory for generated assets (default: generated_assets/)
These use the original run_json_script / run_batch / run_script patterns:
| Tool | Description |
|---|---|
sprite_create |
Create a new sprite (saves to output_dir by default) |
sprite_export |
Export a sprite to PNG, GIF, etc. |
sprite_info |
Get metadata (dimensions, layers, tags, frames, palette) as JSON |
sprite_list_layers |
List all layers in a sprite |
sprite_list_tags |
List all frame tags in a sprite |
spritesheet_export |
Export as spritesheet with JSON atlas |
script_execute |
Run a custom Lua script |
ws_connect |
Launch Aseprite with WebSocket bridge |
draw_pixels |
Draw pixels on active sprite via WebSocket |
fill_rect |
Fill a rectangle on active sprite via WebSocket |
| Tool | Description |
|---|---|
create_canvas |
Create a new sprite with specified dimensions |
add_layer |
Add a named layer to a sprite |
add_frame |
Add a new frame |
set_frame |
Set active frame by 1-based index |
set_frame_duration |
Set duration of a specific frame (ms) |
set_layer |
Set active layer by name (optionally create it) |
| Tool | Description |
|---|---|
draw_pixels |
Draw multiple pixels on the active cel |
draw_line |
Draw a line with configurable thickness |
draw_rectangle |
Draw an outline or filled rectangle |
fill_area |
Flood-fill from a point |
draw_circle |
Draw an outline or filled circle/ellipse |
draw_pixels_at |
Draw pixels on a specific layer/frame |
draw_line_at |
Draw a line on a specific layer/frame |
draw_rectangle_at |
Draw a rectangle on a specific layer/frame |
draw_circle_at |
Draw a circle on a specific layer/frame |
fill_area_at |
Flood-fill on a specific layer/frame |
draw_polygon |
Draw a polygon on a specific layer/frame |
draw_path |
Draw a polyline path on a specific layer/frame |
apply_gradient_rect |
Apply a linear gradient fill to a rectangle |
| Tool | Description |
|---|---|
add_frames |
Add multiple frames with optional duration |
set_frame_duration_all |
Set duration for all frames |
set_layer_visibility |
Show or hide a layer by name |
set_layer_opacity |
Set layer opacity (0-255) |
get_sprite_info |
Get structured sprite info (dimensions, frames, layers) |
duplicate_frame_range |
Duplicate a range of frames |
set_cel_position |
Set a cel's position on a specific layer/frame |
tween_cel_positions |
Interpolate cel positions linearly across frames |
offset_cel_positions |
Offset cel positions by a delta across frames |
create_cel |
Create an empty cel on a layer/frame |
clear_cel |
Delete a cel on a layer/frame |
copy_cel |
Copy a cel between frames on the same layer |
copy_frame |
Copy all cels from one frame to another |
propagate_frame_to_range |
Copy a frame's cels to a range of frames |
set_tag |
Create or update an animation tag (with direction) |
tween_cel_positions_eased |
Tween cel positions with easing functions |
oscillate_cel_positions |
Sine-wave oscillation of cel positions |
tween_cel_opacity_eased |
Tween cel opacity with easing functions |
propagate_cels |
Copy cels across specific layers and frame range |
| Tool | Description |
|---|---|
export_sprite |
Export sprite to PNG, GIF, etc. via CLI --save-as |
copy_sprite |
Copy sprite to a new .aseprite file |
| Tool | Description |
|---|---|
get_palette |
Get the color palette as hex color list |
set_palette |
Set palette from a list of hex colors |
remap_colors_in_cel_range |
Replace colors in cels across a frame range |
| Tool | Description |
|---|---|
get_pixel_color |
Read the RGBA color at a single pixel |
get_pixels_rect |
Read all pixels in a rectangular region |
| Tool | Description |
|---|---|
start_preview_server |
Start an HTTP server for browser preview |
stop_preview_server |
Stop the preview server |
| Tool | Description |
|---|---|
copy_layers_between_sprites |
Copy named layers from one sprite to another |
| Tool | Description |
|---|---|
animation_workflow_guide |
Return a text guide for animation workflows |
| Tool | Description |
|---|---|
ensure_layers_present |
Create missing cels for specified layer/frame combos |
validate_scene |
Check for missing layers and cels |
audit_animation |
Audit for overlaps and out-of-range layer activity |
animation_sanitize |
Validate and fix animation consistency issues |
| Tool | Description |
|---|---|
flip_layer |
Flip a cel horizontally or vertically |
rotate_layer |
Rotate a cel by 90, 180, or 270 degrees |
resize_canvas |
Resize sprite (scales all content) |
crop_canvas |
Crop sprite to a specified region |
aseprite://sprites/{path}- Sprite metadataaseprite://palettes/{name}- Built-in palette data (dawnbringer32,pico8)
pixel_art_asset_gen- Template for LLM-guided pixel art generation
| Tool | Config Key | Config Path | stdio | HTTP | Notes |
|---|---|---|---|---|---|
| Claude Desktop | mcpServers |
~/Library/Application Support/Claude/claude_desktop_config.json |
Y | N | Must restart after config change |
| VS Code Copilot | servers |
.vscode/mcp.json |
Y | Y | Agent mode required; VS Code 1.99+ |
| Claude Code | mcpServers |
.mcp.json or claude mcp add |
Y | Y | 3 scopes: local/project/user |
| Cursor | mcpServers |
~/.cursor/mcp.json |
Y | SSE | Global config only |
| opencode | mcp |
opencode.json |
Y | Y | Uses type: "local"/"remote", command as array |
| Windsurf | mcpServers |
~/.codeium/windsurf/mcp_config.json |
Y | Y | ${env:VAR} interpolation; max 100 tools |
| Cline | mcpServers |
VS Code global state (UI) | Y | SSE | Configured via extension UI |
| Continue | mcpServers |
~/.continue/config.json |
Y | SSE | Inside existing config.json |
| Zed | context_servers |
Zed settings.json |
Y | Y | Different key name! |
Below are config snippets for each tool in four variants:
- uvx (zero-install) —
uvx aseprite-mcp, no clone or install needed - Local (uv run) — running from a source checkout
- Installed —
aseprite-mcpinstalled viapipx install aseprite-mcp - Docker — running inside a container
Replace /path/to/aseprite-mcp-python and /path/to/aseprite with your actual paths.
Config file: ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows)
Claude Desktop only supports stdio transport. You must fully quit and restart the app after editing the config.
uvx (zero-install):
{
"mcpServers": {
"aseprite": {
"command": "uvx",
"args": ["aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Local (uv run):
{
"mcpServers": {
"aseprite": {
"command": "uv",
"args": ["run", "--directory", "/path/to/aseprite-mcp-python", "aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Installed (pipx):
{
"mcpServers": {
"aseprite": {
"command": "aseprite-mcp",
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Docker:
{
"mcpServers": {
"aseprite": {
"command": "docker",
"args": ["run", "--rm", "-i", "aseprite-mcp", "stdio"]
}
}
}Config file: .vscode/mcp.json in your workspace root
Requires VS Code 1.99+ and Agent mode in Copilot Chat. Organization admins must enable the "MCP servers in Copilot" policy for Business/Enterprise users.
uvx (zero-install):
{
"servers": {
"aseprite": {
"command": "uvx",
"args": ["aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Local (uv run):
{
"servers": {
"aseprite": {
"command": "uv",
"args": ["run", "--directory", "/path/to/aseprite-mcp-python", "aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Installed (pipx):
{
"servers": {
"aseprite": {
"command": "aseprite-mcp",
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Docker:
{
"servers": {
"aseprite": {
"command": "docker",
"args": ["run", "--rm", "-i", "aseprite-mcp", "stdio"]
}
}
}HTTP (connect to a running server):
Start the server first: docker run --rm -p 8080:8080 -p 8765:8765 aseprite-mcp http 8080
Then in VS Code settings.json:
{
"servers": {
"aseprite": {
"url": "http://localhost:8080/mcp"
}
}
}Config file: .mcp.json in project root, or ~/.claude.json for user scope
You can also use the CLI:
# uvx (zero-install)
claude mcp add --transport stdio aseprite -- uvx aseprite-mcp
# stdio (from source)
claude mcp add --transport stdio aseprite -- uv run --directory /path/to/aseprite-mcp-python aseprite-mcp
# stdio (installed via pipx)
claude mcp add --transport stdio aseprite -- aseprite-mcp
# HTTP
claude mcp add --transport http aseprite http://localhost:8080/mcpOr manually in .mcp.json:
uvx (zero-install):
{
"mcpServers": {
"aseprite": {
"type": "stdio",
"command": "uvx",
"args": ["aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Local (uv run):
{
"mcpServers": {
"aseprite": {
"type": "stdio",
"command": "uv",
"args": ["run", "--directory", "/path/to/aseprite-mcp-python", "aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Installed (pipx):
{
"mcpServers": {
"aseprite": {
"type": "stdio",
"command": "aseprite-mcp",
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Docker:
{
"mcpServers": {
"aseprite": {
"type": "stdio",
"command": "docker",
"args": ["run", "--rm", "-i", "aseprite-mcp", "stdio"]
}
}
}HTTP:
{
"mcpServers": {
"aseprite": {
"type": "http",
"url": "http://localhost:8080/mcp"
}
}
}Config file: ~/.cursor/mcp.json
Cursor supports stdio and SSE transports. Config is global (not per-project).
uvx (zero-install):
{
"mcpServers": {
"aseprite": {
"command": "uvx",
"args": ["aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Local (uv run):
{
"mcpServers": {
"aseprite": {
"command": "uv",
"args": ["run", "--directory", "/path/to/aseprite-mcp-python", "aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Installed (pipx):
{
"mcpServers": {
"aseprite": {
"command": "aseprite-mcp",
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Docker:
{
"mcpServers": {
"aseprite": {
"command": "docker",
"args": ["run", "--rm", "-i", "aseprite-mcp", "stdio"]
}
}
}SSE/HTTP (remote):
{
"mcpServers": {
"aseprite": {
"url": "http://localhost:8080/mcp"
}
}
}Config file: opencode.json in project root
opencode uses a different schema: type: "local" for stdio, type: "remote" for HTTP, and command as an array (not command string + args array). Environment variables use {env:VAR} interpolation.
uvx (zero-install):
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"aseprite": {
"type": "local",
"command": ["uvx", "aseprite-mcp"],
"enabled": true,
"environment": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Local (uv run):
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"aseprite": {
"type": "local",
"command": ["uv", "run", "--directory", "/path/to/aseprite-mcp-python", "aseprite-mcp"],
"enabled": true,
"environment": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Installed (pipx):
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"aseprite": {
"type": "local",
"command": ["aseprite-mcp"],
"enabled": true,
"environment": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Docker:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"aseprite": {
"type": "local",
"command": ["docker", "run", "--rm", "-i", "aseprite-mcp", "stdio"],
"enabled": true
}
}
}HTTP (remote):
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"aseprite": {
"type": "remote",
"url": "http://localhost:8080/mcp",
"enabled": true
}
}
}Config file: ~/.codeium/windsurf/mcp_config.json
Windsurf supports ${env:VAR} and ${file:/path} interpolation in commands and args. Remote servers use serverUrl (not url). Max 100 MCP tools total.
uvx (zero-install):
{
"mcpServers": {
"aseprite": {
"command": "uvx",
"args": ["aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Local (uv run):
{
"mcpServers": {
"aseprite": {
"command": "uv",
"args": ["run", "--directory", "/path/to/aseprite-mcp-python", "aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Installed (pipx):
{
"mcpServers": {
"aseprite": {
"command": "aseprite-mcp",
"env": {
"ASEPRITE_PATH": "${env:ASEPRITE_PATH}"
}
}
}
}Docker:
{
"mcpServers": {
"aseprite": {
"command": "docker",
"args": ["run", "--rm", "-i", "aseprite-mcp", "stdio"]
}
}
}HTTP (remote):
{
"mcpServers": {
"aseprite": {
"serverUrl": "http://localhost:8080/mcp"
}
}
}Config: Managed through the Cline extension UI — click the MCP icon in the sidebar, then "Edit MCP Settings". Paste JSON directly into the settings.
uvx (zero-install):
{
"mcpServers": {
"aseprite": {
"command": "uvx",
"args": ["aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Local (uv run):
{
"mcpServers": {
"aseprite": {
"command": "uv",
"args": ["run", "--directory", "/path/to/aseprite-mcp-python", "aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Installed (pipx):
{
"mcpServers": {
"aseprite": {
"command": "aseprite-mcp",
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Docker:
{
"mcpServers": {
"aseprite": {
"command": "docker",
"args": ["run", "--rm", "-i", "aseprite-mcp", "stdio"]
}
}
}Config file: ~/.continue/config.json
The mcpServers key goes inside the existing config.json alongside other Continue settings.
uvx (zero-install):
{
"mcpServers": {
"aseprite": {
"command": "uvx",
"args": ["aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Local (uv run):
{
"mcpServers": {
"aseprite": {
"command": "uv",
"args": ["run", "--directory", "/path/to/aseprite-mcp-python", "aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Installed (pipx):
{
"mcpServers": {
"aseprite": {
"command": "aseprite-mcp",
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Docker:
{
"mcpServers": {
"aseprite": {
"command": "docker",
"args": ["run", "--rm", "-i", "aseprite-mcp", "stdio"]
}
}
}Config file: Zed settings.json (open via Settings → Edit Settings)
Zed uses context_servers (not mcpServers). This is the only tool with a different top-level key.
uvx (zero-install):
{
"context_servers": {
"aseprite": {
"command": "uvx",
"args": ["aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Local (uv run):
{
"context_servers": {
"aseprite": {
"command": "uv",
"args": ["run", "--directory", "/path/to/aseprite-mcp-python", "aseprite-mcp"],
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Installed (pipx):
{
"context_servers": {
"aseprite": {
"command": "aseprite-mcp",
"env": {
"ASEPRITE_PATH": "/usr/bin/aseprite"
}
}
}
}Docker:
{
"context_servers": {
"aseprite": {
"command": "docker",
"args": ["run", "--rm", "-i", "aseprite-mcp", "stdio"]
}
}
}HTTP (remote):
{
"context_servers": {
"aseprite": {
"url": "http://localhost:8080/mcp"
}
}
}JetBrains IDEs (IntelliJ, PyCharm, WebStorm, etc.) currently act as an MCP server (exposing IDE capabilities to external clients), not an MCP consumer. To use Aseprite MCP with a JetBrains AI assistant, connect JetBrains to an external client (like Claude Desktop or Copilot) that has the Aseprite MCP server configured.
Alternatively, use the JetBrains terminal to run:
aseprite-mcp --transport stdioand pipe it to your preferred AI tool.
The server is organized into a modular tools/ package:
- Entry point:
aseprite_mcp.__main__:main - Server:
aseprite_mcp/server.py-- FastMCP server hosting legacy tools, resources, and prompts - Tool modules:
aseprite_mcp/tools/-- 11 domain modules, each registering tools via@mcp.tool()decorators. Auto-imported by__init__.py - CLI wrapper:
aseprite_mcp/aseprite_cli.py-- subprocess runner withexecute_lua_script()method - WebSocket bridge:
aseprite_mcp/websocket_bridge.py - Lua generators:
aseprite_mcp/lua_scripts.py - Config:
aseprite_mcp/config.py
New tools use execute_lua_script() which returns a (success, output) tuple. Most mutations are wrapped in app.transaction() for undo grouping. Frame indices are 1-based (Aseprite Lua convention). Colors use #RRGGBB hex strings. Layers are targeted by name.
uv sync --extra dev
uv run pytest tests/ -v
uv run ruff check src/ tests/
uv run mypy src/tests/test_aseprite_cli.py-- CLI wrapper andexecute_lua_scriptteststests/test_lua_scripts.py-- Lua script generation teststests/test_server.py-- legacy MCP tool teststests/test_websocket_bridge.py-- WebSocket bridge teststests/test_config.py-- configuration teststests/test_utils.py-- utility teststests/test_main.py-- entry point tests
All tests mock subprocess.run/subprocess.Popen -- no Aseprite binary needed.
MIT