Back to Browse

Wafeq MCP Server

Developer ToolsModerate5.2MCP RegistryLocal
Free

Server data from the Official MCP Registry

Wafeq accounting API: all 251 endpoints as safety-categorized MCP tools, over stdio or HTTP.

About

Wafeq accounting API: all 251 endpoints as safety-categorized MCP tools, over stdio or HTTP.

Security Report

5.2
Moderate5.2Moderate Risk

Wafeq MCP is a well-architected server with strong security practices and thoughtful API design. Credentials are properly handled via environment variables, authentication is enforced on non-loopback endpoints, and the codebase demonstrates careful attention to security (idempotency keys, rate limiting, organization verification at startup). Minor code quality findings around broad exception handling and optional input validation do not materially impact security posture. Permissions align appropriately with the server's purpose as an accounting API proxy. Supply chain analysis found 5 known vulnerabilities in dependencies (0 critical, 3 high severity).

3 files analyzed Β· 8 issues found

Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.

Permissions Required

This plugin requests these system permissions. Most are normal for its category.

HTTP Network Access

Connects to external APIs or services over the internet.

env_vars

Check that this permission is expected for this type of plugin.

What You'll Need

Set these up before or after installing:

Server transport. Set to 'stdio' for local MCP clients; the image otherwise starts the Streamable HTTP transport.Optional

Environment variable: MCP_TRANSPORT

Private organization API key, sent as `Authorization: Api-Key <key>`. Wafeq -> Settings -> Developer -> API keys. Required unless WAFEQ_ACCESS_TOKEN is set.Required

Environment variable: WAFEQ_API_KEY

OAuth2 app access token, sent as `Authorization: Bearer <token>`. Use instead of WAFEQ_API_KEY.Required

Environment variable: WAFEQ_ACCESS_TOKEN

Comma-separated resource groups to expose, e.g. invoices,bills,reports. Empty exposes all 251 generated tools.Optional

Environment variable: WAFEQ_TOOL_GROUPS

Overrides the Wafeq API base URL. Defaults to https://api.wafeq.com/v1Optional

Environment variable: WAFEQ_API_BASE_URL

Only for MCP_TRANSPORT=http: bearer token required on /mcp. Without it a non-loopback bind refuses to start.Required

Environment variable: MCP_AUTH_TOKEN

How to Install

Add this to your MCP configuration file:

{
  "mcpServers": {
    "io-github-ohneben-wafeq-mcp": {
      "env": {
        "MCP_TRANSPORT": "your-mcp-transport-here",
        "WAFEQ_API_KEY": "your-wafeq-api-key-here",
        "MCP_AUTH_TOKEN": "your-mcp-auth-token-here",
        "WAFEQ_TOOL_GROUPS": "your-wafeq-tool-groups-here",
        "WAFEQ_ACCESS_TOKEN": "your-wafeq-access-token-here",
        "WAFEQ_API_BASE_URL": "your-wafeq-api-base-url-here"
      },
      "args": [
        "-y",
        "wafeq-mcp"
      ],
      "command": "npx"
    }
  }
}

Documentation

View on GitHub

From the project's GitHub README.

ohneben's Wafeq MCP

Buy Me A Coffee


License & checks

CI License: MIT

MCP registries

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

Run your Wafeq books in plain language from AI assistants like Claude, Cursor, and any other MCP client.

This Model Context Protocol server exposes the Wafeq Public API β€” all 251 endpoints, generated straight from the OpenAPI spec into MCP tools, plus two hand-written ones. Every tool carries a safety category (🟒 read-only / 🟑 write / 🟠 state change / πŸ”΄ irreversible or destructive) so your assistant knows what an action does before it calls it β€” including the difference between saving an invoice and filing it with a tax authority, which no CRUD-shaped wrapper can tell you. It runs over stdio (Claude Desktop and other local launchers) or Streamable HTTP (hosted in Docker), and ships with retries, client-side rate limiting, request timeouts, idempotency keys, multipart upload and binary PDF handling so it holds up against a live book.

Why you'll want this

Some MCP servers just forward an API. This one is built to be safe to hand to an LLM and easy to run against real accounting data:

What you getWhy it matters
All 251 endpoints, spec-drivenFull coverage of invoices, bills, quotes, credit and debit notes, payments, banking, journals, payroll, projects, inventory and reports β€” nothing hand-picked or left behind.
Nine safety categories, not four 🟒 / 🟑 / 🟠 / πŸ”΄A dozen of Wafeq's POSTs are not creates. Previews write nothing; ending an amortization early posts to the ledger with no undo; reporting an invoice to a tax authority leaves your organization permanently. Each gets its own banner instead of being lumped in with "create".
Server instructions sent on connectThe client is told how to read the safety banners and the handful of Wafeq conventions β€” date format, decimal separator, whole-period report ranges β€” up front, instead of discovering them by getting a call wrong first.
Machine-readable MCP annotations (readOnlyHint, destructiveHint)Hosts that honor annotations (Claude included) can auto-trust the 98 read-only tools and demand confirmation before any of the 44 that delete or cannot be undone.
Correct report parameters, per reportEach of the four reports gets its own schema: balance sheet takes date + period_count; profit-and-loss and cash flow take date_after + date_before; trial balance takes from_date + to_date. Wafeq silently ignores misspelled query parameters, so a wrong name looks like a working call.
Whole-period validation before sendingProfit-and-loss and cash flow reject ranges that don't align to whole months or years. The server checks locally and replies with the nearest valid range instead of spending a round trip on an HTTP 400.
Automatic idempotency keysEvery one of the 146 write endpoints that supports X-Wafeq-Idempotency-Key gets a UUID v4 automatically, reused across retries β€” so a network hiccup can never duplicate an invoice. Supply your own to make a deliberate re-run safe too.
File uploads that actually workPOST /files/ is multipart-only and POST /files/raw/ needs a Content-Disposition header. Both are handled; you pass base64 content and a filename.
Binary PDFs handled as bytesThe nine PDF endpoints are base64-encoded into a small envelope with size and content type, instead of being read as text and corrupted.
Automatic retries with backoffTransient 429 / 5xx responses are retried with jittered exponential backoff, honoring Retry-After β€” with the same idempotency key, exactly as Wafeq's integration guide requires.
Built-in rate limitingSelf-throttles so a burst of tool calls doesn't trip a 429. Wafeq publishes no numeric limit, so the default is deliberately conservative and configurable.
Tenant verified at startupA Wafeq API key is organization-scoped. The server calls GET /organization/ before serving and publishes the result on /health, so a mis-set key shows up as a name you can check rather than as writes against the wrong company's books.
Two transports: stdio and Streamable HTTPUse it locally in Claude Desktop, or run one always-on server that any number of MCP clients reach over HTTP.
Docker + docker-compose, health check, auto-restartdocker compose up and it stays up, bound to localhost only.
Optional bearer-token auth on the HTTP endpointPut the server behind a shared secret the moment it's reachable beyond localhost.
Your secrets never reach the modelCredentials live in the server's environment and are injected on every request. The passthrough tool cannot override Authorization or point the credential at another host.
Drop-in spec updatesWafeq ships a newer spec? Replace one file and rebuild β€” new endpoints become new tools automatically, no code changes.

How it compares

CapabilityThis projectGeneric OpenAPI→MCP wrapper*
All 251 Wafeq endpoints as toolsβœ…βœ…
Per-tool safety category + bannerβœ…βŒ
Tax-authority filing flagged as irreversible, not "create"βœ…βŒ
readOnlyHint / destructiveHint MCP annotationsβœ…βž–
Read-only fields stripped from create/update bodiesβœ…βŒ
Duplicated enum prose compacted out of schemasβœ…βŒ
Correct, per-report date parametersβœ…βœ…
Whole-period range validated before sendingβœ…βŒ
Automatic X-Wafeq-Idempotency-Key, stable across retriesβœ…βŒ
Multipart + raw-binary file uploadβœ…βž–
Binary PDF responses base64-encoded, not mangledβœ…βž–
Transaction dates recovered for journal line itemsβœ…βŒ
Automatic retries on 429 / 5xx (honors Retry-After)βœ…βŒ
Client-side rate limitingβœ…βŒ
Organization identity verified at startupβœ…βŒ
stdio transportβœ…βœ…
Streamable-HTTP transportβœ…βž–
Docker + docker-compose, health check, auto-restartβœ…βŒ
Optional bearer-token auth on the endpointβœ…βŒ
LicenseMITvaries

