MCP: BillOS for AI agents
One line of config puts BillOS inside Claude, Cursor, or anything else that speaks MCP. The agent can then issue a document, record an expense and read the numbers, in the user's own words, through the same key, the same limits and the same ledger as every other call here.
Connect
The endpoint is https://api.billos.co.il/mcp, Streamable HTTP, authenticated with your normal API key (X-Api-Key, or Authorization: Bearer bk_... for clients that only speak Bearer). A bk_test_ key talks to the sandbox exactly as it does over REST; POST /sandboxes (section 10) is how a tool with no key asks for one.
claude mcp add --transport http billos https://api.billos.co.il/mcp --header "X-Api-Key: bk_test_..."
{
"mcpServers": {
"billos": {
"url": "https://api.billos.co.il/mcp",
"headers": { "X-Api-Key": "bk_live_..." }
}
}
}
For a desktop client that only launches local processes, put the same URL behind npx mcp-remote https://api.billos.co.il/mcp --header "X-Api-Key: bk_live_...".
The tools
| Tool | What it does |
|---|---|
list_businesses | The businesses this key can act on. Call it first: every other tool takes a businessId from here |
create_document | Creates and issues a קבלה / חשבונית מס / חשבונית מס-קבלה, and returns the number plus a public PDF link for the customer |
list_documents | Issued documents (or drafts), newest first, filterable by date |
cancel_document | Issues the credit note (זיכוי) that corrects an issued document: the only lawful undo. Both stay in the books |
find_or_create_customer | Matches a customer by phone then name, creating one only if nothing matches: what stops a second card being opened for a customer of years |
list_customers | The business's customers |
record_expense | Records an expense in the ledger. On a pending account it lands as a draft and the result says so, rather than failing |
list_expenses | Recorded expenses (or drafts), newest first |
list_open_items | Who owes the business money: every invoice with a balance, aged, each row carrying the documentId a receipt names in settles |
financial_summary | Income, expenses, profit and the VAT position for a date range: the numbers behind "how much did I make this month" |
create_business | Opens a business under the key and returns its businessId. Free in the sandbox; with a live key it opens a real ledger |
seed_sandbox | Sandbox keys only: one demo business with customers, issued documents and expenses, so there is something to read before any real data exists |
search_docs | Searches this documentation and returns the matching sections with their URLs: for what the tools do not cover, for writing code against the API, for explaining an error |
Thirteen verbs, not a hundred endpoints: a model composes far better from a small set of complete business actions than from a mirror of the REST surface. Anything the tools don't cover is still one REST call away.
> Issuing and correcting arrived together on purpose. An agent that can create a permanent tax document but cannot correct one is the wrong asymmetry to hand a model: it makes the dangerous half easy and the repair impossible. cancel_document is the counterpart, and it is a real credit note: nothing is deleted, both documents stay in the books, which is exactly what the law requires.
What an agent can and cannot do
Everything in this document still applies: the MCP endpoint is another door to the same wall, not a way around it:
- Money is agorot here too.
priceIncVatAgorot: 35400is ₪354.00. One unit convention across every surface beats a friendlier one that silently differs. - Issuing is permanent.
create_documentallocates a legal sequential number and signs a PDF; the tool description tells the model to confirm with the user first, and you should keep that instruction in any wrapper you build. - A dry run and an idempotency key.
create_documentwithdryRun: trueruns every check and issues nothing; withidempotencyKeya retried call returns the document already issued instead of a second one, andcancel_documenttakes one for the same reason. A call that is refused leaves no draft behind. - Refusals teach. A failed tool call answers the REST error body as structured content (
reason,hint,param,retryable) and says how to fix it in its text. - Tools are annotated. Each one declares whether it only reads (
readOnlyHint) or writes a permanent record (destructiveHint), so a client can ask the user before the second kind and not before the first. - The same gates fire. Account approval, per-business monthly ceilings, deactivation, rate limits, scopes: an agent meets them exactly as curl does, with the same
reasoncodes. - A business your key doesn't own is invisible. The tool answers "business not found under this credential", never a hint that the id exists.
- Nothing streams and nothing is stored. The server keeps no session: each call is a stateless, authenticated POST.
> Give an agent a bk_test_ key first. The sandbox is a real second database (section 10) where nothing is signed, nothing reaches the tax authority, and every mistake is free: the right place to discover how your prompts behave before a model issues a real invoice.