API Docs

ChatGPT app (MCP)

Crateyard exposes a Model Context Protocol server at https://crateyard.com/mcp. ChatGPT connects to it so users can see, create, and continue their Crateyard assets from a conversation. Authentication uses OAuth. No OpenAI API key is involved.

The endpoint is off unless the server sets OAUTH_SERVER_ENABLED=true.

Connect in ChatGPT

1. In ChatGPT, open Settings > Security and login and turn on Developer mode.

2. Go to chatgpt.com/plugins, select the plus button, and enter a name (Crateyard) and description.

3. Under Connection, enter https://crateyard.com/mcp and create the connection. ChatGPT reads the tool list.

4. In a new conversation, add Crateyard from the tools menu and ask something like "Show my Crateyard assets". ChatGPT opens the Crateyard consent page. New users can sign up there with an email code or Google.

The website has a short setup walkthrough in Settings, Connected apps, with the configured MCP URL, example prompts, and a disconnect control. The setup URL uses the same issuer as OAuth discovery: OAUTH_ISSUER, then PUBLIC_BASE_URL, SITE_URL, or APP_URL, falling back to the request origin when none is configured. ChatGPT menus and custom-app availability can vary by account or workspace.

The connector starts Asset Studio tasks, not Forge chats. To use OpenAI models directly inside Forge or Studio, connect a provider API key in AI accounts. That provider bills you separately. Alternatively, create an image in ChatGPT and upload it to Studio, which skips image generation here. A ChatGPT subscription does not fund Crateyard image or 3D tasks.

Transport

POST /mcp with a JSON-RPC 2.0 message or batch (up to 20). Responses are JSON (no streaming, no sessions). GET and DELETE return 405. Supported methods: initialize, notifications/initialized, ping, tools/list, tools/call. Supported protocol versions: 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05.

Authentication: Authorization: Bearer cy_at_....

  • initialize, ping, and tools/list work without a token.
  • tools/call without a token returns a tool error with _meta["mcp/www_authenticate"], which makes ChatGPT start account linking.
  • A token that is invalid, expired, revoked, or minted for another resource gets HTTP 401 with WWW-Authenticate: Bearer resource_metadata="https://crateyard.com/.well-known/oauth-protected-resource", error="invalid_token".
  • A token missing a tool's scope gets a tool error whose mcp/www_authenticate has error="insufficient_scope" and scope="...".

Rate limit: 60 requests per minute per connection, or 600 per minute per IP without a token. Over the limit returns 429 with Retry-After.

curl -X POST "https://crateyard.com/mcp" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer cy_at_example" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_assets","arguments":{"stage":"needs-3d","limit":5}}}'
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "isError": false,
    "content": [{ "type": "text", "text": "#12 Forest Knight: Images ready (Step 2 of 4: Refine). Continue: https://crateyard.com/projects/ann/default-project/asset/new-asset-1" }],
    "structuredContent": {
      "assets": [
        {
          "id": 12,
          "name": "Forest Knight",
          "type": "3D Asset",
          "stage": "image",
          "step": "Step 2 of 4: Refine",
          "status": "Images ready",
          "studio_url": "https://crateyard.com/projects/ann/default-project/asset/new-asset-1",
          "next_action": { "label": "Make 3D model", "url": "https://crateyard.com/projects/ann/default-project/asset/new-asset-1" },
          "preview_url": null,
          "updated_at": "2026-10-03T07:00:00.000Z"
        }
      ],
      "my_assets_url": "https://crateyard.com/my-assets"
    }
  }
}

Tools

| Tool | Scope | Spends tokens | Input | Result |

|---|---|---|---|---|

| get_profile | assets:read | No | {} | { id, name?, nickname? }. id is stable. Marked _meta["openai/profile"] |

| list_assets | assets:read | No | query?, stage? (all, in-progress, needs-3d, ready-to-rig, rigged, failed), limit? (1 to 20, default 10) | { assets: [...], my_assets_url } |

| get_asset | assets:read | No | asset_id | asset plus latest_tasks: [{ id, kind, status, created_at, url }] |

| get_task | assets:read | No | task_id | { id, kind, status, asset_id, error, url } |

| create_asset | assets:write | No | name?, asset_type? (3d_asset, pixel_art) | the new asset. Unnamed assets are called New asset {n} |

| rename_asset | assets:write | No | asset_id, name (1 to 180 characters) | { id, name } |

| generate_reference_image | generate | Yes, usually 1 | asset_id, prompt, t_pose? | { task_id, asset_id, task_url } |

| create_3d_model | generate | Yes, 3 or more | asset_id, image_task_id? | { task_id, asset_id, task_url } |

| list_pixel_presets | assets:read | No | category? | { presets: [{ preset_id, name, category, frame_count, columns, fps, directions }], directions } |

| list_pixel_sprites | assets:read | No | asset_id, limit? (1 to 50, default 10) | { asset_id, sprites: [{ file_id, url, grid_w, grid_h, palette, source_file_id, created_at }] } |

