Spritesheet Forge

A hosted MCP server for game-dev spritesheet workflows. Connect it to Claude or any MCP-compatible AI client to pack, split, trim, and animate sprites through natural language โ€” no local tools required.

โญ GitHub ๐Ÿ” Smithery ๐Ÿ“– Live Docs ๐Ÿ”Œ MCP endpoint: mcp.clawstudiouo.com/mcp

Quick Start

Connect Spritesheet Forge to your AI client in under 2 minutes.

Claude Desktop

Add to claude_desktop_config.json (find it via Settings โ†’ Developer):

{
  "mcpServers": {
    "spritesheet-forge": {
      "type": "http",
      "url": "https://mcp.clawstudiouo.com/mcp"
    }
  }
}

Claude Code (CLI)

claude mcp add spritesheet-forge --transport http https://mcp.clawstudiouo.com/mcp
On first use, your client opens a GitHub login page. Approve access and the session is stored for 30 days โ€” no further configuration needed.

Authentication

Uses GitHub OAuth 2.1 with PKCE. MCP clients run the flow automatically. To get a Bearer token manually (for curl or benchmark scripts):

curl -O https://spritesheet-forge.spritesheet-forge.workers.dev/get-token.py && python3 get-token.py

Opens a GitHub login page, then prints and saves the token to ~/.spritesheet-forge-token. Requires Python 3 (pre-installed on macOS/Linux).

Tools

7 processing tools + 1 config tool. All inputs accept base64 data URIs, https:// URLs, or output URLs from previous tool calls.

gif_to_spritesheet GIF โ†’ PNG

Extracts all frames from an animated GIF and packs them into a spritesheet grid. Optionally removes the background from each frame.

Input โ€” animated GIF
Input: animated GIF (498ร—413)
โ†’
Output โ€” spritesheet PNG
Output: spritesheet (1494ร—826)
ParameterTypeDefaultDescription
filestringrequiredGIF file input
columnsintegerautoGrid columns
paddinginteger0Pixel gap between frames
remove_bgbooleanfalseRemove background from each frame
bg_colorstring"auto""auto" or "#RRGGBB"
toleranceinteger30Background removal threshold 0โ€“255
spritesheet_to_animation PNG โ†’ GIF / WebP

Reassembles a spritesheet back into an animated GIF or WebP. Supports grid mode (columns ร— rows) or cell mode (fixed pixel dimensions). You can select frame ranges, trim offsets, and skip empty frames.

Input โ€” spritesheet PNG (3ร—2 grid)
Input: spritesheet (1494ร—826)
โ†’
Output โ€” animated GIF
Output: animated GIF (498ร—413)
ParameterTypeDefaultDescription
filestringrequiredSpritesheet PNG
columnsintegerโ€”Grid columns (grid mode)
rowsintegerโ€”Grid rows (grid mode)
cell_widthintegerโ€”Cell width px (cell mode)
cell_heightintegerโ€”Cell height px (cell mode)
frame_countintegerโ€”Actual frames (for incomplete last row)
durationinteger100Frame duration in ms
loopinteger0Loop count (0 = infinite)
output_formatstring"gif""gif" | "webp"
skip_emptybooleantrueRemove fully transparent frames
png_to_spritesheet PNGs โ†’ spritesheet

Packs multiple PNG files into a single spritesheet. Supports grid, horizontal, vertical, and bin-packed layouts. Optionally generates a JSON / CSS atlas for use in game engines.

Output โ€” two frames packed horizontally
Output: composite spritesheet (2988ร—826)
ParameterTypeDefaultDescription
filesstring[]requiredPNG files
layoutstring"grid""grid" | "horizontal" | "vertical" | "packed"
columnsintegerautoGrid columns
paddinginteger0Pixel gap between frames
metadata_formatstring"none""none" | "json_array" | "json_hash" | "css"
power_of_2booleanfalsePad output to next power of 2
trim_inputbooleanfalseAuto-trim transparent edges before packing
gif_to_frames GIF โ†’ ZIP of PNGs

