Read your MTG Arena collection straight from the running game and export it as CSV/JSON with full card metadata.
It is built from the standalone pieces of the open-source MTG Arena Tool ecosystem — no Electron app required:
- mtga-reader (GPL-3.0, on npm) — reads the collection from the live game process via
readCollection('MTGA'). - mtgatool metadata — card names, sets, rarities, colors, and format legality. arena-vault downloads the latest JSON database from
mtgatool.com/api/databaseand indexes it in memory, or reuses the MTG Arena Tool app's local sqlite — whichever it finds first. - Arena's own raw card database (
~/Library/Application Support/com.wizards.mtga/Downloads/Raw/) — fallback for brand-new sets the metadata database has not caught up with yet. This is what fixed the Reality Fracture "missing IDs" problem.
- Node.js 24+ (
node:sqliteships as a release-candidate module; developed and tested on Node 26) - MTG Arena installed
- On macOS, memory reading requires root — see below
npm install# Check which metadata database is in use (and whether a newer one exists)
npm run db
# Download the latest metadata database into data/
npm run db -- --download
# Export your collection — MTG Arena must be running
sudo env PATH="$PATH" npm run export
# Offline rerun from a saved snapshot
npm run export -- --from-snapshot data/snapshots/collection-<timestamp>.jsonExtra flags: --out-dir DIR, --tool-db FILE, --overwrite.
Outputs land in exports/:
mtga-owned-cards.csv— Excel-friendly (semicolon-delimited, UTF-8 BOM)mtga-owned-cards.json—cards: [{ arena_id, quantity, name, set_code, collector_number, rarity, cmc, ... }]
Every live export also saves the raw snapshot to data/snapshots/, so you can re-run or debug offline.
- Everything flows through Effect 4 — services are
Context.Services (MtgaReader,MetadataDatabase), errors areSchema.TaggedErrors, and all I/O (fs, fetch, sqlite, game memory) is Effect-wrapped with typed errors. - Schema-validated decoding — the memory read, saved snapshots, the mtgatool JSON database, and sqlite rows are all decoded through Effect
Schemaclasses before use; no unvalidatedanycrosses a module boundary. - Maximum TypeScript strictness —
strict,noUncheckedIndexedAccess,exactOptionalPropertyTypes,noUnusedLocals,noUnusedParameters,noImplicitReturns,noFallthroughCasesInSwitch,verbatimModuleSyntax,isolatedModules,skipLibCheck: false. - No package-lock.json —
.npmrcsetspackage-lock=false; dependencies resolve frompackage.json.
mtga-readerreads{ cards: [{ grpId, qty }] }from the running game's memory — untrusted input, decoded through theCardCountschema before anything else touches it.- Those IDs are joined against the metadata database (the downloaded JSON or a local sqlite); every row is Schema-decoded into a normalized
CardMetadata. - IDs the metadata database does not know yet (new sets) fall back to Arena's own raw card database on disk, including a numeric-rarity → label mapping derived from shared printings.
- CSV and JSON are written, then re-read and validated against the raw snapshot (row counts, per-card counts, names).
- node:sqlite is release-candidate stability even in current Node — if a Node update ever breaks it, pin the version you know works (26.x is what this project is tested on).
- macOS root: reading another process's memory needs
task_for_pid, which requires root (or a debugger entitlement). Hencesudo env PATH="$PATH" npm run export. - New sets: the mtgatool metadata database can lag a set by ~a day; the raw-database fallback covers that gap automatically.
- Legality/bans: the metadata sqlite contains format legality bitmasks (
legal_0…legal_5withformats.word/formats.mask), but ban lists change — check the official B&R page before building decks.
GPL-3.0-only, matching mtga-reader, which this project depends on. Metadata from mtgatool.com is free to use with credit to Manuel Etchegaray / MTG Arena Tool.