Skip to main content
Glama
Buchhaltungsbutler MCP

Buchhaltungsbutler MCP

ohneben's Buchhaltungsbutler MCP

Buy Me A Coffee


Lizenz & Checks

CI Lizenz: MIT

MCP-Register

MCP Registry Listed on mcpservers.org Buchhaltungsbutler-MCP MCP server

Paketkennungen

Dieser Server hat eigene Kennungen. Was anders heißt, gehört nicht dazu:

Wo

Kennung

MCP-Register

io.github.ohneben/buchhaltungsbutler-mcp

Container (GHCR)

ghcr.io/ohneben/buchhaltungsbutler-mcp

npm

@ohneben/buchhaltungsbutler-mcp (noch nicht veröffentlicht)

Das npm-Paket buchhaltungsbutler-mcp ohne Scope ist ein anderes Projekt eines anderen Autors (mrvnklm/buchhaltungsbutler-mcp) und hat mit diesem hier nichts zu tun. Verzeichnisse, die von dieser Seite dorthin verlinken, verlinken auf das falsche Paket.

Verwalte deine BuchhaltungsButler-Buchhaltung in natürlicher Sprache aus KI-Assistenten wie Claude, Cursor und jedem anderen MCP-Client.

Dieser Model-Context-Protocol-Server stellt die BuchhaltungsButler API v1 bereit — alle 54 Endpunkte als 46 MCP-Tools, aus der offiziellen OpenAPI-Spezifikation (Spec-Version 1.9.1) generiert. Jedes Tool ist sicherheitskategorisiert (nur lesend / schreibend / destruktiv), damit dein Assistent weiß, was eine Aktion tut, bevor er sie ausführt. Läuft über stdio (Claude Desktop und andere lokale Launcher) oder Streamable HTTP (gehostet in Docker).

Warum dieser Server

Manche MCP-Server leiten eine API einfach nur weiter. Dieser hier ist darauf ausgelegt, gefahrlos an ein Sprachmodell übergeben und im Alltag betrieben werden zu können:

Was du bekommst

Warum das zählt

Alle 54 Endpunkte, automatisch generiert aus der offiziellen Spec

Vollständige Abdeckung von Belegen, Transaktionen, Buchungen, Rechnungen, Auswertungen und Stammdaten. Nichts handverlesen, nichts vergessen.

Jedes Tool ist sicherheitskategorisiert 🟢 / 🟡 / 🔴

Ein Banner am Anfang jeder Tool-Beschreibung sagt dem Modell genau, was passiert — lesen, anlegen, ändern, zurücknehmen oder löschen — bevor es handelt.

Maschinenlesbare MCP-Annotationen (readOnlyHint, destructiveHint)

Hosts, die Annotationen auswerten (Claude gehört dazu), können Lesezugriffe automatisch zulassen und vor destruktiven Aktionen eine Bestätigung verlangen.

Zwei Transporte: stdio und Streamable HTTP

Lokal in Claude Desktop nutzen — oder einen dauerhaft laufenden Server betreiben, den beliebig viele MCP-Clients über HTTP erreichen.

Docker + docker-compose, Health-Check, Auto-Restart

Produktionsnahes Deployment ab Werk: docker compose up, und er bleibt oben.

Bearer-Token-Authentifizierung am HTTP-Endpunkt

Pflicht, sobald der Server über Loopback hinaus gebunden ist: ohne MCP_AUTH_TOKEN verweigert er den Start, statt die API ungeschützt bereitzustellen.

Eingebautes Rate-Limiting

Drosselt sich selbst unter dem BuchhaltungsButler-Limit von 100 Anfragen/Kunde/Minute, damit du nie dagegenläufst.

Deine Zugangsdaten erreichen das Modell nie

Die Credentials liegen in der Server-Umgebung und werden pro Anfrage injiziert — der Assistent sieht nur Tool-Eingaben und API-Antworten.

Im Vergleich

Nach aktuellem Stand ist dies der einzige dedizierte BuchhaltungsButler-MCP-Server. Alternativ könntest du einen generischen OpenAPI→MCP-Wrapper auf die Spec richten — das lässt allerdings einiges liegen:

Fähigkeit

Dieses Projekt

Generischer OpenAPI→MCP-Wrapper*

Alle 54 BuchhaltungsButler-Endpunkte abgedeckt

✅

✅

🟢 / 🟡 / 🔴 Sicherheitskategorie + Banner pro Tool

✅

❌

readOnlyHint / destructiveHint MCP-Annotationen

✅

➖

$ref-Auflösung für Batch-Payloads + HTML-bereinigte Beschreibungen

✅

➖

Eingebautes Rate-Limiting (bleibt unter BBs 100/Kunde/Min.)

✅

❌

stdio-Transport

✅

✅

Streamable-HTTP-Transport

✅

➖

Docker + docker-compose, Health-Check, Auto-Restart

✅

❌

Erzwungene Bearer-Token-Auth am Endpunkt

✅

❌

Credentials serverseitig injiziert, nie ans Modell gesendet

✅

➖

Lizenz

MIT

unterschiedlich

*Generische OpenAPI→MCP-Wrapper machen aus jeder Swagger-/OpenAPI-Spec MCP-Tools. Sie erreichen dieselben Endpunkte, behandeln aber jede Operation gleich — keine Sicherheitskategorien, keine Betriebsgeschichte, keine auf echte Buchhaltungsdaten abgestimmten Leitplanken. „➖“ = je nach Werkzeug unterschiedlich / nicht garantiert.

Related MCP server: sevdesk-mcp

Was du damit machen kannst

Sobald der Server verbunden ist, kannst du deinen Assistenten zum Beispiel bitten:

  • „Liste alle Eingangsbelege vom letzten Monat auf, die noch offen sind.“

  • „Erstelle einen Rechnungsentwurf für die ACME GmbH: 10 Stunden Beratung à 120 €.“

  • „Buche diese Banktransaktion auf Sachkonto 4400.“

  • „Lade diesen PDF-Beleg hoch und ordne ihn der passenden Transaktion zu.“

  • „Zeig mir meine Kreditoren und leg einen neuen für unseren Hosting-Anbieter an.“

  • „Erstelle mir die BWA für das letzte Quartal und zeig mir das Kontenblatt zu Konto 4400.“

Die Tools werden automatisch aus der offiziellen API generiert und in 🟢 nur lesend, 🟡 schreibend und 🔴 destruktiv gruppiert — ein gut umgesetzter Host kann jede Gruppe unterschiedlich behandeln.

Funktionsweise

Claude / Cursor / beliebiger MCP-Client  ──MCP──►  dieser Server  ──HTTPS──►  BuchhaltungsButler API (Cloud)

Der Server liest die mitgelieferte OpenAPI-Spec ein und macht daraus MCP-Tools (inklusive Auflösung von $ref-Batch-Payloads und Entfernen von HTML aus den Beschreibungen), versieht jedes Tool mit seiner Sicherheitskategorie und hängt deine Basic-Auth-Credentials sowie den api_key an jede ausgehende Anfrage. Deine Zugangsdaten bleiben in der Server-Umgebung — das Modell sieht sie nie und fasst sie nie an.

Voraussetzungen

  • Ein BuchhaltungsButler-Konto mit API-Zugang — ein API Client + API Secret (Einstellungen → API) sowie ein Kunden-api_key (siehe API-Zugangsdaten besorgen).

  • Docker (Docker Desktop unter macOS/Windows) für den Schnellstart unten — oder Node.js ≥ 18, um aus dem Quellcode zu starten.

