Spritesheet Forge MCP hosted

A remote Model Context Protocol 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.

MCP endpoint: https://mcp.clawstudiouo.com/mcp  |  GitHub: LAXY9887/Game-Dev.-Spritesheet-Forge

Quick Start

Claude Desktop

Add to claude_desktop_config.json:

{
  "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 MCP client will open a GitHub login page. Approve access and the session is stored for 30 days — no further action needed.

Authentication

Uses GitHub OAuth 2.1 with PKCE. MCP clients (Claude Desktop, Claude Code) run the flow automatically.

To get a Bearer token manually (for curl, benchmark scripts, or custom integrations):

curl -O https://mcp.clawstudiouo.com/get-token.py && python3 get-token.py

The script registers an OAuth client, opens your browser for GitHub login, prints the token, and saves it to ~/.spritesheet-forge-token. Requires Python 3 (pre-installed on macOS/Linux).

Token lifetime: 30 days. OAuth discovery: /.well-known/oauth-authorization-server

File Input Rules

Agents: call server_info to get the runtime upload URL, exact TTL, and encoding rules before processing large files.

All file / files parameters accept three input types:

ConditionMethod
File < ~185 KB
(AI agents: inline-safe)
Base64-encode bytes → prepend data:<mime>;base64,
Strip ALL whitespace and newlines from the base64 string before prepending. Many encoders (e.g. openssl base64) insert newlines every 76 chars — these cause INVALID_BASE64.
File ≥ ~185 KB
(or any file encoded via shell)
POST https://mcp.clawstudiouo.com/upload (multipart/form-data, field file, Bearer token required) → use "url" from response.
AI agents: shell output > ~250 KB is stored to a temp file that cannot be read back (256 KB tool limit). This makes base64 impractical for files larger than ~185 KB even when under the 4 MB MCP payload limit. When in doubt, use upload.
Previous tool outputPass the output url directly — server reads from its own storage, no HTTP round-trip.
Output TTL: all output URLs (tools + uploads) expire 1 hour after creation. Do not cache them across sessions. If a URL is stale, re-run the originating tool.

Tool Output Format

Every tool returns a JSON object in content[0].text:

{
  "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" }
}

Pass url directly as file input to the next tool. The output URL is also a direct browser-viewable download link.

Available Tools

server_info — Runtime configuration

Returns upload URL, TTL, file size limits, and encoding rules. Call this first when working with large files or building chained workflows. No parameters required.

gif_to_spritesheet — GIF → spritesheet PNG

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

gif_to_frames — GIF → individual PNGs (ZIP)

ParameterTypeDefaultDescription
filestringrequiredGIF file input
remove_bgbooleanfalseRemove background
bg_colorstring"auto""auto" or "#RRGGBB"
toleranceinteger30Background removal threshold 0–255

spritesheet_to_animation — Spritesheet PNG → animated GIF/WebP

Grid mode: provide columns + rows. Cell mode: provide cell_width + cell_height.

ParameterTypeDefaultDescription
filestringrequiredSpritesheet PNG input
columnsintegerGrid columns
rowsintegerGrid rows
cell_widthintegerCell width px (cell mode)
cell_heightintegerCell height px (cell mode)
frame_countintegerActual frames (for incomplete last row)
paddinginteger0Pixel gap between cells
column_rangestringe.g. "0-5" or "2"
row_rangestringe.g. "0-3"
skip_emptybooleantrueRemove fully transparent frames
trim_top/right/bottom/leftinteger0Per-edge trim offsets
durationinteger100Frame duration in ms
loopinteger0Loop count (0 = infinite)
output_formatstring"gif""gif" | "webp"
qualityinteger80WebP quality 0–100
losslessbooleanfalseWebP lossless mode

frames_to_animation — PNG frames → animated GIF/WebP

ParameterTypeDefaultDescription
filesstring[]requiredPNG frames
durationinteger100Frame duration ms (10–10000)
loopinteger0Loop count (0 = infinite)
file_name_orderbooleanfalseSort by _N filename suffix
resizestring"transparent""error" | "fill" | "transparent"
bg_fill_colorstring"#000000"Fill color when resize=fill
output_formatstring"gif""gif" | "webp"
qualityinteger80WebP quality 0–100
losslessbooleanfalseWebP lossless mode

