Lexware Office MCP Server
Servidor MCP para a API do Lexware Office — gerencie faturas, contatos, artigos, comprovantes e muito mais. 65 ferramentas em 20 domínios de recursos.
Documentação
lexware-mcp-server
Servidor MCP para a API do Lexware Office. Gerencie faturas, contatos, artigos, comprovantes e muito mais através do Model Context Protocol.
Não oficial — projeto da comunidade. Não é afiliado, endossado ou suportado pela Lexware GmbH ou Haufe Group. "Lexware" e "Lexware Office" são marcas registradas de seus respectivos proprietários; usadas aqui apenas para identificar a API que este cliente utiliza (uso justo nominativo).
66 ferramentas em 20 domínios de recursos, com 6 pontos de entrada para você escolher o servidor certo para o limite de ferramentas do seu cliente MCP.
Instalação
npm install -g @lazyants/lexware-mcp-server
Ou execute diretamente:
npx @lazyants/lexware-mcp-server
Configuração
O token da API é resolvido nesta ordem:
- Chaveiro do sistema operacional (recomendado — o token nunca é gravado em disco em texto puro)
- Variável de ambiente
LEXWARE_API_TOKEN
Armazene o token no chaveiro do sistema operacional
Obtenha seu token nas configurações da API do Lexware Office e armazene-o com o gerenciador de credenciais nativo do seu sistema operacional.
[!IMPORTANT] Os comandos abaixo leem o token de um prompt interativo em vez de recebê-lo como argumento, para que ele nunca apareça no histórico do shell ou na lista de processos. Evite colar o token diretamente na linha de comando.
macOS
Omitir o valor após -w faz com que o security solicite o token (com confirmação):
security add-generic-password -s "lexware-mcp" -a "api-token" -w
Windows (PowerShell)
cmdkey só pode receber o token como argumento de linha de comando, o que o expõe na
lista de processos. Em vez disso, leia-o de um prompt oculto e grave-o diretamente
no Gerenciador de Credenciais do Windows via CredWrite, para que o token nunca chegue ao argv.
O nome de destino da credencial é <account>.<service> — api-token.lexware-mcp
para o serviço padrão — que é exatamente o que o servidor lê de volta:
$secure = Read-Host -AsSecureString "Lexware API token"
Add-Type -Namespace LexwareKeyring -Name Native -MemberDefinition @'
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CREDENTIAL {
public uint Flags;
public uint Type;
[MarshalAs(UnmanagedType.LPWStr)] public string TargetName;
[MarshalAs(UnmanagedType.LPWStr)] public string Comment;
public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
public uint CredentialBlobSize;
public IntPtr CredentialBlob;
public uint Persist;
public uint AttributeCount;
public IntPtr Attributes;
[MarshalAs(UnmanagedType.LPWStr)] public string TargetAlias;
[MarshalAs(UnmanagedType.LPWStr)] public string UserName;
}
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool CredWriteW(ref CREDENTIAL credential, uint flags);
'@
$blob = [Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($secure)
try {
$cred = New-Object LexwareKeyring.Native+CREDENTIAL
$cred.Type = 1 # CRED_TYPE_GENERIC
$cred.Persist = 2 # CRED_PERSIST_LOCAL_MACHINE
$cred.TargetName = 'api-token.lexware-mcp' # "<account>.<service>"
$cred.UserName = 'api-token'
$cred.CredentialBlob = $blob
$cred.CredentialBlobSize = $secure.Length * 2 # UTF-16 bytes, no terminator
if (-not [LexwareKeyring.Native]::CredWriteW([ref]$cred, 0)) {
throw "CredWrite failed (Win32 error $([Runtime.InteropServices.Marshal]::GetLastWin32Error()))"
}
Write-Host 'Stored Lexware API token in Windows Credential Manager.'
} finally {
[Runtime.InteropServices.Marshal]::ZeroFreeCoTaskMemUnicode($blob)
$secure.Dispose()
Remove-Variable secure, blob
}
Usando um
LEXWARE_KEYRING_SERVICEpersonalizado (ex.:acme)? DefinaTargetNamecomoapi-token.acmepara corresponder — o servidor procura o token sob<account>.<service>.
Linux
secret-tool store --label="Lexware Office API" service lexware-mcp username api-token
# (prompts for the token value)
Depois de armazenado, os arquivos de configuração do MCP não precisam de credenciais — o servidor lê o token do chaveiro na inicialização.
Use uma variável de ambiente em vez disso
Se preferir não usar o chaveiro, defina LEXWARE_API_TOKEN no seu shell ou na configuração do cliente MCP:
export LEXWARE_API_TOKEN=your-token-here
Variáveis de ambiente
| Variável | Padrão | Descrição |
|---|---|---|
LEXWARE_API_TOKEN | — | Token da API; usado quando o chaveiro não tem entrada para o serviço configurado |
LEXWARE_KEYRING_SERVICE | lexware-mcp | Nome do serviço no chaveiro. Substitua ao conectar a várias contas Lexware simultaneamente — execute uma instância do servidor por conta, cada uma com seu próprio nome de serviço |
Opcionalmente, substitua a chave pública de assinatura de webhook usada pelo lexware_verify_webhook_signature
(por padrão, buscada da Lexware e armazenada em cache):
export LEXWARE_WEBHOOK_PUBLIC_KEY="$(cat lexware-webhook-public.pem)"
Pontos de Entrada
| Comando | Domínios | Ferramentas |
|---|---|---|
lexware-mcp-server | Todos os 20 domínios | 66 |
lexware-mcp-sales | Faturas, Notas de Crédito, Cotações, Confirmações de Pedido, Notas de Entrega, Faturas de Adiantamento, Cobranças, Lista de Comprovantes | 32 |
lexware-mcp-contacts | Contatos, Artigos | 10 |
lexware-mcp-bookkeeping | Comprovantes, Lista de Comprovantes, Pagamentos | 8 |
lexware-mcp-reference | Países, Condições de Pagamento, Categorias de Lançamento, Perfil, Layouts de Impressão | 5 |
lexware-mcp-system | Assinaturas de Eventos, Arquivos, Modelos Recorrentes | 12 |
Use servidores divididos para reduzir o tamanho do contexto — escolha apenas as divisões que você precisa.
Claude Code
Adicione ao ~/.claude/settings.json. Se você armazenou o token no chaveiro do sistema operacional sob o nome de serviço padrão lexware-mcp (recomendado), nenhuma chave env é necessária:
{
"mcpServers": {
"lexware": {
"command": "npx",
"args": ["-y", "@lazyants/lexware-mcp-server"]
}
}
}
Se preferir a abordagem com variável de ambiente:
{
"mcpServers": {
"lexware": {
"command": "npx",
"args": ["-y", "@lazyants/lexware-mcp-server"],
"env": { "LEXWARE_API_TOKEN": "your-token-here" }
}
}
}
Servidores divididos
Use servidores divididos para reduzir o tamanho do contexto — escolha apenas os pontos de entrada que você precisa. A flag -p @lazyants/lexware-mcp-server informa ao npx de qual pacote obter o comando; o argumento final (ex.: lexware-mcp-sales) é o binário específico do ponto de entrada definido nesse pacote (veja Pontos de Entrada):
{
"mcpServers": {
"lexware-sales": {
"command": "npx",
"args": ["-y", "-p", "@lazyants/lexware-mcp-server", "lexware-mcp-sales"]
},
"lexware-contacts": {
"command": "npx",
"args": ["-y", "-p", "@lazyants/lexware-mcp-server", "lexware-mcp-contacts"]
}
}
}
Exemplo com múltiplas contas (duas empresas Lexware, tokens armazenados sob nomes de serviço separados no chaveiro):
{
"mcpServers": {
"lexware-company-a": {
"command": "npx",
"args": ["-y", "@lazyants/lexware-mcp-server"],
"env": { "LEXWARE_KEYRING_SERVICE": "lexware-company-a" }
},
"lexware-company-b": {
"command": "npx",
"args": ["-y", "@lazyants/lexware-mcp-server"],
"env": { "LEXWARE_KEYRING_SERVICE": "lexware-company-b" }
}
}
}
Claude Desktop
Adicione ao claude_desktop_config.json. Com o chaveiro do sistema operacional (recomendado — assume que o token está armazenado sob o nome de serviço padrão lexware-mcp):
{
"mcpServers": {
"lexware": {
"command": "npx",
"args": ["-y", "@lazyants/lexware-mcp-server"]
}
}
}
Com uma variável de ambiente em vez disso:
{
"mcpServers": {
"lexware": {
"command": "npx",
"args": ["-y", "@lazyants/lexware-mcp-server"],
"env": { "LEXWARE_API_TOKEN": "your-token-here" }
}
}
}
Ferramentas
Faturas (5 ferramentas) — vendas
lexware_create_invoice (suporta finalize=true na criação), lexware_get_invoice, lexware_download_invoice_file, lexware_pursue_invoice, lexware_deeplink_invoice
Notas de Crédito (5 ferramentas) — vendas
lexware_create_credit_note, lexware_get_credit_note, lexware_download_credit_note_file, lexware_pursue_credit_note, lexware_deeplink_credit_note
Cotações (4 ferramentas) — vendas
lexware_create_quotation, lexware_get_quotation, lexware_download_quotation_file, lexware_deeplink_quotation
Confirmações de Pedido (5 ferramentas) — vendas
lexware_create_order_confirmation, lexware_get_order_confirmation, lexware_download_order_confirmation_file, lexware_pursue_order_confirmation, lexware_deeplink_order_confirmation
Notas de Entrega (5 ferramentas) — vendas
lexware_create_delivery_note, lexware_get_delivery_note, lexware_download_delivery_note_file, lexware_pursue_delivery_note, lexware_deeplink_delivery_note
As ferramentas independentes de criação de fatura, nota de crédito, cotação, confirmação de pedido e nota de entrega
aceitam finalize: true para finalizar na criação. Omita-o ou defina false para criar um rascunho; apenas
true explícito envia o parâmetro de consulta ?finalize=true da API.
Faturas de Adiantamento (3 ferramentas) — vendas
lexware_get_down_payment_invoice, lexware_download_down_payment_invoice_file, lexware_deeplink_down_payment_invoice
Cobranças (4 ferramentas) — vendas
lexware_get_dunning, lexware_download_dunning_file, lexware_pursue_dunning, lexware_deeplink_dunning
Lista de Comprovantes (1 ferramenta) — vendas, contabilidade
lexware_list_voucherlist
Para sincronização incremental, updatedDateFrom e updatedDateTo filtram a data da última modificação
(yyyy-MM-dd, dias completos em CET/CEST). sort aceita voucherDate, voucherNumber, createdDate
ou updatedDate seguido por ASC ou DESC, por exemplo updatedDate,DESC. Os filtros de status incluem
transferred e sepadebit; o status transitório overdue não pode ser combinado com outros status.
Por padrão, isso é uma passagem de página única da resposta da API. Duas adições são opcionais:
fetchAllPages: truesegue a paginação até que todas as páginas sejam recuperadas, limitado a 100 solicitações. O resultado adicionafetchedPagesetruncated, sendo este último uma marcação de conjunto interrompido pelo limite — campos da API comototalElementssão preservados.contactName(curingas estilo SQL%/_, sem diferenciar maiúsculas de minúsculas) ehasOpenAmountfiltram no lado do cliente após a busca, e cada um implicafetchAllPages. Eles são aplicados aqui em vez de emlexware_list_vouchersporque/voucherlisté a forma de resposta que carregacontactNameeopenAmount.
page não pode ser combinado com nenhum dos três — esses modos leem todas as páginas, então um deslocamento inicial é
sem sentido. Use size para controlar o tamanho do lote em vez disso. A combinação é rejeitada em vez de
ignorada silenciosamente, para que ninguém acredite que um deslocamento foi respeitado quando não foi.
Contatos (5 ferramentas) — contatos
lexware_list_contacts, lexware_get_contact, lexware_create_contact, lexware_update_contact, lexware_deeplink_contact
lexware_deeplink_contact retorna deeplink e o alias permanente url, ambos contendo a
mesma URL de contato. Qualquer chave de saída é suportada.
Artigos (5 ferramentas) — contatos
lexware_list_articles, lexware_get_article, lexware_create_article, lexware_update_article, lexware_delete_article
Comprovantes (6 ferramentas) — contabilidade
lexware_list_vouchers, lexware_get_voucher, lexware_create_voucher, lexware_update_voucher, lexware_upload_voucher_file, lexware_deeplink_voucher
lexware_list_vouchers exige voucherNumber. GET /vouchers é um endpoint de consulta, não uma
coleção navegável — a API responde 400 "voucherNumber parameter is required" sem ele. Para
navegar ou filtrar comprovantes, use lexware_list_voucherlist, que é o endpoint de coleção e também
carrega os campos de resumo (contactName, openAmount) que /vouchers não carrega.
lexware_get_voucher normaliza voucherStatus para minúsculas e tenta novamente um 404 três vezes
(1 s / 2 s / 4 s) para cobrir o atraso de indexação após um upload; se o comprovante ainda estiver ausente,
retorna { voucherId, status: "processing", message }. Outras falhas são relatadas como erros.
Pagamentos (1 ferramenta) — contabilidade
lexware_get_payments
Países (1 ferramenta) — referência
lexware_list_countries
Condições de Pagamento (1 ferramenta) — referência
lexware_list_payment_conditions
Categorias de Lançamento (1 ferramenta) — referência
lexware_list_posting_categories
Perfil (1 ferramenta) — referência
lexware_get_profile
Layouts de Impressão (1 ferramenta) — referência
lexware_list_print_layouts
Assinaturas de Eventos (5 ferramentas) — sistema
lexware_create_event_subscription, lexware_list_event_subscriptions, lexware_get_event_subscription, lexware_delete_event_subscription, lexware_verify_webhook_signature
Seu aplicativo hospeda o manipulador de callbacks; este servidor MCP gerencia assinaturas e verifica assinaturas, mas não hospeda um receptor. Confirme os callbacks prontamente com HTTP 200 ou 204 dentro do tempo limite de 5 segundos (5000 ms) da Lexware, coloque o payload recebido na fila e processe-o de forma assíncrona.
Use a fila para absorver rajadas de eventos e aplicar novas tentativas/backoff controlados de processamento independentemente das novas tentativas de entrega da Lexware. Limite as chamadas de API de saída para respeitar os limites de taxa da API. Veja as práticas recomendadas de assinatura de eventos da Lexware.
Arquivos (4 ferramentas) — sistema
lexware_upload_file, lexware_download_file, lexware_get_file_status, lexware_deeplink_file
lexware_download_file aceita format: "pdf" (padrão) ou format: "xml" para recuperar um
original XML de e-invoice disponível. XML incorporado em um PDF não pode ser recuperado separadamente; a Lexware
retorna 404 quando o XML solicitado não está disponível. Os downloads retornam os bytes como contentBase64.
lexware_get_file_status chama GET /files/{id}/status. O GET /files/{id} puro é a rota de download
binário — com Accept: application/json ele ainda responde 200 com o corpo do arquivo
codificado em base64, então nunca pode produzir metadados de status. A rota de status é limitada por escopo: chaves de API
sem a permissão necessária recebem access_denied da Lexware em vez de um status.
Ambas as ferramentas de upload (lexware_upload_file e lexware_upload_voucher_file) recebem o arquivo como
contentBase64 ou como filePath — um caminho absoluto legível pelo processo do servidor MCP. Prefira
filePath para qualquer coisa grande: base64 infla o payload em cerca de um terço e precisa percorrer
a janela de contexto do modelo. Com filePath, fileName assume o nome base do arquivo e
contentType é detectado automaticamente para .png, .jpg/.jpeg, .tiff/.tif e .xml, com fallback
para application/pdf. Forneça exatamente um dos dois — fornecer ambos, ou nenhum, é um erro de
validação.
Os uploads são limitados a 5 MB. Para filePath, o tamanho é obtido do descritor aberto antes de o
arquivo ser lido, então um arquivo superdimensionado custa um stat em vez de um carregamento completo na memória, e qualquer coisa
que não seja um arquivo regular é recusada imediatamente (ler /dev/zero de outra forma nunca retornaria).
A contagem de bytes decodificados é verificada novamente depois, o que também cobre contentBase64. Falhas
carregam um erro file_too_large com os tamanhos real e máximo.
Modelos Recorrentes (3 ferramentas) — sistema
lexware_list_recurring_templates, lexware_get_recurring_template, lexware_deeplink_recurring_template
Segurança
- Use o chaveiro do sistema operacional para manter seu token da API fora dos arquivos de configuração e do histórico do shell (veja Configuração)
- Nunca envie seu token da API para o controle de versão
- Use acesso somente leitura quando precisar apenas listar/obter recursos
- As ferramentas de criar, atualizar e excluir modificam dados comerciais reais — faturas, contatos e registros contábeis na sua conta Lexware
- A limitação de taxa é tratada automaticamente: as solicitações são repetidas com backoff exponencial em 429, incluindo uploads de arquivos — o corpo multipart é reconstruído do zero em cada tentativa, para que possa ser reproduzido com segurança
Lançamento
Releases são publicados por meio do evento GitHub Release. Fluxo do mantenedor:
-
Atualize a versão em
package.json,package-lock.jsoneserver.json(npm version <x.y.z> --no-git-tag-versionatualiza os dois primeiros juntos).npm run check-versionsfalha de forma rígida, a menos quepackage.json#/version,server.json#/packages[0].versione ambos os campos de versãopackage-lock.json(raiz epackages[""]) estejam de acordo.server.json#/versioné verificado de forma mais flexível: ele deve estar presente, mas só é comparado compackages[0].versioncomo uma verificação de regressão — ele pode legitimamente estar à frente (republicações apenas no registro atualizam apenas esse campo), então um valor deixado para trás na versão anterior passa com uma linhaWARN:e sem falha. Para uma versão comum, ambos devem avançar juntos, então leia a saída do script em vez de confiar no código de saída.CHANGELOG.mdnão é verificado de forma alguma. -
Atualize
CHANGELOG.md. -
Faça o commit e mescle o aumento de versão em
mainantes de criar o release. Em seguida, crie a tag você mesmo, em um SHA que você verificou, e só então crie o release a partir dela:V=X.Y.Z && PR=<release-pr-number> && SHA="$(gh pr view "$PR" --json mergeCommit -q .mergeCommit.oid)" && test -n "$SHA" && git fetch origin main && git merge-base --is-ancestor "$SHA" origin/main && PKG="$(git show "$SHA:package.json")" && test "$(printf '%s' "$PKG" | node -pe 'JSON.parse(require("fs").readFileSync(0,"utf8")).version')" = "$V" && CL="$(git show "$SHA:CHANGELOG.md")" && printf '%s\n' "$CL" | awk -v v="$V" 'index($0,"## ["v"]")==1{f=1;next} /^## \[/{f=0} /^\[[0-9]+\.[0-9]+\.[0-9]+\]:/{f=0} f' > "/tmp/notes-v$V.md" && grep -q '[^[:space:]]' "/tmp/notes-v$V.md" && git tag -a "v$V" "$SHA" -m "v$V" && git push origin "v$V" && gh release create "v$V" --verify-tag --notes-file "/tmp/notes-v$V.md"A falha que isso evita: sem uma tag existente,
gh release createcoloca uma na ponta do branch padrão, então executá-lo enquanto o aumento ainda está em um branch de release marca o commit da versão anterior. O workflow então publica qualquer versão que encontrar naquele commitpackage.json, e você obtém um GitHub ReleasevX.Y.Zque silenciosamente republica a versão antiga. Desde a 5.2.0, o próprio workflow de publicação se recusa a continuar quandoGITHUB_REF_NAMEnão év<package.json version>(#103), então um release com tag incorreta agora falha antes denpm publishem vez de republicar silenciosamente. Essa proteção só é acionada quando o workflow já está em execução — a sequência acima é o que impede que o commit errado seja marcado em primeiro lugar, então continue usando-a em vez de confiar no workflow para detectar o erro.Cada elemento é essencial:
gh pr view … .mergeCommit.oidnomeia o commit de squash do próprio PR do release. Não substitua porgit rev-parse origin/main— isso é apenas o que estiver emmainno momento em que você olhar, então um merge não relacionado que chegar no intervalo será marcado e publicado em seu lugar.ghsai com 0 e não imprime nada para um PR não mesclado, daí otest -nexplícito.- A cadeia
&¶ na primeira falha em vez de cair na etapa irreversível. Ambas as chamadasgit showsão atribuídas a uma variável em vez de serem canalizadas diretamente, para que seu status de saída seja realmente verificado — um pipeline relata apenas o status do seu último comando, a menos quepipefailesteja definido, o que não é assumido aqui. git merge-base --is-ancestorprova que o commit está realmente acessível a partir demain. A mera existência não é suficiente — um commit pode estar presente localmente porque algum outro branch foi buscado, e se seus arquivos de versão coincidirem, ele passaria por todas as verificações restantes.- O teste de versão lê
package.jsondo commit alvo, não da árvore de trabalho, que ainda mostraria a versão correta enquanto$SHAapontasse para outro lugar. - O
awkextrai a seção dessa versão doCHANGELOG.mddo commit para--notes-file. Sem ele, o corpo do release é o que--notes-from-tagencontrar na anotação — para este fluxo, a string literalvX.Y.Z, que é uma nota de release ruim para qualquer versão e ativamente enganosa para uma major com uma mudança que quebra compatibilidade. Ele para no próximo cabeçalho## [ou na primeira definição de referência de link, porque a entrada mais antiga do arquivo não tem cabeçalho depois dela e, de outra forma, engoliria todo o bloco de referências de link.grep -qem vez detest -sprotege o resultado: uma seção que está vazia exceto por sua linha em branco ainda produz um arquivo de um byte, quetest -saceita. --verify-tagfazghabortar em vez de inventar uma tag se o push não chegou — a proteção contraghcair no comportamento de ponta-do-branch-padrão descrito acima.
Se
gh release createfalhar depois que a tag já foi enviada, não execute todo o bloco novamente — ele parará emgit tag, o que está correto. Execute novamente apenas o comando final. -
O workflow
Publish to npm + MCP Registryé executado automaticamente: elenpm publishcom proveniência, consulta o registro até que o tarball esteja disponível e então envia oserver.jsoncorrespondente para o MCP Registry viamcp-publisher.
O workflow ignora npm publish de forma limpa se a versão já estiver no npm (proteção de transição para releases que foram parcialmente publicados manualmente).
Autenticação de publicação — npm Trusted Publishing (sem token)
A publicação usa npm Trusted Publishing via OIDC — não há segredo NPM_TOKEN. A permissão id-token: write do workflow é trocada por um token de publicação de uso único e curta duração no momento da publicação, usando a vinculação de editor confiável configurada para @lazyants/lexware-mcp-server na interface web do npm. A única configuração necessária é essa vinculação de editor confiável no npm; nada precisa ser armazenado nos segredos do repositório.
Aviso legal
Este é um projeto comunitário independente e não oficial. Não é afiliado, endossado, patrocinado ou apoiado pela Lexware GmbH, Haufe Group ou qualquer uma de suas afiliadas. Para suporte oficial da Lexware, entre em contato diretamente com a Lexware — problemas com este servidor MCP devem ser relatados aqui, não à Lexware.
"Lexware" e "Lexware Office" são marcas registradas de seus respectivos proprietários e são usadas no nome e na documentação deste projeto sob uso justo nominativo, apenas para identificar a API de terceiros à qual este cliente se conecta.
Operações de criar, atualizar e excluir modificam dados comerciais reais na sua conta Lexware. Os autores fornecem este software "no estado em que se encontra" e não aceitam responsabilidade por alterações não intencionais, perda de dados ou quaisquer outros danos decorrentes do seu uso. Teste em uma conta sandbox ou não crítica antes de executar operações de escrita em dados de produção.
Licença
FSL-1.1-MIT — consulte LICENSE para os termos completos.