lorcana-mcp
The lorcana-mcp server provides tools for searching, analyzing, and managing Disney Lorcana cards and decks.
Search and filter cards by name, color, type, cost, stats, keywords, text, set, rarity, and more, with pagination, sorting, and an optional TOON-encoded output (≈10% token savings).
Count cards that match any combination of filters.
Aggregate cards by cost (ink curve), rarity, color, set, or type for distribution breakdowns.
Resolve card names using fuzzy matching to find the closest official cards with full data.
Get top traits across all available cards.
Export decks to Dreamborn/Pixelborn-compatible plain text lists.
Import decks from text lists, resolving card names and suggesting candidates for unmatched lines.
Validate decks against format rules (min 60 cards, max 4 copies per card, max 2 ink colors).
Analyze deck statistics including ink curve, color split, inkable counts, type breakdown, keyword/subtype counts, and per-card keyword tags.
Guided deck building via a prompt that assists in assembling a legal deck for chosen colors and playstyles.
Check server status for startup metadata (card count, configuration).
Cards are stored in-memory for fast filtering, with daily data refreshes and local JSON caching.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@lorcana-mcp Show me all legendary amber cards"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Disney Lorcana MCP Server
An MCP server that lets Claude (or any MCP client) search, analyze, and build decks for the Disney Lorcana TCG. Ask for cards in plain English, get rules-checked deck validation, ink curves and keyword breakdowns, and round-trip deck lists with Dreamborn/Pixelborn.
2,506 unique cards (3,192 printings including alternate arts and promos), refreshed daily. No API key, no database, no rate limits — the server ships against a snapshot published from our own pipeline, so it never depends on a third-party API being up at query time.
Tools
Tool | What it does |
| Filter and retrieve cards by name, color, cost, rarity, type, keyword, stats, set, and body text. Supports |
| Count cards matching a filter without paying for the card objects |
| Group counts by |
| Fuzzy-match an informal, partial, or misspelled card name to the closest cards |
| Most common traits (Storyborn, Hero, Villain, Ally, ...) across all cards |
| Check a deck against format rules (≥60 cards, max 4 copies, ≤2 inks, dual-ink requirements); returns |
| Ink curve, color split, inkable count, type breakdown, keyword counts, subtype counts, and per-card keyword tags |
| Parse a Dreamborn/Pixelborn deck list into resolved cards, with fuzzy candidates for unresolved lines |
| Render a deck back out as a Dreamborn/Pixelborn-compatible text list |
| Startup metadata (card count, configuration) |
Related MCP server: lorcana-oracle
Install
uvx (recommended — no clone, no Docker)
uvx lorcana-cards-mcpClaude Desktop / claude_desktop_config.json:
{
"mcpServers": {
"lorcana": {
"command": "uvx",
"args": ["lorcana-cards-mcp"]
}
}
}Claude CLI:
claude mcp add --scope user -- lorcana uvx lorcana-cards-mcppip / pipx
pipx install lorcana-cards-mcp # then run: lorcana-cards-mcpDocker
The server is also published to GHCR and the MCP Registry.
docker run --rm -i ghcr.io/danielenricocahall/lorcana-mcp:latest{
"mcpServers": {
"lorcana": {
"command": "docker",
"args": ["run", "--rm", "-i", "ghcr.io/danielenricocahall/lorcana-mcp:latest"]
}
}
}To persist the card cache across container restarts, mount a volume:
docker run --rm -i \
-e LORCANA_CACHE_PATH=/data/cards.json \
-e LORCANA_SKIP_IF_DB_EXISTS=true \
-v lorcana_mcp_data:/data \
ghcr.io/danielenricocahall/lorcana-mcp:latestFrom a clone
uv run python main.pydocker build -t lorcana-mcp:latest .
docker run --rm -i lorcana-mcp:latest
# or via compose
docker compose build
docker compose run --rm -T lorcana-mcpNo port is exposed; MCP communication is over stdio.
Example questions
Once connected to an MCP client, you can ask natural language questions like:
Card lookup
"Show me all cards named Moana"
"What does the card Maui - Hero to All do?"
"Find all legendary amber cards"
Deck building
"What are the cheapest ruby characters with at least 3 strength?"
"Show me inkable sapphire cards that cost 4 or less"
"Find steel characters with 5 or more willpower"
"What 3-lore characters exist in emerald?"
Keyword & ability search
"How many Singer cards cost exactly 5?"
"How many Evasive characters are there in the first set?"
"How many ruby cards have Reckless?"
"Find all cards with Ward in their text"
"Show me Shift cards in amethyst"
Stats & aggregations
"How many cards are in each set?"
"What's the color distribution across all cards?"
"What are the most common traits?"
"Show me the ink curve — how many cards exist at each cost?"
"How many legendary cards are inkable?"
Cross-filter queries
"How many amber characters have 3 or more lore?"
"Find cheap (cost 2-3) characters with high strength (4+) in steel"
"How many cards in set 1 have Evasive and cost less than 4?"
Note: For plain keyword queries (Evasive, Bodyguard, Shift, etc.) use the
keywordparameter — it filters against the structured ability list and is more reliable than substring search. For value-specific queries likeSinger 5orResist +2, usebody_text(keyword values live in the card's full text, not the ability list).
MCP prompts
build_deck(colors, playstyle="balanced")— guides the model through assembling a legal Lorcana deck (60-card minimum, ≤2 inks, max 4 copies of any card) for the requested color(s) and playstyle (aggressive/control/lore-race/balanced). Uses the search/aggregate tools above plus the rules embedded in the server instructions.
Card data & startup behavior
On startup, the server fetches a JSON list of cards from
https://danielenricocahall.github.io/lorcana-mcp/allCards.json. The snapshot is refreshed daily
by data_pipeline/fetch_cards.py, which pulls from the Lorcast API,
normalizes each card into our internal schema, and publishes the list to the gh-pages branch.
That middle layer insulates running servers from Lorcast's availability and rate limits — the
runtime never calls Lorcast directly.
Cards are kept in memory as a Python list for fast filtering. The dataset holds 2,506 unique
cards, each carrying a printings array for its alternate sets, numbers, and rarities (3,192
printings in total). Consolidating printings onto one row per card means a search for "Elsa"
returns each distinct Elsa once rather than repeating her for every promo reprint. A local JSON
file cache (LORCANA_CACHE_PATH, default cards.json) lets the server skip the network fetch on
subsequent startups.
Config
LORCANA_API(default:https://danielenricocahall.github.io/lorcana-mcp/allCards.json)LORCANA_CACHE_PATH(default:cards.json) — local file for caching fetched cardsLORCANA_HTTP_TIMEOUT_SECONDS(default:60)LORCANA_REFRESH_ON_STARTUP(default:false) —truealways fetches and repopulates storageLORCANA_SKIP_IF_DB_EXISTS(default:true) —falsefetches and repopulates even if the cache is populated
TOON response format
search_cards accepts a response_format argument:
"json"(default) — list of card objects, unchanged from prior versions."toon"— a TOON string with one column header line and one row per card, encoded by thetoonsRust-backed library (the official community reference implementation).
Example (search_cards(name="elsa", limit=2, response_format="toon")):
cards[2]:
- id: crd_01c4835a62df4960bb973aeff81f2bb2
name: Elsa
version: Ice Maker
full_name: Elsa - Ice Maker
cost: 7
...
printings[3]{set_code,set_name,number,rarity}:
"7",Archazia's Island,69,Super Rare
C2,Lorcana Challenge Year 3,2,Promo
C2,Lorcana Challenge Year 3,6,Promo
- id: crd_04bca46a8e2d4e9ba0fbdbfc6c99e51e
name: Elsa
...The outer cards[2]: falls back to YAML-style per-card blocks (rather than a single tabular table) because card shapes vary — Actions and Items don't carry strength/willpower/lore, for example. The inner printings[N]{...}: block is fully tabular since every printing has the same four fields.
Benchmark
Measured with benchmarks/bench_toon.py against the live 2,506-card dataset, tokenizing with
tiktoken cl100k_base (used as a proxy for Claude's tokenizer):
query | rows | JSON tokens | TOON tokens | Δ |
| 200 | 44,101 | 39,680 | −10.0% |
| 50 | 10,522 | 9,519 | −9.5% |
| 50 | 10,154 | 9,250 | −8.9% |
| 50 | 11,602 | 10,391 | −10.4% |
| 14 | 3,488 | 2,940 | −15.7% |
total | 79,867 | 71,780 | −10.1% |
Note: TOON's relative savings are smaller here than they were before the printings consolidation
(pre-PR-#29 the same queries showed ~50% reductions). That gap is structural to the nested
printings array — TOON's columnar encoding wins on the top-level fields but falls back to
JSON-style encoding inside the per-printing entries, so the array dilutes the relative gain.
Absolute token counts are still down meaningfully versus the equivalent count of pre-consolidation
rows, since each unique card is now represented once with a small printings list rather than as
1-3 separate full rows.
Reproduce with PYTHONPATH=. uv run python benchmarks/bench_toon.py (requires a populated
cards.json cache).
Disclaimer
This is a personal, unofficial fan and engineering project. It is not affiliated with, endorsed by, sponsored by, or reviewed by Disney, Ravensburger, or the Disney Lorcana TCG team. It is built and distributed in accordance with Ravensburger's Disney Lorcana TCG Community Code, using only publicly available and community data sources. All Disney Lorcana TCG names, card text, trademarks, and related intellectual property belong to Disney and Ravensburger. This project is non-commercial and reflects my personal views only, not those of my employer.
MCP Registry ownership verification — the registry reads this line from the published package description to confirm this project owns the server name.
mcp-name: io.github.danielenricocahall/lorcana-mcp
Available Tools
10 toolsaggregate_cardsA
Return card counts grouped by a field. Valid fields: cost (ink curve), rarity, color, set_code, type. Examples: aggregate_cards('cost') for the ink curve, aggregate_cards('color') for color breakdown, aggregate_cards('rarity') for rarity breakdown, aggregate_cards('set_code') for set distribution.
Inputs: field (required). Returns: result
count_cardsA
Count cards matching the given filters. Use this for questions like 'how many ruby cards are there?' or 'how many evasive characters?'. Supports stat ranges: min_attack/max_attack, min_defence/max_defence, min_cost/max_cost. Use keyword to filter by Lorcana keyword (Bodyguard, Challenger, Evasive, Reckless, Resist, Rush, Shift, Singer, Sing Together, Support, Vanish, Voiceless, Ward, etc.) — matches against the structured ability list. Use body_text for value-specific keyword queries like 'Singer 5' or 'Resist +2', or for non-keyword phrases like 'gain 2 lore'. Use lore/min_lore/max_lore to filter by lore value. Use card_type to filter by card type: Character, Action, Item, Song, or Location. Use set_code to filter by set number (e.g. '1' for The First Chapter). Use set_name to filter by set name as a case-insensitive substring (e.g. 'Wilds Unknown', 'frozen') — preferred when the user names a set in plain English. Color must be one of: ruby, sapphire, emerald, amber, amethyst, steel.
Inputs: cost, lore, name, color, +16 more. Returns: result
deck_statsA
Compute summary stats for a Lorcana deck: ink curve (copies at each cost), color split (copies per color — dual-ink contributes to BOTH buckets, so the sum may exceed total_cards), inkable/uninkable counts, type breakdown (Character/Action/Item/Song/Location), keyword_counts (copies per keyword — Evasive, Ward, Bodyguard, Shift, Singer, ...), subtype_counts (copies per subtype — Floodborn, Hero, Puppy, ...), and card_keywords (per-card keyword tags, so archetype questions like 'how many Evasive bodies does this run?' are answerable without a follow-up search_cards call). Each entry is {name: str, count: int} where name is the card's full_name. Names that don't resolve are listed under unresolved and excluded from the per-card stats (but still counted in total_cards).
Inputs: deck (required). Returns: object
export_deckA
Render a Lorcana deck as a Dreamborn/Pixelborn-compatible text deck list (<count> <full_name> per line, no sections, no set codes). Each entry is {name: str, count: int} where name is the card's full_name from search_cards (e.g. 'Mickey Mouse - Brave Little Tailor'). Returns plain text suitable for pasting into Dreamborn, Pixelborn, untap.in, or a Limitless tournament submission.
Inputs: deck (required). Returns: result
import_deckA
Parse a Dreamborn/Pixelborn-style deck list (<count> <full_name> per line) into resolved card objects. Each line is matched to a card by exact full_name first; lines that don't match exactly are returned in unresolved with the top fuzzy candidates so the user can disambiguate. Returns {parsed: [{count, card}], unresolved: [{raw, candidates}]}. Blank lines, comments (#, //), totals (Total: 60), and bracketed section headers are silently skipped.
Inputs: text (required). Returns: object
resolve_cardA
Resolve an informal, partial, or misspelled card name to the closest matching cards. Returns full card data (stats, abilities, cost, etc.) for each candidate — no follow-up query needed. Use this as follows:
'Tell me about / get stats for X' → call resolve_card only, use the result directly.
'Find cards that synergize with / work well with X' → resolve_card to get X's traits and abilities, then use those as inputs to search_cards.
'Build a deck with X' → resolve_card to identify X, then search_cards for supporting cards. Never call search_cards first when the user has named a specific card — resolve_card avoids failed searches and retry loops. Example: 'Maui Half Shark' resolves to 'Maui - Half-Shark' as the top result.
Inputs: query (required), limit. Returns: result
search_cardsA
Search Lorcana cards with optional filters. Returns card objects (not counts). Color must be one of: ruby, sapphire, emerald, amber, amethyst, steel. Use card_type to filter by card type: Character, Action, Item, Song, or Location. Use min_attack/max_attack and min_defence/max_defence for stat-based queries (e.g. 'characters with 4+ strength'). Use min_cost/max_cost for cost ranges. Use keyword to filter by Lorcana keyword (Bodyguard, Challenger, Evasive, Reckless, Resist, Rush, Shift, Singer, Sing Together, Support, Vanish, Voiceless, Ward, etc.) — matches against the structured ability list, more reliable than substring search. Use body_text to search card ability text — useful for value-specific keyword queries like 'Singer 5' or 'Resist +2', or for non-keyword phrases like 'gain 2 lore'. Use lore/min_lore/max_lore to filter by lore value. Use sort_by to order results (id, name, cost, strength, willpower, lore, rarity, set_code); use sort_order='asc' or 'desc'. Use set_code to filter by set number (e.g. '1' for The First Chapter). Use set_name to filter by set name as a case-insensitive substring (e.g. 'Wilds Unknown', 'frozen', 'Floodborn') — preferred when the user names a set in plain English so you don't have to look up the code first. Use offset to paginate through results (e.g. offset=20 for the next page). Use count_cards instead if you only need a total count. Set response_format='toon' to receive a TOON-encoded string instead of JSON objects (~10% fewer tokens; the printings array is nested so the savings are smaller than a purely flat schema would yield); default is 'json'.
Inputs: cost, lore, name, color, +21 more. Returns: result
server_statusA
Show startup metadata for this server instance.
Inputs: no named parameters. Returns: object
top_traitsC
Return most common traits.
Inputs: limit. Returns: object
validate_deckA
Validate a Lorcana deck against the format rules: at least 60 cards (no maximum — 60 is just the floor), max 4 copies of any card, max 2 distinct ink colors across the deck. Each entry is {name: str, count: int} where name is the card's full_name (e.g. 'Mickey Mouse - Brave Little Tailor'). Returns {legal: bool, total_cards, inks, violations: [...]}. Violation types: deck_size (under 60 — total below minimum), max_copies (>4 of one card), ink_limit (>2 distinct colors — also catches dual-ink cards adding a forbidden third color), unknown_card (name didn't resolve to a known card). If you have the output of import_deck, build the input as [{name: card.full_name, count: count}] for each parsed entry.
Inputs: deck (required). Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 10 tools
Each tool targets a distinct task: search returns card objects, count returns totals, aggregate returns grouped counts, top_traits returns trait frequencies, resolve_card handles fuzzy name matching, and the deck tools each handle import, export, validation, or stats. No two tools overlap in purpose, and the descriptions make the boundaries clear.
Most tools follow a verb_noun pattern (search_cards, count_cards, aggregate_cards, resolve_card, export_deck, import_deck, validate_deck), but top_traits, server_status, and deck_stats use noun phrases. The mixed convention is still readable but not uniformly predictable.
With 10 tools, the set is well-scoped for a Lorcana card and deck assistant. It covers both card querying (search, count, aggregate, resolve) and deck management (import, export, validate, stats) without unnecessary bloat.
The tool surface provides comprehensive coverage for the domain: card discovery, count/aggregation, fuzzy name resolution, deck import/export, format validation, and detailed deck statistics. Common workflows like 'search for a card -> build a deck -> validate -> analyze stats' are fully supported with no obvious dead ends.
Maintenance
Related MCP Connectors
Market data tools for the MCP ecosystem: server stats, events, search, leaderboards, package trends.
MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.
Remote MCP server for saving, searching, syncing, and managing Teak cards.
Related MCP Servers
- AlicenseAqualityDmaintenanceMagic: The Gathering MCP server with card search, rules lookup, deck analysis, and Commander intelligence1465 npm5MIT
- AlicenseAqualityDmaintenanceDisney Lorcana TCG MCP server -- card search, deck analysis, and franchise browsing powered by LorcanaJSON.7107 npm4MIT
- AlicenseNot gradedqualityDmaintenanceMCP server that searches and retrieves Magic: The Gathering card data from the Scryfall API.75,114 npmMIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that lets AI assistants look up Disney Lorcana TCG events, stores, and tournament data via the Ravensburger Play API.28 npm-