Home · Guides

Bill a retainer on a schedule without a billing SaaS

A retainer is the easiest money to invoice and the easiest to forget. The amount does not change, the date does not move, and that is exactly why nobody notices when a month goes unbilled. MCP Recurring Invoices holds the schedule so you do not have to: client, line items, cadence, start date, terms. When you ask, it creates the invoices that have actually fallen due as real records in the invoice server, with its number series, its client list and its A4 PDF.

Install

claude mcp add recurring -- npx -y @theluckystrike/mcp-recurring
{
  "mcpServers": {
    "recurring": {
      "command": "npx",
      "args": ["-y", "@theluckystrike/mcp-recurring"]
    }
  }
}

The npm publish is pending, so until it lands use the .mcpb bundle from the latest release or a clone and build; build servers/invoice first, because the engine is imported from it. Per client paths are on the setup pages. Install the invoice server too: this one has no business_set of its own on purpose, so there is exactly one issuer profile to keep correct.

One schedule, then nothing

schedule_create {
  client: "Acme Retainer", currency: "EUR", every: "monthly",
  start_date: "2026-06-01", due_days: 14,
  items: [{ description: "Retainer hours", quantity: 12, unit_price: 90 }]
}
-> schedule 9f2c1a04, next dates 2026-06-01, 2026-07-01, 2026-08-01, 2026-09-01

Cadences are weekly, monthly, quarterly, yearly or {days: n}. Occurrence 0 is the start date itself, so a schedule starting today is due today. end_date is inclusive: an occurrence landing exactly on it is generated and the next one is not.

The month-end rule

This is the part a naive date library gets wrong, and getting it wrong changes a client's payment date permanently. The month step keeps the day of month of the start date and clamps it to the length of the target month, and it never carries the clamp forward. From 2026-01-31 the series is 01-31, 02-28, 03-31, 04-30, 05-31.

The naive version adds one month to 31 January, lands on 28 February, and then adds one month to that, so March becomes the 28th and every month after it does too. February silently turns a month-end retainer into a 28th-of-the-month retainer, and nobody reads the invoice date closely enough to catch it. The same rule makes a yearly schedule starting 2028-02-29 fall on 02-28 in common years and back on 02-29 in the next leap year, because the anchor day is 29 throughout.

On Pro, anchor_day replaces the day of month before clamping, so anchor_day: 31 means the last day of every month regardless of what the start date was, and end_of_month: true says the same thing explicitly. Both are ignored for weekly and {days: n}, which have no month to anchor to. An anchored first occurrence that would land before the start date is dropped rather than billed early.

The idempotency key is the period, not the day

Here is the run that matters. On 3 September, against the schedule above:

invoice_generate_due {}
-> as_of 2026-09-03: created 4 invoices, skipped 0 already invoiced.
   INV-2026-0001  period 2026-06-01  EUR 1080.00  due 2026-06-15
   INV-2026-0002  period 2026-07-01  EUR 1080.00  due 2026-07-15
   INV-2026-0003  period 2026-08-01  EUR 1080.00  due 2026-08-15
   INV-2026-0004  period 2026-09-01  EUR 1080.00  due 2026-09-15
   Total: EUR 4320.00

invoice_generate_due {}      # five minutes later, having forgotten
-> as_of 2026-09-03: created 0 invoices, skipped 4 already invoiced.

The second call is the whole design. The key written to the history is (schedule_id, period), not a timestamp and not the calendar day the run happened on. That choice is what makes a billing run safe to repeat, safe to run from two clients, and safe to run after a crash halfway through. Key it on the run date instead and a second run on a different day re-bills everything; key it on the day and a run at 23:59 followed by one at 00:01 does the same. Because the period is the key, "did I already bill September" is a question the data answers rather than one you have to remember, and dry_run shows you the run before it happens.

The same key survives deletion. Deleting a schedule keeps its history rows deliberately, so a re-created schedule cannot double-bill a period that was already invoiced, and the tool warns when a new schedule's periods were covered by an old one.

Why a run is capped at 60 invoices

A mistyped year is an ordinary typo. Before the cap existed, a schedule starting 1900-01-01 offered 1,520 due periods, and one call with as_of: "2126-01-01" on a plain monthly schedule created 1,193 real invoices and 1,193 PDFs, 6.0 MB in 6.8 seconds, burning 1,193 numbers out of the shared invoice number series. Numbers are never reused, so that damage is permanent in the sequence a tax authority reads. A run now stops at 60, oldest periods first, and the answer says how many are still due. Idempotency is untouched by the cap, because the key is still the period: another call simply continues.

Two locks, always in the same order

Anything that writes an invoice takes the recurring lock first and the invoice lock second, always in that order, so a billing run and a hand-written invoice in the other server cannot interleave, cannot allocate the same number and cannot deadlock. Numbers are allocated inside the lock and the PDFs are rendered after it is released, so a slow render never holds up the counter.

One more thing worth knowing: if schedules.json or history.json is unreadable, it is never treated as empty. The file is moved aside byte for byte, a marker is written and every tool fails loudly until you restore it. A history file read as empty would re-bill every period the schedule has ever covered, which is the worst failure this server could have.

What it does not do

Nothing runs in the background. This is a stdio MCP server: it exists while your client runs it. There is no daemon, no cron and no email, so invoices appear when you ask for them, typically through the monthly_billing_run prompt. Delivering the invoice and chasing payment are still yours; overdue_report in the invoice server tells you who to chase. There is no proration, no mid-period cancellation credit and no currency conversion.

Free tier and Pro

Free gives 3 active schedules, unlimited generation, a 30 day upcoming view and a 3 month forecast. Pro ($19 once) gives unlimited schedules, a 10 year horizon, a 120 month forecast, the schedule_history audit log and the anchor day and end of month rules. Product page: MCP Recurring Invoices. Side by side with the alternatives: recurring billing comparison. The one-sentence invoice for everything that is not on a retainer is in the invoice guide.

Questions

What happens if I run the billing twice?

Nothing the second time. The history key is the schedule id plus the period, not the run date, so a repeated run reports created 0, skipped 4. That is what makes it safe to run from two clients, after a crash, or when you cannot remember whether you already did it.

My retainer bills on the 31st. What happens in February?

It bills on 28 February, then back on 31 March. The month step keeps the start date's day of month and clamps it to the target month's length without carrying the clamp forward, so February does not permanently move a month-end retainer to the 28th.

Does it send the invoice to my client?

No. It creates the invoice record and renders the PDF into the invoice server's store. Delivery and chasing are yours; overdue_report in the invoice server lists who is late.

Where do the generated invoices go?

Into the invoice server's own data directory, with the PDFs in its pdf subfolder, so they appear in invoice_list, count in overdue_report and can be re-rendered with invoice_pdf. Both servers must see the same XDG_DATA_HOME or you end up with two stores.

Can one call create hundreds of invoices by accident?

Not any more. A run is capped at 60 periods, oldest first, and says how many remain. Before the cap, one call with a mistyped as_of year created 1,193 invoices and PDFs and burned 1,193 numbers out of a series that never reuses one.

Related

All MCP servers and prices · All guides