Unofficial Lexware Office MCP Server

MCP serverCommerce & finance

Lets your agent manage Lexware Office accounting tasks like invoices and contacts.

Unavailable. This server has no hosted endpoint yet, so Ahel can't serve it.

Ahel cannot run this one yet; its page stays here for reference.

About this server

Unofficial MCP server for the Lexware Office accounting API, runs over stdio or HTTP.

Getting started

  1. Read the source or reference documentation for what it needs to run.
  2. Check this page for availability before you add it to a pipeline on Ahel.

From the project's README

As published by benethos-hub/lexware-office-mcp in README.md.

Disclaimer

  • This project is not affiliated with, endorsed by, or sponsored by Lexware or Haufe-Lexware GmbH & Co. KG. "Lexware" and "Lexware Office" are trademarks of their respective owners.
  • It uses the documented public API with an API key you generate and can revoke yourself. Use of that API is governed by Lexware's own terms, which you accept independently of this project. The API can change at any time, and requests may be rate limited or blocked.
  • It reaches real accounting records. Write access is off by default. If you enable it, anything created through the API is a real and legally relevant record — a finalized document cannot be withdrawn through the API.
  • Data may be incomplete or out of date. Nothing here is tax, accounting or legal advice. Do not rely on it for filings, audits, or your bookkeeping obligations.
  • Provided "as is", without warranty. Intended for personal and professional use at your own risk. See LICENSE.
  • For commercial use, review Lexware's API terms and your own retention and documentation duties.

Contents

  • Why this exists
  • Safety first
  • How it works
  • Tools
  • Requirements
  • Getting an API key
  • Installation
    • As a Claude Desktop extension
    • With uvx, for any MCP client
  • Configuring it in a browser
  • Switching individual tools off
  • Configuration
    • Where a value comes from, and which one wins
    • Naming the files
    • The settings
  • Transport
  • In a container
    • With Compose
    • As single containers
    • Turn the interface off when you are done
  • Logs
  • Example prompts
  • Rate limits
  • Development
  • License
  • Trademarks and affiliation

An MCP server that connects an MCP client such as Claude Desktop to a Lexware Office account through the official public REST API. Ask about invoices, contacts, articles and vouchers in plain language, and let the client fetch them for you.

Status: 0.6.1. The server handles contacts, vouchers and documents: find them, read them, create them, change them, see what is still unpaid, download a PDF and upload a receipt and book it. get_profile answers which account is connected. Every tool in the table below is built, and each was exercised against a live account. It speaks stdio to a client that starts it, as a Claude Desktop extension or from PyPI, and streamable HTTP behind a bearer token where something else has to reach it - as a published container image, with Compose files for running it and for building it from a checkout. See SPECS.md for the full technical specification and the roadmap.

Why this exists

Lexware Office holds the day-to-day accounting of a small business. Most questions about it are read questions — what is still unpaid, what did this customer order, which receipt belongs to that expense — and those are exactly the questions an assistant answers well once it can see the data. This server makes that possible without exporting anything, using an API key the account owner generates and can revoke.

Safety first

The server points at a real accounting system, so the defaults are cautious.

Run it read-only unless you have a reason not to. This server can change real accounting records - create a contact, record a voucher, issue an invoice, attach a receipt - and it is the assistant that decides when to call such a tool, not you. --tools read-only gives it everything it needs to answer questions about the books, which is what most people want it for: search, read, and download. Nothing in that set writes.

Turn a write tool on when you have a job for it, and know what it leaves behind. This API cannot delete a bookkeeping voucher at all, so a wrong one is corrected in the web app rather than withdrawn here, and a finalized invoice is a real document with a number that has been used. If you are not sure which tools you need, read-only is the honest starting point - the permissions page adds one later in a click, and a client that honours notifications/tools/list_changed, as Claude Desktop does, picks it up without a restart.

  • Nothing is enabled until you say so. A fresh installation has no policy file, and a server without one offers no tools at all. What this server may do is a decision somebody made, never a default that happened.
  • One flag per tool, in a JSON file you write with --tools, tick through setup, or edit by hand. Not a level, not a group: create_contact on and upload_file off is an ordinary thing to want, and there is no combination the file cannot express.
  • What a tool costs you is visible while you decide. Every enabled tool is sent to the assistant on every request, and the permissions page puts that number on each row.
  • The file is checked twice, once when the tool list is built and again when a call arrives, so a stale tool list on the client cannot slip past it.
  • The API key is never logged, never returned in a tool result, and redacted from error messages. It belongs in the .env and nowhere else — not in your client's configuration file, which another program owns and rewrites, and which is the one people screenshot when they ask for help. Nor does any path from your machine reach the assistant.

