Skip to main content

What it is

The LootRush MCP server lets an AI assistant — Claude, Cursor, or any Model Context Protocol client — read your own LootRush data: your account balance, cards, card transactions, card balance (collateral) and its ledger, cashback, spending-limit auto-refills, and your account history. So you can ask your assistant “how much USDC do I have on Base right now?” or “list my card transactions at Amazon last month” without leaving the chat. If your key also carries the mcp:write scope, the assistant can create cards and change them (status, nickname, spending limit and interval). Nothing else is writable — the server moves no funds and changes no account settings.
Every tool reads only your own account. The server works out who you are from your API key, and there is no parameter for pointing a tool at anyone else.
Writing is off unless you asked for it. A read-only key connects and lists the write tools, but every call to one returns “This API key is not authorized to make changes”. Scopes are fixed when a key is created, so to start writing you’ll need a new key with MCP + Write selected — then revoke the old one. Only give mcp:write to a key you trust with your cards.

At a glance

Connecting

You need two things: the endpoint above and your LootRush API key — the same per-user key that authenticates the Withdraw and History APIs. Send it as a Bearer credential on every request.
Treat your API key like a password. Anyone holding it can read your account data — and, if the key carries mcp:write, create and cancel your cards. Keep it out of any config you commit to source control, and rotate it if it leaks.

Claude Code

Claude Desktop / Cursor / other JSON-configured clients

Add LootRush to your client’s MCP server list:
Some MCP clients can’t attach custom headers to a remote server. For those, the server also accepts the key as a query parameter: https://mcp.lootrush.com/mcp?token=YOUR_API_KEY. Prefer the Authorization header where you can — a key in a URL is easier to leak.

Authentication

Generate your API key at Settings → API Key. The same key works across the Withdraw, History, and MCP APIs. The server looks for it in this order:
  1. Authorization: Bearer <api-key> header — preferred.
  2. ?token=<api-key> query parameter — fallback for clients that can’t set headers.
Cookies are not accepted.
Your key also needs the right scopes, chosen when the key is created:
  • mcp — required for every request. Without it, a valid key still gets 403.
  • mcp:write — required by the two write tools, checked per call.
  • mcp_card_reveal — required to reveal a card number and CVV.
If your key has an IP allowlist, requests from other IPs return 403 too. You can review both at Settings → API keys.

Available tools

Tool names are called exactly as written (camelCase).

getAccountBalance

Your total account value in USD — crypto holdings, staked balances, tokenized assets, and available wallet stablecoins, exactly like the portfolio Summary. Also reports your card balance (collateral) as a separate bucket.

getUserCards

Your cards across all issuers, with aggregated balances and a normalized card balance summary. Optionally reveals a single card’s number and CVV — end-to-end encrypted, decrypted only on your client.

getUserCardTransactions

Card transactions across all cards, or a single card.

getCashbackSummary

Your LootRush Rewards cashback — what’s redeemable now, what’s still maturing, and this month’s rate.

getUserCardSummary

A point-in-time snapshot of your cards — per-card balance, status, and limits as of any instant.

getUserCardBalanceMovements

Your card balance (collateral) ledger — each entry’s running balance and previous balance, the statement-style running total transactions don’t carry.

getUserCardBalanceAutomation

Your card spending-limit auto-refill history — each automatic balance top-up (amount, status, retries, on-chain tx hash, when it ran).

getAccountHistory

Your account history — deposits, withdrawals, converts, sends, and card operations — by date window, or one transaction by hash/id.

aggregate

Totals, counts, averages, min, max and medians over your card transactions or account history — computed over the whole filtered set, without paging every row.

createUserCards

Write (mcp:write). Creates one card, or queues a batch of up to 30 and returns a batchId you poll with the same tool.

updateUserCard

Write (mcp:write). Changes one card — status (block, unblock, cancel), nickname, spending limit and interval.

getAccountBalance

Returns the total USD value of your account — everything shown in your portfolio Summary: crypto holdings, staked balances, tokenized assets (stocks/ETFs) plus their profit/loss, and your available wallet stablecoins — with a per token/network breakdown so the balance can be charted, not just totalled. Your card balance (collateral) is reported as a separate bucket and is not included in totalUsdValue. Takes no parameters. All values are human-readable strings. If your balance snapshot is more than 5 minutes old, the tool refreshes it on-chain before responding. (The refresh runs at most once every 5 minutes per account; if it can’t complete, you get the last snapshot.) lastFetchedAt tells you when the returned data was captured.

getUserCards

