ohneben's Wafeq MCP

Execute seus livros Wafeq pelo Claude, Cursor ou qualquer cliente MCP — todos os 251 endpoints da API como ferramentas MCP categorizadas por segurança, via stdio ou Streamable HTTP, em Docker.

Documentação

MCP Wafeq do ohneben

Buy Me A Coffee


Licença e Verificações

CI License: MIT

Registros MCP

MCP Registry Listed on mcpservers.org Wafeq-MCP MCP server

Execute seus livros do Wafeq em linguagem natural a partir de assistentes de IA como Claude, Cursor e qualquer outro cliente MCP.

Este servidor Model Context Protocol expõe a API Pública do Wafeq — todos os 251 endpoints, gerados diretamente da especificação OpenAPI para ferramentas MCP, além de dois escritos manualmente. Cada ferramenta carrega uma categoria de segurança (🟢 somente leitura / 🟡 escrita / 🟠 mudança de estado / 🔴 irreversível ou destrutiva) para que seu assistente saiba o que uma ação faz antes de chamá-la — incluindo a diferença entre salvar uma fatura e registrá-la junto à autoridade tributária, algo que nenhum wrapper no formato CRUD consegue informar. Ele roda via stdio (Claude Desktop e outros lançadores locais) ou Streamable HTTP (hospedado em Docker), e vem com novas tentativas, limitação de taxa no lado do cliente, timeouts de requisição, chaves de idempotência, upload multipart e tratamento de PDF binário para aguentar um livro contábil real.

Por que você vai querer isso

Alguns servidores MCP apenas encaminham uma API. Este foi construído para ser seguro de entregar a um LLM e fácil de executar contra dados contábeis reais:

O que você obtémPor que importa
Todos os 251 endpoints, orientados por especificaçãoCobertura completa de faturas, contas a pagar, cotações, notas de crédito e débito, pagamentos, bancos, diários, folha de pagamento, projetos, inventário e relatórios — nada selecionado manualmente ou deixado de fora.
Nove categorias de segurança, não quatro 🟢 / 🟡 / 🟠 / 🔴Uma dúzia dos POSTs do Wafeq não são criações. Pré-visualizações não gravam nada; encerrar uma amortização antecipadamente lança no razão sem desfazer; reportar uma fatura a uma autoridade tributária deixa sua organização permanentemente. Cada uma recebe seu próprio aviso em vez de ser agrupada com "criar".
Instruções do servidor enviadas na conexãoO cliente é informado sobre como ler os avisos de segurança e as poucas convenções do Wafeq — formato de data, separador decimal, intervalos de relatório por período completo — antecipadamente, em vez de descobri-las errando uma chamada primeiro.
Anotações MCP legíveis por máquina (readOnlyHint, destructiveHint)Hosts que respeitam anotações (incluindo o Claude) podem confiar automaticamente nas 98 ferramentas somente leitura e exigir confirmação antes de qualquer uma das 44 que excluem ou não podem ser desfeitas.
Parâmetros de relatório corretos, por relatórioCada um dos quatro relatórios tem seu próprio esquema: balanço patrimonial usa date + period_count; DRE e fluxo de caixa usam date_after + date_before; balancete usa from_date + to_date. O Wafeq ignora silenciosamente parâmetros de consulta com erro de digitação, então um nome errado parece uma chamada que funciona.
Validação de período completo antes do envioDRE e fluxo de caixa rejeitam intervalos que não se alinham a meses ou anos completos. O servidor verifica localmente e responde com o intervalo válido mais próximo em vez de gastar uma ida e volta em um HTTP 400.
Chaves de idempotência automáticasCada um dos 146 endpoints de escrita que suportam X-Wafeq-Idempotency-Key recebe um UUID v4 automaticamente, reutilizado entre novas tentativas — para que uma falha de rede nunca duplique uma fatura. Forneça a sua própria para tornar uma reexecução deliberada segura também.
Uploads de arquivos que realmente funcionamPOST /files/ é somente multipart e POST /files/raw/ precisa de um cabeçalho Content-Disposition. Ambos são tratados; você passa conteúdo base64 e um nome de arquivo.
PDFs binários tratados como bytesOs nove endpoints de PDF são codificados em base64 em um envelope pequeno com tamanho e tipo de conteúdo, em vez de serem lidos como texto e corrompidos.
Novas tentativas automáticas com backoffRespostas transitórias 429 / 5xx são repetidas com backoff exponencial com jitter, respeitando Retry-After — com a mesma chave de idempotência, exatamente como o guia de integração do Wafeq exige.
Limitação de taxa integradaAuto-regula para que uma rajada de chamadas de ferramentas não dispare um 429. O Wafeq não publica limite numérico, então o padrão é deliberadamente conservador e configurável.
Locatário verificado na inicializaçãoUma chave de API do Wafeq é limitada à organização. O servidor chama GET /organization/ antes de servir e publica o resultado em /health, para que uma chave mal configurada apareça como um nome que você pode verificar em vez de gravações nos livros da empresa errada.
Dois transportes: stdio e Streamable HTTPUse localmente no Claude Desktop, ou execute um servidor sempre ativo que qualquer número de clientes MCP alcança via HTTP.
Docker + docker-compose, health check, reinício automáticodocker compose up e ele permanece ativo, vinculado apenas ao localhost.
Autenticação opcional por bearer token no endpoint HTTPColoque o servidor atrás de um segredo compartilhado assim que ele estiver acessível além do localhost.
Seus segredos nunca chegam ao modeloAs credenciais vivem no ambiente do servidor e são injetadas em cada requisição. A ferramenta de passagem não pode sobrescrever Authorization ou apontar a credencial para outro host.
Atualizações de especificação sem esforçoO Wafeq lançou uma especificação mais nova? Substitua um arquivo e reconstrua — novos endpoints viram novas ferramentas automaticamente, sem mudanças de código.

Como ele se compara

