Skip to main content
Glama
ZhangDongyang800

Aseprite MCP Server

🎨 Aseprite MCP Server

Let AI draw pixel art in Aseprite

A Model Context Protocol (MCP) server that enables AI to create pixel art in Aseprite through pixel-level drawing primitives, read canvas screenshots, and iterate until satisfied.

Python FastMCP Aseprite Stars

Demo

All three characters were drawn by an AI through this MCP — every pixel written by apply_operations. The structural work (adding frames, setting durations, building tags, exporting the sheet) had to go through run_lua when these were made; three of those four now have ops of their own — add_frames, set_durations, add_tag.

Character

↓ Down

↑ Up

← Left

→ Right

Sprite Sheet

Chibi Knight4 dirs × 6 frames

Dark Reaper4 dirs × 6 frames

Slime Devourer4 dirs × 5 action frames

The first two are walk cycles (the knight steps on anti-phase leg swings; the reaper has no legs, so the walk reads through a travelling wave in the robe hem plus alternating bone feet). The third is an action animation: idle → crouch → lunge with open maw → chomp → swallow, with per-phase frame durations. Each character ships a re-runnable parametric generator and a per-frame pixel check under demo/<name>/generator/.


IMPORTANT

This project requires a local installation ofAseprite v1.3+. AI performs drawing via the MCP protocol by calling the Aseprite CLI + Lua scripts.

Two execution modes are supported:

  • CLI mode (default): Each tool call spawns a headless Aseprite process (aseprite -b). No UI, state passed via .ase files.

  • Live mode (WebSocket): AI operates the running Aseprite instance directly through a WebSocket bridge. UI is visible, state is persistent, and you can watch AI draw in real time. See Live Mode Setup below.


Related MCP server: aseprite-mcp

Table of Contents


Tools

Exactly three MCP tools:

Tool

Description

apply_operations

Execute a batch of ops inside one transaction — the only mutation entry point. Pass session_id + ops[]; dry_run=true validates without side effects; confirmed=true is required when the batch contains a destructive op (clear_canvas, close_session). If session_id is omitted and the first op is create_sprite / open_sprite, a session is created automatically.

inspect

Read-only perception: returns a canvas preview image plus quantitative metrics (palette, color count, bounding box, coverage, semi-transparent and isolated pixels). On animated documents, frame=N steps through frames one at a time. Never modifies the document.

run_lua

Escape hatch: run arbitrary Lua. Requires unsafe=true and confirmed=true.

Ops are named operations registered in src/v2/ops/ (Pydantic parameter models) with their Lua implementations in scripts/ops_*.lua. Built-in ops: create_sprite, open_sprite, save_sprite, close_session, draw_pixel, draw_rect, fill_region, clear_canvas, undo, redo, plus the structural ones — add_frames, set_durations, add_tag and paint_grid.

paint_grid takes a path to a Lua file returning {palette = {b = "#F0A65A"}, rows = {"..bb..", ...}}, one character per pixel, . for transparent. It keeps whole-sprite art out of the tool call: a 32×32 four-frame sheet costs a few hundred tokens through paint_grid instead of tens of thousands as draw_pixel ops, and still runs validated and inside the same rollback as everything else.

apply_operations(ops=[
    {"op": "create_sprite", "width": 32, "height": 32},
    {"op": "draw_rect", "x": 4, "y": 4, "width": 24, "height": 24, "color": "#E74C3C", "filled": True},
    {"op": "draw_pixel", "x": 16, "y": 6, "color": "#FFFFFF"},
])

All drawing ops accept layer / frame (1-based, default 1/1). A batch runs inside one app.transaction, so atomic=true (the default) rolls the whole batch back if any op fails.

TIP

inspect is the core of the workflow: after drawing, AI calls it to "see" the canvas, analyze it, and decide whether to fix it, forming a draw → inspect → analyze → fix loop.


How to Use

1. Prerequisites

Dependency

Version

Notes

uv

any recent

manages Python and the dependencies for you

Aseprite

v1.3+

note the full path to the executable, not the folder holding it

Install uv with winget install astral-sh.uv (Windows), brew install uv (macOS), or curl -LsSf https://astral.sh/uv/install.sh | sh.

2. Clone

