@rmarinsky/wayforpay-mcp
v1.0.0
Published
Model Context Protocol (MCP) server for WayForPay — query merchant balance, transactions, regular payments, and trigger gated mutations (create invoice / refund / settle) from any MCP client (Claude Desktop, Claude Code, Cursor).
Maintainers
Readme
wayforpay-mcp
Model Context Protocol (MCP) server for WayForPay — a popular Ukrainian payment gateway. Configure one or more merchant profiles once, then let any MCP-capable agent query WayForPay data or trigger a limited set of payment operations.
Status: production-shaped. 15 tools available in read-only mode by default, 21 total when
WFP_ENABLE_WRITE_TOOLS=true, plus 6 prompts. Output is TOON by default; read tools useapiVersion: 2by default so lean projections keep useful customer/product/PRRO fields without dumping the full payload.
What it does
| Tool | Kind | Wraps |
|---------------------------------|----------|------------------------------------|
| wfp_list_profiles | read | (config introspection) |
| wfp_get_merchant_info | read | mms/merchantInfo.php |
| wfp_get_balance | read | mms/merchantBalance.php |
| wfp_get_currency_rates | read | CURRENCY_RATES |
| wfp_get_transaction_list | read | TRANSACTION_LIST raw rows (paginated, default limit 20) |
| wfp_summarize_transactions | read | TRANSACTION_LIST aggregates (counts, totals, by-status/day) — no rows |
| wfp_search_transactions | read | TRANSACTION_LIST filter (status / amount / paymentSystem / substrings) — requires at least one filter |
| wfp_list_active_instruments | read | Prefix-based analytics for social invoices / payment buttons |
| wfp_instrument_transactions | read | Prefix-based transaction slice with summary + paginated rows |
| wfp_check_status | read | CHECK_STATUS |
| wfp_get_regular_status | read | regularApi STATUS |
| wfp_verify_payment_signature | local | HMAC-MD5 verifier |
| wfp_build_service_ack | local | webhook ack builder |
| wfp_create_invoice 🔥 | write | CREATE_INVOICE |
| wfp_refund_payment 🔥 | write | REFUND |
| wfp_settle_payment 🔥 | write | SETTLE |
| wfp_suspend_recurring | write | regularApi SUSPEND |
| wfp_resume_recurring | write | regularApi RESUME |
| wfp_delete_recurring 🔥 | write | regularApi REMOVE |
| wfp_health | meta | health check via getMerchantInfo |
| wfp_capabilities | meta | tool discovery for foreign agents |
🔥 = destructive: requires confirm: true in the tool input. Description
tells the model to confirm with you in chat first.
A full endpoint reference (including endpoints not yet wrapped) is in
docs/api-endpoints.md.
Output format
Tool responses follow MCP's dual-channel pattern:
content[].text(what the model reads) — defaults to TOON (Token-Oriented Object Notation). Tabular arrays of uniform objects collapse to CSV-with-schema, ~40% fewer tokens than JSON.structuredContent(programmatic consumers) — always plain JSON-friendly objects.
Knobs on read tools:
| Param | Type | Effect |
|------------|-----------------------|-----------------------------------------------------------------------|
| format | "toon" | "json" | Switch the text channel back to JSON. Default "toon". |
| verbose | boolean | Skip the lean projection and return every field. Default false. |
| limit | number (1–500) | Page size. Transaction list only. |
| offset | number (≥0) | Page offset. Use next_offset from a prior response. |
| merchant | string | Merchant alias from wfp_list_profiles. Defaults to WFP_DEFAULT_MERCHANT. |
Errors come back as JSON in text — they're small and diagnostics are
easier when format is universal.
Read payloads
wfp_get_transaction_list and wfp_check_status use apiVersion: 2 by
default. That means responses can include richer fields like products,
clientName, clientEmail, clientPhone, clientComment, prroLink,
prroNumber, processingDate, settlementDate, settlementReference,
baseAmount, and baseCurrency. Lean mode keeps the most useful of these;
verbose: true returns the full payload.
Quickstart
1. Get WayForPay credentials
For each merchant in your account: merchantAccount, secretKey (used to
sign every request), optionally merchantPassword (only for regularApi).
2. Add to your MCP client
Claude Code
claude mcp add wayforpay \
--env WFP_DEFAULT_MERCHANT=main \
--env WFP_ENABLE_WRITE_TOOLS=false \
--env WFP_MERCHANTS_JSON='[{"alias":"main","merchantAccount":"...","secretKey":"...","domainName":"shop.example.com","defaultCurrency":"UAH"}]' \
-- bun run /path/to/wayforpay-mcp/src/index.tsClaude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"wayforpay": {
"command": "bun",
"args": ["run", "/path/to/wayforpay-mcp/src/index.ts"],
"env": {
"WFP_DEFAULT_MERCHANT": "main",
"WFP_ENABLE_WRITE_TOOLS": "false",
"WFP_MERCHANTS_JSON": "[{\"alias\":\"main\",\"merchantAccount\":\"...\",\"secretKey\":\"...\"}]"
}
}
}
}3. Try it
Show me yesterday's WayForPay transactions for my main merchant.Claude will call wfp_get_transaction_list with the right date range,
paginate if needed, and summarize via TOON.
Local development
bun install
bun run dev # MCP server in stdio mode
bun run validate # typecheck + lint + tests
bun test # unit tests onlyConfiguration (env vars)
| Variable | Required | Default | Notes |
|----------------------------|----------|---------|----------------------------------------------------------------|
| WFP_MERCHANTS_JSON | yes* | — | Inline JSON array of merchant profiles. Either this or WFP_MERCHANTS_FILE. |
| WFP_MERCHANTS_FILE | yes | — | Path to a JSON file with the same shape. |
| WFP_DEFAULT_MERCHANT | no | (auto) if 1 merchant | Alias to use when merchant parameter is omitted. |
| WFP_ENABLE_WRITE_TOOLS | no | false | Set true to expose invoice/refund/settle plus recurring suspend/resume/delete. |
| WFP_REQUEST_TIMEOUT_MS | no | 15000 | Per-request timeout. |
Merchant profile shape:
{
"alias": "main", // identifier used in `merchant` param
"merchantAccount": "merchant_x", // from WFP dashboard
"secretKey": "secret_x", // signs every request
"merchantPassword": "optional_regular_password", // only for regularApi
"domainName": "shop.example.com", // required for createInvoice
"defaultCurrency": "UAH",
"serviceUrl": "https://shop.example.com/api/wfp/webhook"
}Working with transaction lists safely
WayForPay's TRANSACTION_LIST returns the entire 31-day window in one response.
On a busy merchant that's hundreds of dense rows — enough to blow the LLM
context window if dumped raw. This MCP exposes three tools so the agent picks
the right shape for the question:
| Question | Tool | Returns rows? |
|-------------------------------------------------------|-------------------------------|:-------------:|
| "How many / what's the total / how's it trending?" | wfp_summarize_transactions | ❌ aggregates only |
| "Find declined / over 5000 / from acme@..." | wfp_search_transactions | ✅ filtered + paginated |
| "Show me the rows" (after narrowing by date) | wfp_get_transaction_list | ✅ raw + paginated |
wfp_search_transactions refuses unfiltered calls (must pass at least one
of status / amount_min / amount_max / payment_system /
orderReference_contains / email_contains / card_pan_contains).
wfp_get_transaction_list defaults to 20 rows per page and refuses
verbose: true when limit > 20. The response carries a hint field
when total > 100 so the model is reminded of the safer alternatives.
How other coding agents discover this MCP
Foreign agents (Cursor / Cline / Continue) attach without context. The
expected first call is wfp_capabilities, which returns:
- Server
versionandname. - Configured
merchantslist anddefault_merchant. output_format:{default: "toon", alternative: "json"}.destructive_safetynote aboutconfirm: truediscipline.tools[]: every registered tool withname,title, one-linesummary, and metadata flags (destructive,has_pagination,has_format,has_verbose,input_keys).
That single response replaces a README round-trip — agents can plan a multi-step workflow (e.g. "find a transaction, then refund it") with no trial-and-error tool guessing.
Prompts
The server also registers 6 prompts for common flows:
financial-reportdaily-monitoringreconciliationsubscription-overviewfind-transactionrevenue-comparison
Each prompt supports an optional merchant argument so multi-merchant setups
can stay explicit.
Safety model
Every destructive tool requires confirm: z.literal(true):
wfp_create_invoice(generates a payment URL)wfp_refund_payment(real money out — irreversible)wfp_settle_payment(captures held funds)wfp_delete_recurring(irreversible recurring cancel)
The tool description for each one instructs the model to confirm the
action with you in chat before sending confirm: true. You can also force
read-only mode with WFP_ENABLE_WRITE_TOOLS=false, which removes all
mutation tools from the registered list, including recurring suspend/resume/delete.
Secrets are loaded from env or file, never from tool arguments. The server
never echoes secretKey or merchantPassword back to the client.
Known constraints
TRANSACTION_LISTis limited by WayForPay to a 31-day window — the tool enforces this.- The
regularApiis a different auth model and requiresmerchantPassword. - WFP webhook ack signature wording is inconsistent across docs; this server
uses the
HMAC_MD5(secretKey, "orderReference;status;time")pattern documented on Purchase/Invoice pages. - WFP API requires HMAC-MD5; cannot be upgraded to a stronger MAC.
License
Private package; see workspace owner.
