Build with metaphor cards

A REST API and an MCP-friendly OpenAPI for AI agents that help users reflect, journal or practice on their own. Draw a card, fetch its watermarked image, respect a license – that is the whole loop.

Pick a path

Three ways agents talk to us. Pick the one that matches what you are building, then jump to the right doc.

Want a chat that draws cards

ChatGPT Custom GPT

Import the AI-safe OpenAPI in Custom GPT builder. The chat can list decks, draw cards, and link a watermarked image into the conversation. It cannot spend your pearls – the AI subset has no invite-code operations.

Action source: openapi.ai.json ›
Have your own backend or script

Direct REST

Make HTTP calls with your mk_live_ key in Authorization: Bearer. The full OpenAPI covers everything, including invite-codes if you also sell decks. One key, two profiles.

Reference: openapi.json ›
Want a model context protocol bridge

MCP server

Hosted at mcp.makcards.online and as a local stdio package @maccards/mcp (via npx or Docker). Same tools, same auth, one codebase. Pick the connection style in the section below.

Connect with API key ›

OAuth: one-click connect from ChatGPT and Claude

If your users start from ChatGPT or Claude, they don’t need to copy an API key. The chat app shows our consent screen, the user clicks Allow, and the chat gets a scoped token. The user can revoke access from their Profile any time.

For end users

From your chat’s “+ Connectors”

In ChatGPT (Apps) or Claude.ai (“+ Connectors”), look for MAC Cards Online in the picker. The first time you pick it, you’ll land on our consent screen with a clear list of what the AI can and cannot do. Approve once, it works in every chat after that.

Coming as soon as OpenAI and Anthropic list us in their catalogs. Until then, use the API key path below.

For developers

Build your own OAuth client

We expose a standard OAuth 2.1 + PKCE Authorization Server. Discover endpoints at /.well-known/oauth-authorization-server on the app host. Scopes are read and draw. PKCE S256 is mandatory.

Three registration paths: pre-registered for verified partners, DCR (RFC 7591) with a moderation queue, and Client ID Metadata Documents.

AS metadata ›
What the token can do

Scoped, brand-bound, rolling refresh

Access tokens live one hour. Refresh tokens live 30 days with rolling rotation: each refresh mints a new refresh, the old one is single-use, reuse triggers chain-wide revoke plus a security event. Tokens are bound to one host (a token minted on app.makcards.online won’t work on mcp.journalingapp.app).

Users see and revoke connected apps in their Profile → Access for AI and integrations → Connected apps.

What you can build today

Reflection chatbot

User describes a situation, the agent draws one card with scope=any, sends back the image and a reflective question. The user does the work – the agent holds the space.

Journaling companion

Daily prompt that pulls three cards (count=3), invites the user to free-write, and stores the spread on their side. Card images expire in 15 minutes; the agent fetches fresh ones each session.

Group facilitation copilot

For workshops and team retrospectives: draw cards from a specific deck (scope=deck), display them on the agent's side, optionally hand a code to participants via /invite-codes/generate.

REST quick-start

Two commands: draw a card, fetch its image. No webhook, no callback, no pre-flight.

KEY=mk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# 1) Draw one card from any accessible deck
curl -X POST https://app.makcards.online/api/v1/public/draw \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"scope":"any","count":1,"image_width":1024}'

# 2) Response carries drawn[0].image_url – fetch it as-is
curl https://app.makcards.online/api/v1/public/decks/.../cards/.../image?w=1024&token=eyJhbGc... \
  -o card.jpg

Full machine-readable reference: openapi.json · AI-safe subset: openapi.ai.json · User guide: docs/en/24-public-api.

