aseprite-mcp
# aseprite-mcp
MCP server for controlling Aseprite from Codex. It wraps Aseprite's native CLI plus Lua scripting so Codex can create pixel art, edit sprites, build animation frames, inspect files, and export PNG/GIF/sprite sheets.
The broad capability path is intentional:
- High-level tools cover common pixel-art workflows.
- `aseprite_command_sequence` exposes Aseprite's built-in `app.command.<CommandId>(params)` action system.
- `aseprite_cli` exposes any Aseprite CLI flag.
- `aseprite_run_lua` exposes Aseprite's Lua API, so features not modeled by the high-level schema are still reachable.
## Requirements
- Node.js 20+
- Aseprite installed locally
- Aseprite executable available as one of:
- `ASEPRITE_PATH=/path/to/aseprite`
- `aseprite` on `PATH`
- macOS user app path such as `~/Applications/Aseprite.app/Contents/MacOS/aseprite`
- macOS app path such as `/Applications/Aseprite.app/Contents/MacOS/aseprite`
This machine has Aseprite at `/Users/sunjiaxiang/Applications/Aseprite.app/Contents/MacOS/aseprite`.
## Build
```bash
cd /Users/sunjiaxiang/workspace/tmp/aseprite-mcp
npm install
npm run build
npm test
npm run test:e2e
```
## Add To Codex
Use the Codex CLI:
```bash
codex mcp add aseprite -- node /Users/sunjiaxiang/workspace/tmp/aseprite-mcp/dist/index.js
```
If Aseprite is not on `PATH`, pass the executable path:
```bash
codex mcp add aseprite \
--env ASEPRITE_PATH=/Users/sunjiaxiang/Applications/Aseprite.app/Contents/MacOS/aseprite \
-- node /Users/sunjiaxiang/workspace/tmp/aseprite-mcp/dist/index.js
```
After adding the server, restart Codex so the new MCP tools are loaded.
Equivalent `~/.codex/config.toml` shape is:
```toml
[mcp_servers.aseprite]
command = "node"
args = ["/Users/sunjiaxiang/workspace/tmp/aseprite-mcp/dist/index.js"]
[mcp_servers.aseprite.env]
ASEPRITE_PATH = "/Users/sunjiaxiang/Applications/Aseprite.app/Contents/MacOS/aseprite"
```
## Tools
`aseprite_status`
Resolves Aseprite and reports version/configuration.
`aseprite_list_commands`
Lists Aseprite command IDs extracted from upstream `src/app/commands/commands_list.h`, such as `NewFile`, `SpriteSize`, `Flip`, `HueSaturation`, `NewFrame`, `SaveFileAs`, and `ExportSpriteSheet`.
`aseprite_command_sequence`
Runs Aseprite built-in actions through Lua as `app.command.<CommandId>(params)`. Use this for menu/action behavior such as creating files, resizing sprites, flipping, changing color mode, adding frames/layers, applying filters, and saving. It accepts `dryRun: true` to inspect the generated Lua.
`aseprite_create_sprite`
Creates a new sprite from structured JSON drawing operations. Supports `pixel`, `rect`, `line`, `circle`, `text`, `matrix`, and embedded `lua` operations. Use `dryRun: true` to inspect generated Lua without launching Aseprite.
`aseprite_run_lua`
Runs inline Lua or a `.lua` file through Aseprite's `--script`, optionally after opening input sprites and passing `app.params`.
`aseprite_cli`
Runs raw Aseprite CLI args. This is the escape hatch for all native Aseprite features.
`aseprite_export`
Exports an existing sprite/image using common flags such as `--save-as`, `--sheet`, `--data`, `--trim`, `--frame-range`, `--layer`, and `--tag`.
`aseprite_sprite_info`
Opens a sprite and returns width, height, frames, layers, and tags.
## Example Codex Prompt
After registration and restart, ask Codex:
```text
Use the aseprite MCP to create a 16x16 four-frame bouncing green slime.
Save the source as /Users/sunjiaxiang/workspace/tmp/slime.aseprite and export a GIF to /Users/sunjiaxiang/workspace/tmp/slime.gif.
```
Codex can call `aseprite_create_sprite` for the source file and `aseprite_export` or `aseprite_cli` for the GIF.
For native Aseprite actions:
```text
Use the aseprite MCP command sequence tool to create a sprite in scriptBefore, run Aseprite's Flip and NewFrame commands, draw a few pixels in scriptAfter, then save it as /Users/sunjiaxiang/workspace/tmp/action-test.aseprite.
```
Codex can call `aseprite_list_commands` to discover command IDs and `aseprite_command_sequence` to run them.
## Structured Sprite Example
`examples/slime.json` contains a four-frame sample. To inspect the Lua generated from it:
```bash
npm run build
node examples/create-slime.mjs
```
If Aseprite is installed:
```bash
node examples/create-slime.mjs > /tmp/slime.lua
/Applications/Aseprite.app/Contents/MacOS/aseprite --batch --script /tmp/slime.lua
```
Or through the MCP tool:
```json
{
"dryRun": false,
"spec": {
"width": 16,
"height": 16,
"output": "/Users/sunjiaxiang/workspace/tmp/test.aseprite",
"operations": [
{
"type": "rect",
"x": 2,
"y": 2,
"width": 12,
"height": 12,
"color": "#ffcc00ff"
}
]
}
}
```
## Command Sequence Example
This dry-run request generates a Lua script that calls Aseprite's native command system. Some UI/document commands can be disabled in `--batch`; set `requireEnabled: false` only when you have verified the command still behaves correctly headlessly.
```json
{
"dryRun": true,
"validateKnownCommands": true,
"scriptBefore": "local sprite = Sprite(16, 16, ColorMode.RGB); app.activeSprite = sprite; app.activeImage:drawPixel(1, 1, Color{r=255,g=0,b=0,a=255})",
"actions": [
{
"command": "Flip",
"params": {
"orientation": "horizontal"
},
"requireEnabled": false
},
{
"command": "NewFrame",
"params": {}
}
],
"scriptAfter": "app.activeImage:drawPixel(2, 2, Color{r=0,g=0,b=255,a=255})",
"saveAs": "/Users/sunjiaxiang/workspace/tmp/action-test.aseprite"
}
```
For commands with newer or version-specific IDs, keep `validateKnownCommands` false and let the installed Aseprite validate the command at runtime.
## Notes
- `transparentColor` maps to Aseprite's transparent color index/mask color. Pass a numeric string like `"0"` or provide a palette and a matching hex color.
- Command parameters are passed as a Lua table to Aseprite. Aseprite's `CommandWithNewParams` supports booleans, numbers, strings, rectangles/sizes, colors, and enum strings for many commands.
- The MCP server does not reimplement Aseprite. It uses Aseprite itself for file creation, scripting, export, and conversion.
- When no Aseprite executable is available, tests still verify TypeScript, Lua generation, and stdio MCP tool registration.
- Full end-to-end image generation requires a real Aseprite executable. On this machine, `/Users/sunjiaxiang/Applications/Aseprite.app/Contents/MacOS/aseprite` is available and used for smoke tests.
- `npm run test:e2e` creates real `.aseprite` files and exports PNGs through the MCP server.
TDQS
Scored across 8 tools
Most tools have clearly distinct purposes: status, listing commands, command sequences, raw CLI, Lua, create, export, info. However, aseprite_cli overlaps with many others since it can perform any of those actions, and aseprite_command_sequence and aseprite_run_lua both execute Lua, creating some ambiguity.
All tools share the aseprite_ prefix and use snake_case, but the pattern is mixed: some are verb_noun (list_commands, run_lua, create_sprite), some are noun-only (status, cli), and others are noun_noun (command_sequence, sprite_info). This inconsistency reduces predictability, though names remain readable.
8 tools is well within the ideal 3-15 range and appropriate for covering Aseprite's main capabilities: status, command introspection, execution, scripting, creation, export, and metadata. Each tool earns its place without bloat.
Core workflows are well covered: create, export, inspect, run commands/scripts, and get config. Minor gaps exist, such as no high-level edit/modify tool, but aseprite_run_lua and aseprite_cli provide escape hatches for any missing operations, making the surface reasonably complete.