Returns your cards across all issuers plus aggregated balances. Each card carries its cardId and cardIssuerUserId — pass those to getUserCardTransactions to scope to a single card, or back into this tool (with includeCardSecrets) to reveal that card’s number and CVV. The response also carries cardBalance — your card collateral, shared across all your cards, normalized to { total, pendingDeposit, pendingWithdraw } (the same shape getAccountBalance returns; null if the balances read failed). The raw balances field sits alongside it if you need the full licensed/nonLicensed regulatory split. cashback comes back too — the same summary getCashbackSummary returns, minus monthProgress. If cashback can’t be read you still get your cards, with a cashbackError in place of that section.

Revealing card number & CVV

The server returns only the issuer’s ciphertext — the number and CVV are decrypted on your client, with a key that never leaves it. That makes this an advanced flow: your MCP client has to run a small encryption handshake, which a plain chat client can’t do. Wrap the tool in your own client (Node/Python/Bash) that implements the two steps below. Beyond the base mcp scope, revealing secrets needs the mcp_card_reveal scope on your key, read permission on the card-details feature, and a card you own. The handshake
  1. Fetch the reveal public key with getCardRevealPublicKey. Generate a random AES-128 key locally and RSA-OAEP–wrap it with that key (SHA-1 hash). The base64 of the wrapped key is your sessionId.
  2. Call getUserCards with includeCardSecrets: true, the target cardId / cardIssuerUserId, and your sessionId. The response carries cardSecrets.encryptedPan and cardSecrets.encryptedCvc, each { data, iv } (both base64) — AES-GCM ciphertext, where data is the ciphertext with the 16-byte auth tag appended and iv is the nonce.
  3. Decrypt each locally with the AES key you kept in step 1.
You only need to do step 1 once. The AES key doesn’t have to be ephemeral — generate one, derive the sessionId a single time, and store both. Later reveals just pass the stored sessionId and decrypt with the stored key. Each response ships a fresh iv, so reusing the AES key never reuses a nonce. Keep that key on your side only.
Reveals share one per-account budget: 10 per minute across all your cards, not per card. Beyond that the tool returns a “too many card reveals” error — back off and retry.
A key that can reach this endpoint can read your card numbers, with no extra confirmation step. Keep it in a trusted MCP client only, never commit or sync it, and rotate it right away if it may have leaked. Every reveal is recorded in an audit log (card id and outcome only — never the number, CVV, or your session key).
Don’t hardcode the public key: getCardRevealPublicKey always serves the current one, so LootRush can rotate it without any change on your side. It also returns the wrapping algorithm (RSA-OAEP, SHA-1).
Set the OAEP hash to SHA-1 explicitly — don’t rely on your library’s default. Most crypto libraries (WebCrypto, Python cryptography, and others) default RSA-OAEP to SHA-256, and with that default the issuer cannot unwrap your sessionId. The reveal then fails server-side and cardSecrets comes back null with a cardSecretsError, rather than a clear “wrong hash” message. Always pass the hash explicitly, as the Node example below does (oaepHash: "sha1").

getCardRevealPublicKey (reveal helper)

The helper tool behind step 1. Takes no parameters; fetch it once and cache the result — it changes only when LootRush rotates the key. Node example

getUserCardTransactions

Fetches your card transactions across all issuers, or a single card’s when cardId is given.
Card transactions carry no running balance. For the statement-style running total, use getUserCardBalanceMovements.
A cardId that matches none of your cards does not fail. You get the full cross-card listing instead, with filterMatchedNothing: true and a filterHint explaining why. Check that flag before presenting the result as one card’s transactions — otherwise a mistyped id looks like “this card has no transactions”. aggregate behaves differently and rejects the filter outright.

getCashbackSummary

Your LootRush Rewards cashback across every enrolled card-issuer account. Takes no card ids — enrollment is resolved from your identity server-side.

The four cashback balances

Cashback isn’t a single balance with a pending amount — it has four states, and only one of them is money you can use today: Also returned: currency, expiring (soonest slice about to lapse, or null), accruingByMonth (a release calendar: month, amount, releaseDate), accounts (how many accounts were folded in), and monthProgress — this month’s spend buckets with their band ladder. A meaning object restates each field in one line, so your assistant doesn’t have to guess which bucket is which.
enrolled: false is not “you earned zero”. It means no card-issuer account has cashback active, so the amounts are zero because the programme is off. Check the flag before quoting the number.
If your accounts disagree about currency, the headline amounts stay zero and a byCurrency array carries the real split — amounts in different currencies are never added together.partial: true means at least one account did not answer, so the amounts cover only the ones that did.

getUserCardSummary

A point-in-time snapshot of your cards across all issuers — each card’s balance, status, and limits as of asOf (defaults to now). Handy for “what did my cards look like at the end of last month?”. Returns cardsSnapshot (the per-card rows) plus pagination.
The snapshot covers cards of every status, canceled ones included — read each row’s status if you only want the ones still spendable.

getUserCardBalanceMovements