CapacidadeEste projetoWrapper genérico OpenAPI→MCP*
Todos os 251 endpoints do Wafeq como ferramentas
Categoria de segurança + aviso por ferramenta
Registro junto à autoridade tributária sinalizado como irreversível, não "criar"
Anotações MCP readOnlyHint / destructiveHint
Campos somente leitura removidos dos corpos de criação/atualização
Prosa de enum duplicada compactada dos esquemas
Parâmetros de data corretos, por relatório
Intervalo de período completo validado antes do envio
X-Wafeq-Idempotency-Key automático, estável entre novas tentativas
Upload de arquivo multipart + binário bruto
Respostas PDF binárias codificadas em base64, não corrompidas
Datas de transação recuperadas para itens de linha do diário
Novas tentativas automáticas em 429 / 5xx (respeita Retry-After)
Limitação de taxa no lado do cliente
Identidade da organização verificada na inicialização
Transporte stdio
Transporte Streamable-HTTP
Docker + docker-compose, health check, reinício automático
Autenticação opcional por bearer token no endpoint
LicençaMITvaria

*Wrappers genéricos OpenAPI→MCP transformam qualquer especificação em ferramentas MCP. Eles podem alcançar os mesmos endpoints, mas tratam toda operação de forma idêntica — e contra a especificação do Wafeq especificamente, eles herdam o problema de campo obrigatório somente leitura descrito em MIGRATION.md. "➖" = varia por ferramenta / não garantido.

O que você pode fazer

Depois de conectado, pergunte ao seu assistente coisas como:

  • "Qual foi nosso lucro e prejuízo no primeiro semestre deste ano?"
  • "Mostre todas as faturas não pagas com mais de 30 dias, com o nome do cliente."
  • "Crie uma fatura rascunho para a Acme Ltda por 3 dias de consultoria a €800/dia."
  • "Baixe a fatura INV-2026-014 como PDF."
  • "Em qual conta o transferência de €7.000 de janeiro foi lançada?"
  • "Anexe este recibo à despesa EXP-118."
  • "Concilie as linhas do extrato bancário de março com o razão."
  • "Converta a cotação QUO-31 em fatura e registre o pagamento."

Como funciona

Claude / Cursor / any MCP client  ──MCP──►  this server  ──HTTPS──►  Wafeq API (your organization)

Na inicialização, o servidor analisa a especificação OpenAPI incluída em ferramentas MCP — resolvendo $refs, protegendo contra esquemas recursivos e removendo campos atribuídos pelo servidor (readOnly) dos corpos de requisição — marca cada ferramenta com sua categoria de segurança, verifica a qual organização do Wafeq as credenciais pertencem e então injeta sua credencial em cada requisição de saída. Sua chave permanece no ambiente do servidor; o modelo nunca a vê ou manipula.

Requisitos

  • Uma organização Wafeq com acesso à API — seja uma chave de API privada (Wafeq → Configurações → Desenvolvedor → Chaves de API) ou um token de acesso OAuth2. Veja Obtenha suas credenciais de API.
  • Docker (Docker Desktop no macOS/Windows) para o início rápido abaixo — ou Node.js ≥ 20 para executar a partir do código-fonte.

Início rápido (Docker)

1. Adicione suas credenciais. Copie a configuração de exemplo e preencha:

cp .env.example .env

Depois edite .env e defina WAFEQ_API_KEY. Se o servidor for acessível além do localhost, defina MCP_SHARED_TOKEN com uma string aleatória longa também.

2. Inicie o servidor:

docker compose up -d --build

docker-compose.yml vincula-se apenas a 127.0.0.1:8765, então o servidor é acessível da sua máquina, mas não da rede.

3. Confirme que está rodando — e que está apontado para os livros certos:

curl -s http://localhost:8765/health
{
  "status": "ok",
  "server": "wafeq-mcp",
  "version": "2.0.0",
  "tools": 253,
  "organization": {
    "status": "ok",
    "id": "org_...",
    "name": "Your Company FZCO",
    "base_currency": "EUR",
    "country": "AE"
  },
  "auth_required": false
}

Verifique o campo name. Essa é a organização na qual sua chave grava. Se não for a empresa que você esperava, pare e corrija a chave antes de fazer qualquer outra coisa. /health responde 503 e "status": "degraded" quando as credenciais não podem ser verificadas.

4. Aponte seu cliente MCP para ele: http://localhost:8765/mcp (Streamable HTTP).

Endpoints remotos são adicionados ao Claude como um conector personalizado (Configurações → Conectores), ou conectados localmente com mcp-remote. Para a ponte, adicione isto sob mcpServers na configuração do seu cliente e reinicie o aplicativo completamente:

{
  "mcpServers": {
    "wafeq": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "http://localhost:8765/mcp",
        "--header", "Authorization: Bearer YOUR_MCP_SHARED_TOKEN"
      ]
    }
  }
}

(Remova a linha --header se você deixou MCP_SHARED_TOKEN vazio.)

Prefere uma imagem pronta?

Cada versão publica uma imagem pronta para executar no GitHub Container Registry, então você pode pular a compilação local completamente:

docker run -d --name wafeq-mcp -p 127.0.0.1:8765:8765 --env-file .env \
  ghcr.io/ohneben/wafeq-mcp:latest

Fixe uma versão (:2.0.0) em vez de latest se quiser que as versões sejam algo que você opta por adotar.

Instalar a partir do Registro MCP

O servidor está publicado no Registro MCP como io.github.ohneben/wafeq-mcp, então clientes que reconhecem o registro podem instalá-lo pelo nome. A entrada do registro inicia a imagem via stdio — veja Executar o contêiner via stdio para a configuração manuscrita equivalente.

curl -s "https://registry.modelcontextprotocol.io/v0.1/servers/io.github.ohneben%2Fwafeq-mcp/versions/latest"

Obtenha suas credenciais de API

Chave de API privada (para a maioria das pessoas): no Wafeq, vá em Configurações → Desenvolvedor → Chaves de API e crie uma chave. Ela é limitada a uma organização. Coloque-a em .env como WAFEQ_API_KEY; o servidor a envia como Authorization: Api-Key <key>.

