Skip to content

For developers

KRONENWERK MCP server: connect an AI agent to your accounting

Last reviewed SUPPORTED

KRONENWERK exposes a Model Context Protocol (MCP) server at https://kronenwerk.org/api/extern/mcp. An AI agent that speaks MCP over Streamable HTTP authenticates with OAuth 2.1 (Claude, ChatGPT and other hosted assistants) or with the same Bearer API key as the REST API, reads one company's customers, invoices, transactions and reports, and creates drafts, transactions and notes. Whether it may also issue an invoice, send it or record a payment is the company's decision: by default those remain a person's acts, and the company can allow them under Settings → AI assistants up to an amount limit it sets, with every act on the record. The MCP server is part of the Enterprise plan.

What MCP is

The Model Context Protocol is an open specification, published at modelcontextprotocol.io, that defines how an AI application (the client) discovers and calls tools offered by an external system (the server). Messages are JSON-RPC 2.0. The server publishes a list of tools with names, descriptions and JSON input schemas; the model reads those descriptions, decides what to call, and the client sends a tools/call request on its behalf. The result comes back as content the model can read and, optionally, as structured JSON.

Two transports are standardised: stdio for a server launched as a local subprocess, and Streamable HTTP for a server reached over the network. KRONENWERK is a network service, so it implements Streamable HTTP only. The protocol is versioned by date. As of 2026-09-03 the specification names 2026-07-28 as the current revision; earlier revisions (2025-11-25, 2025-06-18, 2025-03-26) open a connection with an initialize handshake, while the current revision carries the protocol version and client identity in a _meta object on every request and adds a server/discover method. A server may serve more than one revision on the same endpoint, and KRONENWERK does.

Endpoint, transport and authentication

Everything happens on one address with one HTTP method: POST https://kronenwerk.org/api/extern/mcp, body application/json, one JSON-RPC message per request.