git clone https://github.com/ZhangDongyang800/Aseprite_MCP.git

There is no install step: the uv run command in step 3 provisions an isolated environment from pyproject.toml on first launch, with fastmcp / pillow / websockets.

3. Client Configuration

Replace C:\path\to\Aseprite_MCP with where you cloned this repo, and the two env paths with your own.

JSON config (TRAE, Claude Desktop, Cursor, Qoder, …):

{
  "mcpServers": {
    "aseprite": {
      "command": "uv",
      "args": ["run", "--directory", "C:\\path\\to\\Aseprite_MCP", "server.py"],
      "env": {
        "ASEPRITE_PATH": "C:\\Program Files\\Aseprite\\aseprite.exe",
        "ASEPRITE_WORK_DIR": "C:\\ase_work"
      }
    }
  }
}

If the client cannot find uv, give command the absolute path to uv. Never fall back to a bare python — Windows shadows it with a Store alias — or to pip install --user, because hosts strip APPDATA and Python then cannot find the packages. To skip uv entirely, install into a virtualenv and point command at that interpreter:

python -m venv .venv                                  # Windows, if `python` is missing: py -3 -m venv .venv
.venv/Scripts/python.exe -m pip install -e .          # Windows
.venv/bin/python -m pip install -e .                  # macOS / Linux

🎥 Live Mode (Optional, WebSocket)

Live mode lets AI operate your running Aseprite instance directly — you can watch every stroke happen in real time on your screen, and the sprite state persists across tool calls (no repeated file open/save overhead).

How It Works

┌─────────┐    MCP (stdio)    ┌──────────────┐   WebSocket    ┌──────────────────┐
│  AI/TRAE │ ───────────────► │ Python MCP   │ ─────────────► │ Aseprite Extension│
│          │ ◄─────────────── │ Server       │ ◄──────────── │ (WebSocket client) │
└─────────┘                   └──────────────┘                └──────┬───────────┘
                                                                     │ Lua app.* API
                                                                     ▼
                                                              ┌──────────────┐
                                                              │ Visible Aseprite │
                                                              │ Sprite + UI      │
                                                              └──────────────┘

The Python MCP server starts a WebSocket server on 127.0.0.1:9001. The Aseprite extension connects to it as a client. Each MCP tool call is forwarded to Aseprite over WebSocket, executed via the existing Lua scripts, and the result is sent back.

Setup

1. Install the Aseprite extension

The extension is in the extension/ folder of this repo. Install it via:

  • Open Aseprite → File > Scripts > Open Scripts Folder

  • Copy the entire extension/ folder contents into the scripts folder (or use Edit > Preferences > Extensions > Add Extension and select the extension/ folder)

2. Enable WebSocket mode in MCP config

Add ASEPRITE_MCP_MODE=ws to the env section of your MCP server config:

{
  "mcpServers": {
    "aseprite": {
      "command": "uv",
      "args": ["run", "--directory", "C:\\path\\to\\Aseprite_MCP", "server.py"],
      "env": {
        "ASEPRITE_PATH": "C:\\Program Files\\Aseprite\\aseprite.exe",
        "ASEPRITE_WORK_DIR": "C:\\ase_work",
        "ASEPRITE_MCP_MODE": "ws",
        "ASEPRITE_WS_HOST": "127.0.0.1",
        "ASEPRITE_WS_PORT": "9001"
      }
    }
  }
}

3. Connect Aseprite

With the MCP server running, open Aseprite and click:

File > Scripts > MCP Bridge: Toggle Connection

You should see an alert: "MCP Bridge: Connected to ws://127.0.0.1:9001".

Now AI can operate Aseprite directly — create a sprite, draw pixels, and you'll see it happen live.

Environment Variables

Variable

Default

Description

ASEPRITE_PATH

auto-detected

Path to the Aseprite executable (overrides auto-detection via PATH and common install locations)

ASEPRITE_WORK_DIR

<repo>/work

The server's state directory: sessions live in <work>/sessions/<uuid>/ and expire after ASEPRITE_SESSION_TIMEOUT. Absolute by default, and it must stay ASCII-only — Aseprite rejects non-ASCII script paths and blames the Lua engine

ASEPRITE_SESSION_TIMEOUT

