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.
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 ›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.
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.
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.
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.
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 ›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
Sign in to the app.
Open app.makcards.online and sign in (Google or Yandex). One click, no separate account.
-
2
Open Profile → Access for AI and integrations.
The section sits next to Premium and Achievements. Same place shop partners use.
-
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
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 minute | 10 | 120 |
| Draws per hour | 70 | 2 000 |
| Draws per day | 170 | 10 000 |
/decks per minute | 10 | 120 |
| Image fetches per minute | 20 | 240 |
Live state at GET /api/v1/public/usage. Headers on every response: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset (RFC 9331).
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?
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?
What is scope=any?
Do you log my chat?
How fresh is the OpenAPI spec?
Do I need MCP if my agent already has shell access?
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.