Authentication
Either Authorization: Bearer greif_oauth_… — an OAuth 2.1 access token, obtained through authorization code + PKCE at /oauth/authorize and /oauth/token, with dynamic client registration at /oauth/register and discovery under /.well-known/oauth-authorization-server (this is how Claude and ChatGPT connect: the company's owner signs in and consents once) — or Authorization: Bearer greif_live_… / greif_test_…, the same API key the REST API accepts, created in KRONENWERK's settings and bound to exactly one company. A request without a valid credential is answered 401 with WWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource", which MCP clients follow to start the sign-in. See authentication.
Tenant
The company an agent reaches is the key's company. There is no organisation parameter anywhere in the protocol surface, so an agent cannot select or enumerate companies.
Session
None. The server keeps no session and issues no MCP-Session-Id. Every request carries its own credential and its own protocol version. GET (the optional server-to-client stream) and DELETE (session termination) answer 405 Method Not Allowed, which the specification designates for servers that do not offer them.
Protocol versions
2026-07-28 (per-request _meta), and the handshake-based 2025-11-25, 2025-06-18 and 2025-03-26. A request that names another version receives JSON-RPC error -32022 with the supported list in data.supported. A request that names no version at all is served as a legacy client.
Methods
server/discover, initialize, tools/list, tools/call, ping. No resources, prompts, sampling or notifications; the server never opens a stream. Batches are not accepted; each request is one message.
Origin
A request carrying an Origin header from another site is refused with 403, as the specification requires against DNS rebinding. Non-browser clients send no Origin and are unaffected.
Rate limit
The MCP endpoint sits inside the same filter chain as the REST API, so the key's budget of 240 requests, refilling at about two per second, applies to both together. Over budget, the answer is 429 with Retry-After. See rate limits.
Plan
A valid key whose company is not on the Enterprise plan receives 403 with application error code 1402 and a sentence saying so. Plans are described on the pricing page.

For clients on the current revision, the server also checks the mirrored headers the specification introduced — MCP-Protocol-Version, Mcp-Method and, on tools/call, Mcp-Name — against the body, and answers a mismatch with error -32020 and HTTP 400. Clients built on a maintained MCP SDK do this automatically.

The tools

Twenty-two tools exist, in three classes: read tools, which change nothing; draft tools, which create something inert that a person still has to act on; and acting tools, which make a financial fact true and are offered only to companies that chose the level Act within a limit. tools/list returns only the tools the credential's scopes and the company's level permit; a key with invoices:read alone sees the invoice readers and nothing else, and a company at the default level never sees an acting tool. The scopes are the same ones the REST API uses.

ToolClassWhat it doesScope
search_customersreadFind customers by part of a name, number, town or VAT ID; exact containment, never fuzzy.customers:read
get_customerreadOne customer's master data: name, contact, address, VAT ID, currency.customers:read
list_invoicesreadIssued invoices, newest first, with totals, due dates and payment state; filters by state and issue date.invoices:read
get_invoicereadOne issued invoice by number or identifier: totals, outstanding amount, overdue and cancelled flags.invoices:read
get_invoice_draftreadA draft as the books hold it: every line with the quantity, unit price, tax category and rate that were stored, plus the totals the issuing engine computes — or why it cannot be issued yet.invoices:read
list_transactionsreadThe company's transactions (jobs and orders) with stage, customer and due date.transactions:read
get_transactionreadOne transaction by number or identifier.transactions:read
list_receivablesreadWhat customers owe, aged into overdue buckets, reconciling with the receivables control account.reports:read
list_payablesreadWhat the company owes suppliers, aged the same way.reports:read
get_profit_and_lossreadProfit and loss for a period from the ledger, with an is_final flag that is true only when every period in the window is closed.reports:read
get_balance_sheetreadBalance sheet on a date from the ledger.reports:read
get_business_attentionreadWhat is waiting on a person: outstanding, due soon and overdue in both directions, plus non-empty queues; books_open says whether the accounts have been opened at all.reports:read
create_invoice_draftdraftA draft invoice for a customer, optionally with lines (quantity, net unit price and VAT rate as decimal strings). No number is spent, nothing is produced or sent.invoices:write
create_transactiondraftA new transaction (job or order) with a title, optional customer, stage, description and due date.transactions:write
add_transaction_notedraftAppend a note to a transaction's timeline; changes no field.transactions:write
create_quote_draftdraftA draft quote for a customer, optionally with lines, currency, the customer's reference and a transaction to list it under. A number is reserved; nothing is sent.invoices:write
record_billdraftA supplier's bill with its figures as printed — net, tax, gross, optional lines — and, optionally, the file it arrived as and a transaction to list it under. It awaits a person's confirmation; nothing is paid.transactions:write
attach_documentdraftKeep a file — a waybill, a purchase order, a supplier's quote — with a transaction, bill, customer or supplier. No figure changes.transactions:write
link_to_transactiondraftList a quote, invoice draft, bill, expense or received document on a transaction's page. A cross-reference only.transactions:write
issue_invoiceactIssue a draft: spend the number, freeze the document, create the legal record. Refused when the gross total is above the company's per-act limit; then nothing is issued and no number is spent.invoices:write
send_invoiceactE-mail an issued invoice to the customer's address on record (or one given), with the payment link where the company has one.invoices:write
record_paymentactRecord that a customer paid an invoice: posts to the ledger and settles the receivable. Refused above the per-act limit. Accepts an idempotency key.invoices:write

Amounts are returned as a count of minor units with a currency code — {"minor": 105910, "currency": "EUR"} is 1,059.10 EUR — never as a formatted string. Dates are calendar days in YYYY-MM-DD. Every object a draft tool creates is recorded as created by that API key, and the company can see that attribution in the product. A model cannot pass off its work as a person's.

Levels and safety boundaries

The company, not the agent and not KRONENWERK, decides how far software may go. Under Settings → AI assistants the owner sets one of three levels, and the setting applies to every connected assistant and key alike:

  • Read only — the twelve read tools. Drafts are switched off; a draft call answers with a sentence saying so.
  • Read and propose (default) — read tools plus the seven draft tools. Nothing an agent does at this level is a financial fact; a person issues, sends and records.
  • Act within a limit — adds issue_invoice, send_invoice and record_payment. Each single act is checked against a gross amount limit in the company's base currency, inside the act's own transaction, so an invoice that adds up to more than the limit is rolled back whole: no number spent, no record, no e-mail.

Whatever the level, no tool cancels or corrects an issued document, approves or pays a supplier bill, posts a journal, closes a period, or creates, rotates or revokes credentials and settings. Those stay with a person signed in to KRONENWERK.

When a model asks for an act the company has not allowed — record_payment at the default level, cancel_invoice at any level — the server does not answer "unknown tool", which a model reads as a naming problem and retries around. It answers with a normal result marked isError: true whose text states the rule, says that no part of the request was carried out, and names the setting a person would change. The model relays something true and stops.

Every act and every draft is written to the company's authorship record with the tool, the connection and the time, and the services beneath write their usual audit rows under the connection rather than under a person, so the trail always says which assistant did what. Other properties follow from the transport: reads are scoped by the same permissions as the equivalent screen; identifiers belonging to another company are reported as not found rather than as forbidden; internal failures are described in one fixed sentence with no stack trace, so table names and file paths never enter a model's context; and a connection can be revoked at any moment in Settings, which ends that agent's access on the next request. The same rules that govern the REST API apply — see API security.

Connecting a client

Most MCP clients accept a JSON configuration naming remote servers. A generic entry for KRONENWERK looks like this; the key names of the outer object vary by client, the inner fields do not:

{
  "mcpServers": {
    "kronenwerk": {
      "type": "http",
      "url": "https://kronenwerk.org/api/extern/mcp",
      "headers": {
        "Authorization": "Bearer greif_live_XXXXXXXXXXXXXXXXXXXXXXXX"
      }
    }
  }
}

Use a greif_test_ key while building. It reaches the same endpoint in test mode for the company that created it; there is no separate sandbox host. Create the key with only the scopes the agent needs: an assistant that answers "who owes us money" needs reports:read and customers:read and nothing more.

Without a client, the endpoint can be exercised with curl. A legacy-style handshake and a tool call:

curl -s https://kronenwerk.org/api/extern/mcp \
  -H "Authorization: Bearer greif_test_XXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize",
       "params":{"protocolVersion":"2025-11-25","capabilities":{},
                 "clientInfo":{"name":"curl","version":"1"}}}'

curl -s https://kronenwerk.org/api/extern/mcp \
  -H "Authorization: Bearer greif_test_XXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
       "params":{"name":"list_receivables","arguments":{"as_of":"2026-09-03"}}}'

The result of the second call carries the report both as readable text in content and as JSON in structuredContent. A client on the current revision sends the same messages with the version in params._meta["io.modelcontextprotocol/protocolVersion"] and the mirrored headers; the server answers either form.

MCP or REST: which to use

Use MCP when a language model decides at run time what to ask. Use the REST API when your own code decides. The two surfaces read the same data under the same key and scopes, so nothing forces a choice, and a system may use both.

MCP serverREST API
CallerAn AI agent through an MCP clientYour application code
Address/api/extern/mcp, unversioned; MCP carries its own version/api/extern/v1
ReadsCustomers, invoices, transactions, receivables, payables, P&L, balance sheet, attention listCustomers, invoices, transactions, outstanding report, key info
WritesInvoice draft (with lines), transaction, note; with the acting level: issue, send, record paymentCustomer, invoice draft (customer only), transaction
IdempotencyNot applicable; the client retries under the model's controlIdempotency-Key header, required on POST
EventsNone; the server never pushesSigned webhooks

The REST surface is described in the accounting API overview, the reference and the quick start. Application-level integration patterns are covered in connecting your SaaS.

How KRONENWERK handles this

SUPPORTED The MCP server is live at https://kronenwerk.org/api/extern/mcp for companies on the Enterprise plan, speaks Streamable HTTP for protocol revisions 2026-07-28, 2025-11-25, 2025-06-18 and 2025-03-26, authenticates with OAuth 2.1 or an API key, and offers the twelve read tools and seven draft tools to every company and the three acting tools to companies that allowed acting under Settings → AI assistants, each act bounded by the company's own limit and recorded. Cancelling, correcting, paying suppliers, posting, closing and configuring remain without any tool by design. The same server works with a greif_test_ key in test mode. The MCP server, the REST API, webhooks and the integration directory are part of the Enterprise plan; see pricing and the developer overview.

Frequently asked questions

Can an agent issue an invoice through the MCP server?

Only if the company allows it. At the default level it can create a draft, with lines, for a customer, and a person reviews and issues the draft in KRONENWERK, where it is validated as a structured e-invoice for the seller's country. If the owner sets the level Act within a limit, the agent may issue, send and record payments itself, each act up to the gross amount the company set; above it the request is answered with a written refusal and nothing is done.

Which MCP clients work with it?

Any client that implements Streamable HTTP and lets you set an Authorization header. The server accepts both the current per-request protocol revision and the older handshake-based ones, so clients built on either era connect.

Does the MCP server need its own API key?

No. It uses the REST API's keys and scopes. It is good practice to create a separate, narrowly scoped key per agent so that it can be revoked on its own.

Is there a sandbox?

A greif_test_ key reaches the same endpoint in test mode for the company that created it. There is no separate host.

Why does my client get 405 on GET?

The server offers no server-to-client stream and no session, so the optional GET stream and the DELETE session terminator answer 405, which the specification designates for that case. Clients fall back to plain POST responses.

What does the agent see about other companies I manage?

Nothing. A key is bound to one company; an agent with that key cannot list, select or reach any other. Multi-company setups use one key per company.

Sources

  1. Model Context Protocol — Versioning read on
  2. Model Context Protocol — Transports (Streamable HTTP) read on
  3. KRONENWERK developer documentation read on

Start integrating

Read the quickstart Reference

Read next