Extracts each frame from an animated GIF as an individual PNG file, delivered as a ZIP archive. Useful when you need separate frame assets for a game engine.

ParameterTypeDefaultDescription
filestringrequiredGIF file input
remove_bgbooleanfalseRemove background
bg_colorstring"auto""auto" or "#RRGGBB"
toleranceinteger30Background removal threshold 0โ€“255
split_spritesheet Spritesheet โ†’ frames + atlas

Splits a spritesheet PNG into individual frame PNGs (ZIP) and/or a JSON/CSS atlas describing each frame's coordinates. Supports grid mode and cell mode.

ParameterTypeDefaultDescription
filestringrequiredSpritesheet PNG
columnsintegerโ€”Grid columns
rowsintegerโ€”Grid rows
cell_widthintegerโ€”Cell width px (cell mode)
cell_heightintegerโ€”Cell height px (cell mode)
outputstring"frames""frames" | "metadata" | "both"
metadata_formatstringโ€”"json_array" | "json_hash" | "css"
skip_emptybooleantrueRemove fully transparent frames
frames_to_animation PNGs โ†’ GIF / WebP

Composes multiple PNG frames into an animated GIF or WebP. Frames are composited onto a shared canvas โ€” mismatched sizes can be filled, padded with transparency, or rejected.

Output โ€” two spritesheets composited into one animation
Output: frames animation GIF
ParameterTypeDefaultDescription
filesstring[]requiredPNG frames
durationinteger100Frame duration ms
loopinteger0Loop count (0 = infinite)
output_formatstring"gif""gif" | "webp"
resizestring"transparent""error" | "fill" | "transparent"
file_name_orderbooleanfalseSort by _N filename suffix
trim_png Crop transparent edges

Crops transparent (alpha) edges from one or more PNG files. Single file returns a PNG; multiple files return a ZIP. Useful for tightening sprite bounds before packing.

Before โ€” original PNG
Before: PNG with transparent edges
โ†’
After โ€” transparent edges removed
After: trimmed PNG
ParameterTypeDefaultDescription
filesstring[]requiredPNG files (single โ†’ PNG, multiple โ†’ ZIP)
thresholdinteger0Alpha threshold 0โ€“255
paddinginteger0Transparent margin to preserve
server_info Runtime config

Returns the upload endpoint URL, output TTL, file size limits, and base64 encoding rules. No parameters. Call this before working with large files (โ‰ฅ 4 MB) or chained workflows.

File Input Guide

All file / files parameters accept three input types. Choose based on file size.

File < ~185 KB (inline-safe)

Base64-encode and prepend a data URI:

data:image/gif;base64,R0lGODl...

Strip ALL whitespace and newlines from the base64 string. Encoders like openssl base64 insert newlines every 76 chars โ€” these cause INVALID_BASE64.

# Shell (no newlines)
base64 -i file.gif | tr -d '\n'

# Python (no newlines by default)
base64.b64encode(data).decode()

File โ‰ฅ ~185 KB (or any shell-encoded file)

Upload first, then use the returned URL:

curl -X POST https://mcp.clawstudiouo.com/upload \
  -H "Authorization: Bearer <token>" \
  -F "file=@animation.gif"
# โ†’ { "url": "https://..." }

Why ~185 KB and not 4 MB? In Claude Code / Claude Desktop, shell output > ~250 KB is written to a temp file that AI tools cannot read back (256 KB limit). A 185 KB file encodes to ~247 KB base64 โ€” just under the limit. When in doubt, use upload.

Chaining tool outputs

Pass the url from one tool directly as file input to the next โ€” no re-encoding needed. The server reads chained URLs directly from its own storage with no HTTP overhead.