3600

Seconds an idle session survives before the cleanup thread removes it

ASEPRITE_MCP_MODE

cli

Execution mode: cli or ws

ASEPRITE_WS_HOST

127.0.0.1

WebSocket server bind address

ASEPRITE_WS_PORT

9001

WebSocket server port


Example Prompts

The prompt behind each row of the table at the top.

Chibi Knight · 4 directions × 6 frames · 32x32

Use Aseprite MCP to generate a pixel art sprite sheet of a brave knight in silver armor holding a long sword, red plume and red cape. Four-direction walk cycle (down, up, left, right), 6 frames per direction, 32x32, flat colors, transparent background, 1px dark outline, light from the top-left.


Dark Reaper · 4 directions × 6 frames · 32x32

Use Aseprite MCP to generate a pixel art sprite sheet of a dark reaper in a tattered black robe wielding a giant scythe, glowing red eyes under the hood. Four-direction walk cycle (down, up, left, right), 6 frames per direction, 32x32, flat colors, transparent background, 1px dark outline.


Slime Devourer · 4 directions × 5 frames · 32x32

Use Aseprite MCP to generate a pixel art sprite sheet of a slime monster that devours its prey — green blob body, huge jaws, fangs. Four-direction devour animation (down, up, left, right), 5 frames per direction: idle → crouch → lunge with open maw → chomp → swallow. 32x32, flat colors, transparent background, sprite sheet layout.


🤝 Contributing

Issues and Pull Requests are welcome!

I've tried it, but I can't guarantee it works perfectly. It still needs more optimization.


License

This project is open-sourced under the MIT License.

Copyright © 2026 ZhangDongyang800

Built with ❤️ for pixel art lovers

Available Tools

3 tools
apply_operationsApply OperationsA
Destructive

执行一批 Aseprite 操作(唯一变更入口)。

如果 session_id 为空且首个 op 是 create_sprite/open_sprite, 会先创建会话再执行。destructive op 需要 confirmed=true。

成功时 op_results 只保留服务器才知道的新信息(如 open_sprite 读到的实际尺寸), 回显入参的条目会被丢弃;要完整回显或 dry_run 的执行计划就用 verbose=true。

ParametersJSON Schema
NameRequiredDescriptionDefault
opsYes
atomicNo
dry_runNo
verboseNo
confirmedNo
session_idNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses important behaviors beyond annotations: automatic session creation, the confirmed=true requirement for destructive ops, and the filtering of echo results on success. It also explains the verbose flag for complete echoes and dry_run plans, which is valuable for predicting tool behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded with the core purpose, followed by conditional behavior and output semantics. Every sentence adds useful information without redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers session handling, confirmation, and result filtering well, but the central ops parameter is only vaguely defined as a batch of operations with examples. With no output schema and no schema-level parameter descriptions, the lack of op structure details and atomic semantics makes it incomplete for reliably invoking the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description compensates by explaining session_id, confirmed, verbose, and dry_run behavior, and by giving examples of ops such as create_sprite/open_sprite. However, the structure of the ops array is not specified, and the atomic parameter is left unexplained, leaving gaps in full parameter understanding.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action: executing a batch of Aseprite operations, and labels itself as the unique mutation entry point. This clearly distinguishes it from sibling tools like inspect and run_lua by emphasizing that it is the only path for changes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear contextual guidance: it is the only mutation entry, session creation is automatic for create_sprite/open_sprite, and destructive operations require confirmed=true. However, it does not explicitly name alternatives or state when not to use this tool, so it falls short of a fully explicit when/when-not comparison.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

inspectInspectA
Read-only

返回画布预览与量化指标(只读,永不改动文档)。

动画文档用 frame(1 起)指定看哪一帧;越界由 Lua 侧夹到有效范围。