Schnellstart (Docker)

1. Zugangsdaten hinterlegen. Beispielkonfiguration kopieren und ausfüllen:

cp .env.example .env
# .env bearbeiten → BB_API_CLIENT, BB_API_SECRET, BB_API_KEY setzen
#                 → MCP_AUTH_TOKEN setzen. PFLICHT, sonst startet der Server
#                   nicht, denn .env.example bindet auf 0.0.0.0:
#                   openssl rand -hex 32

2. Server starten:

docker compose up -d --build

3. Prüfen, ob er läuft:

curl -s http://localhost:3000/health     # → {"status":"ok","server":"buchhaltungsbutler-mcp"}

4. MCP-Client verbinden. Entfernte Endpunkte werden in Claude als Custom Connector hinzugefügt (Einstellungen → Connectors) oder lokal mit mcp-remote gebrückt. Trage Folgendes unter mcpServers in deiner Client-Konfiguration ein und starte die App danach vollständig neu:

{
  "mcpServers": {
    "buchhaltungsbutler": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "http://localhost:3000/mcp",
        "--header", "Authorization: Bearer DEIN_MCP_AUTH_TOKEN"
      ]
    }
  }
}

(Die --header-Zeile entfällt nur, wenn du ohne Token auf Loopback bindest. Im Docker-Schnellstart oben ist das Token Pflicht.)

Lieber ein fertiges Image?

Jeder Push auf main veröffentlicht ein startbereites Image in der GitHub Container Registry — damit kannst du den lokalen Build komplett überspringen:

docker run -d --name buchhaltungsbutler-mcp -p 3000:3000 --env-file .env \
  ghcr.io/ohneben/buchhaltungsbutler-mcp:latest

API-Zugangsdaten besorgen

BuchhaltungsButler nutzt zwei Authentifizierungsebenen (siehe die offizielle Dokumentation):

  1. HTTP-Basic-Auth — ein API Client + API Secret, deine globalen API-Zugangsdaten. Zu finden bzw. anzulegen in BuchhaltungsButler unter Einstellungen → API.

  2. api_key — legt fest, auf welches Kundenkonto sich eine Anfrage bezieht. Er steht in den Firmendaten-Einstellungen des jeweiligen Kunden.

Trage alle drei Werte in .env ein. Der Server hängt sie an jede Anfrage an, dein Assistent bekommt sie also nie zu sehen. Ein einzelner Tool-Aufruf kann optional einen eigenen api_key mitgeben, um ein anderes Kundenkonto anzusprechen.

Konfiguration

Alles wird in .env gesetzt (kopiert aus .env.example):

Variable

Pflicht

Standard

Beschreibung

BB_API_CLIENT

✅

—

API Client (Basic-Auth-Benutzername)

BB_API_SECRET

✅

—

API Secret (Basic-Auth-Passwort)

BB_API_KEY

✅

—

Standard-Kunden-api_key

MCP_TRANSPORT

—

stdio

stdio oder http (das Docker-Image nutzt standardmäßig http)

PORT

—

3000

HTTP-Port, auf dem gelauscht wird

HOST

—

0.0.0.0

HTTP-Bind-Adresse

MCP_HTTP_PATH

—

/mcp

HTTP-Route für MCP

MCP_AUTH_TOKEN

⚠️

(aus)

Verlangt Authorization: Bearer <Token> auf /mcp. Pflicht, wenn HOST keine Loopback-Adresse ist — sonst startet der Server nicht

MCP_ALLOWED_HOSTS

—

(automatisch)

Erlaubte Host-Header, kommagetrennt (Schutz vor DNS-Rebinding). Nötig hinter einem Reverse-Proxy

MCP_ALLOW_INSECURE

—

(aus)

Hebt die Startverweigerung ohne Token auf. Nur für nachweislich unerreichbare Endpunkte

MCP_SESSION_TTL

—

1800

Sekunden Leerlauf, bevor eine Session verworfen wird

MCP_MAX_SESSIONS

—

256

Obergrenze gleichzeitiger Sessions

BB_ALLOW_API_KEY_OVERRIDE

—

(aus)

Erlaubt einem Tool-Aufruf, den api_key zu überschreiben

BB_RATE_LIMIT

—

90

Clientseitiges Limit an Anfragen pro Minute

BB_READ_TIMEOUT_MS

—

55000

Gesamtbudget eines Lese-Tools in Millisekunden, über alle Versuche. Liegt unter den 60 s, nach denen der SDK-Client aufgibt

BB_READ_RETRIES

—

2

Weitere Versuche eines Lese-Tools nach Timeout, Netzwerkfehler oder HTTP 429/502/503/504 (max. 5), solange das Budget reicht. Bricht der Client ab, startet kein weiterer Versuch. Schreib-Tools werden nie wiederholt und haben kein Timeout

BB_BASE_URL

—

(aus der Spec)

Überschreibt die Basis-URL der API

Nach Änderungen an .env neu laden mit docker compose up -d --force-recreate.

Toolnamen

Jedes Tool heißt <ressource>_<verb>. Die Verben sind fest: list, get, create, update, delete, upload, assign, unassign, unconfirm, restore, cancel. Damit heißt dieselbe Sache überall gleich, unabhängig davon, wie der jeweilige BB-Pfad geschrieben ist (die API mischt add und create, und zwei Batch-Pfade sind camelCase).

Anlegen geht immer über ein Tool, das eine Liste nimmt. receipts_create legt einen Beleg oder hundert an, ein einzelner Datensatz ist eine Liste mit einem Eintrag. Deshalb gibt es 46 Tools für 54 Endpunkte: acht Einzel-Endpunkte sind in ihrem Batch-Gegenstück aufgegangen.

Alte Namen bleiben aufrufbar

Die Namen bis 1.1.1 funktionieren weiter. Sie stehen nicht mehr im Katalog, werden aber beim Aufruf aufgelöst, damit fest verdrahtete Aufrufe aus älteren Releases nicht ins Leere laufen. Ein Aufruf von receipts_add mit Einzelfeldern landet weiterhin auf /receipts/add.

BB_READ_ONLY und BB_TOOL_ALLOWLIST greifen vorher: über einen alten Namen lässt sich kein Tool erreichen, das die Policy ausschließt.

Alt (bis 1.1.1)

Neu

accounts_get

accounts_list

receipts_get

receipts_list

receipts_get_id_by_customer

receipts_get_by_id

receipts_add, receipts_addBatch

receipts_create

transactions_add, transactions_addBatch

transactions_create

settings_get_creditors

creditors_list

settings_add_creditor, settings_add_batch_creditors

creditors_create

settings_get_postingaccounts

postingaccounts_list

postings_add_free, postings_add_batch_free

postings_create_free

transactions_assign_receipt, transactions_assign_batch_receipt

transactions_assign_receipts

Die vollständige Zuordnung steht in src/naming.ts.

Sicherheitskategorien der Tools

Jede Tool-Beschreibung beginnt mit einem dieser Banner und trägt die passenden MCP-Annotationen:

Banner

Anzahl

readOnlyHint

destructiveHint

Bedeutung

🟢 READ-ONLY

15

true

false

Ruft nur Daten ab. Ungefährlich.

🟡 WRITE · legt Daten an

17

false

false

Erzeugt Datensätze (nicht idempotent, mehrfach aufgerufen entstehen Duplikate).