How it works

The client starts the server, or reaches it over HTTP, and speaks MCP with it. What a model can do is settled before anything reaches Lexware: a tool the policy file does not name does not exist for the client, and every call that is left goes through one API client with one rate limiter. The key and the permissions live in two files that setup writes, a process of its own that the client's prompt Set up Lexware Office starts, and so does benethos-lexware-office-mcp setup in a terminal.

Tools

Every tool below is built and was exercised against a live account. None of them is enabled until the policy file names it.

Read tools:

ToolWhat it does
get_profileCompany profile and connection check
search_contactsFind customers and vendors by name, email, number or role
get_contactOne contact with addresses, roles and version
search_articlesList articles, filtered by number, barcode or kind. The API offers no search by title
get_articleOne article with its price block and version
search_vouchersThe central query — filter the voucher list by type, status, contact, document number, date range and what is still open
get_sales_documentRead an invoice, quotation, credit note, order confirmation, delivery note, dunning or down payment invoice in full
get_voucherRead a bookkeeping voucher, by id or by its document number
get_paymentsPayment status and open amount of a voucher
get_recurring_templatesTemplates that issue invoices on a schedule, one or a page of them
get_master_dataCountries, payment conditions, posting categories and print layouts, with a search to narrow them
download_documentSave the rendered PDF or XML of a sales document
download_fileSave a stored file, such as an uploaded receipt
read_downloadPut a downloaded file into the answer, for clients that cannot follow a resource link
get_deeplinkBuild a permalink to a sales document, contact or voucher in the web app, without an API call

Write tools. These change real accounting records, so enable them one at a time and against an account you are willing to have changed:

ToolWhat it does
create_contactCreate a customer or vendor
update_contactChange one, without touching what you did not name
create_articleAdd an article to the catalogue
update_articleChange one, without touching what you did not name
create_voucherRecord a bookkeeping voucher
update_voucherChange one that is already recorded, or book a receipt that upload_file left unchecked
create_sales_documentCreate an invoice, quotation, credit note, order confirmation, delivery note or dunning — a draft unless you ask for it to be issued, which the assistant may only do on your explicit instruction
upload_fileUpload a receipt from a path or a URL, which also creates its voucher
attach_file_to_voucherHang a file on a voucher that already exists

update_contact and update_voucher cost two API calls rather than one. The API replaces a record instead of patching it, so the current one is read first and the change is laid on top. Without that, changing only an email address would empty out the addresses, the note and everything else. Both also need the version you last read: if the record changed in between, the update is refused and nothing is written.

One tool deletes, and it is the only one:

ToolWhat it does
delete_articleRemove an article. The API cannot bring it back. Takes confirm: true, and sends nothing without it

It is the only member of the --tools irreversible step so far, so that step is the only way to switch it on. An article is also the only thing this API lets you delete, which is the other half of the point:

--tools write is not the same as undoable. Nothing that preset enables deletes a record, but five of its tools create one this API cannot remove afterwards: create_contact, whose contact only the web app deletes, and create_voucher, create_sales_document, upload_file and attach_file_to_voucher, which leave a bookkeeping record.

A bookkeeping voucher cannot be deleted through the API. There is no endpoint for it, so a wrong create_voucher has to be corrected in the Lexware Office web app, and it is booked the moment it is created - the API accepts no status on the way in. The same applies to upload_file: uploading a receipt also creates the voucher that goes with it, so it leaves a record behind even though its name only mentions the file. That voucher starts unchecked, and update_voucher fills it in and, when you ask for it, books it.

