Home · Guides

A petty cash float from chat, and why the cheque is not the sum of the vouchers

A petty cash tin is the smallest book in the business and the one most likely to be wrong. Somebody holds some cash, receipts come back, and at the end of the month a cheque goes in to top it up. The MCP Petty Cash server runs that tin on the imprest system: a voucher for every receipt, a count whenever you like with the difference to the minor unit, and a replenishment worked out from the count rather than from the paperwork. It stores no balance and posts nothing anywhere.

Install it

claude mcp add petty-cash -- npx -y @theluckystrike/mcp-petty-cash

Cursor, in .cursor/mcp.json, and Claude Desktop with the same block under claude_desktop_config.json:

{
  "mcpServers": {
    "petty-cash": {
      "command": "npx",
      "args": ["-y", "@theluckystrike/mcp-petty-cash"]
    }
  }
}

It reads no other server's store and writes into none. Its own store is three files: the floats, the vouchers and an id counter.

The cheque is not the sum of the vouchers

This is the finding worth the whole page. Take the worked month: a 50,000 minor unit imprest, EUR 500.00, and five vouchers.

Imprest                                     50,000
VOU-2026-0001  2026-03-02  postage  Stamps    1,250
VOU-2026-0002  2026-03-05  travel   Taxi      3,480
VOU-2026-0003  2026-03-11  office   Coffee      899
VOU-2026-0004  2026-03-18  office   Paper    12,500
VOU-2026-0005  2026-03-24  travel   Bus       2,065
                                            -------
vouchers                                     20,194
expected on 2026-03-31                       29,806
counted                                      29,795
difference                                      -11
replenishment (50,000 - 29,795)              20,205

The paperwork says the tin holds 29,806 on the 31st. It holds 29,795. The count is short by exactly 11 minor units: eleven cents that no voucher explains and no receipt will ever be found for. The replenishment is therefore 20,205, not 20,194.

What makes this worth a test rather than a footnote is what the wrong version looks like. Reimbursing the voucher total is not obviously wrong. It is the number the paperwork adds up to, it is the number a person reaches for, it reconciles against the receipts one by one, and the next count comes back short by 11 again, which reads as a fresh 11 rather than as the same one that was never put back. The unit suite runs three cycles of exactly that: the float ends at 49,967 against a 50,000 imprest, 33 minor units light, with three clean-looking reconciliations behind it, each reporting a difference of exactly 11 and nothing worse. Nothing ever looks broken. The tin just gets smaller.

So replenish_request computes imprest - balance and never sum(vouchers), and the 11 comes back as its own cash_over_short journal line rather than folded into a category where it would look like postage.

A count is a fact, so it moves the book balance

Once a count is recorded, the balance is what was counted. The difference is carried forward as an over or short rather than re-reported at every later count. The alternative, leaving the book at what the vouchers say and reporting the same difference forever, makes the second count a copy of the first and hides the moment a NEW difference appears. Count the tin twice on the same day with nothing spent in between and the second count comes back at exactly zero, which is the point. The count history keeps every difference, so a tin that is short by a little every month is visible as a run rather than as one number.

Under the imprest system the float account does not move

replenish_request hands back the double entry in the cash book's own account ids, character for character:

expenses:office            13,399   debit
expenses:postage            1,250   debit
expenses:travel             5,545   debit
cash_over_short                11   debit
cash                       20,205   credit

petty_cash is not in that journal at all. It is debited once when the float is opened, and again only if the imprest itself changes. That is what the imprest system means, and a journal that moves the float account at every replenishment double-counts the tin. The per-category lines come from the cash book's own expenseAccount, so a category spelled Office Supplies, office supplies and   OFFICE   SUPPLIES   is one account and one 300 line, not three. Beside the journal sits an expense_add-ready payload per category.

A request is not a payment

replenish_request writes nothing. It says what the cheque should be. The cash is recorded with topup_record when it is physically back in the tin, and it is that call which marks the vouchers reimbursed. A float that counts a request as cash is short by the whole request until the cheque clears, which is a bigger error than the one this page opened with.

What the tin refuses

A tin holds cash and can never hold less than nothing. A voucher larger than the balance on its own date is refused. So is a back-dated one that would make any LATER day negative, which an at-the-date check alone does not catch: back-dating takes the cash out earlier, so every day after it is short too. Record 30,000 on the 10th and then try to back-date 25,000 to the 2nd, and the refusal names the 10th, the day it breaks, not the day it was typed.

A reconciled voucher cannot be deleted, because the cash it took out was counted on the day of the count, and removing it would make a recorded count wrong by its own amount. Deletion is free while a voucher is still uncounted, which is what keeps the monthly cap honest. The VOU series never reissues a number, so a gap in it is the record that a voucher was deleted. And a byte-identical voucher, same float, date, amount, category, description, payee and receipt reference, is refused by name, because that is one voucher entered twice far more often than it is two identical purchases; duplicate_ok admits the second taxi fare of the day deliberately.

Ask it

Open a EUR 500 office float on 2026-03-01, Anna holds the tin.
Stamps 1,250 minor units on 2026-03-02, postage. Taxi 3,480 on the 5th, travel, receipt 4471.
I counted 29,795 in the tin on 2026-03-31. What does the replenishment cheque have to be?

float_open, voucher_add, voucher_delete, topup_record and reconcile are free; replenish_request and float_report are Pro ($19 one-time, lifetime, verified offline, or every server in the bundle).

Questions

Why is the replenishment not the total of my vouchers?

Because the two differ by exactly what the counts found over or short, and that difference is the whole reason a float shrinks. On the worked month the vouchers total 20,194 and the cheque is 20,205: the tin was counted 11 short. Reimbursing 20,194 restores the float 11 light, the same defect repeats every cycle, and every reconciliation still reports a clean 11. Three cycles of it leave a 50,000 float at 49,967.

What happens to the difference a count finds?

It becomes a cash_over_short line in the replenishment journal, on its own, rather than being folded into an expense category. Folded in, eleven cents of unexplained shortfall would look like postage, and the account that exists to carry exactly that would stay empty forever.

Is reconcile metered?

No, on any tier. Whether the cash in the tin matches the paperwork is the question this server exists to answer, and a free tier that withholds the answer is a demo rather than a tool. The meter is on the volume of record keeping: one float and twenty vouchers a calendar month on the free tier.

Why does the second count on the same day come back at zero?

Because a count is treated as a fact and moves the book balance. Once you have counted, the balance IS what you counted, and the difference is carried forward rather than re-reported. Leaving the book at what the vouchers say would make the second count a copy of the first and would hide the moment a genuinely new difference appears.

Can I delete a voucher I typed wrongly?

While it is still uncounted, yes, free on every tier, and the slot goes back. Once a reconciliation has covered it, no: the cash it took out was counted on the day of the count, so removing it would make a recorded count wrong by its own amount, and the refusal says so with the number. The VOU series never reissues a number, so the gap is the record that a voucher was deleted.

Does the petty_cash account move when I replenish?

No. Under the imprest system it is debited once when the float is opened and again only if the imprest itself changes. A replenishment credits cash and debits the expenses per category, and the suite asserts petty_cash is absent from that journal. A journal that moves the float account every cycle double-counts the tin.

Can a voucher take the tin below zero?

No. A voucher larger than the balance on its own date is refused, and so is a back-dated one that would make any later day negative, which the at-the-date check alone does not catch. The whole run of events is replayed in date order and the refusal names the day it breaks rather than the day it was typed.

Does replenish_request record the cash?

No, it writes nothing at all. It says what the cheque should be. topup_record is what registers the cash when it is physically back in the tin, and that call is what marks the vouchers reimbursed. A request is not a payment, and a float that counts one as cash is short by the whole request until the cheque clears.

Where is the data kept?

Three plain JSON files under ~/.local/share/mcp-servers/petty-cash/, or $XDG_DATA_HOME if you set it: floats.json, vouchers.json and counter.json. No balance is stored anywhere, because a stored balance is a second copy of what the vouchers already decide and the copy is the one that gets believed after somebody deletes a voucher. There is no network call anywhere in this server, no account and no API key, and license keys are verified offline.

Related

All MCP servers and prices · All guides · Buy the bundle $39