*Generic OpenAPIβ†’MCP wrappers turn any spec into MCP tools. They can reach the same endpoints, but treat every operation identically β€” and against Wafeq's spec specifically they inherit the read-only-required-field problem described in MIGRATION.md. "βž–" = varies by tool / not guaranteed.

What you can do

Once it's connected, ask your assistant things like:

  • "What was our profit and loss for the first half of this year?"
  • "Show me every unpaid invoice older than 30 days, with the customer name."
  • "Create a draft invoice for Acme Ltd for 3 days of consulting at €800/day."
  • "Download invoice INV-2026-014 as a PDF."
  • "Which account did the €7,000 transfer in January post to?"
  • "Attach this receipt to expense EXP-118."
  • "Reconcile the bank statement lines for March against the ledger."
  • "Convert quote QUO-31 to an invoice and record the payment."

How it works

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

At startup the server parses the bundled OpenAPI spec into MCP tools β€” resolving $refs, guarding against recursive schemas, and stripping server-assigned (readOnly) fields out of request bodies β€” tags each tool with its safety category, verifies which Wafeq organization the credentials belong to, and then injects your credential on every outgoing request. Your key stays in the server's environment; the model never sees or handles it.

Requirements

  • A Wafeq organization with API access β€” either a private API key (Wafeq β†’ Settings β†’ Developer β†’ API keys) or an OAuth2 access token. See Get your API credentials.
  • Docker (Docker Desktop on macOS/Windows) for the quick start below β€” or Node.js β‰₯ 20 to run from source.

Quick start (Docker)

1. Add your credentials. Copy the example config and fill it in:

cp .env.example .env

Then edit .env and set WAFEQ_API_KEY. Unless HOST is a loopback address the server also requires MCP_AUTH_TOKEN and refuses to start without one, so set it to a long random string: MCP_AUTH_TOKEN=$(openssl rand -hex 32).

2. Start the server:

docker compose up -d --build

docker-compose.yml binds to 127.0.0.1:8765 only, so the server is reachable from your machine but not from the network.

3. Confirm it's running β€” and that it's pointed at the right books:

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
}

Check the name field. That is the organization your key writes to. If it isn't the company you expected, stop and fix the key before doing anything else. /health answers 503 and "status": "degraded" when the credentials can't be verified.

4. Point your MCP client at it: http://localhost:8765/mcp (Streamable HTTP).

Remote endpoints are added to Claude as a custom connector (Settings β†’ Connectors), or bridged locally with mcp-remote. For the bridge, add this under mcpServers in your client config and restart the app completely:

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

(Drop the --header line only if the server runs without a token, which it allows on a loopback bind alone.)

Prefer a ready-made image?

Every release publishes a ready-to-run image to the GitHub Container Registry, so you can skip the local build entirely:

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

Pin a version (:2.0.0) rather than latest if you want releases to be something you opt into.

Install from the MCP Registry

The server is published to the MCP Registry as io.github.ohneben/wafeq-mcp, so registry-aware clients can install it by name. The registry entry launches the image over stdio β€” see Run the container over stdio for the equivalent hand-written config.

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

Get your API credentials

Private API key (most people): in Wafeq, go to Settings β†’ Developer β†’ API keys and create a key. It is scoped to one organization. Put it in .env as WAFEQ_API_KEY; the server sends it as Authorization: Api-Key <key>.

OAuth2 app: if you have an access token from a Wafeq OAuth2 app, put it in .env as WAFEQ_ACCESS_TOKEN instead. The server switches to Authorization: Bearer <token> automatically. Set WAFEQ_AUTH_SCHEME only if you need to force one scheme while both variables are present.

Configuration

All configuration is environment variables. Everything except the credential has a working default.