Your card balance (collateral) ledger. Unlike card transactions, each movement carries a runningBalance and previousBalance — the classic statement running total. The upstream feed is per-issuer, so results are grouped by issuer to keep each running-balance series coherent. Returns balanceMovements: an array of { cardIssuerUserId, movements, pagination } groups, where each movement carries runningBalance and previousBalance.

getUserCardBalanceAutomation

Your card balance-automation history: spending-limit auto-refills. Each entry is one automatic top-up of your card’s spending limit — its amount, status, retry count, on-chain transaction hash, and when it executed. Returns autoRefillHistories (the per-top-up rows) plus pagination.

getAccountHistory

Your account history as report transactions — deposits, withdrawals, converts, sends, and card operations, joined with their source records (amounts human-readable). Newest first. Pass filterByHash or filterByOrderId to fetch a single transaction (this replaces the date window); otherwise you get the window bounded by startDate/endDate, capped by limit.

aggregate

Computes a total over your data without paging every row. getUserCardTransactions and getAccountHistory return rows; this returns the number those rows add up to, across the whole filtered set rather than the page you happened to fetch. You describe the slice — column, grouping, filters — and get back the figure. The response carries byGroup (one entry per group, with its value and row count), plus rowsCovered, totalCount and complete.
Check complete before quoting the number. When it is false the result covers only part of the slice — rowsCovered of totalCount rows — and note suggests how to narrow the query.
Amounts in different currencies come back as separate entries and are never added together. Card money columns are also split by status unless you pin one: a declined transaction is an attempt, not spend, and only settled (and on_hold, still authorising) is money that actually left the account.
Two ways to call it — reuse a listing’s slice, or describe it directly:

Filtering and grouping by merchant

Card networks don’t send a clean merchant name. What arrives is a settlement descriptor — a brand fragment, an acquirer prefix and a per-transaction reference, truncated at 25 characters:
Two rows from the same merchant rarely look alike, so aggregate canonicalises them. groupBy: "merchantName" returns one group per merchant, and each group carries a few of the raw descriptors behind it under samples so you can check the grouping. For the same reason, where/whereNot on merchantName take the brand as a person would say it"facebook", "tiktok" — and match loosely enough to reach the abbreviations the networks send. Don’t pass a descriptor copied off a row: that filters down to the single transaction it came from.
Merchant terms must be 3–64 characters. whereNot works on cardTransactions only — accountHistory rejects it rather than silently ignoring it.

Grouping by card nickname

cardNickname is groupable too, and matched the same loose way. It’s the name you gave the card, not cardName — that one carries the embossed legal name, which is identical on every card of a business account. So if you name cards per campaign or per person (DAVID LORRAN 15), one call totals them:
Unlike merchants, nicknames are grouped verbatim — canonicalising them would merge cards you deliberately named apart.

Reading matched

Every response that used a loose match carries matched — the canonical names each term actually selected, keyed by column and then term:
When a term in where resolves to an empty array, nothing by that name was found — which is a different fact from spending nothing there, and the accompanying note says so. Don’t present that 0 as spend at the merchant; use groupBy: "merchantName" to see which merchants exist.An empty array for a whereNot term is harmless — there was nothing to remove, so the “everything except X” total is still exactly right.

What each source can aggregate

accountHistory has no fiat column to aggregate — that column is stored in different scales depending on the transaction type, so a total over it would add incompatible units. Use the token columns, or aggregate cardTransactions for spend in your account currency.

The datasetId handle

Listing responses carry a datasetId alongside their rows, plus the columns you can aggregate and group by: filterableText names the keys that take free text in where/whereNot, and aggregateFilterHint says how to phrase them. ops lists the operations that source can answer, and appears only where a source supports fewer than all six — treat its absence as “all of them”. The handle stores that call’s filters, never its rows, and expires after 15 minutes. Passing it to aggregate re-runs the same filters with the aggregation applied, so the total covers the same slice you were shown rather than just the page you fetched. A listing sometimes returns no datasetId — one pinned to a single cardId, for example, which the aggregate can’t reproduce. Pass source and filters yourself in that case.

Writing — creating and changing cards

The two tools below are the only ones that change anything, and both need a key carrying the mcp:write scope. Without it the tool returns This API key is not authorized to make changes (missing the mcp:write scope). and nothing is created or changed. You usually don’t pass cardIssuerUserId. Most accounts have a single card-issuer account and it’s filled in for you, so you can leave the parameter out. If your account holds more than one, the tool asks for it and lists the ids you can use. An account with no approved card-issuer account can’t create or change cards yet, and the tool says so.

Write limits