🟡 WRITE · ändert Daten

4

false

false

Aendert bestehende Stammdaten direkt.

🟡 WRITE · verknüpft/löst

3

false

false

Ordnet Beleg und Transaktion zu bzw. hebt die Zuordnung auf. Umkehrbar.

🟡 WRITE · nimmt Zustand zurück

4

false

false

Setzt Buchungen auf unbestätigt / stellt Belege wieder her. Umkehrbar.

🔴 DESTRUCTIVE · löscht

3

false

true

Löscht oder storniert einen Datensatz. Vorher bestätigen lassen.

Hosts, die Annotationen respektieren (Claude gehört dazu), können für destructiveHint-Tools eine Bestätigung verlangen und readOnlyHint-Tools automatisch vertrauen.

Jedes Tool bringt zusätzlich ein outputSchema mit, also die Form der Erfolgsantwort. Erfolgreiche Aufrufe liefern die Antwort deshalb nicht nur als Text, sondern auch als structuredContent.

Mit npm run list-tools (ohne Zugangsdaten) lässt sich der vollständige Katalog jederzeit ausgeben.

Tool

Endpunkt

accounts_list

POST /accounts/get

cost_locations_list

POST /cost-locations/get

creditors_list

POST /settings/get/creditors

debtors_list

POST /settings/get/debtors

postingaccounts_list

POST /settings/get/postingaccounts

postings_list

POST /postings/get

receipts_get_by_id

POST /receipts/get/id_by_customer

receipts_list

POST /receipts/get

receipts_list_assigned_transactions

POST /receipts/assigned-transactions/get

reports_get_bwa

POST /reports/get/bwa

reports_get_sums

POST /reports/get/sums

reports_get_sums_ledger

POST /reports/get/sums/ledger

transactions_get_by_id

POST /transactions/get/id_by_customer

transactions_list

POST /transactions/get

transactions_list_assigned_receipts

POST /transactions/assigned-receipts/get

Tools mit zwei Endpunkten nehmen eine Liste. Kommt der Aufruf stattdessen mit Einzelfeldern, geht er an den Einzel-Endpunkt.

Tool

Endpunkt

Einzel-Endpunkt

accounts_create

POST /accounts/add

comments_create

POST /comments/add

cost_locations_create

POST /cost-locations/add

creditors_create

POST /settings/add-batch/creditors

POST /settings/add/creditor

debtors_create

POST /settings/add-batch/debtors

POST /settings/add/debtor

invoices_create

POST /invoices/create

invoices_create_draft

POST /invoices/create/draft

invoices_create_e_invoice

POST /invoices/create/e-invoice

postingaccounts_create

POST /settings/add/postingaccount

postings_create_for_receipt

POST /postings/add-batch/receipts

POST /postings/add/receipt

postings_create_for_transaction

POST /postings/add-batch/transactions

POST /postings/add/transaction

postings_create_free

POST /postings/add-batch/free

POST /postings/add/free

receipts_create

POST /receipts/addBatch

POST /receipts/add

receipts_upload

POST /receipts/upload

reports_create_bwa

POST /reports/create/bwa

reports_create_sums

POST /reports/create/sums

transactions_create

POST /transactions/addBatch

POST /transactions/add

Tool

Endpunkt

Unterkategorie

cost_locations_update

POST /cost-locations/update

ändert

creditors_update

POST /settings/update/creditor

ändert

debtors_update

POST /settings/update/debtor

ändert

postingaccounts_update

POST /settings/update/postingaccount

ändert

postings_assign_receipt_to_free

POST /postings/assign/receipt-to-free-posting

verknüpft

transactions_assign_receipts

POST /transactions/assign-batch/receipt

verknüpft

transactions_unassign_receipt

POST /transactions/unassign/receipt

verknüpft

postings_unconfirm_free

POST /postings/unconfirm/free

nimmt zurück

postings_unconfirm_for_receipt

POST /postings/unconfirm/receipt

nimmt zurück

postings_unconfirm_for_transaction

POST /postings/unconfirm/transaction

nimmt zurück

receipts_restore

POST /receipts/restore/id_by_customer

nimmt zurück

Tool

Endpunkt

Hinweis

receipts_delete

POST /receipts/delete/id_by_customer

Wiederherstellbar über receipts_restore

cost_locations_delete

POST /cost-locations/delete

Nicht wiederherstellbar

postings_cancel

POST /postings/cancel

Noch nicht festgeschriebene Buchungen werden gelöscht; festgeschriebene werden durch eine Stornobuchung ausgeglichen

Was die v1-API nicht kann

Diese Lücken stehen absichtlich auch in den Tool-Beschreibungen, damit das Modell nicht nach einem Endpunkt sucht, den es nicht gibt:

Ressource

Fehlt

Kreditoren, Debitoren, Buchungskonten

kein Löschen

Konten (accounts)

kein Aendern, kein Löschen

Kommentare

kein Lesen, kein Aendern, kein Löschen

Rechnungen

kein Lesen, kein Aendern, kein Stornieren

Transaktionen

kein Aendern, kein Löschen

Aus dem Quellcode starten (stdio, ohne Docker)

Du bevorzugst den klassischen stdio-Modus für Claude Desktop? Dann lokal bauen:

npm install
npm run build

Anschließend Claude Desktop in claude_desktop_config.json auf den kompilierten Einstiegspunkt zeigen lassen:

{
  "mcpServers": {
    "buchhaltungsbutler": {
      "command": "node",
      "args": ["/ABSOLUTER/PFAD/Buchhaltungsbutler MCP/dist/index.js"],
      "env": {
        "MCP_TRANSPORT": "stdio",
        "BB_API_CLIENT": "dein-api-client",
        "BB_API_SECRET": "dein-api-secret",
        "BB_API_KEY": "dein-kunden-api-key"
      }
    }
  }
}

Oder den Container stattdessen über stdio betreiben:

{
  "mcpServers": {
    "buchhaltungsbutler": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "MCP_TRANSPORT=stdio",
        "-e", "BB_API_CLIENT", "-e", "BB_API_SECRET", "-e", "BB_API_KEY",
        "buchhaltungsbutler-mcp:latest"
      ],
      "env": {
        "BB_API_CLIENT": "dein-api-client",
        "BB_API_SECRET": "dein-api-secret",
        "BB_API_KEY": "dein-kunden-api-key"
      }
    }
  }
}

(Das Image vorher bauen: docker build -t buchhaltungsbutler-mcp:latest .)

Spec aktuell halten

Die mitgelieferte spec.json ist die offizielle BuchhaltungsButler-v1-OpenAPI-Spec — die maßgebliche Quelle für die Tools. So aktualisierst du sie auf einen neueren API-Stand:

curl -s https://app.buchhaltungsbutler.de/docs/api/v1.de.json -o spec.json
npm run build

Neue Pfade werden automatisch übernommen; trage sie in PATH_CATEGORY in src/categories.ts ein, damit sie die richtige Sicherheitskategorie bekommen (nicht zugeordnete Pfade fallen konservativ auf die Kategorie create zurück).

Hinweis zur Versionsnummer: BuchhaltungsButler pflegt das Feld info.version in der Spec nicht zuverlässig — der Inhalt kann sich ändern, ohne dass die Nummer steigt. Verlass dich beim Abgleich also nicht auf die Version, sondern vergleiche die Pfadliste (paths) und die Parameter der Endpunkte.

