AI assistants (MCP)
AccountFUN runs a remote Model Context Protocol (MCP) server, so an AI assistant can work in an organization’s books as the person who connected it — reading records and carrying out the accounting tasks that person is authorized for. For step-by-step setup in a specific assistant, see Connect an AI assistant.
https://app.accountfun.com/api/v1/mcpHow it works
Section titled “How it works”- Transport: Streamable HTTP. It is stateless: every request is a JSON-RPC
POSTanswered withapplication/json. There is no server-sent event stream and noMcp-Session-Id.GETandDELETEreturn405. - Capabilities: tools only. Supported protocol revisions are
2025-11-25,2025-06-18,2025-03-26and2024-11-05; an unknown revision is answered with2025-06-18. - Same rules as the REST API. Every tool runs the matching
public API endpoint with the caller’s access token. That means the
same scope checks, role checks, validation, rate limits and audit trail.
tools/listreturns only the tools the token’s scopes allow, and a tool ignores any argument its input schema doesn’t list. - Tool errors come back as results with
isError: true, with the API’s message and field errors in the text, so the model can correct its input and retry.
Authorization
Section titled “Authorization”The MCP server is an OAuth 2.0 protected resource that uses AccountFUN’s own authorization server. The flow is the authorization code flow with PKCE.
-
An unauthenticated request gets
401with:WWW-Authenticate: Bearer resource_metadata="https://app.accountfun.com/.well-known/oauth-protected-resource/api/v1/mcp", scope="org:read chart_of_accounts:read tax_rates:read items:read tracking:read projects:read bank_accounts:read reports:read fixed_assets:read contacts:read contacts:write payments:read payments:write bank_transactions:read bank_transactions:write credit_notes:read credit_notes:write credit_notes:approve credit_notes:delete credit_notes:settle prepayments:read prepayments:write prepayments:approve prepayments:settle bills:read bills:write bills:approve bills:delete expense_claims:read expense_claims:write expense_claims:approve invoices:read invoices:write invoices:approve invoices:delete offline_access" -
Protected resource metadata (RFC 9728) is served at
/.well-known/oauth-protected-resource/api/v1/mcp(and at the root form). It nameshttps://app.accountfun.comas the authorization server. -
Authorization server metadata (RFC 8414) is served at
/.well-known/oauth-authorization-server. It lists the authorize, token, revoke and registration endpoints,S256PKCE, and both public (none) and client-secret client authentication.
Connecting an assistant
Section titled “Connecting an assistant”Assistants that support dynamic client registration (RFC 7591) register themselves — no client ID or secret to enter — and any MCP client that reads the metadata works the same way. See Connect an AI assistant for the popular ones. They register at:
POST https://app.accountfun.com/api/v1/oauth/registerYou create nothing in AccountFUN: add the MCP URL as a custom connector, and when AccountFUN opens, sign in and approve the access. A self-registered client is a public client — no secret, PKCE-bound — and can be connected to any organization you belong to in your own right. The consent screen names the assistant and where it will send you back, and labels a self-registered client as not verified, so only continue if you started connecting it yourself.
Those assistants register themselves this way. A client that can’t register itself needs an app instead: create one under Settings → API & Developers, register it with the client’s callback URLs and the scopes in the challenge above, and enter its client ID and secret in the connector’s advanced OAuth settings. A developer app can be connected only to organizations its creator belongs to.
A requested scope the client isn’t registered for is left out of the
connection rather than failing it — so a client registered without
bills:approve can never approve. If an authorize request omits scope, the
client’s registered scopes are used.
Access is fixed once a connection is made. To add a scope later — a capability released after the connector was added, or one the user left unticked — the client re-authorizes: the user reconnects the assistant and approves the updated list, where their previous choices are pre-selected and new ones are marked New. Access can’t be widened from AccountFUN’s settings on its own.
Posting, deleting and moving money are opt-in
Section titled “Posting, deleting and moving money are opt-in”The connector asks for the full scope set above, but the consent screen offers the higher-trust scopes as unticked checkboxes under Only if you tick it::
- Approving documents —
bills:approve,invoices:approve,credit_notes:approve,prepayments:approveandexpense_claims:approve(voiding a credit note or prepayment uses its approve scope too); - Moving money —
payments:write,bank_transactions:writeand the settle scopescredit_notes:settle/prepayments:settle; - Deleting documents —
bills:delete,invoices:deleteandcredit_notes:delete(a posted document is reversed first); - Creating a draft prepayment —
prepayments:write.
Unless the user ticks the matching box and their role has the required
permission, the token doesn’t carry the scope and the tools that need it
aren’t listed: by default an assistant can read the books and draft bills,
invoices and credit notes, but it cannot post, approve, delete, pay out,
transfer or settle anything. Tools that move or post money (approve_bill,
approve_invoice, approve_expense_claim, approve_credit_note,
record_payment, spend_money, transfer_money, refund_prepayment, …) are
marked destructive and require confirm: true in the call — see
guardrails.
Other access the user’s role can’t grant is left out the same way, and the
connection works with the rest. For example, the built-in Purchase role can’t
approve and can’t see the sales side, so its connection never gets
approve_bill or the invoice tools. If the role can grant none of the access,
the connection is refused.
Guardrails
Section titled “Guardrails”Destructive tools are guarded in depth: explicit confirmation on every destructive call, plus — for money — an organization policy, per-connection velocity limits and a security-event trail.
Confirmation is mandatory
Section titled “Confirmation is mandatory”The 30 destructive tools require confirm: true in the same call. Without
it the call is refused and nothing is performed — the error says so, and
the assistant is told to ask the user first and retry.
| Area | Tools that need confirm: true |
|---|---|
| Bills | approve_bill, void_bill, revert_bill_to_draft, revert_bill_to_submitted, delete_bill |
| Expense claims | approve_expense_claim |
| Invoices | approve_invoice, void_invoice, revert_invoice_to_draft, revert_invoice_to_submitted, delete_invoice |
| Payments | record_payment, record_bill_payment, reverse_payment |
| Bank | spend_money, receive_money, transfer_money |
| Credit notes | approve_credit_note, void_credit_note, revert_credit_note_to_submitted, delete_credit_note, allocate_credit_note, refund_credit_note |
| Prepayments | approve_prepayment, void_prepayment, allocate_prepayment, unallocate_prepayment, refund_prepayment, reverse_prepayment_refund |
| Contacts | delete_contact |
submit_prepayment (a draft-to-submitted step that posts nothing) and the
create, note, upload-link and read tools don’t need confirmation.
The organization’s money policy
Section titled “The organization’s money policy”An admin sets what assistants may do with money under Settings → Organization → AI Assistants → Money Actions:
| Setting | Effect on money tools |
|---|---|
| Ask the Assistant to Confirm — Default | Every destructive call must carry confirm: true. |
| Allow | Destructive calls run without asking; confirm: true is still accepted. |
| Block | Kill switch: every money tool is refused immediately, before anything is read or changed. |
The policy is read fresh on every destructive call, so an admin’s change takes effect at once, and it is fail-closed to Confirm: if it can’t be read or holds an unexpected value, confirmation is required.
Velocity limits
Section titled “Velocity limits”Money tools are capped per connection (OAuth grant) at 10 per minute and 100 per day. An over-limit call is refused before anything runs, with a retry-after hint in the error. A refused attempt still counts against the window that refused it (retrying can’t reset the clock), and only a call that passes the policy and confirmation checks consumes quota — blocked or unconfirmed calls never do.
Consent and badges
Section titled “Consent and badges”Requesting any money scope makes the OAuth consent screen show a red “This app can move money” warning. It is a warning only: each money scope stays an individually unticked opt-in, so nothing is granted unless the user ticks it. A connection that holds a money scope is badged Can Move Money under Settings → Account → Connected Apps, and admins see the same badge under Settings → Authorized Applications.
Every bill, invoice, expense claim, payment, credit-note, prepayment and
transaction result includes a url to the record in AccountFUN. Tools noted as
destructive require confirm: true — see guardrails.
Organisation & lookups
Section titled “Organisation & lookups”| Tool | Scopes | What it does |
|---|---|---|
get_organisation | org:read | Organization name, base currency, tax settings. |
list_accounts | chart_of_accounts:read | Chart of accounts, optionally filtered by type; archived accounts left out. |
list_tax_rates | tax_rates:read | Tax rates for lines[].taxRateId. |
list_items · get_item | items:read | Products and services for lines[].itemId — including tracked-inventory items (isTracked, weighted-average cost). |
list_tracking_categories | tracking:read | Tracking categories and their options for trackingOption1Id / trackingOption2Id. |
list_projects · get_project | projects:read | Projects for projectId on invoices/bills, and one project’s live money summary. |
list_bank_accounts | bank_accounts:read | Bank accounts for bankAccountId / fromAccountId / toAccountId. |
list_fixed_assets · get_fixed_asset | fixed_assets:read | Fixed assets, and one asset with its depreciation schedule. |
Contacts
Section titled “Contacts”| Tool | Scopes | What it does |
|---|---|---|
find_contacts | contacts:read | Search customers and suppliers. |
get_contact | contacts:read | One contact’s full record by id (address, names, website, social links, tax number, settlement terms) — for when the model already has a contactId. |
create_contact | contacts:write | Add a supplier (default) or customer. |
update_contact | contacts:write | Edit a contact — the fields you send change; the rest are kept. |
delete_contact | contacts:write | Deactivate a contact (default) or permanently delete one with no related records. Destructive; requires confirm: true. |
| Tool | Scopes | What it does |
|---|---|---|
list_bills | bills:read | List bills. reference is an exact, case-insensitive match (_ and % aren’t wildcards). To check whether a receipt is already recorded, the assistant is told to match the receipt number and the supplier, and to ignore voided bills. |
get_bill | bills:read | A bill with its lines, attachments and notes. If any part of the lookup fails, the whole call fails rather than reporting no attachments or notes. |
create_bill | bills:write | Record a bill — always as a draft; there’s no status option. Takes an optional note. |
approve_bill | bills:approve | Post a draft or submitted bill. Opt-in; requires confirm: true. |
add_bill_note | bills:write | Add a note to the bill’s History & Notes. |
create_bill_upload_link | bills:write | A 15-minute upload link for attaching the original file to a bill. The assistant gives the link to the user. |
update_bill | bills:write | Edit a bill: reference and project at any status; number, supplier, currency, dates, lines and tax mode only while it’s a draft. |
submit_bill | bills:write | Move a draft bill to submitted (posts nothing). |
void_bill | bills:approve | Void a bill; a posted one is reversed. Destructive; requires confirm: true. |
revert_bill_to_draft | bills:approve | Revert a submitted/unpaid approved bill to draft, reversing a posted entry. Destructive; requires confirm: true. |
revert_bill_to_submitted | bills:approve | Revert an unpaid approved bill to submitted, reversing the posted entry. Destructive; requires confirm: true. |
delete_bill | bills:delete | Delete a bill; refused if it has allocations, and a posted one is reversed first. Destructive; requires confirm: true. |
Expense claims
Section titled “Expense claims”| Tool | Scopes | What it does |
|---|---|---|
create_expense_claim | expense_claims:write | File a draft expense claim for the connected member (the claimantId defaults to them). The assistant attaches the receipt through the REST API or the user attaches it in AccountFUN. |
approve_expense_claim | expense_claims:approve | Approve a claim the connected user filed themselves; the final approval creates the supplier bill — posted immediately for a base-currency claim, and for a foreign-currency one either posted with the system exchange rate or left as a draft, per the organization’s setting. Opt-in; requires confirm: true. Approving another member’s claim stays inside AccountFUN. |
Invoices
Section titled “Invoices”| Tool | Scopes | What it does |
|---|---|---|
list_invoices | invoices:read | List sales invoices, newest first; filter by status or customer. Check invoiceNumber in the results for one that’s already recorded. |
get_invoice | invoices:read | One invoice with its lines, attached files and notes. Fails the whole call rather than misreporting if part of the lookup fails (like get_bill). |
create_invoice | invoices:write | Record a sales invoice — always as a draft; there’s no status option. Lines are revenue lines. |
approve_invoice | invoices:approve | Post a draft or submitted invoice. Opt-in; requires confirm: true. |
add_invoice_note | invoices:write | Add a note to the invoice’s History & Notes. |
create_invoice_upload_link | invoices:write | A 15-minute upload link for attaching the original file to an invoice. |
update_invoice | invoices:write | Edit an invoice: reference, reminder and online-payment toggles, project and settlement at any status; number, customer, currency, dates, lines and tax mode only while it’s a draft. |
submit_invoice | invoices:write | Move a draft invoice to submitted (posts nothing). |
void_invoice | invoices:approve | Void an invoice; a posted one is reversed. Destructive; requires confirm: true. |
revert_invoice_to_draft | invoices:approve | Revert a submitted/unpaid approved invoice to draft, reversing a posted entry. Destructive; requires confirm: true. |
revert_invoice_to_submitted | invoices:approve | Revert an unpaid approved invoice to submitted, reversing the posted entry. Destructive; requires confirm: true. |
delete_invoice | invoices:delete | Delete an invoice; refused if it has allocations, and a posted one is reversed first. Destructive; requires confirm: true. |
Payments
Section titled “Payments”| Tool | Scopes | What it does |
|---|---|---|
list_payments | payments:read | Customer receipts and supplier payments, newest first; filter by direction or contact. |
get_payment | payments:read | One payment with its contact, bank account, the invoices/bills it settled, its files and notes. |
record_payment | payments:write | Record a customer receipt against approved invoices. Posted immediately; requires confirm: true. |
record_bill_payment | payments:write | Record a supplier payment against approved bills. Posted immediately; requires confirm: true. |
reverse_payment | payments:write | Reverse a payment, restoring the invoices/bills it settled. Destructive; requires confirm: true. |
add_payment_note | payments:write | Add a note to the payment’s History & Notes. |
create_payment_upload_link | payments:write | A 15-minute upload link for attaching the remittance to a payment. |
Bank transactions
Section titled “Bank transactions”| Tool | Scopes | What it does |
|---|---|---|
spend_money | bank_transactions:write | Record money leaving a bank account with no bill (a fee, cash expense, drawing). Posted immediately; requires confirm: true. |
receive_money | bank_transactions:write | Record money entering a bank account with no invoice (interest, a refund, a contribution). Posted immediately; requires confirm: true. |
transfer_money | bank_transactions:write | Transfer between two of the organisation’s bank accounts. Posted immediately; requires confirm: true. |
get_transaction | bank_transactions:read | Read the posted journal entry behind a payment or money action, with its debit/credit lines. |
Credit notes
Section titled “Credit notes”| Tool | Scopes | What it does |
|---|---|---|
list_credit_notes | credit_notes:read | Customer and supplier credit notes, newest first; filter by status or direction. |
get_credit_note | credit_notes:read | One credit note with its lines, the invoices/bills it was applied to, and any refunds. |
create_credit_note | credit_notes:write | Create a draft credit note — receivable (to a customer) or payable (from a supplier). |
approve_credit_note | credit_notes:approve | Post a draft or submitted credit note. Opt-in; requires confirm: true. |
void_credit_note | credit_notes:approve | Void a credit note; a posted one is reversed, with its allocations unwound first. Destructive; requires confirm: true. |
allocate_credit_note | credit_notes:settle | Apply an approved credit note to invoices (receivable) or bills (payable). Destructive; requires confirm: true. |
refund_credit_note | credit_notes:settle | Record a cash refund of an approved/allocated credit note. Destructive; requires confirm: true. |
add_credit_note_note | credit_notes:write | Add a note to the credit note’s History & Notes. |
create_credit_note_upload_link | credit_notes:write | A 15-minute upload link for attaching the signed credit note. |
update_credit_note | credit_notes:write | Edit a credit note: reference (draft only) and settlement terms (customer notes, any status); number, contact, type, currency, date, lines and tax mode only while it’s a draft. |
submit_credit_note | credit_notes:write | Move a draft credit note to submitted (posts nothing). |
revert_credit_note_to_draft | credit_notes:write | Revert a submitted credit note to draft. |
revert_credit_note_to_submitted | credit_notes:approve | Revert an approved/allocated credit note to submitted, unwinding its allocations (refused if it has refunds). Destructive; requires confirm: true. |
delete_credit_note | credit_notes:delete | Delete a draft credit note. Destructive; requires confirm: true. |
Prepayments
Section titled “Prepayments”| Tool | Scopes | What it does |
|---|---|---|
list_prepayments | prepayments:read | Supplier advances (spend) and customer advances (receive), newest first; filter by status/direction or search number, reference or contact. |
get_prepayment | prepayments:read | One prepayment with its bank account, lines, the invoices/bills it was applied to, and any refunds. |
create_prepayment | prepayments:write | Create a draft prepayment — an advance paid to a supplier or received from a customer. |
submit_prepayment | prepayments:write | Submit a draft prepayment so it can be posted. |
approve_prepayment | prepayments:approve | Post a draft or submitted prepayment. Opt-in; requires confirm: true. |
void_prepayment | prepayments:approve | Void a prepayment; a posted one is reversed. Destructive; requires confirm: true. |
allocate_prepayment | prepayments:settle | Apply an approved prepayment to invoices (receive) or bills (spend). Destructive; requires confirm: true. |
unallocate_prepayment | prepayments:settle | Undo one application, restoring the document’s and the prepayment’s balances. Destructive; requires confirm: true. |
refund_prepayment | prepayments:settle | Record a cash refund of an approved/allocated prepayment. Destructive; requires confirm: true. |
reverse_prepayment_refund | prepayments:settle | Reverse a refund recorded by mistake. Destructive; requires confirm: true. |
Reports
Section titled “Reports”Read-only financial statements in the organization’s base currency.
| Tool | Scopes | What it does |
|---|---|---|
get_trial_balance | reports:read | Trial balance as of a date, or net movement over a date range. |
get_profit_and_loss | reports:read | Accrual-basis profit & loss for a date range. |
get_balance_sheet | reports:read | Balance sheet as of a date. |
get_aging | reports:read | AR or AP aging: outstanding invoices/bills by contact and age bucket. |
get_contact_statement | reports:read | A customer or supplier statement — an outstanding balance or itemised activity. |
No tool returns the content of a file, and AccountFUN never reads or extracts text from your files for an assistant. The assistant reads a receipt in its own chat, where you showed it, and is told to ask you rather than guess when it can’t read something clearly.
Attaching the original file
Section titled “Attaching the original file”An assistant in a chat never holds the original file, so no tool takes file
content: the assistant could only attach something it had re-created.
Instead, the original reaches AccountFUN through an upload link: the
assistant creates the document, calls create_bill_upload_link,
create_invoice_upload_link, create_credit_note_upload_link or
create_payment_upload_link, and gives the user the link. The user opens it,
with no sign-in, and picks the file or takes a photo. An assistant that can
run shell commands and has the file on disk can upload it itself:
curl -F file=@receipt.jpg <uploadUrl>. The link works for 15 minutes, takes
up to 5 files, and can only add files to that document. See
Upload links. Uploaded images are resized and
re-encoded under the shared file processing rules.
A program that holds the real file can also use the REST endpoint —
POST /api/v1/bills/{id}/attachments,
POST /api/v1/invoices/{id}/attachments,
POST /api/v1/payments/{id}/attachments,
POST /api/v1/credit-notes/{id}/attachments or
POST /api/v1/expense-claims/{id}/attachments.
There is no upload-link tool for expense claims: an assistant files the claim and the member attaches the receipt in AccountFUN (or a program with the file posts it to the REST endpoint above).
Audit trail
Section titled “Audit trail”Everything the assistant changes is recorded as the connected user via the OAuth client’s name, with the time and where the request came from (IP address and user agent). This covers bills, invoices, expense claims, credit notes and prepayments created, approved, voided, allocated and refunded; payments and bank transactions recorded or reversed — every ledger posting names the app too — files attached, and notes. It shows in each record’s History & Notes (where the record has one) and in the organization’s Audit History. Notes restored from a data export don’t carry a “via” label.
Every tool call, and every API call a tool makes, is also logged and kept for 30 days. A file uploaded through an upload link is recorded under the user’s name via the app, with the link and the IP address it was sent from.
Each destructive money-tool call is additionally recorded as an
mcp.money_action security event with its outcome — executed,
refused_policy, refused_confirm, rate_limited or failed — naming the
tool, the OAuth client and grant, and the target ids or amount (never the full
arguments). That gives the organization an audit trail of everything an
assistant tried to move, including the calls it was refused.
The user disconnecting it under Settings → Account → Connected Apps, or an admin revoking the grant under Settings → Authorized Applications, cuts the assistant off at its next request.
Rate limits
Section titled “Rate limits”MCP requests count against the same per-token and per-client limits as the
REST API (see Errors & rate limits). So does each
API call a tool makes: most tools make one, and get_bill, get_invoice and
get_payment each make three. A token gets roughly 100 to 150 tool calls a
minute.