Skip to main content
Glama
si0nDE

mcp-buchhaltungsbutler

by si0nDE
README.md
# mcp-buchhaltungsbutler

**[Deutsch](README.de.md) | English**

An MCP (Model Context Protocol) server that exposes the [BuchhaltungsButler](https://www.buchhaltungsbutler.de/) API (v1) — a German bookkeeping/accounting SaaS — as a set of curated, token-efficient tools for LLM agents.

> Unofficial, community project. Not affiliated with or endorsed by BuchhaltungsButler.

## Built for agents, not just wrapped from the API

- **32 tools covering all 48 endpoints** — batch, list, and singular variants of the same action are merged into one tool, so your context window isn't full of near-duplicate tool definitions.
- **Lean by default** — list tools return trimmed, LLM-friendly fields out of the box; pass `full: true` whenever you need the complete record.
- **No array-juggling** — invoice line items, posting splits, and other API quirks are exposed as clean, ordinary objects. No more keeping five parallel arrays in sync by hand.
- **Always in sync with the spec** — endpoint definitions are generated straight from BuchhaltungsButler's official API spec, not hand-maintained.

## Setup

1. `npm install`
2. Copy `.env.example` to `.env` and fill in `BB_API_CLIENT`, `BB_API_SECRET`, `BB_API_KEY` (BuchhaltungsButler → Settings → API).
3. `npm test` — runs against mocked HTTP responses, no live credentials needed.
4. `npm run build && npm start` — or `npm run dev` for a quick local run without building first.

`npm run generate` regenerates `src/bb-client/generated/endpoints.ts` from the vendored spec (`spec/buchhaltungsbutler-v1.json`); the output is already committed, so this is only needed after updating the spec file itself.

## Using with an MCP client

`.env` only covers local `npm run dev`/`npm start` runs. A real MCP client (e.g. Claude Desktop) launches the server itself and won't read `.env` — pass credentials via the client's own `env` config instead. Example `claude_desktop_config.json` entry:

```json
{
  "mcpServers": {
    "buchhaltungsbutler": {
      "command": "node",
      "args": ["/absolute/path/to/mcp-buchhaltungsbutler/dist/index.js"],
      "env": {
        "BB_API_CLIENT": "your-api-client",
        "BB_API_SECRET": "your-api-secret",
        "BB_API_KEY": "your-customer-api-key"
      }
    }
  }
}
```

Run `npm run build` first so `dist/index.js` exists.

## Bewirtungsbeleg (business entertainment receipts)

`generate_entertainment_receipt` fills the gap between a restaurant bill and a legally complete
Bewirtungsbeleg (§ 4 Abs. 5 Satz 1 Nr. 2 EStG). `generate_and_upload_entertainment_receipt` does the
same and uploads the result via the same endpoint `upload_receipt` calls, so the full base64 PDF
doesn't have to round-trip through the model twice. See
[docs/bewirtungsbeleg-faq.md](docs/bewirtungsbeleg-faq.md) for the legal background (German only, since
it documents German tax law).

## Remote deployment (Docker)

For clients that can't launch a local process (e.g. Claude on mobile), the server also runs as a
Streamable HTTP service instead of stdio, container-ready.

1. Pull the published image: `ghcr.io/si0nde/mcp-buchhaltungsbutler:latest` (built automatically from
   `main` by `.github/workflows/docker-publish.yml`), or build locally with `docker build -t mcp-buchhaltungsbutler .`.
2. Run it with the usual `BB_API_CLIENT`/`BB_API_SECRET`/`BB_API_KEY`, plus:
   - `MCP_AUTH_TOKEN` (required) — a long random secret; every request must send `Authorization: Bearer <token>`.
   - `MCP_ALLOWED_HOSTS` (recommended) — comma-separated hostnames this server is reachable as (e.g. your reverse proxy's domain), for DNS-rebinding protection.
   - `PORT` (optional, default `3000`).

   ```bash
   docker run -d --name mcp-buchhaltungsbutler \
     -e BB_API_CLIENT=... -e BB_API_SECRET=... -e BB_API_KEY=... \
     -e MCP_AUTH_TOKEN=... -e MCP_ALLOWED_HOSTS=mcp.your-domain.example \
     -p 3000:3000 \
     ghcr.io/si0nde/mcp-buchhaltungsbutler:latest
   ```
3. Put a reverse proxy (Caddy, nginx, Traefik, ...) in front for TLS — this container only speaks plain
   HTTP. `GET /health` returns `200 {"status":"ok"}` with no auth, for health checks; the MCP endpoint is
   `POST /mcp` and requires the bearer token.
4. Add it to Claude as a remote/custom connector using `https://mcp.your-domain.example/mcp` and an
   `Authorization: Bearer <token>` header — this is what makes it reachable from Claude on iOS/iPadOS,
   not just Desktop.

## Tools

| Category | Tools |
|---|---|
| Accounts | `list_accounts`, `create_account` |
| Comments | `add_comment` |
| Cost Locations | `list_cost_locations`, `manage_cost_location` |
| Contacts (Debtors/Creditors) | `list_contacts`, `create_contacts`, `update_contact` |
| Posting Accounts | `list_posting_accounts`, `manage_posting_account` |
| Receipts | `list_receipts`, `get_receipt`, `create_receipts`, `upload_receipt`, `set_receipt_deleted`, `get_receipt_transactions` |
| Transactions | `list_transactions`, `get_transaction`, `create_transactions`, `assign_receipts_to_transactions`, `unassign_receipt`, `get_transaction_receipts` |
| Postings | `list_postings`, `add_receipt_postings`, `add_transaction_postings`, `add_free_postings`, `unconfirm_posting`, `assign_receipt_to_free_posting`, `confirm_payment` |
| Invoices | `create_invoice`, `create_einvoice` |
| Bewirtungsbeleg | `generate_entertainment_receipt`, `generate_and_upload_entertainment_receipt` |

## Architecture

```
src/
  config.ts              # env var loading, fail-fast validation
  bb-client/
    generated/            # spec-derived endpoint metadata (regenerate with npm run generate)
    client.ts              # generic HTTP client: auth, api_key injection, error mapping
  formatting/trim.ts       # trims list responses to LLM-friendly fields
  tools/                   # one file per category, curated MCP tools on top of the client
  server.ts, index.ts      # MCP server bootstrap (stdio)
  http-server.ts           # MCP server bootstrap (Streamable HTTP, bearer auth) — for remote/Docker deployment
scripts/generate-client.ts # parses spec/buchhaltungsbutler-v1.json into src/bb-client/generated/
```

Single-tenant, no multi-tenant support, no OAuth. Credentials never reach the model; they're injected
into requests by the client layer from env vars. Runs locally over stdio (Claude Desktop) or as a
Streamable HTTP service behind your own reverse proxy and bearer token (see "Remote deployment" above)
for clients that need a network-reachable server.

## Status

All 48 BuchhaltungsButler endpoints are covered by 32 of these tools; `generate_entertainment_receipt` is a client-side PDF generator that makes no BuchhaltungsButler API calls of its own, while `generate_and_upload_entertainment_receipt` reuses the same `receiptsUpload` endpoint `upload_receipt` already covers rather than adding a 49th one (see [docs/bewirtungsbeleg-faq.md](docs/bewirtungsbeleg-faq.md)). Verified against a live account (both a read call and a create+delete round trip).

## Development

```bash
git clone https://github.com/si0nDE/mcp-buchhaltungsbutler.git && cd mcp-buchhaltungsbutler
npm install
npm test           # vitest run
npm run build       # tsc, strict mode
```

## License

[MIT](LICENSE) + [Commons Clause](https://commonsclause.com/) — free to use (including commercially, e.g. for your own bookkeeping), modify, and contribute to. The one thing it doesn't permit is reselling this software or offering it as a paid hosted/managed service. If you find it useful, consider [supporting development](https://ko-fi.com/simonfieber) instead of building a rival funding page around it.