Downloads are written into the download directory on the machine the server runs on, and reported two ways: a path, which is what you want when the client and the server share that machine, and a resource URI, which the client can read to get the bytes wherever the server is. The file itself never travels inside the tool result, because base64 costs roughly 1.37 times the file size in context and no model can read a PDF anyway. An existing file is never replaced: a download identical to one already there reuses it, and one that differs is saved beside it with a counter in its name.

The download directory is a cache of the last 100 documents. Older downloads are deleted when the server starts and after each download, since every document is still in Lexware Office and one call away. LXO_MCP_KEPT_DOWNLOADS changes the number, and 0 keeps everything. A directory you name yourself with LXO_MCP_DOWNLOAD_DIR is left alone unless you set it there too, and even then only files named the way a download is named are deleted: a space, an umlaut or an extension such as .docx keeps a file out of it. The resource list is read from the directory each time a client asks, names the same newest downloads, and survives a restart. A new download is announced the way a changed tool list is: the server sends notifications/resources/list_changed, so a client that listed the downloads once can ask again rather than keep the list from the start of its session. Whether it does is the client's business.

The resource list is not part of the prompt. The tool list goes to the model with every request. The resource list is sent only when a client asks for it, and what the client does with it is up to the client. Claude Desktop offers it in its attachment menu, under Add from the server, and a file reaches the conversation when somebody picks it. A client that hands the whole list to the model pays for it instead: an entry carries the lexware:// URI, the file name, the type and the size - never a path of this machine - and comes to about 230 characters, so the default 100 make roughly 23,000, around 6,000 to 7,000 tokens. For such a client, set LXO_MCP_KEPT_DOWNLOADS lower, which shortens the list and the cache together.

Claude Desktop does not follow a resource link at all, so read_download is the route that always works. It takes the same URI and puts the content into the answer. What arrives depends on the file:

FileArrives as
XMLtext, so an XRechnung can actually be read
PDFpictures of its pages, the first 10 by default
Imagethe image
Anything elsean embedded binary for the client to handle

A PDF is rendered rather than passed through because Claude Desktop turns an embedded binary into an image block when it calls the API, and application/pdf is not a permitted image type there, so the whole request is refused. Rendering costs no API call either, since the file is already on the server.

A link into the web app is a separate tool. get_deeplink turns an id into a URL for a browser, costs no API call, and is the route that still works when the client can display neither the file nor a resource link: somebody opens it themselves. A download does not carry one — it answers where the bytes are, which is a different question, and the two were joined once long enough for a broken link to ride along with a working download.

upload_file and attach_file_to_voucher take a source: a path on the machine the server runs on, or a URL to fetch the file from. Either way they accept PDF, JPEG, PNG and XML, at most 5 MiB per file, which is what the API takes. An XML file is treated as an XRechnung and is rejected if it is not one.

The model chooses the path. Without LXO_MCP_UPLOAD_DIR, upload_file and attach_file_to_voucher read any file this process can read that has one of those extensions, and send it to Lexware. That includes any .xml: a configuration file or an export is refused as not an XRechnung only after it has reached the API. Set it to one directory - an inbox for receipts - and nothing outside it is read, links included.

A URL only from addresses you allow. Another server can hand the model a short-lived link to a file - a mailbox server for an attachment, say - and the file then goes from that server to Lexware without passing through the model. LXO_MCP_UPLOAD_URLS lists the addresses such a link may point to, comma separated: a scheme and a host, optionally a port and the start of a path, such as https://files.example.com/inbox/. Without it no URL is fetched. The list is required because the model chooses the URL, and a model reads email: one instruction hidden in a message could otherwise have the server fetch from anywhere it can reach, a document server on your own network included, and file what came back in your books. A link outside every prefix is refused before anything is sent, a redirect is not followed, the fetch gets 30 seconds, and the file is cut off at 5 MiB. It is asked for uncompressed, an empty file is refused, and behind a proxy a service on this machine is fetched directly, since the proxy cannot reach it. A file served only as bytes, application/octet-stream or without a type, as a mail attachment often is, is taken by its first bytes, and only as one of the four types. The Lexware key is never sent along, and the log names a link's host, never its path or query, which is where a signed link keeps its key.