Aplicativo OAuth2: se você tiver um token de acesso de um aplicativo OAuth2 do Wafeq, coloque-o em .env como WAFEQ_ACCESS_TOKEN em vez disso. O servidor muda para Authorization: Bearer <token> automaticamente. Defina WAFEQ_AUTH_SCHEME apenas se você precisar forçar um esquema enquanto ambas as variáveis estiverem presentes.

Configuração

Toda a configuração é feita por variáveis de ambiente. Tudo, exceto a credencial, tem um padrão funcional.

VariávelPadrãoO que faz
WAFEQ_API_KEYChave de API privada da organização. Enviada como Api-Key <key>. Uma credencial é obrigatória.
WAFEQ_ACCESS_TOKENToken de acesso OAuth2. Enviado como Bearer <token>. Tem precedência sobre WAFEQ_API_KEY.
WAFEQ_AUTH_SCHEMEautoForça api-key ou bearer. Normalmente, deixe sem definir.
WAFEQ_API_BASE_URLhttps://api.wafeq.com/v1URL base da API Wafeq.
WAFEQ_OPENAPI_PATHspec incluídaUsar um documento OpenAPI diferente (JSON ou YAML).
MCP_TRANSPORTstdiostdio ou http. Docker define http.
PORT8765Porta de escuta HTTP.
HOST0.0.0.0Endereço de bind HTTP.
MCP_HTTP_PATH/mcpCaminho onde o endpoint MCP é servido.
MCP_SHARED_TOKENToken Bearer exigido em /mcp. Vazio = sem autenticação. Defina-o se a porta estiver acessível além de localhost.
WAFEQ_TOOL_GROUPSGrupos de recursos separados por vírgula para expor, ex.: invoices,bills,reports. Vazio = todos os 251. Execute npm run list-tools para a lista.
WAFEQ_MAX_REQUESTS20Limite de taxa no cliente: solicitações por janela. 0 desativa a limitação.
WAFEQ_RATE_WINDOW_MS10000Janela do limite de taxa em milissegundos.
WAFEQ_MAX_RETRIES3Tentativas em 429 / 5xx / erros de rede.
WAFEQ_TIMEOUT_MS30000Tempo limite de solicitação por tentativa.
WAFEQ_ALLOW_LOCAL_FILE_UPLOADfalsePermitir que ferramentas de upload leiam o sistema de arquivos desta máquina via file_path. Veja Segurança.
WAFEQ_MAX_UPLOAD_BYTES26214400Tamanho máximo de upload decodificado (25 MiB).

Ferramentas demais?

251 ferramentas é muita coisa. O catálogo completo tem cerca de 0,5 MB de JSON (~133k tokens) em tools/list, e alguns hosts ficam mais lentos ou menos precisos com tantas. Duas coisas ajudam.

Os schemas já estão compactados. A spec da Wafeq renderiza os valores de cada enum na descrição além de em enum — só a lista de moedas tem ~4 KB, embutida em 203 lugares. O gerador colapsa esses wrappers de allOf de membro único e remove as listas com marcadores duplicadas, o que reduz ~29% do payload sem remover um único valor permitido.

Reduza o catálogo se ainda quiser menor — sem mudanças de código:

WAFEQ_TOOL_GROUPS=invoices,bills,contacts,payments,reports,accounts,items,tax-rates

As duas ferramentas escritas à mão estão sempre disponíveis, então nada fica inacessível — qualquer coisa que você filtrar ainda pode ser chamada via wafeq_request.

Categorias de segurança das ferramentas

A descrição de cada ferramenta abre com um banner, e cada ferramenta carrega as anotações MCP correspondentes. As contagens são para a spec incluída (251 geradas + 2 escritas à mão = 253).

BannerFerramentasreadOnlyHintdestructiveHintO que cobre
🟢 READ-ONLY85Todo GET, além da ferramenta de conveniência do razão da conta.
🟢 READ-ONLY · returns a PDF9Os downloads de PDF: fatura, fatura simplificada, nota de crédito, nota de débito, conta, cotação, ordem de compra, pagamento, recibo de salário. Retornados codificados em base64.
🟢 READ-ONLY · preview / simulation4Pré-visualizações de amortização e reconhecimento de receita. POST, mas documentado como não gravando nada.
🟡 WRITE · creates data39Criações de coleção, ambos os uploads de arquivo e as duas conversões (cotação→fatura, ordem de compra→conta). Não idempotentes por natureza — daí a chave de idempotência automática.
🟡 WRITE · updates data70Todo PUT e PATCH.
🟠 STATE CHANGE · moves a document in or out of the ledger2Marcar despesa como lançada / rascunho. Reversível — cada um desfaz o outro.
🔴 IRREVERSIBLE · files the document with an external tax authority3Reportar fatura / nota de crédito / fatura simplificada à autoridade fiscal. Sai da sua organização e não pode ser revertido.
🔴 IRREVERSIBLE · posts the remaining balance to the ledger2Encerrar amortização / reconhecimento de receita antecipadamente. Sem desfazer via API — execute a pré-visualização correspondente primeiro.
🔴 DESTRUCTIVE · deletes39Todo DELETE, além do passthrough wafeq_request (seu efeito não pode ser conhecido antecipadamente).
2539844

Os três grupos 🔴 todos definem destructiveHint: true, então um host que honra anotações para e pergunta antes de qualquer um deles — não apenas antes de exclusões. Registrar uma fatura junto a uma autoridade fiscal é pelo menos tão consequente quanto excluir uma, e ao contrário de uma exclusão, isso alcança fora da sua organização.

Imprima o catálogo ativo a qualquer momento, sem credenciais:

npm run list-tools
🟢 SOMENTE LEITURA (85)
FerramentaEndpoint
wafeq_account_ledgerescrita à mão
wafeq_accounts_listGET /accounts/
wafeq_accounts_retrieveGET /accounts/{id}/
wafeq_amortizations_listGET /amortizations/
wafeq_amortizations_retrieveGET /amortizations/{id}/
wafeq_bank_accounts_ledger_transactions_listGET /bank-accounts/{bank_account_id}/ledger-transactions/
wafeq_bank_accounts_ledger_transactions_retrieveGET /bank-accounts/{bank_account_id}/ledger-transactions/{id}/
wafeq_bank_accounts_listGET /bank-accounts/
wafeq_bank_accounts_retrieveGET /bank-accounts/{id}/
wafeq_bank_accounts_statement_transactions_listGET /bank-accounts/{bank_account_id}/statement-transactions/
wafeq_bank_accounts_statement_transactions_retrieveGET /bank-accounts/{bank_account_id}/statement-transactions/{id}/
wafeq_beneficiaries_listGET /beneficiaries/
wafeq_beneficiaries_retrieveGET /beneficiaries/{id}/
wafeq_bills_line_items_listGET /bills/{bill_id}/line-items/
wafeq_bills_line_items_retrieveGET /bills/{bill_id}/line-items/{id}/
wafeq_bills_listGET /bills/
wafeq_bills_retrieveGET /bills/{id}/
wafeq_branches_listGET /branches/
wafeq_branches_retrieveGET /branches/{id}/
wafeq_contacts_listGET /contacts/
wafeq_contacts_retrieveGET /contacts/{id}/
wafeq_cost_centers_listGET /cost-centers/
wafeq_cost_centers_retrieveGET /cost-centers/{id}/
wafeq_credit_notes_line_items_listGET /credit-notes/{credit_note_id}/line-items/
wafeq_credit_notes_line_items_retrieveGET /credit-notes/{credit_note_id}/line-items/{id}/
wafeq_credit_notes_listGET /credit-notes/
wafeq_credit_notes_retrieveGET /credit-notes/{id}/
wafeq_custom_fields_listGET /custom-fields/
wafeq_custom_fields_retrieveGET /custom-fields/{id}/
wafeq_debit_notes_line_items_listGET /debit-notes/{debit_note_id}/line-items/
wafeq_debit_notes_line_items_retrieveGET /debit-notes/{debit_note_id}/line-items/{id}/
wafeq_debit_notes_listGET /debit-notes/
wafeq_debit_notes_retrieveGET /debit-notes/{id}/
wafeq_employees_listGET /employees/
wafeq_employees_retrieveGET /employees/{id}/
wafeq_expenses_listGET /expenses/
wafeq_expenses_retrieveGET /expenses/{id}/
wafeq_files_listGET /files/
wafeq_files_retrieveGET /files/{id}/
wafeq_invoices_line_items_listGET /invoices/{invoice_id}/line-items/
wafeq_invoices_line_items_retrieveGET /invoices/{invoice_id}/line-items/{id}/
wafeq_invoices_listGET /invoices/
wafeq_invoices_retrieveGET /invoices/{id}/
wafeq_item_units_of_measure_listGET /item-units-of-measure/
wafeq_item_units_of_measure_retrieveGET /item-units-of-measure/{id}/
wafeq_items_listGET /items/
wafeq_items_retrieveGET /items/{id}/
wafeq_journal_line_items_listGET /journal-line-items/
wafeq_journal_line_items_retrieveGET /journal-line-items/{id}/
wafeq_manual_journals_listGET /manual-journals/
wafeq_manual_journals_retrieveGET /manual-journals/{id}/
wafeq_organization_retrieveGET /organization/
wafeq_payment_requests_listGET /payment_requests/
wafeq_payment_requests_retrieveGET /payment_requests/{id}/
wafeq_payments_listGET /payments/
wafeq_payments_retrieveGET /payments/{id}/
wafeq_payslips_listGET /payslips/
wafeq_payslips_pay_items_listGET /payslips/{payslip_id}/pay-items/
wafeq_payslips_pay_items_retrieveGET /payslips/{payslip_id}/pay-items/{id}/
wafeq_payslips_retrieveGET /payslips/{id}/
wafeq_projects_listGET /projects/
wafeq_projects_retrieveGET /projects/{id}/
wafeq_purchase_orders_line_items_listGET /purchase-orders/{purchase_order_id}/line-items/
wafeq_purchase_orders_line_items_retrieveGET /purchase-orders/{purchase_order_id}/line-items/{id}/
wafeq_purchase_orders_listGET /purchase-orders/
wafeq_purchase_orders_retrieveGET /purchase-orders/{id}/
wafeq_quotes_line_items_listGET /quotes/{quote_id}/line-items/
wafeq_quotes_line_items_retrieveGET /quotes/{quote_id}/line-items/{id}/
wafeq_quotes_listGET /quotes/
wafeq_quotes_retrieveGET /quotes/{id}/
wafeq_reports_balance_sheet_listGET /reports/balance-sheet/
wafeq_reports_cash_flow_listGET /reports/cash-flow/
wafeq_reports_profit_and_loss_listGET /reports/profit-and-loss/
wafeq_reports_trial_balance_listGET /reports/trial-balance/
wafeq_revenue_recognitions_listGET /revenue-recognitions/
wafeq_revenue_recognitions_retrieveGET /revenue-recognitions/{id}/
wafeq_simplified_invoices_line_items_listGET /simplified-invoices/{invoice_id}/line-items/
wafeq_simplified_invoices_line_items_retrieveGET /simplified-invoices/{invoice_id}/line-items/{id}/
wafeq_simplified_invoices_listGET /simplified-invoices/
wafeq_simplified_invoices_retrieveGET /simplified-invoices/{id}/
wafeq_tax_rates_listGET /tax-rates/
wafeq_units_of_measure_listGET /units-of-measure/
wafeq_units_of_measure_retrieveGET /units-of-measure/{id}/
wafeq_warehouses_listGET /warehouses/
wafeq_warehouses_retrieveGET /warehouses/{id}/
🟢 SOMENTE LEITURA (PDF) (9)
FerramentaEndpoint
wafeq_bills_download_retrieveGET /bills/{id}/download/
wafeq_credit_notes_download_retrieveGET /credit-notes/{id}/download/
wafeq_debit_notes_download_retrieveGET /debit-notes/{id}/download/
wafeq_invoices_download_retrieveGET /invoices/{id}/download/
wafeq_payments_download_retrieveGET /payments/{id}/download/
wafeq_payslips_download_retrieveGET /payslips/{id}/download/
wafeq_purchase_orders_download_retrieveGET /purchase-orders/{id}/download/
wafeq_quotes_download_retrieveGET /quotes/{id}/download/
wafeq_simplified_invoices_download_retrieveGET /simplified-invoices/{id}/download/
🟢 SOMENTE LEITURA (PRÉ-VISUALIZAÇÃO) (4)
FerramentaEndpoint
wafeq_amortizations_preview_createPOST /amortizations/preview/
wafeq_amortizations_preview_end_early_createPOST /amortizations/{id}/preview-end-early/
wafeq_revenue_recognitions_preview_createPOST /revenue-recognitions/preview/
wafeq_revenue_recognitions_preview_end_early_createPOST /revenue-recognitions/{id}/preview-end-early/
🟡 ESCRITA · CRIAÇÕES (39)
FerramentaEndpoint
wafeq_accounts_createPOST /accounts/
wafeq_bank_accounts_createPOST /bank-accounts/
wafeq_bank_accounts_ledger_transactions_createPOST /bank-accounts/{bank_account_id}/ledger-transactions/
wafeq_bank_accounts_statement_transactions_createPOST /bank-accounts/{bank_account_id}/statement-transactions/
wafeq_beneficiaries_createPOST /beneficiaries/
wafeq_bills_createPOST /bills/
wafeq_bills_line_items_createPOST /bills/{bill_id}/line-items/
wafeq_branches_createPOST /branches/
wafeq_contacts_createPOST /contacts/
wafeq_cost_centers_createPOST /cost-centers/
wafeq_credit_notes_createPOST /credit-notes/
wafeq_credit_notes_line_items_createPOST /credit-notes/{credit_note_id}/line-items/
wafeq_custom_fields_createPOST /custom-fields/
wafeq_debit_notes_createPOST /debit-notes/
wafeq_debit_notes_line_items_createPOST /debit-notes/{debit_note_id}/line-items/
wafeq_employees_createPOST /employees/
wafeq_expenses_createPOST /expenses/
wafeq_invoices_createPOST /invoices/
wafeq_invoices_line_items_createPOST /invoices/{invoice_id}/line-items/
wafeq_item_units_of_measure_createPOST /item-units-of-measure/
wafeq_items_createPOST /items/
wafeq_manual_journals_createPOST /manual-journals/
wafeq_payment_requests_createPOST /payment_requests/
wafeq_payments_createPOST /payments/
wafeq_payslips_createPOST /payslips/
wafeq_payslips_pay_items_createPOST /payslips/{payslip_id}/pay-items/
wafeq_projects_createPOST /projects/
wafeq_purchase_orders_bill_createPOST /purchase-orders/{id}/bill/
wafeq_purchase_orders_createPOST /purchase-orders/
wafeq_purchase_orders_line_items_createPOST /purchase-orders/{purchase_order_id}/line-items/
wafeq_quotes_createPOST /quotes/
wafeq_quotes_invoice_createPOST /quotes/{id}/invoice/
wafeq_quotes_line_items_createPOST /quotes/{quote_id}/line-items/
wafeq_simplified_invoices_createPOST /simplified-invoices/
wafeq_simplified_invoices_line_items_createPOST /simplified-invoices/{invoice_id}/line-items/
wafeq_units_of_measure_createPOST /units-of-measure/
wafeq_upload_filePOST /files/
wafeq_upload_file_rawPOST /files/raw/
wafeq_warehouses_createPOST /warehouses/
🟡 ESCRITA · ATUALIZAÇÕES (70) | Ferramenta | Endpoint | |---|---| | `wafeq_accounts_partial_update` | `PATCH /accounts/{id}/` | | `wafeq_accounts_update` | `PUT /accounts/{id}/` | | `wafeq_bank_accounts_ledger_transactions_partial_update` | `PATCH /bank-accounts/{bank_account_id}/ledger-transactions/{id}/` | | `wafeq_bank_accounts_ledger_transactions_update` | `PUT /bank-accounts/{bank_account_id}/ledger-transactions/{id}/` | | `wafeq_bank_accounts_partial_update` | `PATCH /bank-accounts/{id}/` | | `wafeq_bank_accounts_statement_transactions_partial_update` | `PATCH /bank-accounts/{bank_account_id}/statement-transactions/{id}/` | | `wafeq_bank_accounts_statement_transactions_update` | `PUT /bank-accounts/{bank_account_id}/statement-transactions/{id}/` | | `wafeq_bank_accounts_update` | `PUT /bank-accounts/{id}/` | | `wafeq_beneficiaries_partial_update` | `PATCH /beneficiaries/{id}/` | | `wafeq_beneficiaries_update` | `PUT /beneficiaries/{id}/` | | `wafeq_bills_line_items_partial_update` | `PATCH /bills/{bill_id}/line-items/{id}/` | | `wafeq_bills_line_items_update` | `PUT /bills/{bill_id}/line-items/{id}/` | | `wafeq_bills_partial_update` | `PATCH /bills/{id}/` | | `wafeq_bills_update` | `PUT /bills/{id}/` | | `wafeq_branches_partial_update` | `PATCH /branches/{id}/` | | `wafeq_branches_update` | `PUT /branches/{id}/` | | `wafeq_contacts_partial_update` | `PATCH /contacts/{id}/` | | `wafeq_contacts_update` | `PUT /contacts/{id}/` | | `wafeq_cost_centers_partial_update` | `PATCH /cost-centers/{id}/` | | `wafeq_cost_centers_update` | `PUT /cost-centers/{id}/` | | `wafeq_credit_notes_line_items_partial_update` | `PATCH /credit-notes/{credit_note_id}/line-items/{id}/` | | `wafeq_credit_notes_line_items_update` | `PUT /credit-notes/{credit_note_id}/line-items/{id}/` | | `wafeq_credit_notes_partial_update` | `PATCH /credit-notes/{id}/` | | `wafeq_credit_notes_update` | `PUT /credit-notes/{id}/` | | `wafeq_custom_fields_partial_update` | `PATCH /custom-fields/{id}/` | | `wafeq_custom_fields_update` | `PUT /custom-fields/{id}/` | | `wafeq_debit_notes_line_items_partial_update` | `PATCH /debit-notes/{debit_note_id}/line-items/{id}/` | | `wafeq_debit_notes_line_items_update` | `PUT /debit-notes/{debit_note_id}/line-items/{id}/` | | `wafeq_debit_notes_partial_update` | `PATCH /debit-notes/{id}/` | | `wafeq_debit_notes_update` | `PUT /debit-notes/{id}/` | | `wafeq_employees_partial_update` | `PATCH /employees/{id}/` | | `wafeq_employees_update` | `PUT /employees/{id}/` | | `wafeq_expenses_partial_update` | `PATCH /expenses/{id}/` | | `wafeq_expenses_update` | `PUT /expenses/{id}/` | | `wafeq_invoices_line_items_partial_update` | `PATCH /invoices/{invoice_id}/line-items/{id}/` | | `wafeq_invoices_line_items_update` | `PUT /invoices/{invoice_id}/line-items/{id}/` | | `wafeq_invoices_partial_update` | `PATCH /invoices/{id}/` | | `wafeq_invoices_update` | `PUT /invoices/{id}/` | | `wafeq_item_units_of_measure_partial_update` | `PATCH /item-units-of-measure/{id}/` | | `wafeq_item_units_of_measure_update` | `PUT /item-units-of-measure/{id}/` | | `wafeq_items_partial_update` | `PATCH /items/{id}/` | | `wafeq_items_update` | `PUT /items/{id}/` | | `wafeq_manual_journals_partial_update` | `PATCH /manual-journals/{id}/` | | `wafeq_manual_journals_update` | `PUT /manual-journals/{id}/` | | `wafeq_payment_requests_partial_update` | `PATCH /payment_requests/{id}/` | | `wafeq_payment_requests_update` | `PUT /payment_requests/{id}/` | | `wafeq_payments_partial_update` | `PATCH /payments/{id}/` | | `wafeq_payments_update` | `PUT /payments/{id}/` | | `wafeq_payslips_partial_update` | `PATCH /payslips/{id}/` | | `wafeq_payslips_pay_items_partial_update` | `PATCH /payslips/{payslip_id}/pay-items/{id}/` | | `wafeq_payslips_pay_items_update` | `PUT /payslips/{payslip_id}/pay-items/{id}/` | | `wafeq_payslips_update` | `PUT /payslips/{id}/` | | `wafeq_projects_partial_update` | `PATCH /projects/{id}/` | | `wafeq_projects_update` | `PUT /projects/{id}/` | | `wafeq_purchase_orders_line_items_partial_update` | `PATCH /purchase-orders/{purchase_order_id}/line-items/{id}/` | | `wafeq_purchase_orders_line_items_update` | `PUT /purchase-orders/{purchase_order_id}/line-items/{id}/` | | `wafeq_purchase_orders_partial_update` | `PATCH /purchase-orders/{id}/` | | `wafeq_purchase_orders_update` | `PUT /purchase-orders/{id}/` | | `wafeq_quotes_line_items_partial_update` | `PATCH /quotes/{quote_id}/line-items/{id}/` | | `wafeq_quotes_line_items_update` | `PUT /quotes/{quote_id}/line-items/{id}/` | | `wafeq_quotes_partial_update` | `PATCH /quotes/{id}/` | | `wafeq_quotes_update` | `PUT /quotes/{id}/` | | `wafeq_simplified_invoices_line_items_partial_update` | `PATCH /simplified-invoices/{invoice_id}/line-items/{id}/` | | `wafeq_simplified_invoices_line_items_update` | `PUT /simplified-invoices/{invoice_id}/line-items/{id}/` | | `wafeq_simplified_invoices_partial_update` | `PATCH /simplified-invoices/{id}/` | | `wafeq_simplified_invoices_update` | `PUT /simplified-invoices/{id}/` | | `wafeq_units_of_measure_partial_update` | `PATCH /units-of-measure/{id}/` | | `wafeq_units_of_measure_update` | `PUT /units-of-measure/{id}/` | | `wafeq_warehouses_partial_update` | `PATCH /warehouses/{id}/` | | `wafeq_warehouses_update` | `PUT /warehouses/{id}/` |
🟠 MUDANÇA DE ESTADO (2)
FerramentaEndpoint
wafeq_expenses_mark_as_draft_createPOST /expenses/{id}/mark-as-draft/
wafeq_expenses_mark_as_posted_createPOST /expenses/{id}/mark-as-posted/
🔴 IRREVERSÍVEL · ARQUIVAMENTO EXTERNO (3)
FerramentaEndpoint
wafeq_credit_notes_tax_authority_report_createPOST /credit-notes/{id}/tax-authority/report/
wafeq_invoices_tax_authority_report_createPOST /invoices/{id}/tax-authority/report/
wafeq_simplified_invoices_tax_authority_report_createPOST /simplified-invoices/{id}/tax-authority/report/
🔴 IRREVERSÍVEL · RAZÃO (2)
FerramentaEndpoint
wafeq_amortizations_end_early_createPOST /amortizations/{id}/end-early/
wafeq_revenue_recognitions_end_early_createPOST /revenue-recognitions/{id}/end-early/
🔴 DESTRUTIVO · EXCLUSÕES (39)
FerramentaEndpoint
wafeq_accounts_destroyDELETE /accounts/{id}/
wafeq_amortizations_destroyDELETE /amortizations/{id}/
wafeq_bank_accounts_destroyDELETE /bank-accounts/{id}/
wafeq_bank_accounts_ledger_transactions_destroyDELETE /bank-accounts/{bank_account_id}/ledger-transactions/{id}/
wafeq_bank_accounts_statement_transactions_destroyDELETE /bank-accounts/{bank_account_id}/statement-transactions/{id}/
wafeq_beneficiaries_destroyDELETE /beneficiaries/{id}/
wafeq_bills_destroyDELETE /bills/{id}/
wafeq_bills_line_items_destroyDELETE /bills/{bill_id}/line-items/{id}/
wafeq_branches_destroyDELETE /branches/{id}/
wafeq_contacts_destroyDELETE /contacts/{id}/
wafeq_cost_centers_destroyDELETE /cost-centers/{id}/
wafeq_credit_notes_destroyDELETE /credit-notes/{id}/
wafeq_credit_notes_line_items_destroyDELETE /credit-notes/{credit_note_id}/line-items/{id}/
wafeq_custom_fields_destroyDELETE /custom-fields/{id}/
wafeq_debit_notes_destroyDELETE /debit-notes/{id}/
wafeq_debit_notes_line_items_destroyDELETE /debit-notes/{debit_note_id}/line-items/{id}/
wafeq_employees_destroyDELETE /employees/{id}/
wafeq_expenses_destroyDELETE /expenses/{id}/
wafeq_files_destroyDELETE /files/{id}/
wafeq_invoices_destroyDELETE /invoices/{id}/
wafeq_invoices_line_items_destroyDELETE /invoices/{invoice_id}/line-items/{id}/
wafeq_item_units_of_measure_destroyDELETE /item-units-of-measure/{id}/
wafeq_items_destroyDELETE /items/{id}/
wafeq_manual_journals_destroyDELETE /manual-journals/{id}/
wafeq_payment_requests_destroyDELETE /payment_requests/{id}/
wafeq_payments_destroyDELETE /payments/{id}/
wafeq_payslips_destroyDELETE /payslips/{id}/
wafeq_payslips_pay_items_destroyDELETE /payslips/{payslip_id}/pay-items/{id}/
wafeq_projects_destroyDELETE /projects/{id}/
wafeq_purchase_orders_destroyDELETE /purchase-orders/{id}/
wafeq_purchase_orders_line_items_destroyDELETE /purchase-orders/{purchase_order_id}/line-items/{id}/
wafeq_quotes_destroyDELETE /quotes/{id}/
wafeq_quotes_line_items_destroyDELETE /quotes/{quote_id}/line-items/{id}/
wafeq_requestescrito à mão
wafeq_revenue_recognitions_destroyDELETE /revenue-recognitions/{id}/
wafeq_simplified_invoices_destroyDELETE /simplified-invoices/{id}/
wafeq_simplified_invoices_line_items_destroyDELETE /simplified-invoices/{invoice_id}/line-items/{id}/
wafeq_units_of_measure_destroyDELETE /units-of-measure/{id}/
wafeq_warehouses_destroyDELETE /warehouses/{id}/

