LedgerLou Docs is optimized for desktop.

Please open this page on a device with a wider screen.

Scope Design

Every AI app accessing LedgerLou via MCP gets exactly the scopes it needs for its task — and no more. Scopes are the central security layer: they decide which tools an agent may call before even a single line is written to the general ledger.

The scope format

Scopes follow the format module:action. Each combination of module and action controls exactly what an agent is allowed to read or write:

module : action
ScopeAllows
journal:readRead journal entries and chart-of-accounts tools
journal:writeExecute journal entries and chart-of-accounts write operations
bank:readRead bank accounts and transactions
bank:writeReconcile and match bank transactions
payables:readRead vendors, incoming invoices and the AP inbox
payables:writeCreate vendors, incoming invoices, invoice-review cases
receivables:readRead customers and outgoing invoices
receivables:writeCreate customers, outgoing invoices, credit notes
periods:readRead period status and lock state
periods:writeSoft-lock and reopen periods, request a hard lock
reports:readTrial balance, P&L, balance sheet, BWA, DATEV export
config:readRead tenant settings, users, API keys (not available via OAuth)
config:writeWrite tenant settings, migration, tax-code changes (not available via OAuth)
adminGlobal superscope — covers all modules and actions

OAuth exclusion. The config:* scopes cannot be requested via the OAuth flow — managing users, API keys, and tenant-level accounting context belongs in the Dashboard or behind an admin API key. Third-party MCP clients that need migration or tax-code changes must use a tenant-issued admin API key.

Refresh tokens. OAuth clients receive both an access_token (30 min default) and a rotating refresh_token (30 days default) on every authorization-code exchange. Hitting /oauth/token with grant_type=refresh_token consumes the presented refresh token and returns a fresh access/refresh pair sharing the same token family. Replaying a consumed refresh token revokes the entire family, so a stolen copy cannot extend an attacker's session.

CIMD. LedgerLou also accepts a Client ID Metadata Document URL as client_id, so MCP clients that publish their metadata publicly do not need to register individually per tenant. The document is fetched once over HTTPS (5 s timeout, 256 KiB cap, SSRF guard), validated against a Zod schema, cached for 24 hours, and revalidated with If-None-Match. The admin superscope and config:* are never granted via CIMD — admin capabilities still require a tenant-issued admin key.

Recommended role separation

Instead of one universal key per AI integration, we recommend a clear role separation: one agent, one purpose, minimal scopes.

Analysis agent
bank:read journal:read reports:read

Reads data, builds reports, answers questions, and can also look up the chart of accounts. Cannot write anything — no risk of incorrect postings.

Posting agent
journal:write payables:write receivables:write bank:write

Creates journal entries, maintains vendors/customers, posts incoming and outgoing invoices, and reconciles bank transactions. No access to admin or tenant-configuration functions.

Scopes gate skill visibility

Beyond gating which tools a caller can invoke, scopes also gate which skills (MCP prompts) appear in prompts/list. A skill is only exposed when the caller holds all of its required scopes. This keeps the agent's palette focused and prevents it from loading playbooks it could not execute anyway.

SkillRequired scopes
process_incoming_invoicepayables:read, payables:write, journal:read, journal:write
process_outgoing_invoicereceivables:read, receivables:write, journal:write, bank:read, bank:write
reconcile_bank_transactionsbank:read, bank:write, journal:read
tenant_setup_migrationadminadmin-only; invisible to OAuth clients because it needs config:write

The admin superscope satisfies every skill's requirements. OAuth clients never see tenant_setup_migration because the migration capability mutates tenant-level configuration, which is reserved for the Dashboard and admin-keyed MCP clients.

Guardrails that have proven themselves

Least privilege

Every agent gets only the scopes it needs for its specific job. An analysis agent does not need write; a posting agent does not need admin.

Human-in-the-loop for write actions

Sensitive tools — especially write operations on the general ledger — should always require explicit user confirmation before the agent executes them.

No shared universal keys

Use a dedicated key/token per integration. That way, if there's a suspicion, a single key can be revoked without disrupting other integrations.

Keys only in server environments

Never keep production keys in the frontend, in browser extensions, or in client-side code. MCP connections belong on the server, not in the user's app.

Key strategy in practice

  • 1 Create a dedicated API key or OAuth client per integration — never share one key across systems.
  • 2 Select scopes deliberately at connect time: grant only the modules the agent actually needs.
  • 3 Rotate keys regularly — especially after team changes or when replacing an integration.
  • 4 On suspicion of compromise, revoke immediately: Dashboard → Connected Apps → revoke connection.
Why this matters

LedgerLou manages GoBD-relevant bookkeeping data. An agent with overly broad scopes can, in a failure case, generate postings that are hard to undo — the general ledger is append-only. Clear scope design is therefore not a nice-to-have but part of the compliance architecture.