VariableDefaultWhat it does
WAFEQ_API_KEYβ€”Private organization API key. Sent as Api-Key <key>. One credential is required.
WAFEQ_ACCESS_TOKENβ€”OAuth2 access token. Sent as Bearer <token>. Takes precedence over WAFEQ_API_KEY.
WAFEQ_AUTH_SCHEMEautoForce api-key or bearer. Normally leave unset.
WAFEQ_API_BASE_URLhttps://api.wafeq.com/v1Wafeq API base URL.
WAFEQ_OPENAPI_PATHbundled specUse a different OpenAPI document (JSON or YAML).
MCP_TRANSPORTstdiostdio or http. Docker sets http.
PORT8765HTTP listen port.
HOST0.0.0.0HTTP bind address.
MCP_HTTP_PATH/mcpPath the MCP endpoint is served on.
MCP_AUTH_TOKENβ€”Bearer token required on /mcp. Required unless HOST is a loopback address, otherwise the server refuses to start. Renamed from MCP_SHARED_TOKEN in 2.1.0.
MCP_ALLOWED_HOSTSβ€”Comma-separated hostnames the Host header may carry. Empty lets the server derive it: the loopback names on a loopback bind, no check behind a reverse proxy.
MCP_ALLOW_INSECURE0Start without a token on a non-loopback bind. Only for a port that genuinely is not reachable by anyone else.
MCP_BODY_LIMIT25mbLargest accepted request body.
MCP_SESSION_TTL1800Seconds an idle session is kept before it is swept.
MCP_MAX_SESSIONS256Concurrent sessions before the least recently used one is evicted.
WAFEQ_TOOL_GROUPSβ€”Comma-separated resource groups to expose, e.g. invoices,bills,reports. Empty = all 251. Run npm run list-tools for the list.
WAFEQ_MAX_REQUESTS20Client-side rate limit: requests per window. 0 disables throttling.
WAFEQ_RATE_WINDOW_MS10000Rate-limit window in milliseconds.
WAFEQ_MAX_RETRIES3Retries on 429 / 5xx / network errors.
WAFEQ_TIMEOUT_MS30000Per-attempt request timeout.
WAFEQ_ALLOW_LOCAL_FILE_UPLOADfalseAllow upload tools to read this machine's filesystem via file_path. See Security.
WAFEQ_MAX_UPLOAD_BYTES26214400Maximum decoded upload size (25 MiB).

Too many tools?

251 tools is a lot. The full catalogue is about 0.5 MB of JSON (~133k tokens) on tools/list, and some hosts get slower or less accurate with that many. Two things help.

The schemas are already compacted. Wafeq's spec renders every enum's values into its description as well as into enum β€” the currency list alone is ~4 KB, inlined at 203 places. The generator collapses those single-member allOf wrappers and drops the duplicated bullet lists, which takes ~29% off the payload without removing a single allowed value.

Narrow the catalogue if you still want it smaller β€” no code changes needed:

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

The two hand-written tools are always available, so nothing becomes unreachable β€” anything you filter out can still be called through wafeq_request.

Tool safety categories

Every tool's description opens with a banner, and every tool carries the matching MCP annotations. Counts are for the bundled spec (251 generated + 2 hand-written = 253).

