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
Add to claude_desktop_config.json:
{
"mcpServers": {
"spritesheet-forge": {
"type": "http",
"url": "https://mcp.clawstudiouo.com/mcp"
}
}
}
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.
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
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:
| Condition | Method |
|---|---|
| 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 output | Pass the output url directly — server reads from its own storage, no HTTP round-trip. |
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.
server_info — Runtime configurationReturns 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| Parameter | Type | Default | Description |
|---|---|---|---|
file | string | required | GIF file input |
columns | integer | auto | Grid columns |
padding | integer | 0 | Pixel gap between frames |
remove_bg | boolean | false | Remove background from each frame |
bg_color | string | "auto" | "auto" or "#RRGGBB" |
tolerance | integer | 30 | Background removal threshold 0–255 |
gif_to_frames — GIF → individual PNGs (ZIP)| Parameter | Type | Default | Description |
|---|---|---|---|
file | string | required | GIF file input |
remove_bg | boolean | false | Remove background |
bg_color | string | "auto" | "auto" or "#RRGGBB" |
tolerance | integer | 30 | Background removal threshold 0–255 |
spritesheet_to_animation — Spritesheet PNG → animated GIF/WebPGrid mode: provide columns + rows. Cell mode: provide cell_width + cell_height.
| Parameter | Type | Default | Description |
|---|---|---|---|
file | string | required | Spritesheet PNG input |
columns | integer | — | Grid columns |
rows | integer | — | Grid rows |
cell_width | integer | — | Cell width px (cell mode) |
cell_height | integer | — | Cell height px (cell mode) |
frame_count | integer | — | Actual frames (for incomplete last row) |
padding | integer | 0 | Pixel gap between cells |
column_range | string | — | e.g. "0-5" or "2" |
row_range | string | — | e.g. "0-3" |
skip_empty | boolean | true | Remove fully transparent frames |
trim_top/right/bottom/left | integer | 0 | Per-edge trim offsets |
duration | integer | 100 | Frame duration in ms |
loop | integer | 0 | Loop count (0 = infinite) |
output_format | string | "gif" | "gif" | "webp" |
quality | integer | 80 | WebP quality 0–100 |
lossless | boolean | false | WebP lossless mode |
frames_to_animation — PNG frames → animated GIF/WebP| Parameter | Type | Default | Description |
|---|---|---|---|
files | string[] | required | PNG frames |
duration | integer | 100 | Frame duration ms (10–10000) |
loop | integer | 0 | Loop count (0 = infinite) |
file_name_order | boolean | false | Sort by _N filename suffix |
resize | string | "transparent" | "error" | "fill" | "transparent" |
bg_fill_color | string | "#000000" | Fill color when resize=fill |
output_format | string | "gif" | "gif" | "webp" |
quality | integer | 80 | WebP quality 0–100 |
lossless | boolean | false | WebP lossless mode |
png_to_spritesheet — Multiple PNGs → spritesheet| Parameter | Type | Default | Description |
|---|---|---|---|
files | string[] | required | PNG files |
layout | string | "grid" | "grid" | "horizontal" | "vertical" | "packed" |
columns | integer | auto | Grid columns |
cell_mode | string | "auto_max" | "auto_max" | "auto_uniform" | "fixed" |
cell_width | integer | — | Required when cell_mode=fixed |
cell_height | integer | — | Required when cell_mode=fixed |
fit_mode | string | — | "scale_fit" | "scale_fill" | "error" |
align | string | — | "center" | "top_left" |
padding | integer | 0 | Pixel gap between frames |
bg_color | string | "transparent" | "transparent" or "#RRGGBB" |
power_of_2 | boolean | false | Pad output to next power of 2 |
file_name_order | boolean | false | Sort by _N filename suffix |
trim_input | boolean | false | Auto-trim transparent edges before packing |
extrude | integer | 0 | Extrude outermost pixels by N px per frame |
metadata_format | string | "none" | "none" | "json_array" | "json_hash" | "css" — required (non-none) for layout=packed |
split_spritesheet — Spritesheet → frames + atlas JSONGrid mode: provide columns + rows. Cell mode: provide cell_width + cell_height.
| Parameter | Type | Default | Description |
|---|---|---|---|
file | string | required | Spritesheet PNG input |
columns | integer | — | Grid columns |
rows | integer | — | Grid rows |
cell_width | integer | — | Cell width px (cell mode) |
cell_height | integer | — | Cell height px (cell mode) |
padding | integer | 0 | Pixel gap between cells |
frame_count | integer | — | Actual frames for incomplete last row |
column_range | string | — | e.g. "0-5" or "2" |
row_range | string | — | e.g. "0-3" |
skip_empty | boolean | true | Remove fully transparent frames |
trim_top/right/bottom/left | integer | 0 | Per-edge trim offsets |
output | string | "frames" | "frames" | "metadata" | "both" |
metadata_format | string | — | "json_array" | "json_hash" | "css" |
trim_png — Crop transparent edges| Parameter | Type | Default | Description |
|---|---|---|---|
files | string[] | required | PNG files (single → PNG, multiple → ZIP) |
threshold | integer | 0 | Alpha threshold 0–255. Pixels ≤ threshold are trimmed. |
padding | integer | 0 | Transparent margin to preserve around content |
server_info first to get the upload URL, then POST the file there before calling the processing tool. Output URLs expire in 1 hour."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.
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.
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.
| Limit | Value |
|---|---|
| Max file size | 20 MB |
| Recommended base64 limit | 4 MB (use upload endpoint above this) |
| Output / upload file TTL | 1 hour |
| Free quota | 100 operations / GitHub account / month |
| Quota reset | 1st of each month |
| Session token lifetime | 30 days |
| Supported input formats | PNG, GIF, WebP |
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).
The output URL has passed its 1-hour TTL. Re-run the tool that produced it to get a fresh URL.
Only PNG, GIF, and WebP are accepted as input. JPEG and other formats are not supported.
The file exceeds the 20 MB limit. Split or compress the file before uploading.
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.
The Bearer token is missing or invalid. Run: curl -O https://mcp.clawstudiouo.com/get-token.py && python3 get-token.py
GitHub — MIT License