Cobertura

ÁreaFerramentas🟢 Leitura🟡 Escrita🔴 Irreversível🔴 Exclusão
Vendas e contas a receber692531310
Compras e contas a pagar54192708
Banco186903
Razão e relatórios3119624
Folha de pagamento197903
Dados mestre e dimensões54182709
Arquivos e organização63201
Saída de emergência e conveniência21001
Total25398111539

"Escrita" inclui as duas ferramentas 🟠 de mudança de estado. As áreas mapeiam para os recursos do Wafeq da seguinte forma — Vendas: faturas, faturas simplificadas, cotações, notas de crédito, pagamentos, solicitações de pagamento · Compras: contas, ordens de compra, notas de débito, despesas, beneficiários · Banco: contas bancárias com seu razão e transações de extrato · Razão e relatórios: contas, lançamentos manuais, itens de lançamento, os quatro relatórios, alíquotas de impostos, amortizações, reconhecimentos de receita · Folha de pagamento: recibos de pagamento, funcionários · Dados mestre: contatos, itens, unidades de medida, armazéns, projetos, centros de custo, filiais, campos personalizados.

Duas ferramentas escritas à mão

Tudo acima é gerado. Duas ferramentas são escritas à mão:

  • wafeq_account_ledger (🟢) — itens de lançamento com sua data real de transação. As linhas de /journal-line-items/ do Wafeq carregam created_ts (quando a linha chegou ao Wafeq), que geralmente é um mês diferente da transação, e nenhum campo de data. Esta ferramenta recupera a data usando os filtros de date_after/date_before do próprio endpoint, que operam na data da transação. Ela testa um mês por vez e só divide em consultas diárias onde existem linhas, então períodos tranquilos custam uma solicitação cada; o resultado relata requests_made.
  • wafeq_request (🔴) — a saída de emergência: qualquer método, qualquer caminho, além de query, corpo e cabeçalhos. É o fallback para qualquer coisa que a especificação incluída não cubra, não a interface principal. Categorizada como destrutiva porque seu efeito não pode ser conhecido antecipadamente.