BannerToolsreadOnlyHintdestructiveHintWhat it covers
🟒 READ-ONLY85βœ…βŒEvery GET, plus the account-ledger convenience tool.
🟒 READ-ONLY Β· returns a PDF9βœ…βŒThe PDF downloads: invoice, simplified invoice, credit note, debit note, bill, quote, purchase order, payment, payslip. Returned base64-encoded.
🟒 READ-ONLY Β· preview / simulation4βœ…βŒAmortization and revenue-recognition previews. POST, but documented as writing nothing.
🟑 WRITE Β· creates data39❌❌Collection creates, both file uploads, and the two conversions (quoteβ†’invoice, purchase orderβ†’bill). Not idempotent by nature β€” hence the automatic idempotency key.
🟑 WRITE · updates data70❌❌Every PUT and PATCH.
🟠 STATE CHANGE Β· moves a document in or out of the ledger2❌❌Mark expense posted / draft. Reversible β€” each undoes the other.
πŸ”΄ IRREVERSIBLE Β· files the document with an external tax authority3βŒβœ…Report invoice / credit note / simplified invoice to the tax authority. Leaves your organization and cannot be recalled.
πŸ”΄ IRREVERSIBLE Β· posts the remaining balance to the ledger2βŒβœ…End amortization / revenue recognition early. No API undo β€” run the matching preview first.
πŸ”΄ DESTRUCTIVE Β· deletes39βŒβœ…Every DELETE, plus the wafeq_request passthrough (its effect can't be known in advance).
2539844

The three πŸ”΄ groups all set destructiveHint: true, so a host that honors annotations stops and asks before any of them β€” not just before deletions. Filing an invoice with a tax authority is at least as consequential as deleting one, and unlike a deletion it reaches outside your organization.

Print the live catalogue any time, without credentials:

npm run list-tools
ToolEndpoint
wafeq_account_ledgerhand-written
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}/
ToolEndpoint
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/
ToolEndpoint
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/
ToolEndpoint
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/
ToolEndpoint
wafeq_accounts_partial_updatePATCH /accounts/{id}/
wafeq_accounts_updatePUT /accounts/{id}/
wafeq_bank_accounts_ledger_transactions_partial_updatePATCH /bank-accounts/{bank_account_id}/ledger-transactions/{id}/
wafeq_bank_accounts_ledger_transactions_updatePUT /bank-accounts/{bank_account_id}/ledger-transactions/{id}/
wafeq_bank_accounts_partial_updatePATCH /bank-accounts/{id}/
wafeq_bank_accounts_statement_transactions_partial_updatePATCH /bank-accounts/{bank_account_id}/statement-transactions/{id}/
wafeq_bank_accounts_statement_transactions_updatePUT /bank-accounts/{bank_account_id}/statement-transactions/{id}/
wafeq_bank_accounts_updatePUT /bank-accounts/{id}/
wafeq_beneficiaries_partial_updatePATCH /beneficiaries/{id}/
wafeq_beneficiaries_updatePUT /beneficiaries/{id}/
wafeq_bills_line_items_partial_updatePATCH /bills/{bill_id}/line-items/{id}/
wafeq_bills_line_items_updatePUT /bills/{bill_id}/line-items/{id}/
wafeq_bills_partial_updatePATCH /bills/{id}/
wafeq_bills_updatePUT /bills/{id}/
wafeq_branches_partial_updatePATCH /branches/{id}/
wafeq_branches_updatePUT /branches/{id}/
wafeq_contacts_partial_updatePATCH /contacts/{id}/
wafeq_contacts_updatePUT /contacts/{id}/
wafeq_cost_centers_partial_updatePATCH /cost-centers/{id}/
wafeq_cost_centers_updatePUT /cost-centers/{id}/
wafeq_credit_notes_line_items_partial_updatePATCH /credit-notes/{credit_note_id}/line-items/{id}/
wafeq_credit_notes_line_items_updatePUT /credit-notes/{credit_note_id}/line-items/{id}/
wafeq_credit_notes_partial_updatePATCH /credit-notes/{id}/
wafeq_credit_notes_updatePUT /credit-notes/{id}/
wafeq_custom_fields_partial_updatePATCH /custom-fields/{id}/
wafeq_custom_fields_updatePUT /custom-fields/{id}/
wafeq_debit_notes_line_items_partial_updatePATCH /debit-notes/{debit_note_id}/line-items/{id}/
wafeq_debit_notes_line_items_updatePUT /debit-notes/{debit_note_id}/line-items/{id}/
wafeq_debit_notes_partial_updatePATCH /debit-notes/{id}/
wafeq_debit_notes_updatePUT /debit-notes/{id}/
wafeq_employees_partial_updatePATCH /employees/{id}/
wafeq_employees_updatePUT /employees/{id}/
wafeq_expenses_partial_updatePATCH /expenses/{id}/
wafeq_expenses_updatePUT /expenses/{id}/
wafeq_invoices_line_items_partial_updatePATCH /invoices/{invoice_id}/line-items/{id}/
wafeq_invoices_line_items_updatePUT /invoices/{invoice_id}/line-items/{id}/
wafeq_invoices_partial_updatePATCH /invoices/{id}/
wafeq_invoices_updatePUT /invoices/{id}/
wafeq_item_units_of_measure_partial_updatePATCH /item-units-of-measure/{id}/
wafeq_item_units_of_measure_updatePUT /item-units-of-measure/{id}/
wafeq_items_partial_updatePATCH /items/{id}/
wafeq_items_updatePUT /items/{id}/
wafeq_manual_journals_partial_updatePATCH /manual-journals/{id}/
wafeq_manual_journals_updatePUT /manual-journals/{id}/
wafeq_payment_requests_partial_updatePATCH /payment_requests/{id}/
wafeq_payment_requests_updatePUT /payment_requests/{id}/
wafeq_payments_partial_updatePATCH /payments/{id}/
wafeq_payments_updatePUT /payments/{id}/
wafeq_payslips_partial_updatePATCH /payslips/{id}/
wafeq_payslips_pay_items_partial_updatePATCH /payslips/{payslip_id}/pay-items/{id}/
wafeq_payslips_pay_items_updatePUT /payslips/{payslip_id}/pay-items/{id}/
wafeq_payslips_updatePUT /payslips/{id}/
wafeq_projects_partial_updatePATCH /projects/{id}/
wafeq_projects_updatePUT /projects/{id}/
wafeq_purchase_orders_line_items_partial_updatePATCH /purchase-orders/{purchase_order_id}/line-items/{id}/
wafeq_purchase_orders_line_items_updatePUT /purchase-orders/{purchase_order_id}/line-items/{id}/
wafeq_purchase_orders_partial_updatePATCH /purchase-orders/{id}/
wafeq_purchase_orders_updatePUT /purchase-orders/{id}/
wafeq_quotes_line_items_partial_updatePATCH /quotes/{quote_id}/line-items/{id}/
wafeq_quotes_line_items_updatePUT /quotes/{quote_id}/line-items/{id}/
wafeq_quotes_partial_updatePATCH /quotes/{id}/
wafeq_quotes_updatePUT /quotes/{id}/
wafeq_simplified_invoices_line_items_partial_updatePATCH /simplified-invoices/{invoice_id}/line-items/{id}/
wafeq_simplified_invoices_line_items_updatePUT /simplified-invoices/{invoice_id}/line-items/{id}/
wafeq_simplified_invoices_partial_updatePATCH /simplified-invoices/{id}/
wafeq_simplified_invoices_updatePUT /simplified-invoices/{id}/
wafeq_units_of_measure_partial_updatePATCH /units-of-measure/{id}/
wafeq_units_of_measure_updatePUT /units-of-measure/{id}/
wafeq_warehouses_partial_updatePATCH /warehouses/{id}/
wafeq_warehouses_updatePUT /warehouses/{id}/
ToolEndpoint
wafeq_expenses_mark_as_draft_createPOST /expenses/{id}/mark-as-draft/
wafeq_expenses_mark_as_posted_createPOST /expenses/{id}/mark-as-posted/
ToolEndpoint
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/
ToolEndpoint
wafeq_amortizations_end_early_createPOST /amortizations/{id}/end-early/
wafeq_revenue_recognitions_end_early_createPOST /revenue-recognitions/{id}/end-early/
ToolEndpoint
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_requesthand-written
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}/