Get an API key

  1. 1
    Sign in to the app.

    Open app.makcards.online and sign in (Google or Yandex). One click, no separate account.

  2. 2
    Open Profile → Access for AI and integrations.

    The section sits next to Premium and Achievements. Same place shop partners use.

  3. 3
    Generate the key and copy it.

    The key looks like mk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. It is shown once; the second view never happens. Paste it into a password manager or your secret store.

  4. 4
    Treat the key as a password.

    No public repositories, no support chats, no screenshots. If a key may have leaked, regenerate it – the old one stops working within a minute.

Connect with API key

Same key, seven surfaces. Hosted MCP for fast setup, local stdio to keep the key on your machine, plain Bash for agents that already have a shell. Pick what matches your client.

Add an entry under mcpServers in ~/.claude.json (Claude Code) or ~/Library/Application Support/Claude/claude_desktop_config.json (Desktop).

{
  "mcpServers": {
    "makcards": {
      "type": "http",
      "url": "https://mcp.makcards.online/v1",
      "headers": {
        "Authorization": "Bearer mk_live_xxxxxxxxxxxxxxxxxx"
      }
    }
  }
}

Cursor and Cline share the same MCP config format. The block is identical to Claude's.

{
  "mcpServers": {
    "makcards": {
      "type": "http",
      "url": "https://mcp.makcards.online/v1",
      "headers": {
        "Authorization": "Bearer mk_live_xxxxxxxxxxxxxxxxxx"
      }
    }
  }
}

Two options. MCP node (available in recent n8n builds) – point at https://mcp.makcards.online/v1, set the Authorization header in credentials. HTTP Request node – call REST directly:

URL:      https://app.makcards.online/api/v1/public/draw
Method:   POST
Headers:  Authorization: Bearer mk_live_xxxxxxxxxxxxxxxxxx
          Content-Type: application/json
Body:     { "scope": "any", "count": 1, "image_width": 1024 }

Custom GPT Actions reads OpenAPI. Use the AI-safe subset so the chat cannot accidentally spend pearls.

Action source: https://makcards.online/api/v1/public/openapi.ai.json
Authentication: API Key (Bearer)
Auth value:     mk_live_xxxxxxxxxxxxxxxxxx

Local stdio MCP. The key never leaves your machine – it goes straight to our REST API as Bearer. Requires Node.js 20+.

{
  "mcpServers": {
    "makcards": {
      "command": "npx",
      "args": ["-y", "@maccards/mcp"],
      "env": {
        "MAKCARDS_API_KEY": "mk_live_xxxxxxxxxxxxxxxxxx"
      }
    }
  }
}

No Node.js? Run the same binary as a container. The image is published only for linux/amd64, so Apple Silicon needs one extra flag (see below). If you have Node 20+, the npx tab above is simpler.

linux/amd64 hosts (Intel Mac, Intel/AMD Linux, Windows WSL2):

{
  "mcpServers": {
    "makcards": {
      "command": "docker",
      "args": [
        "run", "--rm", "-i",
        "-e", "MAKCARDS_API_KEY",
        "ghcr.io/makcards/mcp:latest",
        "node", "dist/transports/stdio.js"
      ],
      "env": {
        "MAKCARDS_API_KEY": "mk_live_xxxxxxxxxxxxxxxxxx"
      }
    }
  }
}

Apple Silicon (M1 / M2 / M3 / M4): add --platform linux/amd64 so Docker pulls the amd64 image and runs it through Rosetta. Works, but startup is slower than the native npx option above.

{
  "mcpServers": {
    "makcards": {
      "command": "docker",
      "args": [
        "run", "--rm", "-i",
        "--platform", "linux/amd64",
        "-e", "MAKCARDS_API_KEY",
        "ghcr.io/makcards/mcp:latest",
        "node", "dist/transports/stdio.js"
      ],
      "env": {
        "MAKCARDS_API_KEY": "mk_live_xxxxxxxxxxxxxxxxxx"
      }
    }
  }
}

If your agent already runs in a shell (Claude Code, Cursor agent mode, Aider, Codex, any container), this is the shortest path: plain HTTPS + Bearer, JSON responses, no MCP runtime to install. The four recipes below cover everything our MCP tools wrap.

