Unofficial Lexware Office MCP Server
非官方 Lexware Office MCP Server
免责声明
本项目与 Lexware 或 Haufe-Lexware GmbH & Co. KG 无关联、未经其认可,也未获其赞助。“Lexware”和“Lexware Office”是其各自所有者的商标。
它使用有文档记录的公共 API,并使用您自行生成且可自行撤销的 API 密钥。该 API 的使用受 Lexware 自身条款的约束,您需独立于本项目接受这些条款。API 可能随时更改,请求可能受到速率限制或被阻止。
它涉及真实的会计记录。默认情况下写入访问是关闭的。如果您启用它,通过 API 创建的任何内容都是真实且具有法律意义的记录——已定稿的文档无法通过 API 撤回。
数据可能不完整或过时。此处内容不构成税务、会计或法律建议。 请勿依赖它进行申报、审计或履行您的记账义务。
按“原样”提供,不提供任何担保。仅供个人和专业使用,风险自负。请参阅 LICENSE。
对于商业用途,请审阅 Lexware 的 API 条款以及您自身的保留和文档义务。
一个 MCP 服务器,通过官方 公共 REST API 将 MCP 客户端(如 Claude Desktop)连接到 Lexware Office 账户。您可以用自然语言询问发票、联系人、商品和凭证,并让客户端为您获取它们。
状态:0.2.2。 该服务器处理联系人、凭证和文档:查找、读取、创建、修改它们,查看哪些尚未付款,下载 PDF 并上传收据。
get_profile回答连接的是哪个账户。下表中的每个工具都已构建,并已针对真实账户进行过测试。它通过 stdio 与启动它的客户端通信,并在需要其他方式访问时通过 bearer token 支持流式 HTTP——作为已发布的容器镜像,并附带一个 Compose 文件来协调两者。完整的技术规范和路线图请参阅 SPECS.md。
为什么存在
Lexware Office 保存着小企业的日常会计数据。关于它的大多数问题都是读取类问题——哪些尚未付款,这位客户订购了什么,哪张收据属于那笔费用——而这些问题正是助手在能够看到数据后能很好回答的。该服务器无需导出任何内容即可实现这一点,使用的是账户所有者生成并可撤销的 API 密钥。
Related MCP server: lexware-mcp-server
安全第一
该服务器指向真实的会计系统,因此默认设置是谨慎的。
除非有理由,否则以只读方式运行。 此服务器可以更改真实的会计记录——创建联系人、记录凭证、开具发票、附加收据——而决定何时调用此类工具的是助手,而不是您。--tools read-only 为其提供了回答有关账簿问题所需的一切,这正是大多数人想要的:搜索、读取和下载。该集合中没有任何写入操作。
当您有任务需要时,再启用写入工具,并了解它会留下什么。此 API 根本无法删除记账凭证,因此错误的凭证应在 Web 应用中更正,而不是在此处撤回;已定稿的发票是带有已使用编号的真实文档。如果您不确定需要哪些工具,只读是诚实的起点——权限页面稍后只需点击一下即可添加,而像 Claude Desktop 这样尊重 notifications/tools/list_changed 的客户端无需重启即可获取更新。
除非您明确指定,否则不会启用任何功能。 全新安装没有策略文件,而没有策略文件的服务器不会提供任何工具。此服务器可以做什么是某人做出的决定,而不是默认发生的。
每个工具一个标志,放在您通过
--tools编写的 JSON 文件中,通过setup勾选,或手动编辑。不是级别,不是组:create_contact开启而upload_file关闭是常见的需求,该文件可以表达任何组合。每个工具的成本在您决定时可见。 每个启用的工具都会在每次请求时发送给助手,权限页面会在每一行上显示该数字。
该文件会被检查两次,一次在构建工具列表时,一次在调用到达时,因此客户端上过时的工具列表无法绕过它。
API 密钥永远不会被记录,永远不会在工具结果中返回,并且会从错误消息中删除。它应放在
.env中,而不是其他任何地方——不要放在客户端的配置文件中,该文件由另一个程序拥有并重写,而且人们在寻求帮助时通常会截图该文件。您机器上的任何路径也不会到达助手。
工具
下面的每个工具都已构建,并已针对真实账户进行过测试。在策略文件指定之前,它们都不会被启用。
读取工具:
工具 | 功能 |
| 公司资料和连接检查 |
| 按名称、电子邮件、编号或角色查找客户和供应商 |
| 单个联系人,包含地址、角色和版本 |
| 列出商品,按编号、条形码或种类筛选。API 不提供按标题搜索 |
| 单个商品及其价格块和版本 |
| 核心查询——按类型、状态、联系人、日期范围以及未结项目筛选凭证列表 |
| 完整读取发票、报价单、贷项通知单、订单确认、交货单、催款单或预付款发票 |
| 按 ID 或文档编号读取记账凭证 |
| 凭证的付款状态和未结金额 |
| 按计划开具发票的模板,单个或一页 |
| 国家、付款条件、过账类别和打印布局,并提供搜索以缩小范围 |
| 保存销售文档的渲染 PDF 或 XML |
| 保存存储的文件,例如上传的收据 |
| 将下载的文件放入答案中,适用于无法跟随资源链接的客户端 |
| 构建指向 Web 应用中销售文档、联系人或凭证的永久链接,无需 API 调用 |
写入工具。这些会更改真实的会计记录,因此请逐个启用,并针对您愿意被更改的账户使用:
工具 | 功能 |
| 创建客户或供应商 |
| 更改一个,不触及您未指定的内容 |
| 向目录添加商品 |
| 更改一个,不触及您未指定的内容 |
| 记录记账凭证 |
| 更改已记录的凭证 |
| 创建发票、报价单、贷项通知单、订单确认、交货单或催款单——除非您要求开具,否则为草稿,而助手只能在您明确指示时才能开具 |
| 上传收据,同时创建其凭证 |
| 将文件挂到已存在的凭证上 |
update_contact 和 update_voucher 需要两次 API 调用而不是一次。API 会替换记录而不是修补,因此会先读取当前记录,然后将更改叠加在上面。否则,仅更改电子邮件地址就会清空地址、备注和其他所有内容。两者还需要您上次读取的 version:如果记录在此期间发生变化,更新将被拒绝,并且不会写入任何内容。
有一个工具会删除,而且它是唯一的一个:
工具 | 功能 |
| 删除商品。API 无法恢复它。需要 |
到目前为止,它是 --tools irreversible 步骤中唯一的成员,因此该步骤是启用它的唯一方式。商品也是此 API 允许您删除的唯一内容,这是另一半要点:
--tools write 与可撤销不是一回事。该预设启用的任何工具都不会删除记录,但其中两个工具会创建一条之后无法移除的记录。
会计凭证无法通过 API 删除。 没有对应的端点,因此错误的 create_voucher 必须在 Lexware Office 网页应用中更正,而且凭证在创建的那一刻就已入账——API 在传入时不接受任何状态。upload_file 也是如此:上传收据的同时也会创建与之关联的凭证,因此尽管其名称只提到文件,它仍会留下一条记录。
下载内容会写入服务器运行所在机器上的下载目录,并通过两种方式报告:路径,当客户端与服务器共享同一台机器时这是你想要的;以及资源 URI,无论服务器在哪里,客户端都可以读取它来获取字节。文件本身绝不会出现在工具结果中,因为 base64 在上下文中大约要占用文件大小的 1.37 倍,而且任何模型反正也读不了 PDF。已有文件绝不会被替换:第二次下载会以带计数器的名称保存在第一个文件旁边。
资源列表在服务器启动时从下载目录填充,因此 URI 在重启后仍然可读。服务器无法做到的是宣布新的下载:MCP SDK 没有给它发送列表变更通知的方式,因此在启动时列出过一次的客户端将看不到会话期间后来获取的任何内容。
再加上 Claude Desktop 根本不跟随资源链接,read_download 是始终有效的途径。它接受相同的 URI 并将内容放入回答中。到达的内容取决于文件:
文件 | 到达形式 |
XML | 文本,因此 XRechnung 实际上可以被读取 |
其页面的图片,默认前 10 页 | |
图片 | 图片 |
其他任何内容 | 嵌入的二进制文件,由客户端处理 |
PDF 是渲染而不是直接传递的,因为 Claude Desktop 在调用 API 时会将嵌入的二进制文件转换为图片块,而 application/pdf 在那里不是允许的图片类型,因此整个请求会被拒绝。渲染也不消耗 API 调用,因为文件已经在服务器上了。
指向网页应用的链接是一个单独的工具。get_deeplink 将 id 转换为浏览器用的 URL,不消耗 API 调用,并且在客户端既无法显示文件也无法显示资源链接时仍然有效:由用户自己打开。下载不附带链接——它回答的是字节在哪里,这是另一个问题,而这两者曾经被合并过一次,结果是一个失效链接搭上了有效下载的便车。
upload_file 接受 PDF、JPEG、PNG 和 XML,每个文件最多 5 MiB,这是 API 的接受范围。XML 文件被视为 XRechnung,如果不是则会被拒绝。
要求
uv,它自带 Python 以及下面每个示例都使用的
uvx命令Python 3.11 或更高版本,如果你更愿意自带的话。安装会拉入 MCP SDK、httpx、platformdirs 和 pypdfium2,最后一个是用来渲染 PDF 页面的
一个启用了公共 API 附加组件的 Lexware Office 账户
来自 https://app.lexware.de/addons/public-api 的 API 密钥
获取 API 密钥
以账户所有者的身份登录 Lexware Office。
在 https://app.lexware.de/addons/public-api 打开公共 API 附加组件。
创建密钥并复制一次——它只显示一次。
不要把它放进任何会进入版本控制的文件中。把它放在
config/.env(已被 gitignore)中,或作为环境变量传入。config/.env中的密钥无论服务器从哪个目录启动都能被找到,因此像 Claude Desktop 这样的客户端无需在自己的配置文件中保存密钥。
密钥可以随时在同一页面上撤销,这是出现任何异常时切断访问的最快方式。
安装
运行服务器的最简单方式——无需克隆、无需手动创建虚拟环境、无需 git。uvx 按需从 PyPI(发布名为 benethos-lexware-office-mcp)获取并运行它。如果想改为在容器中运行,请参阅在容器中。
1. 安装 uv,如果你还没有安装的话——uv 安装页面涵盖了所有平台。它会带来 uvx,而这里只需要它。
2. 配置服务器。 为此无需安装任何东西:uvx 会获取包并运行它。
uvx benethos-lexware-office-mcp setup这会打开在浏览器中配置中描述的界面:密钥、设置以及每个工具一个复选框。它所做的所有事情也可以手动完成——用 uvx benethos-lexware-office-mcp --settings-sample > config/.env 启动一个设置文件,把密钥放进去,然后按下面描述的方式使用 --tools。
检查它是否正常工作:
uvx benethos-lexware-office-mcp --help3. 在 claude_desktop_config.json 中把 Claude Desktop 指向它:
{
"mcpServers": {
"benethos-lexware-office-mcp": {
"command": "uvx",
"args": ["benethos-lexware-office-mcp"]
}
}
}其中不会出现你机器上的任何路径,这正是关键所在:uvx 按名称查找包。关于该条目有两点值得了解:
固定版本以保证稳定性:
"args": ["benethos-lexware-office-mcp==0.2.2"]。不固定版本的话,uvx会取它能解析到的最新版本,而客户端重启就足以改变它运行的内容。uvx必须在客户端使用的PATH上,这不总是你终端里的那个——某些 GUI 客户端会传入精简后的环境。如果服务器无法启动,请把uvx的绝对路径放进command,并完全重启客户端而不是重新加载它。
想要自己的命令?
uv tool install benethos-lexware-office-mcp 会给你 benethos-lexware-office-mcp 而不需要前面的 uvx,如果你经常从命令行更改权限,这是值得的。除此之外它没有带来任何好处:两种方式都可以固定相同版本,热启动的差异只有几十毫秒。有一点需要知道——uv 会把它安装到自己的工具目录中,而该目录不在全新安装的 PATH 上。它完成时会说明这一点。运行 uv tool update-shell 并打开一个新终端。
或者从源码运行,用于开发或运行未发布的内容:
git clone https://github.com/benethos-hub/lexware-office-mcp
cd lexware-office-mcp
uv sync
uv run benethos-lexware-office-mcp setup客户端随后需要该检出目录虚拟环境的解释器,command 在 Windows 上指向 .venv/Scripts/python.exe,在其他平台上指向 .venv/bin/python,args 为 ["-m", "benethos_lexware_office_mcp"]。
那里故意没有密钥。 服务器会在 .env 中找到它。客户端的配置文件不是存放凭据的地方:它不是你的文件——另一个程序拥有它,决定它存放在哪里以及何时重写它。它是人们在寻求 MCP 设置帮助时截图的那个文件,在客户端自己的设置视图中可读,并且会随客户端其余配置一起传到下一台机器。.env 至少是这个项目有文档说明的文件,没有任何东西会替你同步它,而且配置界面在写入时永远不会把密钥显示回给你。
那个 .env 已经是需要小心对待的部分。它保存着实时会计系统的凭据,所以要让它远离版本控制、共享文件夹以及其他人能读到的备份。当你停止使用服务器时,删除它并撤销密钥——在扩展、公共 API 下操作——撤销才是真正终止访问的唯一步骤。
4. 完全重启 Claude Desktop——从托盘退出而不是关闭窗口。这是为了你刚编辑的配置文件,客户端只在启动时读取一次,而且 .env 中更改的设置也需要这样做——服务器同样在启动时读取这些设置。权限不需要重启:之后更改权限时,运行中的客户端会收到通知,请参阅单独关闭工具。
在浏览器中配置
uvx benethos-lexware-office-mcp setup127.0.0.1 上的三个页面,用 Ctrl+C 关闭。它们写入与命令行相同的文件,因此你可以使用其中任何一种或两者都用。界面是德语的,因为 Lexware Office 只面向德国公司销售,下面每个页面都按其功能命名,并附上方括号中的标签。
概览(Übersicht)——实际生效的是哪个 .env 和哪个 tools.json,每个设置解析为什么值以及该值来自哪里,每个文件是否已存在,有多少工具处于开启状态以及它们的成本。连接测试在按钮上,绝不在页面加载时进行。
凭据(Zugangsdaten)——API 密钥,在保存前会对照 API 检查(除非你另有说明),以及非机密的设置。密钥绝不会显示回给你、绝不会被记录、也绝不会被导出。如果环境变量在设置它,页面会说明这一点,因为那会覆盖你保存的任何内容。
权限(Rechte)——每个工具一个复选框,分组显示,预设作为按钮。在全新安装且尚无策略文件时,读取工具会预先勾选作为起点——这是表单中的建议,而不是权限:在你按下保存之前仍然没有文件,因此也仍然没有工具,页面会说明这一点。每一行都标明该工具在上下文中消耗助手多少成本,总计会跟随你的勾选:每个启用的工具都会在每次请求时发送给模型,因此开启一个工具既是预算决策也是权限决策。写入工具会被标记,API 无法收回其结果的那些工具会被单独标记:联系人标为 nur App,Lexware Office 会毫不客气地删除它;进入账簿的记录标为 nur App · Buchhaltung。两者都不意味着被卡住——创建时没有任何东西被 festgeschrieben,页面上的图例会列出之后确实会绑定记录的四件事。
配置文件也在这里。将当前选择保存到名称下,之后加载。加载只填充复选框:在你按下保存之前,没有任何内容写入 tools.json。已被占用的名称会被拒绝,而不是悄悄替换已有内容——大小写和空格不会产生第二个配置文件——替换它则是列表旁边自己的按钮。它们存储在策略文件旁边的 tool_profiles.json 中。
策略文件本身可以从同一页面下载并读回——文件原样保存,因此它可以在另一台安装上使用,无论有没有这个界面,而由 --tools 写入的 tools.json 也可以在这里读取。读取一个只会勾选复选框,保存仍然是单独的一次按下。文件未提及的工具保持关闭状态,页面会说明有多少个,这正是命令行中 --tools sync 所做的。
有两点值得了解。它只绑定 127.0.0.1,不绑定其他任何地址——这些页面没有密码,只有在无法从其他机器访问的情况下这才说得过去,因此没有更改它的选项。而且它是一个单独的命令:MCP 服务器从不提供 HTTP 服务,像 Claude Desktop 这样的客户端启动的是那个命令,而不是这个。
--port N 可以移动它,--no-browser 只打印地址,--env-file 和 --tools-file 指定它编辑哪些文件。与其他地方不同,这些文件不必已经存在。
如果你的客户端用 --tools-file 启动服务器,请给 setup 相同的参数——否则它会编辑不同的文件并报告成功。两个进程在启动时都会固定自己的文件,之后绝不会更改它们,而且两者都无法看到对方是如何启动的。概览页面会打印 "args" 行,使你的客户端与界面持有的文件匹配,这是更简单的方向。
单独关闭工具
一个 JSON 文件决定这个服务器提供什么,其他任何东西都不起作用。要么在上面的 setup 下勾选复选框,要么用以下内容启动该文件:
uvx benethos-lexware-office-mcp --tools read-only该命令将每个工具写入 tools.json,读取时已启用的保持启用、其余保持禁用,并打印它所执行的操作。有三个预设,每个都包含后一个:
启用 | |
| 仅查询 |
| 以及创建和更新 |
| 以及删除文章 |
| 不改变任何标志,只添加文件中尚未见过的工具 |
--tools show 仅报告。--tools-file PATH 指定写入位置,并可与所有预设配合使用——--tools write --tools-file ./tools.json 会在该位置创建文件。
预设会覆盖整个文件,因此手动编辑会丢失。请用预设来创建文件,而不是更新文件。升级带来新工具后,运行 --tools sync:它会将新工具写入为禁用状态,保留你设置的所有标志,并且绝不会启用任何工具。最后这一点正是它成为这些预设中唯一适合从脚本运行的原因。
第三步之所以独立,是因为它本身就是一个独立的决定:被删除的东西就永远消失了,因此应该通过明确指定名称来选择,而不是通过选择最大的选项。恰好有一个工具具有这种效果,即 delete_article,而且这不是临时状态——文章是此 API 唯一能删除的内容,并且事后也无法预订、定稿或作废任何内容。
如果不使用 --tools-file,文件的搜索方式与 .env 完全相同,优先级从低到高:
每用户配置目录
从源码运行时,检出目录的
config/工作目录的
config/,然后是工作目录根目录
最后找到的文件胜出,而尚未被任何人创建的文件则解析为第一个位置。之后,编辑它:
{
"create_contact": false,
"search_contacts": true,
"upload_file": false
}设置为 false 的工具不会被列出,也无法被调用。文件中未提及的工具同样处于禁用状态——沉默即拒绝,因此随升级而来的工具会等待你,而不是自行出现。完全没有文件意味着没有任何工具,这正是 --tools 属于服务器设置环节的原因。
文件在工具列表构建时被读取,并在每次调用时再次读取,因此编辑会立即在两个方向生效——无需重启。服务器还会在启用工具集合发生变化时通知客户端,因此客户端会自行重新获取列表:Claude Desktop 在运行中就能感知到变化。无论哪种方式都不依赖于此,因为已被关闭的工具无论客户端仍在显示什么列表都无法被调用。如果你的客户端没有注意到,请重启它——Claude Desktop 通过从托盘退出来重启。
每个工具还声明了自身的性质——读取还是写入、属于哪个分组,以及它写入的内容是否可以被再次删除。这个分类正是 --tools read-only 所启用的内容,也是浏览器界面进行分组和标记的依据。它绝不会决定一次调用:只有文件才能决定。
配置
值的来源,以及哪个值胜出
只应用一个 .env,绝不会多个。 以下是查找它的位置,从低到高,存在的最高的那个就是所使用的文件——其他文件不会被读取:
每用户配置目录中的
.env服务器运行所在的检出目录的
config/.env(如果从检出目录运行)工作目录中的
config/.env,然后是.env
--env-file 直接指定文件名,此时完全不进行搜索。这与 --tools-file 对策略文件遵循的规则相同,因此两个标志含义相同:就是这个文件,没有别的。
有两样东西位于该文件之外,一个在其下,一个在其上:
内置默认值,用于文件中未提及的设置
真实的环境变量,它胜过文件中的任何内容
最后一项是让人意外的地方。在你的 shell 中导出的、放在客户端 env 块中的、或固定在 Compose 文件中的设置,无法通过编辑 .env 来更改——无论是手动编辑,还是通过 setup。值被写入了,文件是正确的,但什么也不会发生。
配置界面会直接告诉你,而不是让你自己去发现:每个设置都带有一个标明其来源的徽章,被环境变量持有的设置会以这种方式标记。当你保存的内容似乎被忽略时,那个徽章就是答案。
在容器中,这不是边缘情况。 compose.yaml 将传输方式、绑定地址、端口和允许的主机固定为真实的环境变量,因为这些属于容器而非容器内的安装。其他一切——API 密钥、HTTP 令牌、限制——都留给配置卷,这正是配置界面能够更改它们的原因。
相同的顺序适用于策略文件,LXO_MCP_TOOL_POLICY 和 --tools-file 可以直接指定一个文件。界面固定了它启动时找到的那个文件,因此页面无法在你不知情的情况下更换自己的操作对象。
文件命名
--env-file PATH 直接指定设置文件而不是搜索,并与 --tools-file 配对,使客户端配置中的一条条目携带自己的账户和自己的权限:
"args": ["--env-file", "/path/to/test.env",
"--tools-file", "/path/to/test-tools.json"]不存在的路径会被拒绝,而不是静默回退到搜索——setup 除外,它的存在部分就是为了创建文件。
setup 会为你写入此文件。
设置
变量 | 含义 | 默认值 |
| 你的 Lexware Office API 密钥。必填。 | — |
| 按工具启用的文件,见下文 | 配置目录中的 |
| API 基础 URL |
|
| 深链接的 Web 应用基础地址 |
|
| 下载文档的存放位置 | 用户缓存目录 |
| HTTP 超时时间(秒) |
|
| 每秒请求数,全局适用于所有端点 |
|
| 令牌桶容量。账户自身的桶容量为 4 |
|
| 搜索请求和返回的每页行数 |
|
|
|
|
| stderr 上的日志级别 |
|
|
|
|
| 每个 HTTP 请求必须携带的共享密钥。HTTP 传输方式必填。 | — |
| HTTP 传输方式的绑定地址 |
|
| 绑定端口 |
|
| 传输方式服务的 URL 路径 |
|
| 除回环地址外接受的 | — |
| 启动时若未设置则生成令牌并写入设置文件 | 关闭 |
| 设置文件变化时结束进程,供负责重启的机制使用 | 关闭 |
以上每个设置都在使用中。LXO_MCP_PAGE_SIZE 上限为 250,这是任何端点接受的最低页面大小,更大的值会在启动时被拒绝,而不是在之后变成 API 错误。
传输方式
stdio 是默认方式,也是 Claude Desktop 和类似的本地客户端所使用的:客户端将服务器作为自己的子进程启动,其他任何东西都无法与之通信。
streamable-HTTP 和 SSE 在端口上提供相同的工具,适用于容器或专用机器:
uvx benethos-lexware-office-mcp --transport streamable-http --port 8770有两样东西挡在该端口前面,两者都不可省略。一个是承载令牌,每个请求都必须以 Authorization: Bearer <token> 的形式携带——没有 LXO_MCP_BEARER_TOKEN,服务器会完全拒绝启动 HTTP 传输方式,因为任何能访问该端口的人都可以消耗你的 Lexware 凭据。另一个是 SDK 的 DNS 重绑定防护,它根据回环名称的允许列表检查 Host 和 Origin,并通过 --allowed-hosts 扩展,适用于容器或代理在端口前放置其他名称的情况。
两者都不会让该端口可以在网络上安全发布。它们只是让它在与其他进程共享的机器上能够存活。--host 绑定到回环以外的地址,容器必须这样做——参见在容器中了解为什么这看起来像是放宽限制但实际上并非如此。
在容器中
镜像为 linux/amd64 和 linux/arm64 发布,因此运行一个容器不需要本仓库中的任何内容:
docker pull ghcr.io/benethos-hub/lexware-office-mcp:latest为你依赖的任何内容固定一个版本——:0.2.2 表示精确版本,:0.2 表示跟随其补丁版本。:latest 随每个版本移动,:edge 按需从 main 分支的当前内容构建,根本不是一个发布版本。
使用 Compose
docker compose up -d # the server, on 127.0.0.1:8770
docker compose --profile setup up -d # add the configuration interface
docker compose rm -f -s setup # take the interface away again不要运行 docker compose --profile setup down。 那是整个项目:它会连同服务器一起关闭。rm -f -s setup 会停止并移除这一个服务,让服务器继续运行。docker compose stop setup 也可以,并保留已停止的容器供下次使用。
按原样提供时,compose.yaml 从本检出目录构建。其两个服务中各有两行被注释掉的行,可切换到已发布的镜像,此时该文件就是你从这里需要的唯一内容。
作为单个容器
docker run -d --name lexware-office-mcp \
--restart unless-stopped \
-p 127.0.0.1:8770:8770 \
-v lxo-config:/config -v lxo-downloads:/downloads \
ghcr.io/benethos-hub/lexware-office-mcp:latest它为自身生成的令牌位于配置卷中,你可以从那里读取:
docker exec lexware-office-mcp grep LXO_MCP_BEARER_TOKEN /config/.env只读取那一行而不是整个文件:一旦输入了密钥,API 密钥也会存放在那里,它不应该在你可能截屏的终端中滚动显示。
配置界面是同一个镜像,使用其另一个命令,指向同一个卷:
docker run --rm -d --name lexware-office-mcp-setup \
-p 127.0.0.1:8771:8771 \
-v lxo-config:/config -v lxo-downloads:/downloads \
ghcr.io/benethos-hub/lexware-office-mcp:latest \
setup --no-browser --host 0.0.0.0 --port 8771 \
--env-file /config/.env --tools-file /config/tools.json它以 --rm 启动,因此停止它也就是它的终结:
docker stop lexware-office-mcp-setup--restart unless-stopped 在这里不是装饰。 容器在设置文件变化时结束其进程,这正是将已保存的设置带入运行中服务器的方式。没有重启策略,它就会结束并保持结束状态。
完成后关闭界面
打开 http://127.0.0.1:8771/,输入密钥,勾选工具——然后停止它。没有任何东西会替你停止它。 它没有登录功能,它接受 API 密钥,并且只要机器在运行,它就会一直愉快地提供该页面。
docker compose rm -f -s setup # Compose
docker stop lexware-office-mcp-setup # a single container
docker ps --filter name=setup # nothing listed means it is off服务器是设计来持续运行的。界面是设计来在你配置它的那几分钟内运行的,这就是为什么普通的 docker compose up 会把它排除在外,也是为什么它没有重启策略:一旦停止,它就会一直保持停止状态,直到你再次要求它运行。
无需事先准备任何东西。 首次启动时,服务器会生成一个 bearer token,将其写入配置卷并告知用户——界面会显示它,这就是客户端需要的值。它没有被烘焙进镜像中,否则每个副本都会共享同一个 token。
容器绑定的是 0.0.0.0,这并非放宽限制。 容器自身回环上的进程根本无法通过已发布的端口访问。隔离性来自网络命名空间,而谁能访问该端口由发布配置决定,它只映射 127.0.0.1。
在浏览器中保存的设置会到达正在运行的服务器。 设置只在启动时读取一次,因此当设置文件发生变化时,容器会被指示结束,Compose 在一秒后重新启动它。Compose 固定为真实环境变量的内容——传输方式、绑定地址、端口、允许的主机——属于容器本身,无法从卷中更改,请参阅配置。
示例提示词
服务器连接后,以下这类提示词是预期的用法:
"哪些发票仍未结清,其中哪些已逾期?"
"显示我们本季度向客户 Muster GmbH 开具的所有账单。"
"发票 RE-2024-0142 包含什么内容,它是否已付款?"
"查找编号为 A-1007 的商品,并告诉我它的当前价格。"
"下载我们开具的最后一张贷项通知单的 PDF。"
"给我一个在 Lexware Office 中打开凭证 X 的链接。"
速率限制
Lexware API 允许每秒两个请求,通过令牌桶强制执行。该配额是全局的——它同时覆盖 API 的所有端点,因此读取联系人和读取发票消耗的是同一个配额。
服务器通过进程中所有请求共享的单个令牌桶来模拟这一点,默认情况下以略低于文档规定速率的速度补充令牌。Lexware 指出,如果精确执行限制而不留缓冲,一旦网络抖动改变到达时间,仍然容易产生 429 错误,因此默认值留有余量。请求通过该令牌桶串行化而不是并行发出,这意味着涉及许多文档的宽泛问题会变慢而不会被阻止。
有两件事值得了解:
该配额属于你的账户,而不是这个进程。服务器的另一个实例、其他集成或你自己运行的脚本,都从同样的每秒两个中消耗。
Lexware 警告说,在收到 429 后继续猛击的客户端可能会被永久封锁。因此,服务器会指数级退避,并在几次尝试后放弃,而不是更努力地重试。
该账户的令牌桶在 2026-08-21 被测量,容量为四:同时发出的五个请求中四个通过,一个被拒绝。默认值 2 将其中一半留给同一账户上的其他消耗者——Web 应用、其他集成、此服务器的另一个实例。只有当你确定此服务器是唯一消费者时,才将其提高到 4。
如果你的账户行为不同,两个限流器值都可以通过 LXO_MCP_RATE 和 LXO_MCP_BURST 配置。
开发
uv sync --extra dev
uv run pytest -q
uv run ruff check .
uv run ruff format --check .
uv run mypy测试套件完全离线。它模拟 HTTP 层,不需要 API 密钥,因此可以在任何地方运行。有两种测试会启动进程但不会离开本机:三种测试将服务器作为真正的子进程启动,并通过 stdio 与它进行 MCP 通信,这也证明了启动路径上没有任何内容写入 stdout;配置界面通过真实的回环 HTTP 服务器和真实的 cookie jar 驱动,因为它的 CSRF 防护只有以浏览器遇到它们的方式测试才有意义。
此仓库不附带任何 API 密钥,CI 中也不应有任何密钥,因此检出代码永远无法自行与 Lexware 通信。因此,针对真实 API 检查服务器始终是使用你提供的密钥进行的有意本地运行,与上述测试套件分开,且永远不属于它:
uv run python tests/smoke.py
uv run python tests/smoke.py --env-file path/to/.env它读取你的账户,不向其写入任何内容。它构建的服务器使用 read-only 预设,因此写入工具根本不存在,无法被调用。它会打印检查了什么、账户中没有什么、什么失败了,并遮蔽记录 ID,以便报告可以粘贴到某处。pytest 永远不会运行它。关于为什么实时检查不是门槛,请参阅 SPECS.md 第 14.1 节。
欢迎贡献和提交问题。SPECS.md 记录了设计决策,以及背后的理由和测量数据。
许可证
MIT。请参阅 LICENSE。
商标与关联关系
本项目与 Lexware、Haufe-Lexware GmbH & Co. KG 或其任何子公司均无关联、未经其认可、亦未受其赞助。 "Lexware" 和 "Lexware Office" 是其各自所有者的商标,此处仅以描述性方式用于指代本软件所集成的 API。
该软件仅使用账户所有者提供且可撤销的凭据与文档化的公共 API 通信。该 API 的使用受 Lexware 自身条款的约束,你独立于本项目接受这些条款。
Maintenance
Related MCP Connectors
Read Lexware Office contacts, articles, invoices and vouchers; create contacts and draft invoices.
211Connect Exact Online to your AI assistant via MCP. Manage Exact Online with natural language.
Connect Claude or Cursor to books, invoices, bills, payroll, and sealed closes.
Read incoming supplier invoices through a remote MCP server and get structured data for accounting.
41
Related MCP Servers
- FlicenseBqualityDmaintenanceMCP server for DACH accounting automation. Connect AI assistants to sevDesk and Lexoffice — create invoices, manage contacts, handle bookings and vouchers for German-speaking businesses.1543 npm-
- AlicenseBqualityAmaintenanceMCP server for the Lexware Office API that enables management of invoices, contacts, articles, vouchers, and more through the Model Context Protocol.66460 npm6Functional Source , Version 1.1, MIT Future
- AlicenseAqualityBmaintenanceEnables MCP-capable assistants to query and manage Lexware Office contacts, sales documents, vouchers, files, payments, webhooks, and reference data via the Lexware Office public API. Adds bank reconciliation tools for matching bank statement CSVs against Lexware vouchers or scanned receipt PDFs.4MIT
- AlicenseAqualityBmaintenanceMCP server for Lexware Office that enables querying and managing contacts, sales documents, vouchers, files, payments, and webhooks through a sandboxed two-tool interface (search/execute) with read-only-by-default write safety.2MIT