{"_id":"@codemill-solutions/e-boekhouden-mcp","_rev":"4-60400e2c61fe8ca37ec70d648d95c119","name":"@codemill-solutions/e-boekhouden-mcp","dist-tags":{"latest":"1.1.0"},"versions":{"0.2.0":{"name":"@codemill-solutions/e-boekhouden-mcp","version":"0.2.0","keywords":["mcp","model-context-protocol","e-boekhouden","eboekhouden","accounting","boekhouden","rest","ai","agent","anthropic","claude"],"author":{"name":"CodeMill Solutions B.V."},"license":"MIT","_id":"@codemill-solutions/e-boekhouden-mcp@0.2.0","maintainers":[{"name":"codemillsolutions","email":"dev@codemill.dev"}],"homepage":"https://github.com/CodeMill-Solutions/e-boekhouden-mcp#readme","bugs":{"url":"https://github.com/CodeMill-Solutions/e-boekhouden-mcp/issues"},"dist":{"shasum":"0afa0a010aaf7146ddda947a66cb1360fbb236ca","tarball":"https://registry.npmjs.org/@codemill-solutions/e-boekhouden-mcp/-/e-boekhouden-mcp-0.2.0.tgz","fileCount":47,"integrity":"sha512-AilZYSgZcouq8F19/tBnB7mlaLSvyh5dMlJ/cJIDgN91aLXTMogEb8ByCx6fDaCsSb9V9c6KfwBvkpItNTua+Q==","signatures":[{"sig":"MEUCIGHKxlUg2Bqr62WcwLGoCwBQclP02jcFYomsWx/OfjlVAiEAh90eB4hIcdUOLCKO+yXbG/+PDyeZBbSnf7HQWFfjQC8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":119259},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=20"},"gitHead":"9859cafe7b51758a4b369d43a74f14a298455d6d","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","whoami":"npx tsx scripts/whoami.ts","inspect":"npx @modelcontextprotocol/inspector node dist/index.js","prepublishOnly":"npm run build","list-administrations":"npx tsx scripts/list-administrations.ts"},"_npmUser":{"name":"codemillsolutions","email":"dev@codemill.dev"},"repository":{"url":"git+https://github.com/CodeMill-Solutions/e-boekhouden-mcp.git","type":"git"},"_npmVersion":"10.8.2","description":"MCP server for the e-Boekhouden REST API","directories":{},"_nodeVersion":"20.20.2","dependencies":{"zod":"^3.25.76","axios":"^1.16.1","dotenv":"^16.6.1","@modelcontextprotocol/sdk":"^1.29.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","prettier":"^3.8.3","typescript":"^5.9.3","@types/node":"^22.19.19"},"_npmOperationalInternal":{"tmp":"tmp/e-boekhouden-mcp_0.2.0_1780944923696_0.17587621005776888","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@codemill-solutions/e-boekhouden-mcp","version":"0.3.0","keywords":["mcp","model-context-protocol","e-boekhouden","eboekhouden","accounting","boekhouden","rest","ai","agent","anthropic","claude"],"author":{"name":"CodeMill Solutions B.V."},"license":"MIT","_id":"@codemill-solutions/e-boekhouden-mcp@0.3.0","maintainers":[{"name":"codemillsolutions","email":"dev@codemill.dev"}],"homepage":"https://github.com/CodeMill-Solutions/e-boekhouden-mcp#readme","bugs":{"url":"https://github.com/CodeMill-Solutions/e-boekhouden-mcp/issues"},"dist":{"shasum":"df8720db1b58a10a35dce24ad9f18785e5843f5c","tarball":"https://registry.npmjs.org/@codemill-solutions/e-boekhouden-mcp/-/e-boekhouden-mcp-0.3.0.tgz","fileCount":59,"integrity":"sha512-I6yfHU4eIFcg4BVAKK/gqoT4f5OI5ccVqKmEo54tbN4OHKtMjpKX8ycvO5Sf3pj23K735QsqvpJnflAY91CVJg==","signatures":[{"sig":"MEQCIG7rDSSklsdPlo9nfBGzev+tVHM5Q+zXwbLB+14L+pqdAiB6R3OUntM+BqSN3unaYrTBbaL/VkCybiLZa1+TKe/8mA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":158422},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=20"},"gitHead":"b59ee93e5548920eefc7469e79544ccd72403acd","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","whoami":"npx tsx scripts/whoami.ts","inspect":"npx @modelcontextprotocol/inspector node dist/index.js","prepublishOnly":"npm run build","list-administrations":"npx tsx scripts/list-administrations.ts"},"_npmUser":{"name":"codemillsolutions","email":"dev@codemill.dev"},"repository":{"url":"git+https://github.com/CodeMill-Solutions/e-boekhouden-mcp.git","type":"git"},"_npmVersion":"10.8.2","description":"MCP server for the e-Boekhouden REST API","directories":{},"_nodeVersion":"20.20.2","dependencies":{"zod":"^3.25.76","axios":"^1.16.1","dotenv":"^16.6.1","@modelcontextprotocol/sdk":"^1.29.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","prettier":"^3.8.3","typescript":"^5.9.3","@types/node":"^22.19.19"},"_npmOperationalInternal":{"tmp":"tmp/e-boekhouden-mcp_0.3.0_1781099343000_0.2848471967641151","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@codemill-solutions/e-boekhouden-mcp","version":"1.0.0","keywords":["mcp","model-context-protocol","e-boekhouden","eboekhouden","accounting","boekhouden","rest","ai","agent","anthropic","claude"],"author":{"name":"CodeMill Solutions B.V."},"license":"MIT","_id":"@codemill-solutions/e-boekhouden-mcp@1.0.0","maintainers":[{"name":"codemillsolutions","email":"dev@codemill.dev"}],"homepage":"https://github.com/CodeMill-Solutions/e-boekhouden-mcp#readme","bugs":{"url":"https://github.com/CodeMill-Solutions/e-boekhouden-mcp/issues"},"dist":{"shasum":"92af793eeaa0582d7778e3aec54aa797bd866d34","tarball":"https://registry.npmjs.org/@codemill-solutions/e-boekhouden-mcp/-/e-boekhouden-mcp-1.0.0.tgz","fileCount":59,"integrity":"sha512-gxxxwr8hVji08f5OhPvBPx0Ihk5HadVYRLq10jiZUP5r48WsoVlff1Hq6aq7T1PBGf0p3JqCeH8c1VM+z73sQw==","signatures":[{"sig":"MEUCIQC0viMt/boqQ9SpETLWfjwsnf5Nudn6+oSlAD8UOgzzGQIgDHRROHxgdV4QBgRCqIcdL4Op5QSg3+A4CptsTljc7z0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":162822},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=20"},"gitHead":"78713904d0489c6b73f40e5c9193bb6959c182f0","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","whoami":"npx tsx scripts/whoami.ts","inspect":"npx @modelcontextprotocol/inspector node dist/index.js","prepublishOnly":"npm run build","list-administrations":"npx tsx scripts/list-administrations.ts"},"_npmUser":{"name":"codemillsolutions","email":"dev@codemill.dev"},"repository":{"url":"git+https://github.com/CodeMill-Solutions/e-boekhouden-mcp.git","type":"git"},"_npmVersion":"10.8.2","description":"MCP server for the e-Boekhouden REST API","directories":{},"_nodeVersion":"20.20.2","dependencies":{"zod":"^3.25.76","axios":"^1.16.1","dotenv":"^16.6.1","@modelcontextprotocol/sdk":"^1.29.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","prettier":"^3.8.3","typescript":"^5.9.3","@types/node":"^22.19.19"},"_npmOperationalInternal":{"tmp":"tmp/e-boekhouden-mcp_1.0.0_1781619423193_0.6897011463257723","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@codemill-solutions/e-boekhouden-mcp","version":"1.1.0","description":"MCP server for the e-Boekhouden REST API","license":"MIT","author":{"name":"CodeMill Solutions B.V."},"keywords":["mcp","model-context-protocol","e-boekhouden","eboekhouden","accounting","boekhouden","rest","ai","agent","anthropic","claude"],"engines":{"node":">=20"},"repository":{"type":"git","url":"git+https://github.com/CodeMill-Solutions/e-boekhouden-mcp.git"},"homepage":"https://github.com/CodeMill-Solutions/e-boekhouden-mcp#readme","bugs":{"url":"https://github.com/CodeMill-Solutions/e-boekhouden-mcp/issues"},"type":"module","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","start":"node dist/index.js","dev":"tsx src/index.ts","inspect":"npx @modelcontextprotocol/inspector node dist/index.js","whoami":"npx tsx scripts/whoami.ts","list-administrations":"npx tsx scripts/list-administrations.ts","prepublishOnly":"npm run build"},"publishConfig":{"registry":"https://registry.npmjs.org","access":"public"},"dependencies":{"@modelcontextprotocol/sdk":"^1.29.0","axios":"^1.16.1","dotenv":"^16.6.1","zod":"^3.25.76"},"devDependencies":{"@types/node":"^22.19.19","prettier":"^3.8.3","tsx":"^4.22.3","typescript":"^5.9.3"},"_id":"@codemill-solutions/e-boekhouden-mcp@1.1.0","gitHead":"616e3ca0c2f721267c82af8781aac7ea8835edd4","_nodeVersion":"20.20.2","_npmVersion":"10.8.2","dist":{"integrity":"sha512-vAuoaWwOOPmH5h9OhwR9YoKQpt5baQMw0Kl6ArsFqB+Uzf8MfclE18i+TV+/ev2NY7j++xaBIXl412uZD5q+hQ==","shasum":"028c126d1e53592a9a422fec928ceccb76848c60","tarball":"https://registry.npmjs.org/@codemill-solutions/e-boekhouden-mcp/-/e-boekhouden-mcp-1.1.0.tgz","fileCount":63,"unpackedSize":178989,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIEp0J9eqLxMj+AbplQjS0qviAatmZX+xtb9q6mlF+xXsAiEAp+q5qbtykMxY+o2mevBLYLyboM6HmLMPOu0cwfeDGRk="}]},"_npmUser":{"name":"codemillsolutions","email":"dev@codemill.dev"},"directories":{},"maintainers":[{"name":"codemillsolutions","email":"dev@codemill.dev"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/e-boekhouden-mcp_1.1.0_1787580965183_0.6090217620467149"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-08T18:55:23.492Z","modified":"2026-08-24T14:16:05.542Z","0.2.0":"2026-06-08T18:55:23.857Z","0.3.0":"2026-06-10T13:49:03.118Z","1.0.0":"2026-06-16T14:17:03.373Z","1.1.0":"2026-08-24T14:16:05.326Z"},"bugs":{"url":"https://github.com/CodeMill-Solutions/e-boekhouden-mcp/issues"},"author":{"name":"CodeMill Solutions B.V."},"license":"MIT","homepage":"https://github.com/CodeMill-Solutions/e-boekhouden-mcp#readme","keywords":["mcp","model-context-protocol","e-boekhouden","eboekhouden","accounting","boekhouden","rest","ai","agent","anthropic","claude"],"repository":{"type":"git","url":"git+https://github.com/CodeMill-Solutions/e-boekhouden-mcp.git"},"description":"MCP server for the e-Boekhouden REST API","maintainers":[{"name":"codemillsolutions","email":"dev@codemill.dev"}],"readme":"# e-Boekhouden MCP\n\n[![npm](https://img.shields.io/npm/v/@codemill-solutions/e-boekhouden-mcp)](https://www.npmjs.com/package/@codemill-solutions/e-boekhouden-mcp)\n\nA [Model Context Protocol](https://modelcontextprotocol.io) server for the\n[e-Boekhouden](https://www.e-boekhouden.nl) **REST API**. It lets MCP clients read your bookkeeping data — administrations, ledgers,\nrelations, mutations, invoices and master data — through a small set of typed\ntools, and book purchase invoices, payments, expenses, sales invoices, relations\nand ledger accounts behind explicit safety guards.\n\n> Built on the modern REST API (`api.e-boekhouden.nl`, OpenAPI v1), **not** the\n> legacy SOAP API. All tools are **read-only by default**; every write tool stays\n> disabled unless you opt in with `EBOEKHOUDEN_ALLOW_WRITES=true`, and even then\n> runs as a dry-run until you pass `confirm: true`.\n\n---\n\n## How it works\n\ne-Boekhouden's REST auth is refreshingly simple:\n\n1. You create a secret **API token** in your administration\n   (*Beheer → Instellingen → API/SOAP*).\n2. The server exchanges that token for a short-lived **session token**\n   (`POST /v1/session`) and caches it, renewing automatically before it\n   expires.\n3. Every business call sends `Authorization: Bearer <session-token>`.\n\nAn API token belongs to one administration, so the token *is* the\nadministration selector. To serve several administrations, give each one a\nlabel in a credentials file (see below).\n\n---\n\n## Installation\n\n```bash\nnpm install -g @codemill-solutions/e-boekhouden-mcp\n```\n\nOr run it straight from a clone:\n\n```bash\ngit clone https://github.com/CodeMill-Solutions/e-boekhouden-mcp.git\ncd e-boekhouden-mcp\nnpm install\nnpm run build\n```\n\n### Requirements\n\n- Node.js 20+\n- An e-Boekhouden account with an API token\n\n---\n\n## Setup\n\n### 1. Configure credentials\n\n**Single administration (env vars)** — copy `.env.example` to `.env`:\n\n```dotenv\nEBOEKHOUDEN_API_TOKEN=your-secret-api-token\nEBOEKHOUDEN_ADMINISTRATION=demo        # optional label (defaults to \"default\")\nEBOEKHOUDEN_SOURCE=codemill            # max 10 chars, optional\n```\n\n**Multiple administrations (credentials file)** — create\n`~/.e-boekhouden/credentials.json`:\n\n```json\n{\n  \"demo\":        { \"apiToken\": \"token-for-demo\", \"source\": \"codemill\" },\n  \"acme-bv\":     { \"apiToken\": \"token-for-acme\", \"source\": \"codemill\" }\n}\n```\n\nPath precedence: `EBOEKHOUDEN_CREDENTIALS_FILE` →\n`~/.e-boekhouden/credentials.json` → `./credentials.json`. The label (`demo`,\n`acme-bv`, …) is what you pass as the optional `administration` argument to any\ntool; omit it to use the default (`EBOEKHOUDEN_ADMINISTRATION`).\n\n### 2. Verify the connection\n\n```bash\nnpm run whoami                 # starts a session + lists administrations\nnpm run list-administrations   # raw GET /v1/administration\n```\n\nIf `whoami` returns your administration(s), you're ready.\n\n### 3. Connect from an MCP client\n\n```json\n{\n  \"mcpServers\": {\n    \"e-boekhouden\": {\n      \"command\": \"node\",\n      \"args\": [\"/absolute/path/to/e-boekhouden-mcp/dist/index.js\"],\n      \"env\": {\n        \"EBOEKHOUDEN_API_TOKEN\": \"your-secret-api-token\",\n        \"EBOEKHOUDEN_ADMINISTRATION\": \"demo\"\n      }\n    }\n  }\n}\n```\n\n---\n\n## Multi-administration support\n\n- Credentials live in a JSON file (`label → { apiToken, source }`); the default\n  administration can also come from env vars as a local-dev fallback.\n- Every tool accepts an optional `administration` argument selecting which\n  token to use.\n- Session tokens are cached per administration and renewed automatically.\n- `reload_credentials` re-reads the file at runtime without restarting the\n  server; sessions for changed/removed administrations are invalidated, others\n  stay warm.\n\n---\n\n## Available tools (25)\n\n### Auth & setup\n| Tool | Description |\n|---|---|\n| `whoami` | Validate auth: start a session + list accessible administrations. |\n| `reload_credentials` | Reload the credentials file at runtime; returns an added/updated/removed diff. |\n\n### Administrations\n| Tool | Description |\n|---|---|\n| `list_administrations` | Administrations the token can access. *(accountant tokens only)* |\n| `get_linked_administrations` | Administrations linked to the current one. *(accountant tokens only)* |\n\n> A regular single-administration token cannot call the administration\n> endpoints (the API returns `EP_001`). `whoami` reports which kind of token you\n> have.\n\n### Ledgers (grootboek)\n| Tool | Description |\n|---|---|\n| `get_ledgers` | List GL accounts (filter by code/category). |\n| `get_ledger` | Single GL account by id. |\n| `get_ledger_balances` | Balances across accounts for a period. |\n| `get_ledger_balance` | Balance of a single account. |\n| `create_ledger` | **Write.** Create a GL account (code + description; `category` is one of `BAL`/`VW`/`FIN`/`DEB`/`CRED`, default `VW`). Gated behind `EBOEKHOUDEN_ALLOW_WRITES`; dry-run unless `confirm: true`. See [Creating ledger accounts](#creating-ledger-accounts). |\n\n### Relations (relaties)\n| Tool | Description |\n|---|---|\n| `get_relations` | List customers/suppliers (filter by code, type, name, …). |\n| `get_relation` | Single relation by id. |\n| `create_relation` | **Write.** Create a relation (supplier/customer). Gated behind `EBOEKHOUDEN_ALLOW_WRITES`; dry-run unless `confirm: true`. See [Writing data](#writing-data). |\n\n### Mutations (mutaties / boekingen)\n| Tool | Description |\n|---|---|\n| `get_mutations` | List bookkeeping entries (filter by type, invoiceNumber, …). |\n| `get_mutation` | Single mutation with booking lines. |\n| `get_outstanding_invoices` | Outstanding invoices (openstaande posten); requires `credDeb` = `D` (receivables) or `C` (payables). |\n| `create_purchase_mutation` | **Write.** Create a purchase invoice (inkoopfactuur). Gated behind `EBOEKHOUDEN_ALLOW_WRITES`; dry-run unless `confirm: true`. See [Writing data](#writing-data). |\n| `create_payment` | **Write.** Register a payment against an invoice — purchase (sent, type 4) or sales (`direction: \"received\"`, type 3). Gated behind `EBOEKHOUDEN_ALLOW_WRITES`; dry-run unless `confirm: true`. See [Writing data](#writing-data). |\n| `create_money_spent` | **Write.** Book money spent directly from a bank/cash account (Geld uitgegeven, type 6) — expenses without a purchase invoice. Gated; dry-run unless `confirm: true`. See [Writing data](#writing-data). |\n\n### Invoices (verkoopfacturen)\n| Tool | Description |\n|---|---|\n| `get_invoices` | List sales invoices. |\n| `get_invoice` | Single sales invoice with lines. |\n| `create_sales_invoice` | **Write.** Create a sales invoice (verkoopfactuur, POST /v1/invoice). Gated behind `EBOEKHOUDEN_ALLOW_WRITES`; dry-run unless `confirm: true`. See [Writing data](#writing-data). |\n\n### Master data\n| Tool | Description |\n|---|---|\n| `get_products` | Products/articles. |\n| `get_product_groups` | Product groups. |\n| `get_cost_centers` | Cost centers (kostenplaatsen). |\n| `get_units` | Units of measure. |\n\nList tools are auto-paginated (`limit`/`offset`) and accept a `maxItems` cap.\n\n---\n\n## Writing data\n\nThe server is read-only out of the box. The write tools —\n`create_purchase_mutation` (purchase invoice / inkoopfactuur, `type: 1`),\n`create_payment` (payment against a purchase invoice, `type: 4`),\n`create_money_spent` (expense paid directly, *Geld uitgegeven*, `type: 6`),\n`create_sales_invoice` (verkoopfactuur via the invoicing module),\n`create_relation` (supplier/customer) and `create_ledger` (grootboekrekening) —\nare each protected by two independent guards:\n\n1. **Environment gate** — writes are refused unless `EBOEKHOUDEN_ALLOW_WRITES`\n   is set to a truthy value (`true`/`1`/`yes`/`on`). When unset, the tool is\n   still listed (so agents can discover it) but every call returns\n   `blocked: true` together with the `plannedMutation` it *would* have sent.\n2. **Dry-run by default** — even with writes enabled, a call only books when\n   `confirm: true` is passed. Otherwise it returns `dryRun: true` and the\n   planned body for review.\n\nEvery write response — blocked, dry-run and confirmed alike — also reports the\n`administration` the call targets (the explicit label, or the configured\ndefault), so a preview shows *where* the write would land.\n\nEnable writes in your client config:\n\n```json\n{\n  \"mcpServers\": {\n    \"e-boekhouden\": {\n      \"command\": \"node\",\n      \"args\": [\"/absolute/path/to/e-boekhouden-mcp/dist/index.js\"],\n      \"env\": {\n        \"EBOEKHOUDEN_API_TOKEN\": \"your-secret-api-token\",\n        \"EBOEKHOUDEN_ADMINISTRATION\": \"demo\",\n        \"EBOEKHOUDEN_ALLOW_WRITES\": \"true\"\n      }\n    }\n  }\n}\n```\n\n> All `env` values must be **strings** — use `\"true\"`, not `true`.\n\n### Booking model\n\n- Top-level `ledgerId` is the **creditor counter-account** (category `CRED`,\n  e.g. *Crediteuren*).\n- Each `rows[]` entry is a **cost line** with a purchase VAT code\n  (`HOOG_INK_21`, `LAAG_INK_9`, `VERL_INK`, `BU_EU_INK`, `GEEN`, …).\n- `inExVat` (`IN`/`EX`) says whether row `amount`s include VAT; the API then\n  computes the VAT amount.\n- Invoice numbers are unique per relation — a duplicate yields `MUT_019` /\n  `MUT_020`.\n\n### Payment term\n\nIf you omit `termOfPayment`, the tool resolves it automatically: it reads the\nterm configured on the relation, then falls back to a caller-supplied\n`termOfPaymentDefault`, then to e-Boekhouden's own default. The chosen source is\nreported as `termOfPaymentSource` (`explicit` / `relation` / `default` /\n`eboekhouden-default`). Note: the relation read endpoint omits the field when it\nis empty, so an unset term falls through to the next fallback.\n\n### Example (dry-run)\n\n```jsonc\n// create_purchase_mutation\n{\n  \"relationId\": 40994969,\n  \"invoiceNumber\": \"68130134\",\n  \"date\": \"2026-05-28\",\n  \"ledgerId\": 22206459,            // Crediteuren (CRED)\n  \"inExVat\": \"IN\",\n  \"rows\": [\n    { \"ledgerId\": 22206483, \"vatCode\": \"HOOG_INK_21\", \"amount\": 29.04, \"description\": \"Boekhoudpakket\" }\n  ]\n  // no \"confirm\" → returns the planned mutation without booking\n}\n```\n\nAdd `\"confirm\": true` to actually book; the response then returns\n`written: true` and the new mutation `id`.\n\n### Registering payments\n\n`create_payment` marks an invoice paid. `direction: \"sent\"` (default) pays a\n**purchase** invoice (`type: 4`, *Factuurbetaling verstuurd*, books against the\ncreditor account); `direction: \"received\"` registers a payment received on a\n**sales** invoice (`type: 3`, *Factuurbetaling ontvangen*, books against the\ndebtor account). It links to the outstanding invoice the same way the web UI's\n\"open post\" row does — by `invoiceNumber` + `relationId` + amount:\n\n- Top-level `ledgerId` (here `bankLedgerId`) is the **bank account** (category\n  `FIN`, e.g. `1010`). It's required — an administration usually has several FIN\n  accounts (Kas + bank).\n- The single row books against the counter account: **creditor** (`CRED`) for\n  `sent`, **debtor** (`DEB`) for `received`. Auto-resolved when `contraLedgerId`\n  is omitted.\n- The linking `invoiceNumber` and `relationId` are placed **on the row** (not\n  only at the mutation level) — the API returns `MUT_120` / `MUT_112` otherwise.\n- `amount` is the full paid total; `inExVat` is `EX`; VAT code `GEEN`.\n\n```jsonc\n// create_payment\n{\n  \"relationId\": 71254172,\n  \"invoiceNumber\": \"2026142893\",\n  \"amount\": 11.69,\n  \"date\": \"2026-06-01\",\n  \"bankLedgerId\": 22206452   // 1010 Bank\n  // no \"confirm\" → returns the planned payment without booking\n}\n```\n\nNote: mutations cannot be edited or deleted via the API (no `PATCH`/`DELETE` on\n`/v1/mutation`); corrections are made in the e-Boekhouden web UI.\n\n### Sales invoices\n\n`create_sales_invoice` posts to the invoicing module (`POST /v1/invoice`).\n`invoiceNumber` is optional — e-Boekhouden assigns the next number when omitted.\n`termOfPayment` is taken from the relation when omitted (then 14 days), reported\nas `termOfPaymentSource`.\n\nThe invoicing module requires a `templateId` (invoice layout) and each line\nneeds a revenue ledger; both are **administration-specific**, so this package\nships no defaults. Supply them per call, or configure environment defaults:\n\n```dotenv\nEBOEKHOUDEN_INVOICE_TEMPLATE_ID=752296   # your invoice template id\nEBOEKHOUDEN_REVENUE_LEDGER_ID=22206462   # e.g. 8000 Omzet\nEBOEKHOUDEN_DEFAULT_UNIT_ID=3214082      # optional, e.g. \"stuk\"\nEBOEKHOUDEN_DEBTOR_LEDGER_ID=22206453    # optional, e.g. 1300 Debiteuren\n```\n\nA call that omits a required id without a configured default fails with a clear\nerror telling you which id to supply. Find the ids via `get_invoice(s)` (template),\n`get_ledgers` (revenue/debtor) and `get_units`.\n\nBy default the invoice is **processed into the accounting** (the \"Factuur direct\nverwerken in de boekhouding\" option): a `mutation` object with the debtor ledger\nis sent so the invoice is journaled and becomes an open post. Without it the\ninvoice stays a concept (not journaled, no open post). The debtor ledger is\nauto-resolved from the single `DEB` ledger, or set via `debtorLedgerId` /\n`EBOEKHOUDEN_DEBTOR_LEDGER_ID`. Pass `process: false` for a concept invoice.\n\n### Creating ledger accounts\n\n`create_ledger` posts to `POST /v1/ledger` — useful when a cost account you need\ndoes not exist yet (a new expense category, a new balance account).\n\n- `code` (max 10) must be free: an existing ledger code yields `LEDG_013`, and a\n  code already used as a *group* code yields `LEDG_017`. `description` max 100.\n- `category` accepts only **`BAL`** (balance sheet), **`VW`** (profit & loss),\n  **`FIN`** (bank/cash), **`DEB`** (debtors) and **`CRED`** (creditors). The VAT\n  categories `get_ledgers` also returns (`AF6`, `AF19`, `AFOVERIG`, `VOOR`,\n  `BTWRC`, `AF`) are read-only and rejected on create (`LEDG_018`). Omitted it\n  defaults to `VW`; the response reports `categorySource` so the default is\n  never silent.\n- `group` (max 50) must be an **existing** ledger group — an unknown group fails\n  with `LEDG_012`.\n- Adding a second `DEB` or `CRED` ledger breaks the single-ledger auto-resolution\n  used by `create_payment` and `create_sales_invoice`; the tool warns about this\n  up front, and those calls then need an explicit `contraLedgerId` /\n  `debtorLedgerId`.\n- On success the API returns only the new **id** (`{ \"id\": 53487554 }`) — read\n  the full record back with `get_ledger`.\n\n```jsonc\n// create_ledger\n{\n  \"code\": \"4200\",\n  \"description\": \"Huisvestingskosten\",\n  \"category\": \"VW\"\n  // no \"confirm\" → returns the planned ledger without creating it\n}\n```\n\nCorrections go through `PATCH /v1/ledger/{id}`, which this server does not wrap\nyet — edit the ledger in the e-Boekhouden web UI. Note that the category of a\nledger with booked mutations can no longer be changed freely (`LEDG_014` /\n`LEDG_015`). There is **no** `DELETE` endpoint: a ledger cannot be removed via\nthe API.\n\n---\n\n## Testing\n\n```bash\nnpm run dev        # run from TypeScript source (tsx)\nnpm run inspect    # open the MCP Inspector against the built server\nnpm run whoami     # standalone auth probe\n```\n\n---\n\n## Architecture\n\n```\nsrc/\n  index.ts                 # MCP wiring: credentials merge, tool registration, stdio transport\n  eboekhouden-client.ts    # REST client: session cache, request(), pagination, error mapping\n  tools/\n    result.ts              # shared ok()/fail()/guard() result helpers\n    auth.ts                # whoami, reload_credentials\n    administrations.ts     # list_administrations, get_linked_administrations\n    ledgers.ts             # get_ledger(s), balances\n    ledgers-write.ts       # create_ledger (gated write tool)\n    relations.ts           # get_relation(s)\n    relations-write.ts     # create_relation (gated write tool)\n    write-helpers.ts       # shared write gate + body helpers\n    mutations.ts           # get_mutation(s), outstanding invoices\n    mutations-write.ts     # create_purchase_mutation + create_payment + create_money_spent\n    invoices.ts            # get_invoice(s)\n    invoices-write.ts      # create_sales_invoice (gated write tool)\n    masterdata.ts          # products, product groups, cost centers, units\nscripts/\n  whoami.ts                # standalone auth probe\n  list-administrations.ts  # standalone GET /v1/administration probe\n```\n\nAll tools go through `EboekhoudenClient.request()`, which transparently\nacquires/renews the session token and retries once on a 401.\n\n---\n\n## Roadmap\n\n- **v0.1** — read-only MVP.\n- **v0.2** — first gated write tool (`create_purchase_mutation`).\n- **v0.3** — write suite: `create_payment`, `create_money_spent`,\n  `create_sales_invoice`, `create_relation`, plus shared write helpers.\n- **v1.0** — first stable release: received payments on sales invoices\n  (`create_payment` `direction: \"received\"`) and sales-invoice processing into\n  the accounting; the read + write tool set is considered stable.\n- **v1.1** (planned) — `create_ledger` (merged, still unreleased — see the\n  CHANGELOG's *Unreleased* section), plus the remaining write tools (products,\n  cost centers), an `update_ledger` wrapper around `PATCH /v1/ledger/{id}`, and\n  richer sales-invoice options (email/PDF, direct debit).\n\n---\n\n## About CodeMill\n\nThis project is built and maintained by [**CodeMill\nSolutions**](https://codemill.dev), a Dutch software development agency\nspecializing in custom web applications, API integrations, mobile apps, and AI\nagents & automation for small and medium-sized businesses.\n\nFounded by engineers with 20+ years of combined experience, CodeMill favors\nshort communication lines, direct client relationships, and open-source\nfoundations to avoid vendor lock-in. A recurring focus is connecting accounting\nand ERP systems to modern AI workflows — this MCP server sits alongside sibling\nprojects such as\n[`@codemill-solutions/yuki-mcp`](https://www.npmjs.com/package/@codemill-solutions/yuki-mcp)\nand\n[`@codemill-solutions/twinfield-mcp`](https://www.npmjs.com/package/@codemill-solutions/twinfield-mcp),\nbringing Dutch accounting platforms within reach of AI agents.\n\nBased in Noord-Brabant and Overijssel (Netherlands), working bilingually in\nDutch and English across the Netherlands and the broader European market.\n\n📧 Interested in a custom integration? Reach out via [codemill.dev](https://codemill.dev).\n\n---\n\n## License\n\nMIT © CodeMill Solutions B.V.\n","readmeFilename":"README.md"}