# One-time setup
export MAKCARDS_API_KEY=mk_live_xxxxxxxxxxxxxxxxxx
BASE=https://app.makcards.online/api/v1/public
H="Authorization: Bearer $MAKCARDS_API_KEY"

# List decks your key can read
curl -s -H "$H" "$BASE/decks" | jq

# Draw 3 cards from any accessible deck
curl -s -X POST "$BASE/draw" -H "$H" -H "Content-Type: application/json" \
  -d '{"scope":"any","count":3,"image_width":1024}' | jq

# Save the first card image straight to disk
curl -s -X POST "$BASE/draw" -H "$H" -H "Content-Type: application/json" \
  -d '{"scope":"any","count":1,"image_width":1024}' \
  | jq -r '.drawn[0].image_url' \
  | xargs curl -s -o card.jpg

# Inspect rate-limit state
curl -s -H "$H" "$BASE/usage" | jq

Two reasons to prefer Bash over MCP: smaller agent context (no tool schemas to load) and one fewer process to manage. Reasons to prefer MCP instead: your client has no shell (ChatGPT Apps, Claude Desktop, Cursor without agent mode), or you want slash-command prompts.

Hosted, local, or shell? Hosted MCP (mcp.makcards.online) is the fastest path and works behind corporate proxies. Local stdio is the choice when your security policy says «no third-party MCP services»: your AI client talks to a local process, which talks to our REST API with your key. Bash skips the MCP layer entirely and only fits agents that can already shell out. Same tools, same data.

Rate limits

Per-account, per-window. POST /draw is batch-accounted: count=5 consumes 5 units.

Window Free Premium
Draws per minute10120
Draws per hour702 000
Draws per day17010 000
/decks per minute10120
Image fetches per minute20240

Live state at GET /api/v1/public/usage. Headers on every response: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset (RFC 9331).

Open Premium with pearls

Privacy and safety

Watermark stays on

Every card image carries a domain watermark at 6% opacity. Removing it violates the terms. The API never exposes the unmarked original.

Untrusted content

Deck and card text are user-generated. Treat them as untrusted input – never let a name or description override your system prompt.

Not a medical service

МАК cards are a reflection tool. Your agent must not present a drawn card as a diagnosis, prediction or treatment. Include crisis-line links if users may be in distress.

Details: Terms of Service · Privacy Policy.

FAQ

Common questions from integrators.

Why two OpenAPI documents?
ChatGPT Custom GPT Builder surfaces every operation to the end user during action setup. The full spec contains POST /invite-codes/generate, which spends pearls. If a user authorized a chat to call that operation by accident, you would pay. The AI-safe subset removes the invite-code surface entirely — there is no code path for the chat to spend pearls.
Can I get an image without watermark?
No. This is a deliberate IP-protection stance. The API serves only watermarked JPEGs at 512 or 1024 pixels. The original lives inside the playable board.
What is scope=any?
Sample uniformly across the cards the caller can read: owned, approved-public and grant-acquired decks. The sampling is per-card, not per-deck, so big decks contribute proportionally.
Do you log my chat?
No. We log API calls — request id, account id, endpoint, status, latency, IP, user-agent. The conversation between the user and the AI does not flow through our servers unless the agent itself sends it.
How fresh is the OpenAPI spec?
It ships with the binary via go:embed. Each API release rebuilds the spec endpoints. There is no separate manifest to forget to publish.
Do I need MCP if my agent already has shell access?
No. If your agent can run curl and parse JSON, the REST API is the simpler path. MCP exists for sandboxed clients (ChatGPT Apps, Claude Desktop, Cursor) that cannot shell out. Hosted MCP and local stdio are thin wrappers over the same REST endpoints, so you are not missing functionality. See the Bash / agent shell tab for ready-made curl recipes.