// Example chain: GIF โ†’ spritesheet โ†’ back to animation
const step1 = await gif_to_spritesheet({ file: gifDataUri, columns: 3 });
const step2 = await spritesheet_to_animation({ file: step1.url, columns: 3, rows: 2 });
// step2.url is the final animated GIF
Output TTL: all output URLs expire 1 hour after creation. Do not cache them across sessions. Re-run the originating tool to get a fresh URL.

Tool output format

Every tool returns a JSON object:

{
  "url": "https://mcp.clawstudiouo.com/output/output-abc123.png",
  "expires_at": "2026-05-05T13:00:00.000Z",
  "content_type": "image/png",
  "size_bytes": 516432,
  "quota": { "used": 4, "limit": 100, "reset_at": "2026-06-01T00:00:00.000Z" }
}

The url is also a direct browser-viewable download link.

Working with AI Agents

Tips for getting the best results when using Spritesheet Forge through Claude or another AI client.

Recommended context to give your agent

I've connected Spritesheet Forge MCP. For files โ‰ฅ 4 MB, call server_info
first to get the upload URL, then POST the file there before calling the
processing tool. Output URLs expire in 1 hour.

How the agent discovers this server

  1. On initialize, the server returns an instructions field pointing to the public documentation page.
  2. The agent fetches the docs page to learn about all tools, parameters, and file input rules.
  3. For runtime config (upload URL, exact TTL), the agent calls server_info.

Getting a token for the upload endpoint

MCP clients (Claude Desktop, Claude Code) store their token in an encrypted internal store โ€” there is no config file or keychain entry you can read. Run the one-line helper instead (Python 3, no extra dependencies):

curl -O https://spritesheet-forge.spritesheet-forge.workers.dev/get-token.py && python3 get-token.py
  1. The script downloads, registers an OAuth client, and opens a GitHub login page.
  2. Approve access in the browser.
  3. The token is printed and saved to ~/.spritesheet-forge-token.
  4. Pass it to your agent: "Here is my upload token: Bearer <token>"
If you cannot run the script, ask your agent to accept the file as a public HTTPS URL instead.

Common errors

ErrorCauseFix
INVALID_BASE64Whitespace or newlines in base64 stringStrip with tr -d '\n' or Python's b64encode().decode()
INVALID_FILE_URLOutput URL expired (past 1-hour TTL)Re-run the originating tool
INVALID_CONTENT_TYPENon-PNG/GIF/WebP inputConvert to a supported format first
FILE_TOO_LARGEFile exceeds 20 MBCompress or split before uploading
quota_exceeded100 ops/month usedWait for monthly reset (check quota.reset_at)
Upload 401Missing or expired Bearer tokenRun get-token.py or use public URL

Limits & Quotas

Free tier limits. All limits are per GitHub account.

LimitValue
Max file size20 MB
Recommended base64 limit4 MB (use upload endpoint above this)
Output / upload file TTL1 hour
Free quota100 operations / GitHub account / month
Quota reset1st of each month
Session token lifetime30 days
Supported input formatsPNG, GIF, WebP

Benchmark

End-to-end latency measured from a local machine over the public endpoint (2026-05-05). All 11 tests passing.

PASS gif_to_spritesheet7185 ms
PASS gif_to_frames3548 ms
PASS split_spritesheet (3ร—2, frames + atlas JSON)4772 ms
PASS spritesheet_to_animation (3ร—2 โ†’ animated GIF)3191 ms
PASS trim_png3406 ms
PASS png_to_spritesheet (2-image horizontal)3745 ms
PASS frames_to_animation (2 frames โ†’ GIF)4441 ms
PASS smol.gif 221 KB โ€” direct base642787 ms
PASS smol.gif 221 KB โ€” upload + URL3519 ms
PASS beeg.gif 4.7 MB โ€” direct base6412472 ms
PASS beeg.gif 4.7 MB โ€” upload + URL12624 ms
For files โ‰ฅ 4 MB, latency is nearly identical between base64 and upload+URL. The real reason to use the upload endpoint is payload size: a 4.7 MB GIF encodes to ~6.3 MB JSON, which most MCP clients reject.