[Purpose] xendit-mcp is a Model Context Protocol (MCP) server for the Xendit payment API, targeting Southeast Asian markets (Indonesia, the Philippines, Thailand, Vietnam, Malaysia). It lets AI clients (such as Claude Code, Claude Desktop, Cursor) call Xendit's payment-related capabilities, including generating payment links via invoices, disbursements/payouts, balance inquiries, and transaction inquiries.
[Main Capabilities] The server organizes functionality into three user-facing modes:
- read-only: balance inquiries, invoice reads, transaction reads.
- invoices: adds create_invoice and expire_invoice on top of read-only.
- guarded-payouts: adds prepare_disbursement and confirm_disbursement on top of invoices mode. It also provides helper tools for non-technical users: doctor prints the current mode, enabled capabilities, and features that are still blocked; setup generates a Claude Code or Claude Desktop configuration snippet based on the selected mode. get_workspace_mode and guided_setup are also available in read-only mode. When available in Claude Code, guided_setup uses MCP elicitation so the user sees a form rather than raw configuration.
[Usage] You must first register in the Xendit Dashboard, go to Settings → API Keys to generate a key, use a test key for development (xnd_development_…), and a live key for production. You can run it on demand via npx xendit-mcp, or run setup to generate a configuration snippet (it asks which client and mode you are using, and outputs a pasteable Claude configuration snippet with the key shown as a placeholder). You can also manually edit claude_desktop_config.json; for Cursor, add the same structure in ~/.cursor/mcp.json. Upgrading from 0.1.x to 0.2.0 involves a breaking default change: invoice creation and one-shot disbursement tools are disabled by default. To restore the old behavior, you need to set the corresponding switches in the MCP configuration env. If disbursements are enabled, four safety gates must be set (XENDIT_MAX_DISBURSEMENT_AMOUNT, XENDIT_MAX_DAILY_AMOUNT, XENDIT_ALLOWED_ACCOUNTS, XENDIT_APPROVAL_CODE), otherwise the server refuses to start. The official recommendation is to migrate to the new two-step disbursement flow (prepare_disbursement → confirm_disbursement, with an approval code).
[Security Mechanisms]
- Read-only by default: invoice write tools are disabled unless XENDIT_ENABLE_INVOICE_MUTATIONS=true is set; money transfer tools are disabled unless XENDIT_ENABLE_DISBURSEMENTS=true is set.
- Live keys denied by default: keys prefixed with xnd_production_, iluma_production_, sk_live_ are rejected at startup unless XENDIT_ALLOW_LIVE=true is set. It is recommended to test with a development key (xnd_development_…) first.
- Fail-closed money transfers: when disbursements are enabled, the four gate variables must be configured, otherwise startup is refused.
- Human in the loop: confirm_disbursement requires a staged token and a separate approvalCode.
- Legacy one-shot disbursements off by default: create_disbursement is not registered unless XENDIT_ENABLE_LEGACY_ONE_SHOT_DISBURSEMENT=true is set.
- Hard caps and allowlists: fail closed before payment via XENDIT_MAX_DISBURSEMENT_AMOUNT, XENDIT_MAX_DAILY_AMOUNT, XENDIT_ALLOWED_ACCOUNTS.
- Idempotency: payment calls use externalId as the Idempotency-Key, so safe retries do not produce duplicate transfers. Important limitation: if sensitive read/write tools are exposed to an untrusted model context, no MCP server can be fully immune to prompt injection. You should connect only trusted agent workflows, manually review before approving money transfer tool calls, and treat tool inputs coming from model output asUntrusted.
[Disbursement Lifecycle] Confirming a disbursement does not necessarily succeed or fail immediately. Statuses returned by Xendit include: ACCEPTED (accepted, being processed by the channel), REQUESTED (submitted to the target channel, awaiting response), SUCCEEDED (funds delivered), FAILED (final failure, such as INVALID_DESTINATION, REJECTED_BY_CHANNEL, INSUFFICIENT_BALANCE). Some targets (observed in PHP sandbox testing) remain in REQUESTED for a period before transitioning to FAILED. Always re-fetch via get_disbursement; do not treat the initial response from confirm_disbursement as proof of delivery.
[Sandbox Verification Scope] 0.2.0 has been verified against the Xendit sandbox using IDR and PHP development keys. The verification flow includes: invoice creation/retrieval/listing/expiry (IDR + PHP), disbursement channel discovery (PHP), controlled disbursement prepare → confirm → get (IDR + PHP), negative disbursement reasons INVALID_DESTINATION and REJECTED_BY_CHANNEL (PHP only; the IDR sandbox key balance is 0, so the IDR negative case manifests as INSUFFICIENT_BALANCE). The behavior for Thailand, Vietnam, and Malaysia has not been verified with real sandbox keys; the behavior should be similar but cannot be claimed as tested.
[Optional Hardening] Claude Code supports PreToolUse hooks, which can enforce an additional approval dialog for sensitive tools such as confirm_disbursement, providing a second layer of control outside the model context.
[Disclaimer] This is an unofficial, community-built MCP server, not affiliated with, endorsed by, or sponsored by Xendit. Xendit is a trademark of its respective owners. Use at your own risk; the author is not liable for financial losses caused by misuse, prompt injection, or defects.