Entwicklung

Hinweise zu korrigierten Buchungs- und Zuordnungsantworten, Teilfehlern und unklarem Schreibausgang: Belege buchen und Zahlungen zuordnen.

npm install
npm run build      # TypeScript → dist/ kompilieren
npm test           # Vitest-Suite ausführen
npm run list-tools # kategorisierten Tool-Katalog ausgeben (ohne Zugangsdaten)

Die CI baut und testet jeden Push unter Node 20 und 22; Pushes auf main veröffentlichen zusätzlich ein Docker-Image in der GitHub Container Registry.

Für eine ergänzende Prüfung mit einem eigenen API-Zugang siehe Lesende API-/MCP-Verifikation. Die normale Testsuite verwendet synthetische Daten und benötigt keine Zugangsdaten.

Hinweise & Konventionen

  • Datumsangaben: YYYY-MM-DD. Beträge: Punkt als Dezimaltrennzeichen (z. B. -12.30).

  • Datei-Uploads (receipts_upload): Die Datei wird als Base64-Zeichenkette im Feld file übergeben. receipts_create legt Belege ohne Datei an.

  • Blättern: Die meisten list-Tools akzeptieren limit und offset. Bei den geprüften Beleg-, Transaktions- und Buchungslisten zählt rows nur die aktuelle Seite, nicht den Gesamtbestand. Wiederholte IDs und fehlenden Fortschritt erkennen. Eine leere Abschlussseite und Deduplizierung beweisen keine Vollständigkeit: gefilterte Transaktionsseiten haben sich im Praxistest überschnitten, während andere IDs fehlten. Für transactions_list bevorzugt id_by_customer_from mit konstanten Filtern und limit, ohne offset, nutzen: Der Cursor ist exklusiv und erzwingt aufsteigende ID-Sortierung. Bei 0 beginnen, anschließend die größte erhaltene ID unverändert als nächsten Cursor setzen; IDs und Fortschritt prüfen, bis zur leeren Seite fortsetzen und unabhängig abstimmen. Details und Grenzen: lesende Verifikation.

  • Einzelabrufe: receipts_get_by_id und transactions_get_by_id benötigen id_by_customer als positive ganze Zahl aus dem jeweiligen Listentool. Der Server setzt diese Nummer in den API-Pfad ein.

  • Anlegen geht immer über ein Tool, das ein Array nimmt; die Item-Schemata werden aus den Spec-Definitionen aufgelöst und dem Modell mitgegeben. Ein einzelner Datensatz ist ein Array mit einem Eintrag.

  • Auswertungen (BWA, Summen- und Saldenliste) werden asynchron im Hintergrund erzeugt: erst reports_create_* aufrufen, dann reports_get_* mit der zurückgegebenen id_by_customer. Eine neue Auswertung desselben Typs ersetzt die vorherige.

  • Kontenblatt: reports_get_sums_ledger benötigt nur Buchungskontonummer und Zeitraum; die API liefert es direkt, ohne vorher erzeugte SuSa und ohne Berichts-ID.

  • Rate-Limit: BuchhaltungsButler erlaubt 100 Anfragen/Kunde/Minute; der Server drosselt sich selbst bei BB_RATE_LIMIT (Standard 90), um sicher darunter zu bleiben.

Sicherheit

  • Deine API-Zugangsdaten liegen ausschließlich in .env, und diese Datei ist von Git ausgeschlossen. Committe niemals echte Geheimnisse. Falls doch etwas abfließt, rotiere die Daten unter BuchhaltungsButler → Einstellungen → API.

  • Der HTTP-Endpunkt verlangt ein Token, sobald er über Loopback hinaus gebunden ist. Ohne MCP_AUTH_TOKEN verweigert der Server den Start und erklärt im Fehlertext, was zu tun ist. Sende das Token als Authorization: Bearer <Token>-Header, idealerweise hinter TLS.

  • Auch auf localhost gilt: ohne Token wird der Host-Header auf localhost-Namen begrenzt, damit keine beliebige Webseite den Endpunkt per DNS-Rebinding ansprechen kann. Hinter einem Reverse-Proxy setzt du dafür MCP_ALLOWED_HOSTS.

  • Hinter einem Reverse-Proxy setzt du den Host-Header im Proxy am besten fest auf den internen Upstream-Namen und trägst genau diesen in MCP_ALLOWED_HOSTS ein. Dann hängt die Prüfung nicht an der öffentlichen Domain und übersteht einen Domainwechsel. (Tipp von @WinFuture23.)

  • Setzt du MCP_ALLOWED_HOSTS und hat deine Plattform einen HTTP-Health-Check, muss dessen Hostname mit in die Liste. Railway sendet Host: healthcheck.railway.app, Kubernetes-Probes fragen je nach Konfiguration über die Container-IP an. Fehlt der Name, bekommt der Health-Check eine 403 und die Plattform wertet das Deployment als kaputt.

  • /health liegt hinter der Host-Prüfung, aber vor der Token-Prüfung: ein Health-Check der Plattform braucht kein Token. Zusätzlich akzeptiert /health immer localhost, 127.0.0.1 und [::1], damit der HEALTHCHECK aus dem mitgelieferten Dockerfile weiterläuft, wenn du MCP_ALLOWED_HOSTS auf deine öffentliche Domain setzt. Fragt dein Health-Check dagegen über die Container-IP oder einen Service-Namen an, musst du diesen Namen in MCP_ALLOWED_HOSTS aufnehmen.

  • Der api_key pro Tool-Aufruf ist standardmäßig deaktiviert (BB_ALLOW_API_KEY_OVERRIDE=1 schaltet ihn frei), damit das Modell nicht selbst entscheiden kann, auf welchen Mandanten geschrieben wird.

Die vollständige Richtlinie und den Meldeweg für Sicherheitslücken findest du in SECURITY.md.

Credits & Lizenz

Eine inoffizielle Community-Integration für BuchhaltungsButler; weder mit BuchhaltungsButler verbunden noch von dort unterstützt. Basiert auf dem Model Context Protocol. Veröffentlicht unter der MIT-Lizenz.

Available Tools

46 tools
accounts_createAccounts: add a basic accountA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

add a basic account

Use to register a new bank, cash or credit-card account before importing transactions for it.

Not for chart-of-accounts entries. To add a posting account number, use postingaccounts_create.

Not idempotent: calling twice with the same name creates two accounts. Check accounts_list first. v1 offers no way to update or delete an account afterwards.

Endpoint: POST /accounts/add

Inputs: name (required), type (required), postingaccount_number (required), is_revision_safe, +1 more. Returns: message, success, postingaccount_number

accounts_listAccounts: get all the accountsA
Read-onlyIdempotent

🟢 READ-ONLY: Fetches data. Makes no changes to the accounting records.

get all the accounts

Use to list the bank, cash and credit-card accounts that transactions can be booked against, e.g. to resolve an account name to the numeric account id the transaction tools expect.

Not the chart of accounts. For posting account numbers such as 1200 or 4400, use postingaccounts_list.

v1 offers no update or delete endpoint for accounts. An account created here can only be listed afterwards.

Endpoint: POST /accounts/get

Inputs: no named parameters. Returns: data, rows, message, success

comments_createComments: add comment to transaction or receiptA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

add comment to transaction or receipt

Add comment to transaction or receipt. NOTE: You have to submit either a transaction_id_by_customer or a receipt_id_by_customer.