Coverage

AreaTools🟒 Read🟑 WriteπŸ”΄ IrreversibleπŸ”΄ Delete
Sales & receivables692531310
Purchasing & payables54192708
Banking186903
Ledger & reporting3119624
Payroll197903
Master data & dimensions54182709
Files & organization63201
Escape hatch & convenience21001
Total25398111539

"Write" includes the two 🟠 state-change tools. Areas map to Wafeq resources as follows β€” Sales: invoices, simplified invoices, quotes, credit notes, payments, payment requests Β· Purchasing: bills, purchase orders, debit notes, expenses, beneficiaries Β· Banking: bank accounts with their ledger and statement transactions Β· Ledger & reporting: accounts, manual journals, journal line items, the four reports, tax rates, amortizations, revenue recognitions Β· Payroll: payslips, employees Β· Master data: contacts, items, units of measure, warehouses, projects, cost centers, branches, custom fields.

Two hand-written tools

Everything above is generated. Two tools are written by hand:

  • wafeq_account_ledger (🟒) β€” journal line items with their real transaction date. Wafeq's /journal-line-items/ rows carry created_ts (when the row reached Wafeq), which is regularly a different month from the transaction, and no date field at all. This tool recovers the date using the endpoint's own date_after/date_before filters, which do operate on the transaction date. It probes a month at a time and only splits into day queries where rows exist, so quiet periods cost one request each; the result reports requests_made.
  • wafeq_request (πŸ”΄) β€” the escape hatch: any method, any path, plus query, body and headers. It is the fallback for anything the bundled spec misses, not the primary interface. Categorized destructive because its effect can't be known in advance.

Run from source (stdio, no Docker)

npm ci
npm run build

Then register it with your MCP client. For Claude Desktop, add to 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"
      }
    }
  }
}

For Claude Code:

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

Run the container over stdio

You can also let your client launch the published image directly, with no HTTP server and no local build:

{
  "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 is required here: the image defaults to the HTTP transport.

Useful scripts:

Documentation truncated β€” see the full README on GitHub.

Reviews

No reviews yet

Be the first to review this server!