Each entry is a URL prefix, not a pattern. A link is fetched when it starts with one: the same scheme, exactly the same host, the same port - none given means 443 for https and 80 for http - and a path at or below the prefix's. What follows is free, the rest of the path and the query a signed link carries. With https://files.example.com/inbox/:

  • https://files.example.com/inbox/9f3c?sig=abc is fetched
  • https://files.example.com/outbox/9f3c is not, another path
  • https://files.example.com.elsewhere.net/inbox/9f3c is not, another host
  • https://files.example.com:8443/inbox/9f3c is not, another port

https://files.example.com/ allows every path on that host. There is no wildcard: a host is always written out in full, and a * is read as a host name that nothing is called, so https://* allows nothing at all.

https:// is the rule. http:// is meant for a service on the same machine, and is accepted for 127.0.0.1, ::1 and localhost alone: the server refuses to start with any other host, since the file would cross the network unencrypted. In a container, the same machine is the container.

Requirements

  • uv, which brings its own Python and the uvx command every example below uses. The Claude Desktop extension needs neither uv nor Python: Claude Desktop brings both
  • Python 3.11 or newer, if you would rather bring your own. Installing pulls in the MCP SDK, httpx, platformdirs, pypdfium2 to render PDF pages, and Jinja2 for the pages of setup
  • A Lexware Office account with the public API add-on enabled
  • An API key from https://app.lexware.de/addons/public-api

Getting an API key

  1. Sign in to Lexware Office as the account owner.
  2. Open the public API add-on at https://app.lexware.de/addons/public-api.
  3. Create a key and copy it once — it is shown a single time.
  4. Keep it out of any file that goes into version control. setup writes it into the .env the server reads, in the per-user configuration directory or, in a checkout, in config/.env, which is gitignored. Either is found no matter which directory the server is started from, so a client such as Claude Desktop needs no key of its own in its configuration file. An environment variable works as well.

A key can be revoked on the same page at any time, which is the fastest way to cut access if anything looks wrong.

Installation

Two ways in. In Claude Desktop the shortest is the extension, which needs nothing installed beside Claude Desktop. For any other client, or to manage the server yourself, run it with uvx. Both read the same configuration, so moving from one to the other keeps the key and the permissions. To run it in a container instead, see In a container.

The server is also listed in the official MCP Registry as io.github.benethos-hub/benethos-lexware-office-mcp, with all three: the PyPI package, the container image and the extension.

As a Claude Desktop extension

All it needs is Claude Desktop, signed in.

1. Get an API key. Sign in to Lexware Office as the account owner, open https://app.lexware.de/addons/public-api, create a key and copy it straight away, as it is shown once only. The same page revokes it at any time. See Getting an API key.

2. Download the extension. This link always gives the newest release: benethos-lexware-office-mcp.mcpb.

3. Drag it into Claude Desktop under Settings → Extensions. Claude Desktop brings Python and uv itself, nothing else has to be installed.

4. Open the setup. In a chat, click the plus in the message box, then Connectors → Add from Unofficial Lexware Office MCP Server → Set up Lexware Office. Your browser opens the interface described under Configuring it in a browser. Only you can pick this, the model cannot.

5. Enter the key and choose the tools. The key goes under Zugangsdaten, the tools are ticked under Rechte, and Beenden closes the page. Both apply at once, without restarting Claude Desktop.

6. Try it. Ask "Which Lexware Office account are you connected to?" The answer names the company the key belongs to.

Worth knowing:

Shortened here. Read the whole README on GitHub.

Signals

GitHub stars
2
Last commit
Oct 2026
Weekly downloads
454
Advanced
Delivery
benethos-lexware-office-mcp MCP server → your Ahel connector (mcp.ahel.ai) → your AI.
Item type
mcp-server
Key
io-github-benethos-hub-benethos-lexware-office-mcp
Source
github.com/benethos-hub/lexware-office-mcp