Executar a partir do código-fonte (stdio, sem Docker)

npm ci
npm run build

Em seguida, registre-o com seu cliente MCP. Para Claude Desktop, adicione em claude_desktop_config.json:

{
  "mcpServers": {
    "wafeq": {
      "command": "node",
      "args": ["/absolute/path/to/Wafeq MCP/dist/index.js"],
      "env": {
        "MCP_TRANSPORT": "stdio",
        "WAFEQ_API_KEY": "your-key-here"
      }
    }
  }
}

Para Claude Code:

claude mcp add wafeq --env WAFEQ_API_KEY=your-key-here -- node /absolute/path/to/dist/index.js

Executar o contêiner via stdio

Você também pode deixar seu cliente iniciar a imagem publicada diretamente, sem servidor HTTP e sem build local:

{
  "mcpServers": {
    "wafeq": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "MCP_TRANSPORT=stdio",
        "-e", "WAFEQ_API_KEY",
        "ghcr.io/ohneben/wafeq-mcp:latest"
      ],
      "env": {
        "WAFEQ_API_KEY": "your-key-here"
      }
    }
  }
}

MCP_TRANSPORT=stdio é necessário aqui: a imagem usa o transporte HTTP por padrão.

Scripts úteis:

ComandoO que faz
npm run buildCompila TypeScript para dist/.
npm testExecuta a suíte Vitest.
npm run list-toolsImprime o catálogo categorizado. Não requer credenciais.
npm run start:stdioExecuta via stdio.
npm run start:httpExecuta o servidor HTTP Streamable.

