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 themcp:write scope, the assistant can create
cards, change them (status, nickname, spending limit and interval) and
organize them into card groups — create, rename and delete groups, move
cards between them, and lock or unlock every card in a group at once. 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.
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.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:Authorization: Bearer <api-key>header — preferred.?token=<api-key>query parameter — fallback for clients that can’t set headers.
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.updateUserCards
Write (
mcp:write). Applies the same status, spending limit or interval
to up to 25 cards in one call.getCardGroups
Your card groups — card count, locked cards, total spending limit and 30-day
spend.
getCardGroupJobs
Progress of a group lock, unlock or cancel running in the background — cards
changed so far, and which ones failed.
getCardSpendReport
Card spend over a date range, broken down by group, by card and by who created
each card.
createCardGroup
Write (
mcp:write). Creates a card group.updateCardGroup
Write (
mcp:write). Renames a group or changes its description.moveCardToGroup
Write (
mcp:write). Puts a card into a group, moves it to another one,
or takes it out of its group.moveCardsToGroup
Write (
mcp:write). Moves up to 25 cards into the same group — or out of
their groups — in one call.setCardGroupCardsStatus
Write (
mcp:write). Locks or unlocks every card in a group at once.deleteCardGroup
Write (
mcp:write). Deletes a group — keeping its cards, or cancelling
them for good.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 intotalUsdValue. 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 itscardId 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.
Each card also carries groupId and groupName — the card group it belongs to,
or null when it isn’t in one.
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 basemcp 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
- 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 yoursessionId. - Call
getUserCardswithincludeCardSecrets: true, the targetcardId/cardIssuerUserId, and yoursessionId. The response carriescardSecrets.encryptedPanandcardSecrets.encryptedCvc, each{ data, iv }(both base64) — AES-GCM ciphertext, wheredatais the ciphertext with the 16-byte auth tag appended andivis the nonce. - Decrypt each locally with the AES key you kept in step 1.
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).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 whencardId is given.
Card transactions carry no running balance. For the statement-style running
total, use
getUserCardBalanceMovements.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.
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 ofasOf (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 arunningBalance 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. PassfilterByHash 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.
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.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: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.
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:
Grouping by card group
groupName works the same way as cardNickname: grouped verbatim, matched
loosely in where/whereNot. Spend on cards that aren’t in any group lands in
its own (no group) entry.
groupId in filters, or list it with
getUserCardTransactions and reuse the datasetId.
A card is counted under the group it is in now. Moving a card to another
group moves its past spend with it.
The card group in these calls is unrelated to
groupBy and byGroup, which
are the aggregate’s own breakdown of the result.Reading matched
Every response that used a loose match carries matched — the canonical names
each term actually selected, keyed by column and then term:
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 card tools below and the card group write tools are the only ones that change anything, and all of them need a key carrying themcp: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.
Locking, unlocking or cancelling a whole card group is one call, however many
cards the group holds.
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.
createUserCards
Creates a single card, or queues a batch of up to 30.batchId decides which
mode you’re in:
batchIdomitted — creates.quantity: 1(the default) returns the card itself; a higherquantityqueues the batch and returns abatchId.batchIdgiven — 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:
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.updateUserCard
Changes one card per call. PasscardId 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:
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.updateUserCards
Applies the same change to up to 25 cards in one call. Use it instead of callingupdateUserCard once per card. Pass cardIds plus at least one of
status, spendingLimit, spendingInterval.
Canceling and nicknames are not available here: cancel a card with
updateUserCard, one card at a time.
Each card gets its own result, in the order you sent them:
updated— the change was applied.failed— that card was not changed.NOT_FOUNDmeans the card does not exist on that card account or is outside the groups you can manage.failedwithUNCERTAIN— the card may or may not have changed. Check it withgetUserCardsbefore sending it again.notAttempted— the call ran out of time before reaching that card. It was not changed; send it again in a new call.
Card groups
Card groups organize cards — per team, per campaign, per client. Every card belongs to at most one group, and a group belongs to one card-issuer account, so a card can only join a group on the same account. Reading groups needs only themcp scope. Every change needs mcp:write, like
the card writes above.
getCardGroups
Lists your card groups across every card-issuer account.
Each group in
cardGroups carries:
cardLimit and spend30Days are decimal strings, so the amounts arrive
exactly. If the spend can’t be read — or your role can’t read card transaction
history — you still get the groups, with spend30Days: null and a spendError
explaining why.
getCardGroupJobs
Locking, unlocking or cancelling a group’s cards runs in the background, a page of cards at a time. Those calls return ajobId right away; this tool tells you how
far it got.
A run reads like this:
statusisPENDING,RUNNING,COMPLETEDorFAILED.eligibleTotalis how many cards the run set out to change, known once its first page has run (nulluntil then).updatedCardscounts those already changed.failedCardslists the cards that couldn’t be changed and why — the first 200;failedCountis the full number.- A listing searches the account’s 100 most recent runs. When it reaches that,
the answer carries
listingCapped: true— filter bystatusesto reach older runs in those states.
Right after starting a run,
getCardGroupJobs can take a few seconds to find it.
A “not found” at that moment isn’t final — wait a moment and ask again.getCardSpendReport
Settled card spend over a date range, with the breakdowns a spend review needs: which group spent the most, which cards, and who created them. Needs your role’s read permission for card transaction history.
The answer carries:
Amounts are decimal strings. A canceled card still counts toward the spend
it made; its
name may come back null. On a very large account the report may
come back with incomplete: true: totalSpend is still exact, but card counts
and some card names are not — pass cardIssuerUserId to report one account at a
time.
The report covers the whole account, so a role limited to specific card groups
can’t run it. Use
aggregate with groupBy: "groupName" for the
groups you can see.createCardGroup
Returns the new group as
cardGroup. Add cards to it with
moveCardToGroup, or create them inside it with
createUserCards and groupId.
updateCardGroup
PassgroupId plus name, description or both. Anything you leave out stays
as it is.
Returns the group after the change as
cardGroup.
moveCardToGroup
Moves one card per call.groupId is required even when you are removing a card: send null explicitly.
Returns the card after the move as card.
moveCardsToGroup
Moves up to 25 cards into the same group in one call — or takes them all out of their groups. Use it instead of callingmoveCardToGroup once per card.
The response lists every card as
moved (with the card after the move),
failed (with a code) or notAttempted, the same way as
updateUserCards. A card on a different card account than
the group fails with NOT_FOUND. Send again only the cards that were not moved.
setCardGroupCardsStatus
Locks or unlocks every card in a group.
Both are reversible. Canceled cards stay canceled. The call returns as soon as the
run has started:
getCardGroupJobs. Asking again while that run
is still going returns the same run rather than starting a second one. A group
can run only one kind of change at a time, so an unlock sent while a lock is still
running is refused — wait for the lock to finish.
To stop a single card, use
updateUserCard instead.deleteCardGroup
It works two very different ways:
cancelCardsomitted orfalse— the group is deleted right away. Its cards keep working; they’re just no longer in a group. The response is{ "deleted": true, "detachedCards": 4 }.cancelCards: true— every card in the group is cancelled in the background, and the group is deleted once none is left. The response is{ "deleted": false, "cancelRunQueued": true, "job": { … } }— follow thejobwithgetCardGroupJobs. If any card can’t be cancelled, the run ends asFAILED, lists those cards, and the group is kept.
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.
- Roles limited to some card groups see only those. If your role covers specific groups, every tool answers for those groups’ cards alone — listings, transactions, group runs and totals. A group or card outside them reads as “not found”. Such a role can’t create, rename or delete groups, or take a card out of its group.
- Deleting a card group needs delete permission. On a business account, creating a group needs your role’s write permission for cards, changing a group or its cards needs update, and deleting a group — with or without its cards — needs delete.
- Writes are limited to cards and card groups. 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, sogetUserCards 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:
429 is
always safe to retry after waiting.
Tips for staying under it
- Ask for a batch, not a loop.
createUserCardstakes aquantityup 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.
aggregatecomputes 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.
createUserCardswith abatchIdspends 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,
bulk creation not being enabled, or a groupId that isn’t one of your groups.Support
Happy to help if you get stuck:- Email: [email protected]
- Dashboard: LootRush Dashboard