reai-mcp
This server is an MCP interface to the ReAI Norwegian cloud accounting API, enabling AI agents to read accounting data and perform bookkeeping operations with robust safety controls.
Identity & tenant management: Authenticate and view accessible companies (
reai_whoami), switch active tenant for session (reai_use_tenant).Read-only bookkeeping: Search chart of accounts, list VAT codes, browse vouchers and postings, generate general ledger reports (opening balance, postings, closing balance per account), and fetch detailed voucher/account data.
Curated write operations (gated by
REAI_WRITE_MODE): Manage customers, suppliers, products, orders, offers, subscriptions, warehouses, departments, fixed assets; create/update/delete vouchers; handle bank reconciliations and VAT returns; adjust inventory, and more.Full API escape hatch: Search all 313+ public API endpoints (
reai_search_endpoints) using Norwegian or English keywords, inspect schemas (reai_describe_endpoint), and call any endpoint directly (reai_request) — including domains like payroll, Peppol, leads, agreements — with write policy enforcement.Safety & controls: Write mode (
read-only,reversible,full) controls which tools are available; irreversible actions require explicit escalation; external sends (EHF, invoice emails, bank transfers) requireREAI_ALLOW_EXTERNAL_SENDflag; voucher balance is validated locally; sensitive field changes (bank details) are always irreversible.Bank reconciliation UI: Optionally expose a manual pairing view (
reai_reconcile_ui) for matching bank transactions with ledger postings via MCP Apps.API insights: Built-in knowledge of ReAI API quirks and Norwegian language support enhances usability.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@reai-mcpWhat did we spend on inventory this year, and which account is it on?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
reai-mcp
An MCP server for ReAI, the Norwegian cloud accounting system — so an AI agent can read the books, look up accounts and VAT codes, and do real bookkeeping through the API.
Not affiliated with or endorsed by ReAI. Community-built, MIT licensed.
You: What did we spend on inventory this year, and which account is it on?
Agent: [reai_general_ledger] Account 1460 "Innkjøpte varer for videresalg" — 12 postings, closing balance 4 812,60 NOK.177 tools: 170 curated across thirteen accounting domains, plus 7 always-on — orientation, and a discovery escape hatch that reaches all 320 public API operations.
Two independent safety switches. One bounds what can be undone in the books; the other decides whether anything may leave the tenant at all. Both default to the cautious setting, and the first does not lift the second.
131 measured API quirks keyed to the operations they affect, so
reai_describe_endpointwarns you before the API rejects you.Discovery works in Norwegian — "lønnskjøring", "send fakturaen" — measured against three query corpora.
Self-hosted, and deliberately not on npm. Run it as local stdio, or deploy your own Streamable HTTP connector with OAuth 2.1. Nothing is published to the registry until it has been seen working against real books, so there is no
npx reai-mcpto copy.
Full reference material lives in docs/: every tool and what each domain actually does, the write policy in detail, the quirk registry, discovery, self-hosting, development and the live audit harnesses.
Why this exists
ReAI's API is genuinely good — 320 documented operations covering the whole accounting domain. But that is far too many to expose as 320 MCP tools: it would exhaust any client's tool budget and bury the agent in choices.
So this server does two things at once:
Curated tools for the operations that matter most, with real guardrails — account lookup, VAT codes, vouchers, postings, the general ledger. A voucher's debit/credit balance is checked before the request is sent, so you get a useful explanation instead of a generic
422.A discovery escape hatch —
reai_search_endpoints,reai_describe_endpointandreai_request— so nothing in the API is out of reach. Leads, agreements, subscriptions, assets, payroll, Peppol: all callable, with schemas on demand.
You get ergonomics where it counts and full coverage everywhere else.
Related MCP server: Inntektsportalen MCP
Safety: this writes to real accounting books
Accounting data is not ordinary application data. Under the Norwegian Bookkeeping Act (bokføringsloven), a voucher posted in a closed period cannot simply be deleted — it must be corrected with a reversing entry. A submitted VAT return cannot be unsubmitted.
An agent exploring an API by trial and error is therefore genuinely dangerous here, so every operation is classified and gated by REAI_WRITE_MODE:
Mode | Allows | Use it when |
|
| Reporting, analysis, letting an agent answer questions about the books |
| Reads, plus master data — customers, suppliers, products, departments, offers. NOT a promise of deletability: several of those archive instead once they carry references | Day-to-day agent work |
| Everything: ledger postings, invoices, payments, payroll, VAT returns | You are prepared to correct mistakes by hand |
Two properties make this more than a label:
Tools you cannot use are not advertised. In
reversiblemode the ledger-write tools are not registered at all, so the agent never sees them and cannot try.The escape hatch fails closed.
reai_requestclassifies each call by method and path. An unrecognised write path is treated as irreversible and blocked — so a future endpoint this server has never heard of cannot slip through as "probably fine". Dot segments cannot straddle two paths either:POST /api/customers/../vouchersis refused, not resolved.The body is inspected too, not just the path. Some payloads are more dangerous than their endpoint suggests: an order carrying
sendEhf: truearms Peppol transmission to a real counterparty, and a subscription withoutputMode: "create_invoice"issues numbered invoices on a schedule. Both escalate to irreversible.
The default is deliberately the middle setting, not the permissive one.
Both switches sit on one path, and a curated tool is not a softer route to the API than the escape hatch is — they converge on the same gates, in this order:
curated tool (170) ---+
+---> 1. write policy .......... REAI_WRITE_MODE
reai_request (320) ---+ 2. external-send gate .... REAI_ALLOW_EXTERNAL_SEND ---> ReAI API
3. PUT omission gate ..... reai_request onlyThe write policy speaks first, so a call the mode forbids is refused for that reason rather than for
a send it also happens to arm. Of the 18 public operations classified as reaching a third party, 17
are also classified irreversible — the exception is GET /vat-return/altinn-sync, which is read-shaped and
whose NAME says it talks to Altinn. Measured 2026-08-11, an API token cannot: it answers 302 to
/auth/login, because that path is the web application's own route rather than an API endpoint. The gate stays
anyway — see TRANSMITTING_GETS for why removing a guard because a route is currently unreachable is
backwards. So the two switches are not redundant in either direction:
turning on external send grants almost nothing by itself, and full alone reaches nothing that
leaves the tenant.
That asymmetry is the whole reason there are two switches rather than one setting with six values:
REAI_ALLOW_EXTERNAL_SEND
off (default) 1
+-------------------------------+----------------------------+
read-only | read the books | + altinn-sync (see above: |
| | a token gets a redirect) |
+-------------------------------+----------------------------+
reversible | + master data (may ARCHIVE | nothing more — 17 of the |
(default) | rather than delete) | 18 sends are ALSO |
| | irreversible |
+-------------------------------+----------------------------+
full | + the ledger, VAT settlement, | + issuing invoices, EHF/ |
| asset write-offs, draft | Peppol, invoice email, |
REAI_WRITE_MODE | payroll runs | reminders, the a-melding,|
| | the tax return, users |
+-------------------------------+----------------------------+Two measured cases shaped that classification, and both are worth reading before running anything in
full. The first is a pair of endpoints: a full replacement can erase where money goes by leaving
it out. PUT /api/company-banks/{id} carrying {name, countryCode, currency} — which is what a
rename looks like — answers 200 and empties the account number its own customers pay into. Sweeping
the document turned up 31 public PUTs that can clear a documented field by omission, so
reai_request now refuses one rather than reporting it afterwards, and the curated tools read and
merge instead: docs/safety.md.
The second is a field set rather than a pair of endpoints, and it has its own section.
Changing where money goes is treated as irreversible
A few fields are ordinary master data as records and permanent as consequences. Undoing the edit
is trivial; undoing what follows is not, because it happens later and through someone acting
perfectly normally. Nine of them name a bank account — iban, bankAccountNumber, swiftCode,
swiftBic, routingNumber, accountNumber, bban, rentAccountNumber, depositAccountNumber —
and one, invoiceEmail, names where invoices are delivered.
A call carrying any of them, on any of the paths that accept them, is classified irreversible and
refused in the default mode, through the curated tools and reai_request alike, even though the
endpoint itself is otherwise reversible. Every other field on the same tool is unaffected: renaming a
supplier still works in reversible. Adding a company bank stays ordinary work; repointing an
existing one does not — and on an employee the field is their salary, paid on a schedule by machinery
nobody re-reads each month.
The exact field set, which paths it reaches, what happens later in each case, and why emptying an
invoiceEmail counts as much as setting one are in
docs/safety.md. The table is
not maintained by hand: test/payment-routing.test.mjs reads the OpenAPI document on every run and
fails the build on a routing-shaped field name that is neither treated as a destination nor
explicitly exempted with its evidence — which is how employees, swiftBic, routingNumber and a
lease's two escrow accounts were found missing from it.
Sending things to other people is a separate switch
REAI_WRITE_MODE answers what can be undone in the books. It deliberately does not answer does this reach someone else — those are different questions, and one setting cannot serve both.
So REAI_ALLOW_EXTERNAL_SEND gates everything that leaves the tenant, independently of the write mode:
EHF/Peppol transmission, and any order carrying
sendEhf: trueInvoice email, payment reminders, agreement signing requests
Issuing a customer invoice —
POST /api/invoicesstarts delivery asynchronously (eFaktura, then EHF, then PDF by email), so it is not a books-only operationGovernment filings: the tax return, and completing a payroll run (the a-melding)
Granting a user access —
POST /api/userscreates apending_invitationwith aninvitationIdand an expiry, which reaches the invitee by email. What it sends is not data but privilege:roleCodeacceptsROLE_TENANT_ADMIN, to an address the caller choosesA bank-integrated supplier payment —
manualPayment: falsecan return anapprovalUrlthat starts a real BankID transfer.manualPayment: truerecords a payment that has already left the bank and needs nothing
It is off by default, and REAI_WRITE_MODE=full does not lift it. A posting can be reversed; an invoice that has gone over Peppol cannot be recalled.
Turn it on if this deployment does your invoicing. That is the ordinary case and the reason an accounting integration exists:
REAI_WRITE_MODE=full
REAI_ALLOW_EXTERNAL_SEND=1Leave it off while evaluating, or when working against books whose real counterparties should not hear from you — which is exactly the situation when there is no sandbox and you are testing against a live company. The combination full + no external send is a genuinely useful place to be: the agent can do real bookkeeping and still cannot email anybody.
Install
Requires Node.js 20 or newer, and a ReAI API token (app.reai.no → settings → API tokens).
There is no npm package
reai-mcp is deliberately unpublished: nothing goes to the registry until this has been seen
working against real books, and the CHANGELOG says so too. Install from source, or build the Docker
image for a remote deployment. Any npx -y reai-mcp recipe you find is wrong — the name does not
resolve.
git clone https://github.com/Stener1/reai-mcp.git
cd reai-mcp
npm install
npm run buildThat leaves an executable server at dist/index.js. Started with no token it exits non-zero and
names the missing variable, which CI asserts on every push.
Claude Code
claude mcp add reai --env REAI_USER_API_TOKEN=your-token -- node /absolute/path/to/reai-mcp/dist/index.jsClaude Desktop / Cursor / any stdio client
{
"mcpServers": {
"reai": {
"command": "node",
"args": ["/absolute/path/to/reai-mcp/dist/index.js"],
"env": {
"REAI_USER_API_TOKEN": "your-token",
"REAI_WRITE_MODE": "reversible"
}
}
}
}An absolute path is required: the client's working directory is not yours.
Verify it works
REAI_USER_API_TOKEN=your-token npm run smokeThis launches the server as a real MCP client would, then exercises read-only tools against the live API and asserts that the write policy blocks a ledger write. It touches nothing, so it is safe against production books.
Which kind of token you have matters
ReAI issues both kinds, and the API behaves differently for each — the OpenAPI spec says X-Tenant-Id is "required for tenant-scoped requests when authenticating with a user access token", and GET /api/me returns "the tenants available to the token".
tenant-scoped token | user-scoped token | |
| exactly one company | every company the user can open |
| ignored when the token reaches one company — any value, even a nonexistent id, returns that company's data | required on every tenant-scoped call, and honoured |
| nothing to switch to | selects which company you are working in |
A user-scoped token is what makes this worth running for an accountant: one connection reaching every
client company, with reai_whoami listing them and reai_use_tenant moving between them. What
reai_whoami can and cannot tell you about which kind you hold — GET /api/me has no field that
distinguishes them — is in docs/tools.md.
The safety consequence cuts the other way, and is why a remote connector binds one company at authorization time rather than handing an agent all thirty because it was asked about one: docs/self-hosting.md.
First steps with an agent
Almost every endpoint is tenant-scoped — the tenant id selects which company's books you are in — so start there:
reai_whoami— who the token belongs to, and which companies it reaches.reai_use_tenant— pick one for the session. Validated against the real list, so a typo fails immediately instead of silently writing into the wrong company.
Then work normally. Set REAI_TENANT_ID to skip step 2.
Tools
7 tools are always on: reai_whoami and reai_use_tenant for orientation, and the escape hatch —
reai_list_api_tags, reai_search_endpoints, reai_describe_endpoint, reai_api_notes and
reai_request — which between them reach all 320 public operations. They cannot be disabled, so a
narrowed server still reaches everything.
The other 170 are curated, in thirteen groups. docs/tools.md is the reference: every tool with its purpose and its risk classification, and per domain what driving it against live books actually turned out to do.
Group | What it covers |
The chart of accounts, VAT codes, vouchers, postings, the general ledger, sub-accounts | |
Customers and their contact people, products, orders, offers, invoices, the customer ledger, and lead prospecting against Brønnøysund | |
Suppliers, supplier invoices, the document inbox, EHF parsing, employee expense claims | |
Company bank accounts, reconciliation both synced and manual, booking rules, the tax return, settling a VAT term | |
Departments, employees and the employee ledger, users, roles and permissions | |
The anleggsmidler register, depreciation schedules, write-offs | |
Recurring billing, its history, and whether it goes out on its own | |
Warehouses, stock on hand per variant, inventory adjustments | |
Leases, employment contracts, purchase and service agreements, signing status | |
Salary runs and their wage lines. Completing a run is deliberately not a tool | |
Country and currency codes, the opening balance, annual-accounts status | |
Loans borrowed and lent, and the creditors and debtors at each end | |
The portfolio and its events — purchases, sales, dividends, write-downs |
Three tools are documented together, apart from their domains, because they exist for one reason: to
stop a rename destroying a payment destination
(docs/tools.md). That is a
documentation grouping only — reai_update_company_bank belongs to bank,
reai_set_supplier_address to purchase and reai_update_creditor to loans, they are inside the
170, and narrowing with REAI_TOOLSETS enables each one with its own domain. One tool genuinely is
outside all thirteen: reai_reconcile_ui is off unless REAI_ENABLE_UI=1, because it is the only view here, and the only
payload in this API that does not fit comfortably in text
(why).
Anything not listed — projects, timesheets, documents — is reachable through
reai_search_endpoints + reai_request, and carries its known quirks automatically.
If 177 tools is more than your client wants to see, narrow it with REAI_TOOLSETS — list only
the groups you want. Each count below includes the 7 always-on tools:
REAI_TOOLSETS=bookkeeping # 19 tools
REAI_TOOLSETS=bookkeeping,sales # 56 tools
REAI_TOOLSETS=purchase # 33 tools
REAI_TOOLSETS=bank # 25 tools
REAI_TOOLSETS=organisation # 25 tools
REAI_TOOLSETS=assets # 13 tools
REAI_TOOLSETS=subscriptions # 16 tools
REAI_TOOLSETS=warehouses # 14 tools
REAI_TOOLSETS=agreements # 13 tools
REAI_TOOLSETS=salary # 14 tools
REAI_TOOLSETS=reference # 11 tools
REAI_TOOLSETS=loans # 20 tools
REAI_TOOLSETS=investments # 14 tools
(unset) # all 177Valid groups are bookkeeping, sales, purchase, bank, organisation, assets, subscriptions, warehouses, agreements, salary, reference, loans and investments; listing all thirteen is the same as leaving it unset. Orientation and discovery are never disabled, so a narrowed server still reaches every endpoint through reai_search_endpoints + reai_request.
Configuration
Variable | Default | Purpose |
| — | Required. ReAI user API token. |
| — | Default tenant, so |
|
|
|
| off | Permit anything that reaches a third party: EHF/Peppol, invoice email, reminders, signing requests, issuing an invoice, government filings, a user invitation, and a bank-integrated supplier payment. Enable this for a business doing its own invoicing — see below |
|
| Override for a staging environment |
|
| Per-request timeout |
|
| Retries on 429/502/503/504, with exponential backoff and jitter |
| off | Log one line per API request to stderr. Never logs tokens |
See .env.example for the annotated version. REAI_TOOLSETS is described
above; REAI_ENABLE_UI under the one UI surface; and
the variables that only matter to a remote deployment — PORT, PUBLIC_URL, REAI_ENCRYPTION_KEY,
REAI_ALLOWED_HOSTS, REAI_ALLOWED_REDIRECT_HOSTS, REAI_ALLOW_TOKEN_PASSTHROUGH — are in
docs/self-hosting.md.
API quirks worth knowing
Most of what this server knows about ReAI was learned from a rejected request rather than from
reading the spec. Rather than leave that in commit messages, it lives in
src/reai/quirks.ts as 131 quirks keyed to the operations they affect — so
they surface automatically in reai_describe_endpoint and reai_search_endpoints, including for the
131 public operations no curated tool covers. A test asserts every quirk still matches a real
operation in the spec, so they cannot quietly rot as the API changes.
Four to give the flavour: an invoice is created from an order, not from line items; there is no
endpoint that lists bank transactions; period on a VAT return is a two-month term index, so passing
4 for April locks Jul–Aug; and a 403 is usually a disabled module rather than a permissions
problem. Browse them from an agent with reai_api_notes, or read the whole registry as prose in
docs/api-quirks.md.
Discovery works in Norwegian
This is a Norwegian accounting system and its users type Norwegian, where the definite article is a
suffix and nouns glue together — so "lønnskjøring", "varelager" and "send fakturaen" have to
resolve to endpoints whose paths are in English. They do, and the definite article is handled rather
than hoped for: the suffixes -n, -ne, -en and -et are stripped and retried whenever the
remaining stem is a word the synonym table already knows, so kunden, ordren, utgiften and
dokumentet all resolve — and a test asserts inflection does not change the rank, not merely that
something comes back. A stem-changing definite (anleggsmiddel → anleggsmidlet, which drops a
vowel) is still out of reach, and the test names that case rather than omitting it.
On a 31-query bilingual set — 21 Norwegian, 10 English — all 31 find their endpoint and 28 of them rank
it in the top three. Three further corpora hold the measurement as regression floors in
test/discovery-heldout.test.mjs, each scored once before anything was tuned against it, because a
benchmark whose failures you have read is no longer measuring anything.
docs/discovery.md has those numbers, the four causes that were fixed, why the
stem gate is load-bearing rather than precautionary, and the sweep that answers "what did this
ranking change do to every other query".
Self-hosting as a remote connector
The same server speaks MCP over Streamable HTTP, so it can be added as a custom connector rather than spawned locally. There is no hosted instance — you run your own, which means your ReAI token never leaves infrastructure you control. It implements OAuth 2.1 as its own authorization server (dynamic client registration, PKCE, refresh tokens) and bridges that to ReAI's static API tokens: the user pastes a ReAI token on the consent page, and the server seals it into its own access tokens, so there is no session database and a scale-to-zero deployment works.
./scripts/deploy-cloud-run.sh --project my-gcp-projectRemotely, the write ceiling is composed rather than chosen once. A grant is sealed at
authorization time carrying the mode the user picked on the consent page, and every request applies
whichever of that and the server's current REAI_WRITE_MODE is narrower — so tightening the
deployment binds tokens that were already issued, and a permissive server never widens a grant
somebody deliberately narrowed:
docs/safety.md.
Docker, the Cloud Run script's three easy-to-get-wrong steps, why an authorization is bound to one company and cannot address another, an honest account of what locking a public connector down can and cannot achieve, how the OAuth flow is verified end to end, and the remote-only environment variables are all in docs/self-hosting.md.
The MCP endpoint also enforces two transport ceilings, both well above any real tool call: an 8 MB
request body and a 50-message JSON-RPC batch. Each has a surprise in it worth reading before
diagnosing one as a network fault — an oversized body does not reliably get a 413, and GET /mcp
answers 405 on purpose, not by omission:
docs/self-hosting.md.
Development
npm install
npm run build # rebuild the spec index, then compile
npm test # build + the unit suite (no credentials needed)
npm run typecheck
npm run smoke # read-only, end-to-end against the live API (needs a token)Unit tests cover the write-policy classifier, the discovery ranker, spec search/describe, the OAuth
server and every curated tool's request shaping, and need no network access or credentials.
docs/development.md covers adding a tool, running CI's whole matrix locally,
refreshing the pinned OpenAPI snapshot, and the live harnesses — which refuse to run unless the
tenant is named in REAI_WRITE_TEST_TENANTS, because a --tenant flag is not consent.
Because there is no sandbox, the documented claims are re-checked against live books rather than trusted: four audit harnesses ask whether the refusals, the stored values and the 131 quirks still say what this repository says they say, and each one has found something false. docs/audits.md has what each covers, what it deliberately does not, and what it found.
Contributing
Issues and PRs welcome. Adding a curated tool is deliberately mechanical, and
docs/development.md has the three steps. Declaring
risk correctly is the part that matters — it is what gates the tool behind REAI_WRITE_MODE.
Changelog
See CHANGELOG.md, which also records the known limitations — tokens cannot be individually revoked, path-prefix deployments are unsupported, and the irreversible write paths have not been exercised end to end against live books because ReAI has no sandbox.
License
MIT — see LICENSE.
Available Tools
12 toolsreai_describe_endpointDescribe a ReAI API endpointARead-only
Get the complete schema for one ReAI endpoint: every parameter, the full request body with nested objects resolved, and response shapes. Use this before calling an unfamiliar endpoint with reai_request, especially for POST and PUT where required fields matter.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | API path exactly as it appears in the spec, including braces for path parameters, e.g. "/api/customers/{id}". | |
| depth | No | How deep to expand nested schemas (default 4). Raise it for deeply nested payloads. | |
| method | Yes | HTTP method of the endpoint. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is known. The description adds valuable behavioral detail beyond annotations by specifying output contents ('every parameter, the full request body with nested objects resolved, and response shapes'), which helps an agent understand what to expect when invoking the tool. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loaded with the core purpose and followed by practical usage guidance. Every word earns its place; there is no repetition of schema details or annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple (3 parameters, no output schema), and the description is sufficient: it explains what the tool returns, when to use it, and why it matters. It also provides enough context to distinguish it from sibling tools without needing to enumerate alternatives.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides 100% description coverage for all three parameters (method, path, depth) with clear explanations. The description does not add meaningful parameter-level semantics beyond the schema, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Get') and clearly identifies the resource ('complete schema for one ReAI endpoint'). It explicitly lists what the tool returns (every parameter, full request body with nested objects resolved, response shapes) and is easily distinguished from sibling tools like reai_search_endpoints.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description states exactly when to use the tool: 'Use this before calling an unfamiliar endpoint with reai_request, especially for POST and PUT where required fields matter.' This names the companion tool (reai_request) and gives a concrete condition (unfamiliar endpoints, POST/PUT), providing clear guidance versus alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reai_general_ledgerGeneral ledger (hovedbok)ARead-only
Read the general ledger for a period: every account with its opening balance, postings and closing balance. This is the report to use for questions like 'what did we spend on X' or 'what is the balance of account 1920'. Narrow with accountNumber or an account range, since a full-year ledger for an active tenant can be large.
| Name | Required | Description | Default |
|---|---|---|---|
| endDate | No | Inclusive end date. Defaults to today. | |
| vatCode | No | Filter by VAT code. | |
| amountTo | No | Maximum posting amount. | |
| tenantId | No | ReAI tenant (company) id. Omit to use the active tenant — set one with reai_use_tenant, or list what this token can reach with reai_whoami. | |
| accountTo | No | End of an account-number range. | |
| projectId | No | Filter by project. | |
| startDate | No | Inclusive start date. Defaults to 1 January of the current year. | |
| amountFrom | No | Minimum posting amount. | |
| customerId | No | Filter by customer. | |
| supplierId | No | Filter by supplier. | |
| accountFrom | No | Start of an account-number range. | |
| accountNumber | No | Restrict to a single account. | |
| voucherNumber | No | Filter by voucher number. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false; the description reinforces the read operation and adds a performance warning ('a full-year ledger ... can be large') that encourages filtering. It also clarifies the report content — accounts with opening/closing balances and postings — which goes beyond the schema. No contradiction found.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the action and result, followed by usage examples and a performance tip. Every sentence earns its place with no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity of 13 optional parameters and no output schema, the description covers the core usage: period, account narrowing, size warning, and example queries. It does not describe the exact result structure, but the general ledger report is well enough characterized to inform correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema covers all 13 optional parameters (100% coverage), so the baseline applies. The description adds meaningful guidance on account-selection parameters ('Narrow with accountNumber or an account range'), but it does not explain the other filters in detail. This is adequate but not exceptional.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Read the general ledger for a period' — a specific verb, resource, and scope — and lists the outputs ('opening balance, postings and closing balance'). It also gives concrete example questions ('what did we spend on X') that position it clearly against sibling list tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use it: 'This is the report to use for questions like...' It also advises narrowing with accountNumber or an account range due to potential size. However, it does not name sibling alternatives or state when not to use it, so it stops short of full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reai_get_voucherGet one voucherARead-only
Fetch a single voucher by id, including all its postings and attachments.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Voucher id. | |
| tenantId | No | ReAI tenant (company) id. Omit to use the active tenant — set one with reai_use_tenant, or list what this token can reach with reai_whoami. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is clear. The description adds the behavioral detail that the result includes postings and attachments, which goes beyond the basic fetch semantics but doesn't disclose any additional side effects, permissions, or rate limits. This is consistent with the annotations and adds moderate context, but not rich behavioral disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence that states the core action and the key included data. It is concise with no filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple single-fetch operation, the description covers the essential information: what is fetched (voucher by id) and what is included in the result (postings and attachments). The schema handles parameter details and annotations cover the read-only nature, so the description is sufficiently complete for an agent to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, with both parameters already having descriptive text, including a helpful note on tenantId referencing reai_use_tenant and reai_whoami. The tool description itself adds no parameter-specific meaning beyond what the schema provides, so it meets the baseline three for high coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states the verb ('Fetch'), the resource ('a single voucher by id'), and the scope ('including all its postings and attachments'). This clearly distinguishes it from sibling tools like reai_list_vouchers, which list multiple vouchers, and reai_list_postings, which list postings separately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description does not explicitly name alternatives or state when not to use the tool. However, the phrase 'by id' clearly implies this is for fetching a specific known voucher, and the sibling names like reai_list_vouchers suggest the alternative for listing. That said, there is no explicit 'use this instead of...' guidance, so the usage context is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reai_list_accountsList chart of accountsARead-only
Search the tenant's chart of accounts (kontoplan). Returns account numbers, names and types. Use this to find the right account number before booking a voucher — every posting must reference an account that exists in this list.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum accounts to return. | |
| query | No | Free-text search over account number and name, e.g. "bank", "salgsinntekt", "1920". | |
| tenantId | No | ReAI tenant (company) id. Omit to use the active tenant — set one with reai_use_tenant, or list what this token can reach with reai_whoami. | |
| accountNumberPrefix | No | Restrict to a leading digit range, e.g. "19" for bank accounts or "3" for revenue. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnlyHint=true, destructiveHint=false, and openWorldHint=true. The description adds context by stating the return fields (account numbers, names, types) and the operational requirement that postings must reference accounts from this list. This is useful context beyond the annotations, though it doesn't detail pagination or edge cases.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is only two sentences, front-loaded with the core action and object. Every sentence provides value: the first defines what it does, the second explains why and when to use it. No redundant or filler content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given there is no output schema, the description compensates by stating the return fields (account numbers, names, types) and providing a clear use case. It doesn't explain the exact response structure or how pagination works, but the schema covers parameters and the description covers the essentials for a read-only search tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the parameters (limit, query, tenantId, accountNumberPrefix) are fully documented in the schema. The description doesn't add specific parameter-level meaning but aligns with the search intent. Baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose with a specific verb ('Search') and resource ('tenant's chart of accounts'). It distinguishes itself from siblings like reai_list_vat_codes and reai_list_postings by mentioning the return of account numbers, names, and types, and by tying it to voucher bookings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says when to use the tool ('Use this to find the right account number before booking a voucher') and gives a compelling rationale ('every posting must reference an account that exists in this list'). It doesn't explicitly mention when not to use or name alternatives, but the context is clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reai_list_api_tagsList ReAI API domainsARead-only
List every documented ReAI API domain (tag) with its operation count — a map of what the accounting system can do. Useful for orienting before a search.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, covering the safety profile. The description adds behavioral context by stating the output includes operation counts and serves as a map of the accounting system's capabilities, which goes beyond the structured hints. It does not contradict any annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tightly written sentences: the first states the action and resource, the second gives the use case. There is no filler, redundant exposition, or over-explanation. The structure is front-loaded with the primary verb.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a no-parameter, no-output-schema tool, the description is sufficiently complete. It explains what is returned (list of domains with operation counts) and why it's useful. The annotations cover safety constraints, so nothing critical is missing for an agent to decide whether to invoke it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, and the schema description coverage is 100% vacuously. Per the baseline for zero-param tools, a score of 4 is appropriate; the description doesn't need to explain parameters. It still adds output context (operation count), but that's not parameter-specific.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses the specific verb 'List' with a clear resource ('every documented ReAI API domain (tag)') and adds 'with its operation count', making the tool's purpose unambiguous. It also distinguishes this from sibling tools by framing it as 'a map of what the accounting system can do', which signals a high-level discovery function rather than a specific endpoint or account listing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides a clear usage context: 'Useful for orienting before a search.' This implies it should be used first to understand available domains. However, it does not explicitly mention when to avoid this tool or name alternatives (e.g., reai_search_endpoints), so it stops short of full exclusion guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reai_list_postingsList postingsARead-only
List individual ledger postings in a date range, with optional filters by account, voucher, customer, supplier, project, employee or bank. Each posting reports canDelete and lockReasons, which tell you whether it can still be changed. Defaults to the current calendar year.
| Name | Required | Description | Default |
|---|---|---|---|
| endDate | No | Inclusive end date. Defaults to today. | |
| tenantId | No | ReAI tenant (company) id. Omit to use the active tenant — set one with reai_use_tenant, or list what this token can reach with reai_whoami. | |
| projectId | No | Filter by project. | |
| startDate | No | Inclusive start date. Defaults to 1 January of the current year. | |
| voucherId | No | Filter to one voucher's postings. | |
| customerId | No | Filter by customer. | |
| employeeId | No | Filter by employee. | |
| supplierId | No | Filter by supplier. | |
| accountNumber | No | Filter by chart-of-accounts number. | |
| companyBankId | No | Filter by company bank account. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, covering safety. The description adds value beyond annotations by revealing that each posting reports canDelete and lockReasons, and by stating the default calendar-year date range.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences front-load the core action and resource, then add filters and behavioral details. Every sentence earns its place with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the core operation, filter options, default date range, and a notable response characteristic (canDelete/lockReasons). It does not mention pagination or sorting, but for a read-only list tool with no output schema, this is reasonably complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with individual descriptions for all 10 parameters. The description groups filters semantically (account, voucher, customer, etc.) but does not add new meanings beyond the schema, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a list operation on individual ledger postings with a date range and multiple optional filters. It distinguishes from sibling tools like reai_list_vouchers and reai_general_ledger by specifying 'individual ledger postings'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage context through the date range and optional filters, but it does not explicitly say when to use this tool versus alternatives like reai_list_vouchers or reai_general_ledger. No exclusions or when-not-to-use guidance is provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reai_list_vat_codesList VAT codesARead-only
List the VAT (mva) codes available in this tenant, with rate, type and description. Postings to revenue and cost accounts generally require a VAT code; look it up here rather than guessing, because the valid set depends on the tenant's VAT registration.
| Name | Required | Description | Default |
|---|---|---|---|
| usage | No | Filter to codes valid in a specific context, e.g. codes usable on a customer invoice. | |
| tenantId | No | ReAI tenant (company) id. Omit to use the active tenant — set one with reai_use_tenant, or list what this token can reach with reai_whoami. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is known. The description adds behavioral context that results vary by tenant and the set is tenant-specific, which is beyond what annotations provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the action and content, with a rationale sentence that earns its place by motivating use. No superfluous information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple list tool with comprehensive annotations and schema, the description covers what, why, and scope. Even without an output schema, it provides enough context for the agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema descriptions cover 100% of parameters, so the description doesn't need to add parameter details. The tenant mention in the description aligns with tenantId, but the usage parameter is left entirely to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb ('List') and resource ('VAT codes') with scope ('available in this tenant') and content ('rate, type and description'). This distinguishes it from sibling tools like reai_list_accounts and reai_list_vouchers.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly instructs to use the tool to look up VAT codes rather than guessing, explaining that postings require them and the valid set depends on tenant VAT registration. It doesn't name an alternative tool but provides clear when-to-use context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reai_list_vouchersList vouchersARead-only
List vouchers (bilag) in a date range, each with its postings. A voucher is the atomic unit of Norwegian bookkeeping: a dated, balanced set of debit and credit postings. Defaults to the current calendar year if no dates are given.
| Name | Required | Description | Default |
|---|---|---|---|
| endDate | No | Inclusive end date. Defaults to today. | |
| tenantId | No | ReAI tenant (company) id. Omit to use the active tenant — set one with reai_use_tenant, or list what this token can reach with reai_whoami. | |
| startDate | No | Inclusive start date. Defaults to 1 January of the current year. | |
| voucherType | No | Filter by how the voucher was created. | |
| registeredBy | No | Filter by the user who registered the voucher. | |
| includeReversed | No | Include reversed vouchers (excluded by default). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the operation as read-only and non-destructive. The description adds valuable behavioral details: it defaults to the current calendar year if dates are omitted, and it returns each voucher with its postings, which is not visible in annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences, front-loaded with the primary action, and each sentence provides necessary context: the operation, the domain concept, and the default behavior. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a list tool with six optional parameters and detailed schema descriptions, the description provides the core purpose, domain definition, and default behavior. It lacks details on response format or pagination, but with no output schema and read-only annotations, it is reasonably complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description mentions date range defaults, but these are already documented in the schema's startDate and endDate descriptions, so no new parameter semantics are added.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists vouchers within a date range, including their postings, and defines the voucher concept. This distinguishes it from sibling tools like get_voucher (single item) and list_postings (postings only).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context for when to use the tool: listing vouchers with postings in a date range, with defaults for date bounds. However, it does not explicitly mention alternatives or when not to use it, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reai_requestCall any ReAI API endpointADestructive
Escape hatch: call any ReAI API endpoint directly. Use it for anything the curated tools do not cover. Discover the endpoint with reai_search_endpoints and check its schema with reai_describe_endpoint first.
Authentication and the tenant header are handled for you. Write calls are subject to the server's write policy, and unrecognised write paths are treated as irreversible and blocked unless REAI_WRITE_MODE=full.
| Name | Required | Description | Default |
|---|---|---|---|
| body | No | JSON request body, for POST, PUT and PATCH. | |
| path | Yes | Concrete API path with path parameters already substituted, e.g. "/api/customers/1234" (not "/api/customers/{id}"). Must start with "/". | |
| query | No | Query-string parameters. | |
| binary | No | Set for endpoints returning a file (PDF, attachment content). Returns base64 plus content type instead of attempting to parse JSON. | |
| method | Yes | HTTP method. | |
| tenantId | No | ReAI tenant (company) id. Omit to use the active tenant — set one with reai_use_tenant, or list what this token can reach with reai_whoami. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Even though annotations already indicate destructiveHint=true and openWorldHint=true, the description adds critical behavioral details: authentication and tenant header are handled automatically, write calls are subject to server write policy, and unrecognized write paths are treated as irreversible and blocked unless REAI_WRITE_MODE=full. This goes beyond the annotations to warn the agent about safety and policy enforcement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, front-loaded, and every sentence earns its place. It covers purpose, usage workflow, and safety policy without unnecessary filler. The structure flows logically from 'what' to 'how' to 'warnings'.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a high-risk escape-hatch tool with no output schema, the description provides complete guidance: how to use it, how to discover endpoints, how to check schemas, how authentication works, and what safety restrictions apply. It is fully contextualized within the sibling toolset and self-sufficient for an agent to use it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the input schema already documents all parameters and their meanings. The description adds no additional parameter-specific semantics beyond clarifying that authentication/tenant header are handled, which helps with tenantId but is a minor addition. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Escape hatch: call any ReAI API endpoint directly,' which clearly states the verb (call), resource (any ReAI API endpoint), and scope. It distinguishes itself from curated tools by noting it covers what they do not, and provides a clear path to discovery via reai_search_endpoints and reai_describe_endpoint.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says to use it for anything the curated tools do not cover, and advises discovering endpoints and checking schemas first. This gives clear when-to-use guidance and names alternative tools (reai_search_endpoints, reai_describe_endpoint) as prerequisites, effectively explaining a safe workflow.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reai_search_endpointsSearch ReAI API endpointsARead-only
Search the full ReAI OpenAPI surface (313 public operations) by keyword, tag or HTTP method. Use this whenever no curated tool covers what you need — for example leads, agreements, subscriptions, assets, warehouses, share investments, salary or Peppol. Returns matching operations with their path, parameters and request-body field names. Follow up with reai_describe_endpoint for full schemas, then call it via reai_request.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No | Restrict to one tag, e.g. "Invoices" or "Bank reconciliations". Use reai_list_api_tags to see them all. | |
| limit | No | Maximum results (default 25). | |
| query | No | Keywords to match against path, tag, summary and description. Norwegian domain terms often appear in descriptions (e.g. "mva", "bilag", "kunde"), and English ones in paths and tags. Omit to browse by tag alone. | |
| method | No | Restrict to one HTTP method. | |
| includeInternal | No | Include undocumented internal endpoints (payment-provider webhooks, the POS app, platform admin). Off by default; these are not intended for API consumers. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses the return format (path, parameters, request-body field names) and warns that internal endpoints are off by default. This adds context beyond the readOnlyHint annotation, which already indicates a safe read operation. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is four compact sentences with no fluff. It front-loads the core function, gives concrete examples, and outlines the workflow, all in an efficient structure.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a search tool with optional parameters and no output schema, the description covers scope, when to use, return format, and next steps. It lacks only minor details like pagination behavior, but the limit parameter is already documented in the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description adds extra value by explaining that Norwegian domain terms often appear in descriptions and English in paths/tags, aiding query construction. It also clarifies the interaction between query and tag parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool searches the full ReAI OpenAPI surface by keyword, tag, or HTTP method, listing concrete example domains. It distinguishes itself from sibling tools like reai_describe_endpoint and reai_request by positioning itself as the initial discovery step.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit guidance says to use this whenever no curated tool covers the need, and provides a follow-up workflow: use reai_describe_endpoint for full schemas, then call via reai_request. This clearly differentiates from curated tools and alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reai_use_tenantSelect the active companyARead-onlyIdempotent
Set the tenant (company) that subsequent tool calls apply to, for the rest of this session. The id is validated against the tenants this token can actually reach, so a typo fails here rather than silently writing into the wrong company's books. Individual tools can still override it with their own tenantId argument.
| Name | Required | Description | Default |
|---|---|---|---|
| tenantId | Yes | Tenant id to make active. Get valid ids from reai_whoami. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint, idempotentHint, and destructiveHint, but the description adds crucial behavioral context: the setting persists for the session, the tenantId is validated against reachable tenants (preventing typos), and per-tool overrides are possible. This goes beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences with the main action front-loaded, followed by valuable context (validation and override behavior). Every sentence earns its place with no fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter tool with no output schema, the description fully covers the session effect, validation safeguards, and interaction with other tools. No important context is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the schema already describes tenantId as the 'Tenant id to make active' and suggests using reai_whoami for valid ids. The description adds no further parameter semantics, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Set') and resource ('tenant (company)'), clearly distinguishing this from sibling tools like reai_whoami which queries tenant info. It states exactly what the tool does: establishes the active tenant for subsequent calls.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains the session-scoped nature ('for the rest of this session') and that individual tools can override the setting, providing clear context for when to use it. It doesn't explicitly state exclusions or alternative tools, but the context is sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reai_whoamiWho am I and which companies can I reachARead-only
Identify the authenticated ReAI user and list every tenant (company) the token can access, with each tenant's id, slug and currency. Call this first in any session: most other tools are tenant-scoped, and the tenant id is what selects which company's books you are working in. Also reports the active tenant and the server's current write policy.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Even with readOnlyHint and destructiveHint annotations, the description adds valuable context: it reports the active tenant and the server's write policy, and clarifies that the tenant list includes id, slug, and currency. This goes beyond the annotations and sets accurate expectations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences long, front-loaded with the core purpose, and the second sentence provides crucial usage context. Every phrase earns its place without redundancy or fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite lacking an output schema, the description fully conveys what the tool returns (user identity, tenant list with fields, active tenant, write policy). It also provides essential session context, making it complete for a zero-parameter tool in this sibling set.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and an empty schema, so the description carries no parameter burden. It appropriately describes the tool's role without needing to explain inputs, meeting the baseline for parameterless tools.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses specific verbs ('Identify' and 'list') and clearly states the resource (the authenticated ReAI user and every accessible tenant). It distinguishes itself from siblings by focusing on session initialization and tenant discovery, which no other sibling tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says 'Call this first in any session' and explains why: most other tools are tenant-scoped and require the tenant id. This provides clear when-to-use guidance and effectively positions it relative to tenant-scoped siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
12 tool updates
v0.1.0- First observed
reai_describe_endpoint - First observed
reai_general_ledger - First observed
reai_get_voucher - First observed
reai_list_accounts - First observed
reai_list_api_tags - First observed
reai_list_postings - First observed
reai_list_vat_codes - First observed
reai_list_vouchers - First observed
reai_request - First observed
reai_search_endpoints - First observed
reai_use_tenant - First observed
reai_whoami
TDQS
Scored across 12 tools
Each tool targets a distinct resource or action: identity, tenant selection, reference data (VAT codes, accounts), transactions (vouchers, postings), reports (general ledger), and API discovery/invocation. Even the three API exploration tools (search_endpoints, describe_endpoint, list_api_tags) serve clearly different purposes: finding, schema-documentation, and high-level orientation.
The vast majority follow a consistent verb_noun pattern with the reai_ prefix (list_accounts, get_voucher, search_endpoints, use_tenant). Minor deviations are reai_whoami (idiomatic command rather than verb_noun) and reai_general_ledger (noun-only, implying a 'get' verb), but these are easily understood and do not disrupt the overall coherence.
With 12 tools, the set is well-scoped for an accounting domain. Each tool has a clear role, and the number is within the ideal 3–15 range. The inclusion of both curated tools and an escape hatch (reai_request) balances usability with power without bloating the surface.
The curated tools cover the core read-side lifecycle: tenant management, reference data (accounts, VAT codes), vouchers (list/get), postings, and the general ledger report. The reai_request tool fills any gap by allowing direct API calls after discovery via reai_search_endpoints/reai_describe_endpoint, ensuring no dead ends for write or uncommon operations.
Maintenance
Related MCP Connectors
MCP server unifying ERPs, CRMs, APIs and knowledge base for Claude, ChatGPT and Gemini.
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
- ZapierOAuthcom.zapier
Hosted MCP server connecting AI assistants to 9,000+ apps and 40,000+ actions via Zapier.
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
Related MCP Servers
- AlicenseBqualityDmaintenanceA read-only MCP server that exposes Fiken accounting API's 61 GET endpoints as tools for AI assistants to query accounting data.6110 npm3MIT
- FlicenseNot gradedqualityDmaintenanceMCP server that enables AI assistants to securely access and manage personal financial data from Inntektsportalen (Norwegian income portal) with fine-grained scope-based authorization via OAuth2.-
- AlicenseNot gradedqualityDmaintenanceMCP server providing deterministic accounting tools for AI agents, including bank statement parsing, document classification, money math, and webhook verification.2Apache 2.0
- FlicenseNot gradedqualityBmaintenanceMulti-tenant MCP server connecting accounting software to AI assistants via ~87 tools. Supports Bokio (Swedish accounting) with mock mode for development.-