There is a particular species of small-business admin that I have never once enjoyed. You buy something. A PDF arrives, or — worse — a paper receipt gets photographed at an angle, in bad light, on a kitchen table (the paper ones are always the ones you need). Then later, always later, you sit down and retype its contents into a web form, one field at a time, so that your books know the purchase happened.
I run a one-person company in Israel, which means my invoicing lives in Green Invoice (now rebranded as Morning, though I don't think anyone here actually calls it that yet). It's good software. It's also software that quietly assumes I'll volunteer as the transcription layer between a receipt and a database, and I've come round to the view that this is a job for a machine.
So I wrote an MCP server for it.
If you haven't run into MCP (the Model Context Protocol), the short version is that it's a standard way of handing an AI assistant a set of tools it can call. Instead of Claude describing to you how to file an expense, it files the expense. The server lives at github.com/danielrosehill/GreenInvoice-MCP and is published on npm as greeninvoice-mcp, currently at 0.3.1.
Local MCP for processing financial transactions using Green Invoice
The disclaimer, first, because it matters here
This is an unofficial, third-party project. It is not affiliated with, endorsed by, or supported by Green Invoice or Optimax Ltd. Nobody there has blessed it, and if it breaks, it breaks on my watch and not theirs.
That matters more here than it would for, say, a weather API. The documents this thing creates are legally binding Israeli tax documents. A tax invoice you issue by accident is not a rendering bug; it's a number that now exists in your books and has to be dealt with properly. I check everything in the Green Invoice dashboard afterwards, and you should too (this is also, as you'll see below, most of the reason I went looking for a sandbox).
What it covers
The API surface is larger than you'd guess from the web interface: 66 endpoints. Rather than expose 66 tools — tool listings cost context, and a wall of near-identical names makes model tool selection worse, not better — they're consolidated into eleven action-based tools (one per resource, each taking an action argument). An earlier version had 29 separate tools and it was noticeably worse to use.
document— the whole lifecycle: search, create, update, close, reopen, send, preview, download links, add a paymentclientandsupplier— CRUD, search, merge, balance updatesexpense— expense tracking, drafts, accounting classificationsitem— the product and service cataloguepayment— payment forms, card tokens, payment linksbusiness,account,webhook,reference_data— configuration, document numbering, subscriptions, and lookups like countries and currenciessandbox— the newest one, and the subject of half this post
JWT handling is automatic (the token lasts about half an hour; the server refreshes on a timer and retries once on any 401), and there's built-in rate limiting at roughly three requests a second to stay inside the API's own limits.
The document codes, where I lost an afternoon
Green Invoice keys everything off numeric document types, and this is the part I'd most want to hand to someone else building against the same API. My first pass had thirteen codes with a couple of names I'd inferred rather than checked. Asking the live API for its own list produced fifteen, with two of my names wrong:
10 — Price Quotation
20 — Bill / Payment Confirmation
100 — Order (sales order or order confirmation)
200 — Delivery Note
210 — Return Delivery
300 — Proforma Invoice (חשבון עסקה)
305 — Tax Invoice
320 — Tax Invoice + Receipt
330 — Credit Note (refund)
400 — Receipt
405 — Donation Receipt
410 — Cancel Donation
500 — Purchase Order (הזמנת רכש, issued to a supplier)
600 — Deposit Receipt
610 — Deposit Withdrawal
Codes 20 and 410 were missing entirely. 300 I had as "Transaction Account" and 330 as "Credit Invoice" — both plausible-sounding translations, both not what the API calls them. That list is now verified against a live call rather than against my memory of a PDF.
Three traps came out of the same afternoon, and none of them are in the documentation:
There is no request-for-quotation type. Quotations are outbound only, which surprised me — if you want to record an RFQ you sent to a supplier, the nearest honest fit is a purchase order.
For type 500, the purchase order, the payload's client object holds the supplier you're ordering from. It's the document recipient, not your customer. Supplier records themselves are managed with a different tool, which means a purchase-order flow touches both.
And expenses reuse the same document-type codes rather than having their own small enum. I assumed a 10/20/30/40 sort of scheme, tried 30, and got error 3308, "invalid expense document type" (320 works, and so does 305). While I was in there: expense creation also silently requires reportingDate (leave it out and you get 3308 then 3310, "invalid reporting month") and an accountingClassification (3312, "please fill in expense type details"). Both are undocumented, and you fetch the valid classification IDs from the API itself.
Field names have their own small collection of traps, all of which cost me a request each: it's income and not items, payment and not payments, remarks and not notes, lang and not language, and emails is an array even when there's one address. Types 320, 400 and 405 reject the document outright if there's no payment array.
The sandbox, and the wall I ran into
Everything above involves writing real documents to real books, which is a deeply unrelaxing way to test a payload. So the thing I added yesterday was sandbox support: a way to try a flow, or validate a payload shape, without issuing anything legally binding.
The good news is that Green Invoice has a test environment and it mirrors production exactly. All 66 documented paths hang off the sandbox base, and a GET on the document-types endpoint answers 200 without any authentication at all, which makes a convenient liveness probe. The sandbox web app isn't mentioned in the API docs; I found it because the sandbox root, without the API path, returns a 302 pointing at it.
The bad news, and the single thing worth knowing before you try any of this:
Production API keys do not work against the sandbox. A valid production key pair gets a 401 there, and the response is byte-identical to what you get from a completely made-up key pair.
Which means the failure mode looks like a broken credential rather than the wrong environment. I re-issued a key before I worked out what was actually happening (twice, in fact, which I'm recording here mostly so the next person doesn't). The sandbox is a separate tenancy with separate accounts, and it needs its own registration and its own API key.
And that's where I currently am. I can't find a self-service route to creating a sandbox account — nothing in the production account UI, nothing in the API docs. I've emailed Morning's support to ask whether registration is meant to be self-service, and whether sandbox data gets periodically wiped. Until they answer, the sandbox tool ships and is wired up, but end-to-end document creation against the sandbox is untested. I'd rather say that plainly than let a green tick imply otherwise.
Two design decisions I'm reasonably happy with in the meantime. The sandbox client is bound to the sandbox base URL at construction, so there is no code path from it to production regardless of what arguments you pass — and the converse holds, so the ten production tools can't be talked into the sandbox either. And the status action never throws on an auth failure: it reports that credentials aren't configured and explains how to configure them. A tool that explains its own absence beats a tool that silently isn't there.
There is deliberately no send action in the sandbox. Sandbox documents are fake, but email delivery isn't, and a test invoice landing in a real inbox is not a test.
One more finding, filed under things that look like your fault and aren't: the account-info endpoint returns 403 for API-key authentication on my production account, which had me convinced my key was scoped wrong. It isn't — the same key works everywhere else. If you want a reliable "are these credentials good" check against this API, use the businesses endpoint instead.
The part that actually saves time: chaining
A single API call is never the interesting bit. What's interesting is that the boring sequence becomes one instruction.
Here's the flow I keep coming back to. I photograph a receipt, or drop in a supplier's PDF, and say: read this, create the supplier if we don't already have them, and file it as an expense. Claude reads the document, pulls out the supplier name and tax ID and amount and VAT and date, searches the existing supplier list, creates the record if it's actually new, works out which document type code applies, fetches the accounting classifications, picks one, and creates the expense with a reporting date attached.
Doing that by hand is maybe four minutes of alt-tabbing and squinting (five if the receipt is faded and in Hebrew). Doing thirty of them is an evening I'd like back. The same chaining works in the other direction: read this quote I've been sent, create the supplier, then issue them a purchase order for it.
The OCR is doing real work here, and it's worth being clear that this is where the errors will live. A model misreading a faded thermal receipt is not a hypothetical, so the amounts get checked. But checking a filled-in form is a fundamentally nicer task than filling one in.
Two ways to run it, and I don't think either one wins
The first is straightforward: register the server with your client, and talk to it. Ask for last quarter's expenses, issue an invoice, look up a client's balance. This is fine, and it's how I started (it's still how I do most one-off lookups).
The second is to treat the MCP as the hands and put your own judgement in a layer above it — in Claude Code terms, wrap it in skills. Your business has rules the API knows nothing about: which accounting classification a particular kind of expense belongs to, how you handle VAT on foreign purchases, what your invoice remarks always say, which clients get 30-day terms. Encoded once as a skill, those stop being things you re-explain every session.
I run both, and I've stopped trying to decide which is better, because they're answers to different questions. The direct route is better when I'm exploring or doing something one-off. The skill route is better for anything I do monthly, where the value is in the consistency rather than the API call.
Setting it up
You'll need an API key pair, which is free (it doesn't count against any quota I can find) and lives in the Green Invoice web app: My Account, then Developer Tools, then API Keys, then Add Key. You get an ID and a secret, and the secret is shown exactly once (ask me how I know).
Then point your MCP client at the package:
{
"mcpServers": {
"greeninvoice": {
"command": "npx",
"args": ["-y", "greeninvoice-mcp"],
"env": {
"GREENINVOICE_API_ID": "your-api-id",
"GREENINVOICE_API_SECRET": "your-api-secret"
}
}
}
}Add GREENINVOICE_SANDBOX_API_ID and GREENINVOICE_SANDBOX_API_SECRET alongside those if you have sandbox credentials, and the sandbox tool wakes up while everything else stays pointed at production. Setting GREENINVOICE_SANDBOX to true instead points every tool at the test environment, which is what you'd want for a dedicated test deployment.
The repository has a longer API reference covering all 66 endpoints and the enum codes, plus a sandbox document that records what I verified against the live hosts versus what I'm still inferring. I've tried to keep that distinction visible, because half the pain of building against this API was not knowing which of the things I'd read were actually true.
Who this is for
Realistically: Israeli freelancers and one-person companies who already use Green Invoice, already use Claude, and have the same folder of un-filed receipts that I do. That's not a large group (I would be surprised if it runs to four figures). But it's a group whose admin overhead is almost entirely transcription, and transcription is the thing these models are unambiguously good at.
It's MIT licensed and it's on GitHub (three stars, all of which I am choosing to find encouraging). If you use it and something's wrong — particularly if you have sandbox access and can tell me what actually happens when a document gets created there — I would very much like to hear about it.