Mantendo a especificação atualizada

As ferramentas são geradas a partir de spec/wafeq-public-api.json na inicialização — não há etapa de geração de código nem lista de ferramentas escrita à mão. Coloque um documento OpenAPI mais recente (JSON ou YAML), recompile, e novos endpoints se tornam novas ferramentas. Veja spec/README.md para saber de onde veio a cópia incluída e o que verificar após uma atualização.

Correções de comportamento observado ficam em src/overrides.ts, identificadas por operationId e datadas, para que uma entrada cuja operação desapareça simplesmente deixe de se aplicar.

Notas e convenções

  • Datas são YYYY-MM-DD. Valores usam ponto como separador decimal.
  • Paginação: ferramentas de listagem aceitam limit e offset, e relatam a contagem total.
  • Relatórios aceitam parâmetros de data específicos do relatório — balanço patrimonial date + period_count; lucros e perdas e fluxo de caixa date_after + date_before; balancete from_date + to_date. O Wafeq ignora silenciosamente um parâmetro de query com erro de digitação, então um nome errado parece uma chamada bem-sucedida; os esquemas por relatório existem para tornar isso impossível.
  • Períodos completos: intervalos de lucros e perdas e fluxo de caixa devem cobrir meses ou anos inteiros. O servidor verifica localmente e responde com o intervalo válido mais próximo, em vez de gastar uma ida e volta em um HTTP 400.
  • Uploads de arquivos (wafeq_files_*): envie conteúdo base64 mais um nome de arquivo. POST /files/ é somente multipart e POST /files/raw/ precisa de um cabeçalho Content-Disposition — ambos são tratados para você.
  • Downloads de PDF retornam codificados em base64 em um envelope pequeno com o tamanho e o tipo de conteúdo, não como texto corrompido.
  • Idempotência: todo endpoint de escrita que suporta X-Wafeq-Idempotency-Key recebe automaticamente um UUID v4, reutilizado em novas tentativas. Envie o seu próprio para tornar uma reexecução deliberada segura.
  • Novas tentativas: respostas transitórias de 429 / 5xx são repetidas com backoff exponencial com jitter, respeitando Retry-After, sob a mesma chave de idempotência.
  • Limite de taxa: o Wafeq não publica limite numérico, então o padrão do lado do cliente (WAFEQ_MAX_REQUESTS=20 por WAFEQ_RATE_WINDOW_MS=10000) é deliberadamente conservador. Aumente se você souber sua cota.
  • Uma organização por credencial. Uma chave de API do Wafeq é limitada à organização; toda chamada de ferramenta atua nessa organização, e /health a nomeia.