ParametersJSON Schema
NameRequiredDescriptionDefault
viewNocomposite
frameNo
scaleNo
session_idYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare readOnlyHint and openWorldHint, and the description adds meaningful behavior beyond that: the operation never mutates the document, frame starts at 1, and out-of-range frames are clamped by the Lua side. This gives the agent concrete expectations about side effects and edge-case handling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences deliver the purpose, safety characteristic, and frame-handling detail with no redundancy. The key purpose is front-loaded, and every clause contributes useful information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is simple and the description covers the core use case, safety, and frame behavior. It is incomplete on parameter semantics for session_id, view, and scale, and it does not explain what the returned preview/metrics look like, which matters because there is no output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description must compensate, but it only explains frame semantics (1-based, clamped). The required session_id and the view and scale parameters are left undefined, so the agent must guess their meaning or defaults.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action and output: it returns a canvas preview and quantitative metrics. The explicit 'read-only, never modifies the document' note clearly sets it apart from the modification-oriented siblings apply_operations and run_lua.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides useful context for animated documents by explaining how to use frame and that out-of-bounds values are clamped. However, it never explicitly tells an agent when to choose inspect over apply_operations or run_lua; the read-only statement only implies the appropriate use case.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_luaRun LuaA
Destructive

执行任意 Lua(逃逸舱)。必须 unsafe=true 且 confirmed=true。

与 op 批量同样受快照保护:snippet 失败会回滚文档,成功则把改前状态留作 undo 备份。 CLI 模式下每次调用都会重写 .ase,所以 changed 表示"文档被重写"而非"内容语义变化"。

ParametersJSON Schema
NameRequiredDescriptionDefault
codeYes
unsafeNo
confirmedNo
session_idYes

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds rich behavioral context beyond the destructiveHint/openWorldHint annotations: snippet failure rolls back the document, success creates an undo backup, and CLI mode rewrites .ase so changed means 'rewritten' rather than 'semantically changed.' This is exactly the kind of non-obvious behavior an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded: purpose and safety gate first, then snapshot/rollback behavior, then CLI caveat. Every sentence carries distinct operational value with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given there is no output schema, the description does well to explain safety gating, rollback, undo behavior, and the meaning of changed in CLI mode. The main gaps are the unexplained session_id parameter and reliance on the reader already knowing apply_operations' snapshot behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It gives real meaning to unsafe and confirmed (both must be true) and implies code is the Lua snippet to execute. However, session_id — a required parameter — is never explained.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states 'Execute arbitrary Lua (escape hatch)' — a specific verb and resource, and clearly frames this as an escape hatch beyond normal operations. It doesn't explicitly name sibling alternatives, but the scope is unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The 'escape hatch' wording implies use when standard operations or inspection are insufficient, and it explicitly mandates unsafe=true and confirmed=true. However, it never states when to prefer this over apply_operations or inspect, nor gives any when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

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

  1. 3 tool updatesv0.1.0
    • First observedapply_operations
    • First observedinspect
    • First observedrun_lua

TDQS

A4.3/5.0

Scored across 3 tools

Disambiguation5/5

The three tools have clearly distinct purposes: apply_operations is the sole programmatic mutation entry point, run_lua is an escape hatch for arbitrary scripts, and inspect is strictly read-only. No two tools overlap in functionality, making selection unambiguous for an agent.

Naming Consistency5/5

All names follow a consistent lowercase snake_case pattern starting with a verb: apply_operations, run_lua, inspect. The convention is uniform and predictable, with no mixed styles or ambiguous verbs.

Tool Count5/5

With only 3 tools, the surface is minimal but perfectly aligned with the server's purpose. The heavy lifting is encapsulated inside operation types for apply_operations, so the small count is intentional and well-scoped rather than sparse.

Completeness5/5

The tool set covers the full lifecycle: mutate (apply_operations), arbitary scripting (run_lua), and read/analyze state (inspect). Supporting operations like create_sprite and open_sprite are exposed as ops within apply_operations, so no critical gap exists for typical Aseprite workflows.

Maintenance

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI assistants to drive Aseprite for pixel-art creation, including sprite setup, grid-based drawing, layer/frame/tag management, reference image import, and export, with rendered previews after every mutation.
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI agents to create and edit pixel art in a live Aseprite window, with tools for drawing, selection, transformation, and animation.
    18
    49 npm
    5
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI coding agents to create, draw, and refine Aseprite documents through deterministic canvas, layer, frame, tag, and palette tools, with pixel analyzers, style validation, and preview/diff visual feedback. It also supports spritesheet and animated GIF export, producing multi-layer game-ready assets.
    1
    MIT