Use to attach a free-text note to one receipt or one transaction, for example to record why a booking was categorised the way it was.

Exactly one of transaction_id_by_customer or receipt_id_by_customer must be set. v1 offers no endpoint to read, edit or delete comments, so a comment written here can only be seen in the BuchhaltungsButler web app.

Endpoint: POST /comments/add

Inputs: comment_text (required), receipt_id_by_customer, transaction_id_by_customer. Returns: message, success

cost_locations_createCost Locations: add cost locationA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

add cost location

Add a new cost location.

Use to create a cost centre before referencing it from a posting.

Not idempotent. Check cost_locations_list first to avoid a duplicate.

Endpoint: POST /cost-locations/add

Inputs: code (required), name (required). Returns: code, message, success

cost_locations_deleteCost Locations: delete cost locationA
DestructiveIdempotent

🔴 DESTRUCTIVE · deletes data: Deletes or cancels a record. Confirm with the user before calling. Receipt deletes are restorable; cost-location deletes are not. Cancelling a posting deletes it if it is not yet fixed, otherwise it books a reversal posting.

delete cost location

Delete a cost location.

Use to remove a cost centre that is no longer needed.

Permanent. Unlike a deleted receipt there is no restore endpoint, so confirm with the user before calling.

Endpoint: POST /cost-locations/delete

Inputs: code (required). Returns: message, success

cost_locations_listCost Locations: get cost locationsA
Read-onlyIdempotent

🟢 READ-ONLY: Fetches data. Makes no changes to the accounting records.

get cost locations

Get cost locations for a specified customer account. The response includes the number of returned rows and an array of cost locations data. NOTE: Each request is limited to 1000 cost locations!

Use to list the cost centres available for the cost_location fields on the posting tools.

Endpoint: POST /cost-locations/get

Inputs: code, limit, offset. Returns: data, rows, message, success

cost_locations_updateCost Locations: update cost locationA
Idempotent

🟡 WRITE · updates data: Modifies existing master data in place.

update cost location

Update a cost location's name/description.

Use to rename an existing cost centre or change its number.

Overwrites the fields you send. Read the current record with cost_locations_list first if you intend a partial change.

Endpoint: POST /cost-locations/update

Inputs: code (required), name (required). Returns: message, success

creditors_createSettings: create creditorA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

create creditor

Create a creditor account.

Use to create one or more suppliers.

For customers you invoice, use debtors_create.

Takes one or many: pass an array of creditors in creditors. A single record is an array of one.

Not idempotent: check creditors_list first, since a repeated call creates duplicate suppliers. v1 offers no delete endpoint, so a creditor created here can only be updated afterwards, never removed.

Endpoint: POST /settings/add-batch/creditors

Inputs: creditors (required). Returns: errors, success, creditors

creditors_listSettings: get creditorsA
Read-onlyIdempotent

🟢 READ-ONLY: Fetches data. Makes no changes to the accounting records.

get creditors

Get all creditors

Use to list suppliers, for example to resolve a supplier name to the creditor id the receipt and posting tools expect.

For customers you invoice, use debtors_list.

Supports limit and offset. Do not assume rows is the grand total. Continue paging until empty and check progress. v1 offers no delete endpoint for creditors, so they can only be created, listed and updated.

Endpoint: POST /settings/get/creditors

Inputs: limit, offset. Returns: data, rows, message, success

creditors_updateSettings: update creditorA
Idempotent

🟡 WRITE · updates data: Modifies existing master data in place.

update creditor

Update a creditor account.

Use to change a supplier's address, bank details or payment terms.

Overwrites the fields you send. Read the current record with creditors_list first if you intend a partial change.

Endpoint: POST /settings/update/creditor

Inputs: postingaccount_number (required), bic, zip, city, +9 more. Returns: data, message, success

debtors_createSettings: create debtorA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

create debtor

Create a debtor account.

Use to create one or more customers.

For suppliers you buy from, use creditors_create.

Takes one or many: pass an array of debtors in debtors. A single record is an array of one.

Not idempotent: check debtors_list first. v1 offers no delete endpoint, so a debtor created here can only be updated afterwards, never removed.

Endpoint: POST /settings/add-batch/debtors

Inputs: debtors (required). Returns: errors, debtors, success

debtors_listSettings: get debitorsA
Read-onlyIdempotent

🟢 READ-ONLY: Fetches data. Makes no changes to the accounting records.

get debitors

Get all debitors

Use to list customers, for example to resolve a customer name to the debtor id the receipt and posting tools expect.

For suppliers you buy from, use creditors_list.

Supports limit and offset. v1 offers no delete endpoint for debtors, so they can only be created, listed and updated.

Endpoint: POST /settings/get/debtors

Inputs: limit, offset. Returns: data, rows, message, success

debtors_updateSettings: update debtorA
Idempotent

🟡 WRITE · updates data: Modifies existing master data in place.

update debtor

Update a debtor account.

Use to change a customer's address, bank details or customer number.

Overwrites the fields you send. Read the current record with debtors_list first if you intend a partial change.

Endpoint: POST /settings/update/debtor

Inputs: postingaccount_number (required), bic, zip, city, +9 more. Returns: data, message, success

invoices_createInvoices: create invoiceA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

create invoice

Add an invoice for the specified customer.

Use to issue a final outgoing invoice that is booked immediately.

For an invoice that should stay editable, use invoices_create_draft. For a structured XML invoice in XRechnung or ZUGFeRD format, use invoices_create_e_invoice.

Not idempotent: a second call issues a second invoice with a new number. v1 offers no endpoint to list, change or cancel an invoice once created.

Endpoint: POST /invoices/create

Inputs: date (required), type (required), item_vat (required), item_name (required), +28 more. Returns: message, success, file_name, invoicenumber, +1 more

invoices_create_draftInvoices: create invoice draftA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

create invoice draft

Add an invoice draft for the specified customer.

Use to prepare an invoice that a human should review and release in the BuchhaltungsButler web app.

A draft is not booked and carries no invoice number. To issue a final invoice directly, use invoices_create.

v1 offers no endpoint to list, edit or release drafts. Releasing happens in the web app.

Endpoint: POST /invoices/create/draft

Inputs: date (required), type (required), item_vat (required), item_name (required), +25 more. Returns: message, success

invoices_create_e_invoiceInvoices: create e-invoiceA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

create e-invoice

Add an e-invoice for the specified customer.

Use when the recipient requires a structured electronic invoice, for example a German public-sector customer expecting XRechnung.

For an ordinary PDF invoice, use invoices_create.

Not idempotent. v1 offers no endpoint to list or cancel an e-invoice once created.

Endpoint: POST /invoices/create/e-invoice

Inputs: zip (required), city (required), date (required), type (required), +30 more. Returns: message, success, file_name, invoicenumber, +1 more

postingaccounts_createSettings: add postingaccountA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

add postingaccount

Create a postingaccount.

Use to add an account number to the chart of accounts that the standard chart does not cover.

To register a bank or cash account, use accounts_create.

Not idempotent. v1 offers no delete endpoint, so a posting account created here can only be updated afterwards.

Endpoint: POST /settings/add/postingaccount

Inputs: name (required), postingaccount_number (required), parent_postingaccount_number (required). Returns: message, success, postingaccount_number, parent_postingaccount_number

postingaccounts_listSettings: get postingaccountsA
Read-onlyIdempotent

🟢 READ-ONLY: Fetches data. Makes no changes to the accounting records.