CI e lançamentos

Todo push e pull request é compilado e testado no Node 20 e 22, e o catálogo de ferramentas é gerado sem credenciais presentes — é isso que detecta um nome de ferramenta duplicado ou inválido para o esquema antes de ser publicado. O CI também falha se .env algum dia for rastreado.

Um lançamento é uma tag vX.Y.Z e nada mais. Nenhum número de versão é mantido manualmente. Enviar a tag executa toda a cadeia:

  1. A versão é derivada uma única vez, a partir da tag.
  2. A imagem é construída e enviada para ghcr.io/ohneben/wafeq-mcp — marcada com a versão, MAJOR.MINOR, o SHA curto e latest em main.
  3. A entrada é publicada no MCP Registry com server.json fixado nessa tag exata da imagem. A propriedade é comprovada pelo rótulo io.modelcontextprotocol.server.name na imagem, que deve corresponder ao name de server.json — um teste garante que isso acontece.
  4. O número publicado é gravado de volta em package.json e server.json em main, e a tag é movida para esse commit. Assim, o repositório sempre informa a última versão publicada, e o servidor a reporta via MCP e em /health sem edição de código.
npm version 2.0.1 --no-git-tag-version   # optional; CI stamps it either way
git tag v2.0.1 && git push origin v2.0.1

workflow_dispatch republica uma determinada versão sem criar uma nova tag. Pushes para main constroem uma imagem -dev.g<sha> e param por aí — eles nunca tocam no registro.

Segurança

  • As credenciais permanecem no lado do servidor. Elas são lidas do ambiente e injetadas por requisição. O modelo vê as entradas das ferramentas e as respostas da API, nunca a chave. A ferramenta de passagem não pode sobrescrever o cabeçalho Authorization e se recusa a enviar a credencial para qualquer host que não seja a base da API configurada.
  • Nunca faça commit de .env. Ele está no git-ignore, e o CI falha se ele for rastreado. .env.example contém apenas placeholders.
  • Vincule ao localhost ou defina um token. docker-compose.yml publica em 127.0.0.1 apenas. Se você expor a porta além disso, defina MCP_SHARED_TOKEN primeiro; ele é comparado em tempo constante.
  • Uploads de arquivos locais estão desativados por padrão. WAFEQ_ALLOW_LOCAL_FILE_UPLOAD=false significa que o servidor não lerá arquivos do próprio sistema de arquivos. Ativá-lo permite que qualquer coisa que possa chamar o servidor peça para ele ler um caminho local — deixe desativado, a menos que você precise e confie em todos os clientes. Uploads em Base64 funcionam de qualquer forma.
  • Verifique a organização em /health antes da primeira gravação. Uma chave de API é limitada a uma organização, e uma chave errada falha ao gravar na empresa errada em vez de gerar um erro.
  • As ferramentas 🔴 significam o que dizem. Exclusões são permanentes, encerrar um agendamento antecipadamente não tem desfazer via API, e um envio à autoridade fiscal não pode ser revertido. Mantenha as confirmações do host ativadas para qualquer coisa que carregue destructiveHint.

Consulte SECURITY.md para relatar uma vulnerabilidade.

Créditos e licença

MIT — consulte LICENSE.md. Construído sobre o Model Context Protocol TypeScript SDK, seguindo a mesma arquitetura do ohneben's LearnWorlds MCP. Não afiliado ou endossado pela Wafeq.