png_to_spritesheet — Multiple PNGs → spritesheet

ParameterTypeDefaultDescription
filesstring[]requiredPNG files
layoutstring"grid""grid" | "horizontal" | "vertical" | "packed"
columnsintegerautoGrid columns
cell_modestring"auto_max""auto_max" | "auto_uniform" | "fixed"
cell_widthintegerRequired when cell_mode=fixed
cell_heightintegerRequired when cell_mode=fixed
fit_modestring"scale_fit" | "scale_fill" | "error"
alignstring"center" | "top_left"
paddinginteger0Pixel gap between frames
bg_colorstring"transparent""transparent" or "#RRGGBB"
power_of_2booleanfalsePad output to next power of 2
file_name_orderbooleanfalseSort by _N filename suffix
trim_inputbooleanfalseAuto-trim transparent edges before packing
extrudeinteger0Extrude outermost pixels by N px per frame
metadata_formatstring"none""none" | "json_array" | "json_hash" | "css" — required (non-none) for layout=packed

split_spritesheet — Spritesheet → frames + atlas JSON

Grid mode: provide columns + rows. Cell mode: provide cell_width + cell_height.

ParameterTypeDefaultDescription
filestringrequiredSpritesheet PNG input
columnsintegerGrid columns
rowsintegerGrid rows
cell_widthintegerCell width px (cell mode)
cell_heightintegerCell height px (cell mode)
paddinginteger0Pixel gap between cells
frame_countintegerActual frames for incomplete last row
column_rangestringe.g. "0-5" or "2"
row_rangestringe.g. "0-3"
skip_emptybooleantrueRemove fully transparent frames
trim_top/right/bottom/leftinteger0Per-edge trim offsets
outputstring"frames""frames" | "metadata" | "both"
metadata_formatstring"json_array" | "json_hash" | "css"

trim_png — Crop transparent edges

ParameterTypeDefaultDescription
filesstring[]requiredPNG files (single → PNG, multiple → ZIP)
thresholdinteger0Alpha threshold 0–255. Pixels ≤ threshold are trimmed.
paddinginteger0Transparent margin to preserve around content

Agent Workflow Guide

Recommended context to give an 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."

Chaining tool outputs

Pass the url from one tool directly as file input to the next — no re-encoding needed. Example chain:

gif_to_spritesheet → split_spritesheet → frames_to_animation

The server reads chained URLs directly from its own storage with no HTTP overhead.

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:

curl -O https://mcp.clawstudiouo.com/get-token.py && python3 get-token.py

This downloads and runs the OAuth helper script (Python 3, no dependencies). It opens a GitHub login page, then prints and saves the token to ~/.spritesheet-forge-token. Pass the token to the agent: "Here is my upload token: Bearer <token>"

If the user cannot obtain a token, ask them to provide the file as a public HTTPS URL instead.

TTL in long workflows

All output URLs expire 1 hour after creation. If a multi-step workflow spans more than one hour, re-run the step that produced the stale URL rather than retrying with it.

Limits & Quotas

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

Common Errors

INVALID_BASE64

The base64 string contains whitespace or newlines. Strip them before prepending the data URI: base64 -i file.gif | tr -d '\n', or in Python: base64.b64encode(data).decode() (no newlines by default).

INVALID_FILE_URL — File not found or expired

The output URL has passed its 1-hour TTL. Re-run the tool that produced it to get a fresh URL.

INVALID_CONTENT_TYPE

Only PNG, GIF, and WebP are accepted as input. JPEG and other formats are not supported.

FILE_TOO_LARGE

The file exceeds the 20 MB limit. Split or compress the file before uploading.

quota_exceeded

You have used all 100 free operations for this month. Quota resets on the 1st. Check quota.reset_at in any tool response for the exact reset time.

Upload returns 401 Unauthorized

The Bearer token is missing or invalid. Run: curl -O https://mcp.clawstudiouo.com/get-token.py && python3 get-token.py

GitHub — MIT License