Like every operation, each write tool gets one call per second on its own budget — see Rate limits. createUserCards and updateUserCard don’t compete with each other, or with any read. Card creation carries one more limit that counts cards, not calls: 300 cards per hour. A request that would cross the ceiling is refused whole — no partial batch — and the message tells you how many you’ve used and how many are left. Because it counts cards, a single call for 30 spends 30. A refused request spends nothing, so asking for 30 when only 5 fit doesn’t burn those 5 — ask for 5 and they go through. The refusal is an error tool result rather than an HTTP status, and nothing is created, so it’s safe to retry once the window rolls over.
One kind of error is not safe to retry blind. If a call fails on its way to the card issuer — dropped connection, or a server error from the issuer — the response tells you the outcome is not known: the card may or may not have been created, and a change may or may not have applied. Check with getUserCards before sending it again, because creating a single card carries no idempotency key and retrying a request that actually succeeded leaves you with two cards. A timeout means the same thing.A rejected request is different, and says so: nothing was created, and the message names what to fix — the holder name (a full name, not initials), the spending limit, the interval.
“Card changes through the MCP are temporarily unavailable.” LootRush can pause card writes — for maintenance, an investigation, or unusual activity on one account. Nothing is changed when you see this: the request stops before it is sent, so there’s no half-created card and it’s safe to retry later. Reading keeps working, and so does checking a batch you already queued.

createUserCards

Creates a single card, or queues a batch of up to 30. batchId decides which mode you’re in:
  • batchId omitted — creates. quantity: 1 (the default) returns the card itself; a higher quantity queues the batch and returns a batchId.
  • batchId given — a pure status read of that batch. Nothing is created, and an id that isn’t a valid batch id is an error rather than a fall-through to creating cards.
A batch never blocks. Thirty cards take longer to issue than the request may stay open, so the tool hands back a handle instead of waiting:
Calling it again with that batchId returns the batch’s progress — status, totalCards, cardsCreated, cardsFailed, and cardIds for the cards issued so far.
Retrying a batch does not double it. If a batch is still running with the same recipe and the same size, that batch is returned (with alreadyRunning: true) instead of a second one being queued — so retrying on a dropped connection is safe without an idempotency key.
Bulk creation is a business-account feature. If your account doesn’t have it enabled, a quantity above 1 creates one card rather than the batch. The response says so — created: 1, requested: 30, bulkUnavailable: true, alongside the card. That card is real and already exists, so create the rest one at a time (or ask support to enable bulk creation) rather than re-sending the same request.

updateUserCard

Changes one card per call. Pass cardId plus at least one of status, nickname, spendingLimit, spendingInterval. The response carries updated: true and the card’s state after the change, read back for you:
canceled is permanent. A canceled card can never be used again, and no call brings it back. To stop a card temporarily — usually what “block my card” means — use inactive or locked, both reversible with active.
If the change lands but the read-back fails, the response still says updated: true and adds a note telling you not to retry — the write already happened, and repeating it would apply it twice.

Access & scoping

  • Your account, always. It’s resolved from your API key when you connect, and every tool is scoped to it.
  • Business roles are honored. If you’re a member of a business, a tool that reads a resource runs only when your role grants read permission for that feature, and a tool that changes one only when your role grants write — you are authorized as yourself, not as the account’s owner. Individual accounts and business owners are unrestricted over their own data.
  • Writes are limited to cards. The only changes are creating a card and changing a card. The server moves no funds, opens no withdrawals, and changes no account settings.

Rate limits

One call per second, per operation. Every tool has its own budget, so getUserCards running at its ceiling leaves getAccountHistory and createUserCards untouched. tools/list and the connection handshake have their own budgets too. In practice you can run different tools back to back without throttling, and only repeated calls to the same tool wait a second. createUserCards with a batchId reads a batch back rather than creating anything, but it’s the same operation and draws on the same row — so poll a batch at most once per second. Beyond the limit, the server returns a 429 with JSON-RPC error code -32005, naming the operation you exceeded:
Nothing is created or changed when you hit it, on read or write, so a 429 is always safe to retry after waiting.

Tips for staying under it

  • Ask for a batch, not a loop. createUserCards takes a quantity up to 30 in one call. Thirty separate calls take thirty seconds and hit the limit twenty-nine times; one call takes one.
  • Page with pageSize, not with parallel calls. The listing tools accept up to 100 rows per page.
  • Total instead of paging. aggregate computes a sum, count or average over the whole filtered set in a single call — it exists precisely so you don’t page thousands of rows to add them up.
  • Reading a batch back doesn’t count as a write. createUserCards with a batchId spends the read budget for that tool, so following a batch you just queued never blocks the next creation.

Errors

Errors come back as a standard JSON-RPC 2.0 error envelope. Request bodies are capped at 256 KB.
A missing mcp:write is not an HTTP error. The key is valid for the server, so the request succeeds and the refusal comes back as a normal tool result marked as an error — “This API key is not authorized to make changes”. Check the tool result, not the status code. The same goes for every other rejection a write tool reports: an unknown batchId, a card-issuer account you don’t own, or bulk creation not being enabled.

Support

Happy to help if you get stuck: