Endpoint

Endpointhttps://mcp.ledger17.com/mcp
TransportStreamable HTTP
Authorization serverhttps://auth2.sirktek.com

Authorization

The server is an OAuth2 protected resource — it issues nothing and stores nothing. Every request must carry a bearer JWT, which the server validates (issuer, signature, expiry, audience) before any tool runs. The token is then forwarded verbatim to the command and query APIs together with the resolved tenant as X-Tenant-ID.

Permissions are enforced upstream, exactly as for direct API calls: reads require {orgId}:read:ledger, writes require {orgId}:write:ledger — see Authentication. A 403 from the APIs is surfaced to the model unchanged. The MCP server adds no permission logic of its own.

A client does not need the authorization server configured manually — it discovers it from the protected-resource metadata:

  https://mcp.ledger17.com/.well-known/oauth-protected-resource
  

A rejected call answers 401 with a WWW-Authenticate header pointing at that same document.

Which tenant a call acts in

The tenant is resolved from the token’s organization claim:

  • One membership — a user who belongs to a single organization, or an API key (always bound to one) — is used automatically. Nothing to configure.
  • Several memberships — tools then require an explicit organizationId argument; the assistant lists the options with organization_list and lets you choose.

An explicitly requested organization is always forwarded as given — membership is the ledger APIs’ verdict, and their refusal is shown unchanged.

Tools

ToolUpstreamWhat it answers
organization_list(token only)which ledger tenants the caller may act in
balance_summaryquery GET /balances/summarytrial balance: opening / movement / closing per account
balance_bucketsquery GET /balances/bucketsbalances bucketed inside an outer period (trends)
transaction_linesquery GET /transactionsgeneral-ledger drill-down: individual debit/credit lines
subledger_rollupquery GET /subledgersubledger per customer / supplier / employee / asset
party_exposurequery GET /parties/{id}/exposureone party’s receivable / payable / net
report_listquery GET /reports/{domain}which reports a domain offers
report_generatequery GET /reports/{domain}/{name}income statement, balance sheet, årsregnskap
transaction_recordcommand POST /transactionswrites: record balanced transaction blocks
transaction_correctcommand POST /transactions/{id}/correctionswrites: compensating reversal of a recorded block
rule_setscommand GET /rule-setsregistered domain rule sets

The admin API is deliberately absent — an agent can keep the books, not administer the tenant.

All amounts are integer minor units (øre for NOK), debit-positive — the server’s instructions state this up front, because it is the single most damaging thing for a model to get wrong in a ledger. See Core concepts.

Freshness and timeouts

Nothing is cached — what the assistant reads is the ledger as it stands right now. Calls forwarded to the APIs time out after 10 seconds.

Next