get postingaccounts

Get all postingaccounts

Use to list the chart of accounts, for example to find the posting account number for office supplies before booking.

Not bank accounts. For the bank, cash and credit-card accounts transactions belong to, use accounts_list.

Supports limit and offset; a full SKR chart runs to several hundred rows. Do not assume rows is the grand total: continue paging until empty and check progress, or filter instead. v1 offers no delete endpoint for posting accounts.

Endpoint: POST /settings/get/postingaccounts

Inputs: limit, order, offset, exclude_debtors, +3 more. Returns: data, rows, message, success

postingaccounts_updateSettings: update postingaccountA
Idempotent

🟡 WRITE · updates data: Modifies existing master data in place.

update postingaccount

Update a postingaccount.

Use to rename a posting account or change its properties.

Overwrites the fields you send. Read the current record with postingaccounts_list first if you intend a partial change.

Endpoint: POST /settings/update/postingaccount

Inputs: name (required), postingaccount_number (required). Returns: data, message, success

postings_assign_receipt_to_freePostings: assign receipt to free postingA

🟡 WRITE · links/unlinks records: Creates or removes an assignment between records (e.g. receipt ↔ transaction). Reversible.

assign receipt to free posting

Assign a receipt to a free posting.

Use to attach a receipt to a free posting that was booked without one, so the entry has its supporting document.

To link a receipt to a bank transaction rather than a posting, use transactions_assign_receipts.

Endpoint: POST /postings/assign/receipt-to-free-posting

Inputs: posting_id_by_customer (required), receipt_id_by_customer (required). Returns: message, success

postings_cancelPostings: cancel postingA
DestructiveIdempotent

🔴 DESTRUCTIVE · deletes data: Deletes or cancels a record. Confirm with the user before calling. Receipt deletes are restorable; cost-location deletes are not. Cancelling a posting deletes it if it is not yet fixed, otherwise it books a reversal posting.

cancel posting

Cancel a specified posting. Postings that are not fixed are deleted, fixed postings are cancelled by creating a reversal posting.

Use to take a booking out of the books entirely.

This is stronger than the postings_unconfirm_* tools: those keep the posting and only clear its confirmation, this one removes or reverses it. Prefer unconfirming when the goal is to edit and rebook.

The effect depends on the posting: one that is not yet fixed is deleted outright, a fixed one stays and is offset by a reversal posting, which leaves two visible entries in the journal. Confirm with the user before calling.

Endpoint: POST /postings/cancel

Inputs: posting_id_by_customer (required). Returns: message, success

postings_create_for_receiptPostings: add receipt postingA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

add receipt posting

Add postings for a specified receipt. Important: Receipt postings are only available if creditor or debtor posting is activated!

IMPORTANT: If you add postings to a receipt with foreign currency, you have to get that receipt (/receipts/get/id_by_customer) and find the calculated amount before performing this request.

Use to book one or more receipts that already exist in BuchhaltungsButler, splitting each across posting accounts, VAT rates and cost centres.

For a journal entry with no receipt behind it, use postings_create_free.

Takes one or many: pass an array of receipts in receipts. A single record is an array of one.

The per-receipt arrays (postingaccounts, amounts, vats, postingtexts) are positional: index 0 of each describes the same split line, so they must all have the same length. Not idempotent. Reversible with postings_unconfirm_for_receipt while the posting is not fixed.

Endpoint: POST /postings/add-batch/receipts

Inputs: receipts (required). Returns: errors, success, receipts

postings_create_for_transactionPostings: add transaction postingA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

add transaction posting

Add postings for a specified transaction.

Use to book one or more bank transactions, splitting each across posting accounts, VAT rates and cost centres.

For a journal entry with no bank transaction behind it, use postings_create_free.

Takes one or many: pass an array of transactions in transactions. A single record is an array of one.

The per-transaction arrays are positional and must all have the same length. Not idempotent. Reversible with postings_unconfirm_for_transaction while the posting is not fixed.

Endpoint: POST /postings/add-batch/transactions

Inputs: transactions (required). Returns: errors, success, transactions

postings_create_freePostings: add free postingA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

add free posting

Add a free posting.

Use to book a debit/credit pair that is not tied to an existing receipt or bank transaction, such as a manual accrual or a correction.

If the booking documents a receipt, use postings_create_for_receipt. If it settles a bank transaction, use postings_create_for_transaction.

Takes one or many: pass an array of free postings in free_postings. A single record is an array of one.

A "free" posting is BuchhaltungsButler's term for a standalone journal entry: you name both sides yourself via postingaccount_debit and postingaccount_credit. Not idempotent, so a repeated call books the amount twice. A receipt can be attached afterwards with postings_assign_receipt_to_free.

Endpoint: POST /postings/add-batch/free

Inputs: free_postings (required). Returns: errors, success, free_postings

postings_listPostings: get postingsA
Read-onlyIdempotent

🟢 READ-ONLY: Fetches data. Makes no changes to the accounting records.

get postings

Get postings for a specified customer account. The response includes the number of returned rows and an array of postings data. NOTE: Each request is limited to 1000 postings!

Use to read the booking journal, filtered by date range or posting account.

Supports limit and offset. Ask for a bounded date range rather than paging through a whole financial year.

Endpoint: POST /postings/get

Inputs: date_to (required), date_from (required), limit, order, +7 more. Returns: data, rows, message, success

postings_unconfirm_for_receiptPostings: unconfirm receipt postingA
Idempotent

🟡 WRITE · reverts state: Reverts a prior state change (un-confirm a posting, restore a deleted receipt). Reversible.

unconfirm receipt posting

Remove postings for a specified receipt by unconfirming them. This will only work if the postings are not fixed.

Use to send a receipt posting back to the unconfirmed state so it can be corrected.

This keeps the posting and only clears its confirmation. To remove the posting itself, use postings_cancel.

Only works while the posting is not fixed.

Endpoint: POST /postings/unconfirm/receipt

Inputs: receipt_id_by_customer (required). Returns: message, success

postings_unconfirm_for_transactionPostings: unconfirm transaction postingA
Idempotent

🟡 WRITE · reverts state: Reverts a prior state change (un-confirm a posting, restore a deleted receipt). Reversible.

unconfirm transaction posting

Remove postings for a specified transaction by unconfirming them. This will only work if the postings are not fixed.

Use to send a transaction posting back to the unconfirmed state so it can be corrected.

This keeps the posting and only clears its confirmation. To remove the posting itself, use postings_cancel.

Only works while the posting is not fixed.

Endpoint: POST /postings/unconfirm/transaction

Inputs: transaction_id_by_customer (required). Returns: message, success

postings_unconfirm_freePostings: unconfirm free postingA
Idempotent

🟡 WRITE · reverts state: Reverts a prior state change (un-confirm a posting, restore a deleted receipt). Reversible.

unconfirm free posting

Remove a specified free posting by unconfirming it. This will only work if the posting is not fixed.

Use to send a free posting back to the unconfirmed state so it can be corrected.

This keeps the posting and only clears its confirmation. To remove the posting itself, use postings_cancel.

Only works while the posting is not fixed. Fixed postings can no longer be unconfirmed.

Endpoint: POST /postings/unconfirm/free

Inputs: posting_id_by_customer (required). Returns: message, success

receipts_createReceipts: add a receiptA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

add a receipt

Add a receipt into the specified customer account. NOTE: Use this endpoint, to add a receipt without a file!

