API/MCP Server

MCP Server

Use FatThumb from any MCP-compatible AI client (Claude Desktop, Cursor, agents).

FatThumb exposes a Streamable-HTTP MCP endpoint at POST /api/mcp so you can call generate_thumbnail from any MCP-compatible client — Claude Desktop, Cursor, n8n agents, or a custom automation script.

Transport

The endpoint implements the MCP Streamable-HTTP transport in stateless mode: each POST /api/mcp is a self-contained JSON-RPC 2.0 request/response pair. There is no long-lived SSE socket; each call is independent.

The server exposes one tool: generate_thumbnail. It fires immediately and returns a generationId. Poll GET /api/v1/generations/:id for the finished thumbnail URLs (same async model as the REST API).

Authentication

MethodAuth required
initializeNo
tools/listNo
tools/callYes — Authorization: Bearer nsk_… or x-api-key: nsk_…

The same API key that authorises the REST endpoints (POST /api/v1/generate) also authorises MCP tools/call. Create a key at:

/orgs/{orgSlug}/settings/api-keys

Wire it into Claude Desktop

Claude Desktop config files only launch local (stdio) servers, so connect to the remote endpoint through the mcp-remote bridge. Add the following to your claude_desktop_config.json:

{
  "mcpServers": {
    "fatthumb": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://fatthumb.klaas.pro/api/mcp",
        "--header",
        "Authorization: Bearer nsk_YOUR_KEY"
      ]
    }
  }
}

Restart Claude Desktop. The generate_thumbnail tool will appear in the tool picker.

Wire it into Cursor

Cursor supports remote HTTP servers natively. In .cursor/mcp.json (or Settings → MCP → Add new server):

{
  "mcpServers": {
    "fatthumb": {
      "url": "https://fatthumb.klaas.pro/api/mcp",
      "headers": {
        "Authorization": "Bearer nsk_YOUR_KEY"
      }
    }
  }
}

The generate_thumbnail tool

Input schema

ArgumentTypeRequiredDefaultDescription
promptstringYesNatural-language thumbnail description.
modelstringNogemini-3-pro"gemini-3-pro" or "gpt-image-2".
countnumberNo1Variations (1–4).
personIdsstring[]No[]Person profile IDs for face consistency.
inspirationIdsstring[]No[]Inspiration IDs for style reference.
aspectRatiostringNo"16:9"Output ratio. YouTube standard is "16:9".

Output

The tool returns a single text/content block with a JSON object:

{
  "generationId": "jd7abc1234",
  "thumbnailIds": ["th_aaa111"],
  "status": "processing",
  "pollUrl": "/api/v1/generations/jd7abc1234",
  "note": "Poll GET /api/v1/generations/:id until status is 'succeeded' or 'failed' to retrieve the thumbnail URLs."
}

After receiving the generationId, poll GET /api/v1/generations/:id (see the Get Generation Status page) until status is "succeeded" or "failed".

Raw JSON-RPC examples

initialize

curl -X POST https://fatthumb.klaas.pro/api/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2024-11-05",
      "clientInfo": { "name": "my-client", "version": "1.0" }
    }
  }'

Expected response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "serverInfo": { "name": "fatthumb", "version": "1.0.0" },
    "capabilities": { "tools": {} }
  }
}

tools/list

curl -X POST https://fatthumb.klaas.pro/api/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

Expected response:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "generate_thumbnail",
        "description": "Generate a YouTube thumbnail using FatThumb AI...",
        "inputSchema": { "type": "object", "properties": { "prompt": {...}, ... } }
      }
    ]
  }
}

tools/call (with bad key)

curl -X POST https://fatthumb.klaas.pro/api/mcp \
  -H "Authorization: Bearer bad_key" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": { "name": "generate_thumbnail", "arguments": { "prompt": "test" } }
  }'

Expected response (401 equivalent in JSON-RPC):

{
  "jsonrpc": "2.0",
  "id": 3,
  "error": {
    "code": -32001,
    "message": "Invalid API key"
  }
}

Error codes

JSON-RPC codeMeaningHTTP equivalent
-32700Parse error — invalid JSON body400
-32600Invalid request — malformed JSON-RPC envelope400
-32601Method not found404
-32602Invalid params — missing required argument422
-32001Auth error — missing or invalid API key401
-32002Rate limit exceeded429
-32003Payment required — insufficient credits or plan402
-32004Content rejected — prompt policy violation422
-32000Internal server error500

Rate limits

The same two-layer rate limit as the REST API applies to tools/call:

LayerScopeLimit
A (Better-Auth)Per API key1 000 requests / hour
B (generation window)Per API key10 requests / 60 seconds

initialize and tools/list are unauthenticated and not rate-limited.

Get Generation Status APIAuth Components