| list_pixel_animations | assets:read | No | asset_id, sprite_file_id?, limit? (1 to 50, default 10) | { asset_id, animations: [{ animation_id, status, sprite_file_id, preset_id, preset_name, direction, frame_count, fps, sheet_file_id, sheet_url, created_at }] } |

| get_pixel_animation | assets:read | No | animation_id | { animation }: the fields above plus frames: [{ index, file_id, url }] and error when failed |

| get_image_file | assets:read | No | file_id | { file_id, mime_type, size_bytes, url } plus the image itself as image content. PNG, JPEG, WebP, or GIF up to 2 MB |

| generate_pixel_animation | generate | Yes, 1.2 to 2 (by quality) | asset_id, sprite_file_id, preset_id, direction?, custom_prompt? (up to 1,000 characters), quality? (low, medium, high; default medium) | { animation_id, asset_id, sprite_file_id, preset_id, status, tokens_charged, token_balance } |

| get_game_kit | assets:read | No | project_id | the project's Game Kit: style, assets (role, primary sprite, animations, consistency), counts. URLs are absolute. See Game Kit API |

| set_game_kit_style | assets:write | No | project_id, sprite_size?, outline?, style_notes? (up to 400 characters), palette? (up to 64 [r, g, b] colours, or null), reference_file_ids? (up to 4) | { project_id, style }. Only the fields you pass change. style uses snake_case keys |

| game_kit_palette_from_sprite | assets:write | No | project_id, file_id, max_colors? (2 to 64, default 16) | { project_id, style }. The sprite's palette becomes the kit palette |

| create_kit_asset | assets:write | No | project_id, role (character, enemy, npc, spell, item, tile, prop), name? (up to 80 characters) | { asset_id, name, role, studio_url } |

| set_kit_asset | assets:write | No | asset_id, role?, primary_sprite_file_id? (or null to clear) | { asset_id, role, primary_sprite_file_id } |

Tool arguments use snake_case names. An argument the tool does not list (for example the old camelCase spriteSize) is rejected with a tool error, not ignored. Kit results in structured also use snake_case keys, such as sprite_size, style_notes, and reference_file_ids.

Token-spending tools are annotated destructiveHint: true so ChatGPT asks the user before calling them. Each call starts at most one task, charges the same price as Asset Studio, and refunds automatically if the task cannot be queued. Failed tasks are never retried automatically. create_3d_model uses image_task_id if given, otherwise the asset's newest finished image, otherwise its uploaded concept image.

generate_reference_image uses the Asset Studio default model for users with a plan and a model that needs no plan for everyone else.

The Game Kit tools read and change one project's shared style and roster. Call get_game_kit to see the style and assets before you make or change sprites. The kit is applied by Pixel Studio's sprite and image steps. MCP generation tools such as generate_pixel_animation animate an existing sprite and do not apply the kit. set_game_kit_style changes only the fields you pass, unlike the REST PUT /api/pixel-kit/:projectId/style, which replaces the whole style. Passing palette clears the palette source sprite. Non-members of a project get "Project 12 was not found." with the project id.

Pixel animations

Pixel animation tools reuse the sprites and animations Pixel Studio already saves on an asset. Sprites come from the Sprite step, so they are listed per asset with list_pixel_sprites, and the file_id you get is the reference for generate_pixel_animation. list_pixel_animations includes animations made by project members on that asset.

The flow is: pick a sprite with list_pixel_sprites, pick a preset with list_pixel_presets, call generate_pixel_animation, then poll get_pixel_animation. The start call saves the animation as processing and returns its animation_id. The job then runs once in the background and saves the record as it goes: processing, then finished with frames and sheet_url, or failed with error. A failed job tries to refund its tokens and is never retried. The job runs in the server process, not in the MCP request, so a server restart during a job leaves that animation in processing. Animate costs match the Pixel Studio animate API: 1.2 tokens for low, 1.8 for medium, 2 for high.

Image links such as /asset-creator/file/<id> need a signed-in browser session, so agents cannot open them. To look at a sprite, frame, or sheet, pass its file_id (the frame file_id, or sheet_file_id on an animation) to get_image_file, which returns the image as image content.

Errors

Tool failures return isError: true with a short message, for example:

  • Asset 42 was not found. (missing, or not the user's)
  • name_required: the new name cannot be empty.
  • Not enough tokens. It costs 3 tokens and you have 1. Get more at https://crateyard.com/pricing
  • Asset 42 has no image yet. Generate one with generate_reference_image or upload one in Asset Studio.
  • Sprite 9 was not found on asset 5. Check list_pixel_sprites.
  • Unknown preset walk-x. Check list_pixel_presets.
  • Not enough tokens. This animation costs 1.8 and you have 0. Get more at https://crateyard.com/pricing
  • Could not start the animation: <reason>. Tokens were refunded. (or Tokens were not refunded; check your balance. if the refund failed)

Protocol errors use JSON-RPC codes: -32700 parse error, -32600 invalid request, -32601 unknown method, -32602 unknown tool.