Use to record receipts that have no file attached, for example when the document lives in another system.

If you have the actual PDF or image, use receipts_upload instead so BuchhaltungsButler can read the document and pre-fill its data.

Takes one or many: pass an array of receipts in receipts. A single record is an array of one.

Not idempotent: a repeated call creates duplicate receipts. The response reports per-item success, so a partial failure leaves the successful entries in place.

Endpoint: POST /receipts/addBatch

Inputs: receipts (required). Returns: errors, success, receipts

receipts_deleteReceipts: delete receipt by id_by_customerA
DestructiveIdempotent

🔴 DESTRUCTIVE · deletes data: Deletes or cancels a record. Confirm with the user before calling. Receipt deletes are restorable; cost-location deletes are not. Cancelling a posting deletes it if it is not yet fixed, otherwise it books a reversal posting.

delete receipt by id_by_customer

Mark a receipt as deleted for a specified customer account by id_by_customer. You can get the "id_by_customer" by using the "/receipts/get method" first.

Use to remove a receipt that was filed by mistake.

Recoverable: receipts_restore brings the receipt back. Confirm with the user before calling.

Endpoint: POST /receipts/delete/id_by_customer

Inputs: id_by_customer (required). Returns: message, success, id_by_customer

receipts_get_by_idReceipts: get receipt by id_by_customerA
Read-onlyIdempotent

🟢 READ-ONLY: Fetches data. Makes no changes to the accounting records.

get receipt by id_by_customer

Get a single receipt for a specified customer account by id_by_customer. You can get the "id_by_customer" by using the "/receipts/get method" first. The response includes an array of receipt data.

Use to fetch a single receipt whose id you already have.

To search or page through receipts, use receipts_list.

id_by_customer is the per-customer counter shown in the BuchhaltungsButler UI, not a global database id.

Endpoint: POST /receipts/get/id_by_customer

Inputs: id_by_customer (required), get_file. Returns: data, message, success

receipts_listReceipts: get receiptsA
Read-onlyIdempotent

🟢 READ-ONLY: Fetches data. Makes no changes to the accounting records.

get receipts

Get receipts for a specified customer account. The response includes the number of returned rows and an array of receipts data.

Use to search receipts by direction, date range or payment status.

To fetch one known receipt, use receipts_get_by_id.

list_direction is required and selects inbound or outbound receipts. Supports limit and offset; observed rows counts only the returned page. Continue paging until empty, deduplicate IDs and check progress.

Endpoint: POST /receipts/get

Inputs: list_direction (required), limit, order, offset, +9 more. Returns: data, rows, message, success

receipts_list_assigned_transactionsReceipts: get all transactions assigned to a specific receiptA
Read-onlyIdempotent

🟢 READ-ONLY: Fetches data. Makes no changes to the accounting records.

get all transactions assigned to a specific receipt

Get all transactions assigned to a specific receipt for a specified customer account by id_by_customer. You can get the "id_by_customer" by using the "/receipts/get method" first.

Use to see which bank transactions are linked to a given receipt, for example to check whether an invoice has been matched to a payment.

For the opposite direction, use transactions_list_assigned_receipts.

Endpoint: POST /receipts/assigned-transactions/get

Inputs: receipt_id_by_customer (required), confirmed_only. Returns: data, rows, message, success

receipts_restoreReceipts: restore deleted receipt by id_by_customerA
Idempotent

🟡 WRITE · reverts state: Reverts a prior state change (un-confirm a posting, restore a deleted receipt). Reversible.

restore deleted receipt by id_by_customer

Restore a marked as deleted receipt for a specified customer account by id_by_customer. You can get the "id_by_customer" by using the "/receipts/get method" first.

Use to bring back a receipt that was deleted with receipts_delete.

Endpoint: POST /receipts/restore/id_by_customer

Inputs: id_by_customer (required). Returns: message, success, id_by_customer

receipts_uploadReceipts: upload receiptA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

upload receipt

Upload a receipt into the specified customer account. The receipt will be processed by the BuchhaltungsButler technology. The response includes the filename (without extension) of the receipt as it is stored.

Note: max 10 requests per minute

Use to send the actual receipt file. BuchhaltungsButler runs document recognition on it and returns the stored filename.

To record a receipt without a file, use receipts_create.

Rate limited to 10 requests per minute. Not idempotent, so uploading the same file twice creates two receipts.

Endpoint: POST /receipts/upload

Inputs: file (required), type (required), date, amount, +11 more. Returns: message, success, filename, id_by_customer

reports_create_bwaReports: create bwa reportA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

create bwa report

Triggers the creation of a BWA report ("Betriebswirtschaftliche Auswertung").

The report is generated asynchronously in the background. The response contains the id_by_customer of the created report, which may be used to retrieve it once the generation has been finished.

A new report may only be requested once the generation of a previously requested report of the same type has been finished.

Use to request a BWA (Betriebswirtschaftliche Auswertung, the German management report). Step one of two.

This only triggers generation. To read the finished report, call reports_get_bwa afterwards.

Runs asynchronously and returns an id, not the report. A new BWA can only be requested once the previous one has finished, and it replaces the previous one.

Endpoint: POST /reports/create/bwa

Inputs: date_to (required), date_from (required). Returns: message, success, id_by_customer

reports_create_sumsReports: create sums reportA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

create sums report

Triggers the creation of a sums report ("Summen- und Saldenliste"). The report is always created for all of the customer's postingaccounts.

The report is generated asynchronously in the background. The response contains the id_by_customer of the created report, which may be used to retrieve it once the generation has been finished.

A new report may only be requested once the generation of a previously requested report of the same type has been finished.

Use to request a sums and balances report (Summen- und Saldenliste). Step one of two.

To read the finished report, call reports_get_sums afterwards.

Runs asynchronously and returns an id. A new report may only be requested once the previous one has finished, and it replaces the previous one.

Endpoint: POST /reports/create/sums

Inputs: date_to (required), date_from (required), base, file_csv, +2 more. Returns: message, success, id_by_customer

reports_get_bwaReports: get bwa reportA
Read-onlyIdempotent

🟢 READ-ONLY: Fetches data. Makes no changes to the accounting records.

get bwa report

Returns a previously created BWA report ("Betriebswirtschaftliche Auswertung").

Reports are generated asynchronously, so a report is only available once its generation has been finished. Note that creating a new report of the same type replaces the previously created one.

Use to read a BWA that reports_create_bwa has finished generating. Step two of two.

Returns nothing useful until generation has finished. If the report is not ready, wait and retry rather than requesting a new one, since a new request replaces the pending one.

Endpoint: POST /reports/get/bwa

Inputs: report_id_by_customer (required), get_files. Returns: files, report, message, success

reports_get_sumsReports: get sums reportA
Read-onlyIdempotent

🟢 READ-ONLY: Fetches data. Makes no changes to the accounting records.

get sums report

Returns a previously created sums report ("Summen- und Saldenliste").

Reports are generated asynchronously, so a report is only available once its generation has been finished. Note that creating a new report of the same type replaces the previously created one.

Use to read a sums and balances report that reports_create_sums has finished generating. Step two of two.

For the individual bookings behind one posting account, use reports_get_sums_ledger.

Endpoint: POST /reports/get/sums

Inputs: report_id_by_customer (required), get_files. Returns: files, report, message, success

reports_get_sums_ledgerReports: get sums report postingaccount ledgerA
Read-onlyIdempotent

🟢 READ-ONLY: Fetches data. Makes no changes to the accounting records.

get sums report postingaccount ledger

Returns the postingaccount ledger ("Kontenblatt") of one postingaccount, holding its postings of the requested period.

The postingaccount numbers available for a sums report are provided by reports/get/sums, both as the keys of the 'sums' object and as its entries' 'postingaccount_number'.

In contrast to the report itself the ledger is created on the fly, so no report has to be created beforehand. Note that retrieving the ledger of a postingaccount holding a lot of postings may take a while.

Use to read one posting account's ledger for a bounded date range.

For the totals across all posting accounts, use reports_get_sums.

The API returns the ledger on demand; no previously generated sums report or report ID is required.

Endpoint: POST /reports/get/sums/ledger

Inputs: date_to (required), date_from (required), postingaccount_number (required), base. Returns: message, success, report_sums_postingaccount_ledger

transactions_assign_receiptsTransactions: assign receipt to transactionA

🟡 WRITE · links/unlinks records: Creates or removes an assignment between records (e.g. receipt ↔ transaction). Reversible.

assign receipt to transaction

Assign a receipt to a transaction.

Use to match receipts to the bank transactions that paid them, one pair or many at once.

To attach a receipt to a posting rather than a bank transaction, use postings_assign_receipt_to_free.

Takes one or many: pass an array of transactions to receipts in transactions_to_receipts. A single record is an array of one.

Reversible with transactions_unassign_receipt. Creating the link does not book anything: use postings_create_for_transaction to post the transaction.

Endpoint: POST /transactions/assign-batch/receipt

Inputs: transactions_to_receipts (required). Returns: errors, success, transactions_to_receipts

transactions_createTransactions: add transactionA

🟡 WRITE · creates data: Creates new records (receipts, transactions, postings, invoices, master data). Not idempotent: calling twice may create duplicates.

add transaction

Add a transaction to a payment account of the specified customer.

Use to import bank transactions that no bank connection delivers automatically, for example from a CSV export or a cash book.

Takes one or many: pass an array of transactions in transactions. A single record is an array of one.

Not idempotent and there is no duplicate detection: re-importing the same statement books every line a second time. Check transactions_list for the date range first. v1 offers no endpoint to update or delete an imported transaction.

Endpoint: POST /transactions/addBatch

Inputs: transactions (required). Returns: errors, success, transactions

transactions_get_by_idTransactions: get transaction by id_by_customerA
Read-onlyIdempotent

🟢 READ-ONLY: Fetches data. Makes no changes to the accounting records.

get transaction by id_by_customer

Get a single transaction for a specified customer account by id_by_customer. You can get the "id_by_customer" by using the "/transactions/get method" first. The response includes an array of transaction data.

Use to fetch a single bank transaction whose id you already have.

To search or page through transactions, use transactions_list.

id_by_customer is the per-customer counter shown in the BuchhaltungsButler UI, not a global database id.

Endpoint: POST /transactions/get/id_by_customer

Inputs: id_by_customer (required). Returns: data, message, success

transactions_listTransactions: get transactionsA
Read-onlyIdempotent

🟢 READ-ONLY: Fetches data. Makes no changes to the accounting records.

get transactions

Get transactions for a specified customer account. The response includes the number of returned rows and an array of transaction datas.

Use to search bank transactions by account and date range.

To fetch one known transaction, use transactions_get_by_id.

For multi-page exports, prefer id_by_customer_from with limit and fixed account/date filters: it is exclusive and forces ID-ascending order. Start at 0, then use the greatest returned ID without incrementing it; omit offset. Validate IDs and forward progress and continue until empty. Offset pages have overlapped in observed filtered exports; deduplication and an empty final page do not prove completeness. Reconcile IDs/counts and signed amounts independently. rows counts the returned page, not the grand total; concurrent changes still need a separate check.

Endpoint: POST /transactions/get

Inputs: limit, offset, account, date_to, +5 more. Returns: data, rows, message, success

transactions_list_assigned_receiptsTransactions: get all receipts assigned to a specific transactionA
Read-onlyIdempotent

🟢 READ-ONLY: Fetches data. Makes no changes to the accounting records.

get all receipts assigned to a specific transaction

Get all receipts assigned to a specific transaction for a specified customer account by id_by_customer. You can get the "id_by_customer" by using the "/transactions/get method" first.

Use to see which receipts are linked to a given bank transaction, for example to check whether a payment has its invoice attached.

For the opposite direction, use receipts_list_assigned_transactions.

Endpoint: POST /transactions/assigned-receipts/get

Inputs: transaction_id_by_customer (required), confirmed_only. Returns: data, rows, message, success

transactions_unassign_receiptTransactions: unassign a specific receipt from a transactionA

🟡 WRITE · links/unlinks records: Creates or removes an assignment between records (e.g. receipt ↔ transaction). Reversible.

unassign a specific receipt from a transaction

Unassign a specific receipt from a transaction.

Use to undo a receipt-to-transaction match that was made in error.

Removes only the link. Neither the receipt nor the transaction is deleted.

Endpoint: POST /transactions/unassign/receipt

Inputs: receipt_id_by_customer (required), transaction_id_by_customer (required). Returns: message, success

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.9/5.0

    Scored across 46 tools

    Disambiguation4/5

    Tools are largely differentiated by resource and action, and descriptions explicitly distinguish easily confused pairs such as accounts vs postingaccounts, debtors vs creditors, and receipt/transaction/free postings. The main remaining risk is cognitive load from many near-parallel variants like postings_create_for_transaction, postings_create_for_receipt, and postings_create_free, which require description reading to choose correctly.

    Naming Consistency5/5

    Names consistently follow an entity_action snake_case convention: debtors_create, receipts_list, postings_unconfirm_for_receipt, reports_get_sums_ledger, etc. Although the pattern is noun-first rather than verb-first, it is applied predictably across the entire set.

    Tool Count2/5

    With 46 tools, the surface is very heavy for agent selection and exceeds the practical range for reliable tool choice. The breadth reflects a substantial accounting domain, but the many analogous create/unconfirm/assign variants make the set cumbersome.

    Completeness3/5

    Coverage is broad across master data, receipts, transactions, postings, and reports, with useful cross-references and workaround guidance. However, lifecycle gaps are notable: invoices cannot be listed or retrieved after creation, transactions lack update/delete, several master-data resources lack delete, and comments are write-only.

    Maintenance

    ActivityActive
    ResponsivenessLimited data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables AI assistants to interact with QuickFile UK accounting software, providing access to invoicing, client management, purchases, banking, and financial reporting through 40+ tools covering the complete QuickFile API.
      22 npm
      4
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Integrates with the sevdesk German accounting API, providing 76 tools for full CRUD operations across contacts, invoices, vouchers, orders, credit notes, bank accounts, transactions, parts, tags, addresses, and communication ways.
      178 npm
      6
      MIT
    • A
      license
      C
      quality
      C
      maintenance
      Provides comprehensive AI-agnostic access to all Firefly III personal finance features via 66 tools, enabling natural language management of accounts, transactions, budgets, and more.
      66
      7 npm
      24
      MIT
    • A
      license
      B
      quality
      D
      maintenance
      Enables AI assistants to interact with the BuchhaltungsButler accounting API via MCP, providing tools for managing receipts, transactions, invoices, postings, and master data directly from Claude Desktop and other MCP-compatible clients.
      23
      20 npm
      MIT