Skip to main content
Glama
README.md
# payments-ops-mcp

An MCP server that lets an AI agent do a payments ops analyst's morning: reconcile the ledger against the PSP and the bank, triage chargebacks, and check refunds against policy.

Setup takes minutes, not an IT project. Share your PSP contract and the exports you already download; the agent reads them, the code checks them, you confirm, and the review is ready.

No tool moves money or submits anything. The agent finds problems, explains them and drafts responses; a person approves every action.

## Why I built this

Most "AI for payments" demos stop at a chatbot that answers FAQs. The expensive work in payments operations is elsewhere: the payout that arrived $12.50 short, the order captured twice, the fee charged above contract, the chargeback due in two days that nobody has looked at.

That work is a good fit for agents because it is rules plus judgment, spread across three systems that don't agree. It is also a bad place to let an agent act on its own. So this server is designed the way I'd ship it in production: the agent gets broad read access, writes only to its own setup files after a person confirms, and every recommendation says who has to approve it.

## How it works

```
  Your PSP contract ─┐                        ┌─ reconcile_payments
  Shop orders CSV  ──┤                        ├─ explain_reconciliation_break
  PSP export CSV   ──┼─► onboarding tools ──► workspace ──► analysis tools ─┼─ list_open_disputes / triage_dispute
  Bank CAMT.053    ──┤   (you confirm)         (local)       (read-only)      ├─ draft_evidence_pack
  Disputes CSV     ──┘                                                      └─ check_refund_policy
```

**Claude reads, code checks, a person confirms, the server stores.** The model is good at reading a contract or guessing which column is which. Code is good at checking that 2.9% is plausible and that a quoted clause really exists. People are good at saying yes. Each does only its part.

## Tools

### Analysis (read-only)

| Tool | What the agent gets |
| --- | --- |
| `reconcile_payments` | Three-way reconciliation: ledger to PSP captures, then PSP payouts to bank deposits. Fees checked against the contract version in force on each date. Match rate, value in breaks, every break with an id. |
| `explain_reconciliation_break` | Likely causes and next steps for one break, plus any open dispute on the same order. |
| `list_open_disputes` | Chargebacks needing a response, most urgent first. |
| `triage_dispute` | Reason code, evidence on file, win likelihood, cost if lost (including the contract's chargeback fee), and a fight / review / accept recommendation. |
| `draft_evidence_pack` | A plain-text evidence pack and draft response for a person to review. |
| `check_refund_policy` | Whether a refund is allowed and who must approve it. Never issues the refund. |

### Onboarding (writes only to the local workspace)

| Tool | What it does |
| --- | --- |
| `list_data_sources` | What is loaded: sample or workspace mode, row counts, date ranges, contract versions, what is still missing. |
| `propose_contract_terms` | Validates terms the agent extracted from a contract and checks each quoted clause really appears in the document and contains the number. Stages a proposal; saves nothing. |
| `save_contract_terms` | Saves a confirmed proposal as a new contract version with an effective date. Refuses unless `confirmed=true`. |
| `list_contract_versions` | Contract versions on file. |
| `preview_import` | Detects CSV or CAMT.053, suggests a column mapping, shows normalised sample rows and errors. |
| `save_mapping_profile` | Remembers how an export's columns map, so the next file imports with no mapping step. |
| `import_transactions` | Imports a file into the workspace. Re-importing the same file is safe. |

Prompts: `onboard_my_payments_data` (guided setup) and `daily_payments_ops_review` (morning review). Resource: `payments://reason-codes`.

### Break types it detects

`missing_at_psp` · `missing_in_ledger` · `amount_mismatch` · `duplicate_capture` · `fee_mismatch` · `settlement_mismatch` · `missing_settlement`

Payouts that are not due yet under the contract's payout delay show as `in_transit`, not as breaks.

## Onboarding your own data

1. **Contract.** Share your PSP pricing schedule and say "set this up as my fee terms". The agent extracts the percentage and fixed fee, international surcharge, chargeback fee, payout delay and reserve, each with the clause it came from. You see every value with a check: `verified`, `quote_not_found` or `number_not_in_quote`. Implausible values (a 29% fee, a fee written as 0.029) are rejected outright. Amendments become new versions, so February's transactions are checked against February's prices.
2. **Exports.** Give it your orders export, PSP transaction report, bank statement and disputes export. For a new CSV layout the agent shows the mapping it suggests and a few normalised rows; once you agree, the mapping is saved and every later file of that layout imports in one step. Common status words (`paid`, `charge`, `succeeded`) are translated automatically, and PSP payout or refund rows are skipped. CAMT.053 bank statements need no mapping at all.
3. **Run.** "Run my daily payments ops review."

See [docs/onboarding.md](docs/onboarding.md) for a real run on the files in [`examples/onboarding/`](examples/onboarding/): a fictional pricing schedule with an amendment, a Stripe-style balance report, a shop orders export with day-first dates, a disputes export and a CAMT.053 statement.

### Where data lives

The workspace is `~/.payments-ops-mcp`, or `PAYMENTS_OPS_DATA_DIR` if set. Until it holds transaction data the tools run on the bundled sample data. Once it does, only the workspace is used, and files not yet imported count as empty, so real and sample data are never mixed.

## Design choices

- **No money moves.** Analysis tools carry `readOnlyHint`. Setup tools write only to the local workspace. Refund checks return `executes_refund: false`; dispute triage returns `requires_human_decision: true`.
- **Extraction is checked, not trusted.** Every contract value needs a verbatim quote, and the server confirms the quote exists in the document and contains the number before the person is asked to confirm.
- **Terms are versioned.** Contracts change. Each version has an effective date, and every fee check names the version it used.
- **Money in minor units.** Amounts are integers internally and formatted once on the way out, so the model never does float arithmetic on money.
- **Connected findings.** A duplicate capture found in reconciliation links to the duplicate-processing chargeback on the same order. That is the kind of connection a tired analyst misses.
- **Deterministic logic, model for language.** Matching, fee checks and policy rules are plain code with tests. The model reads documents, explains, prioritises and drafts.

## Quick start

```bash
git clone <this repo> && cd payments-ops-mcp
pip install -e ".[dev]"
pytest
```

### Use it in Claude Desktop

Add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "payments-ops": {
      "command": "payments-ops-mcp"
    }
  }
}
```

### Use it in Claude Code

```bash
claude mcp add payments-ops -- payments-ops-mcp
```

Then ask: *"Run my daily payments ops review as of 2026-11-05"*, or *"Set up payments-ops with my own data"* to start onboarding.

## The sample data

Fictional: one merchant, one PSP, 36 card orders in USD over three days, six open chargebacks. Seven problems are planted on purpose (see `scripts/generate_sample_data.py`). A run finds all seven:

```
orders_checked: 36 · fully matched: 32 · match rate: 88.9%
BRK-missing_at_psp-ORD-1007            captured in ledger, no PSP capture
BRK-amount_mismatch-ORD-1012           ledger USD 159.00 vs PSP USD 49.99
BRK-duplicate_capture-ORD-1020         captured twice, USD 159.00 extra
BRK-fee_mismatch-TX-5025               USD 0.54 above contract acmepay-2026-01-01
BRK-missing_in_ledger-TX-5037          PSP money with no order
BRK-settlement_mismatch-PO-20261002    bank deposit USD 12.50 short
BRK-missing_settlement-PO-20261003     payout overdue
```

Importing the example exports into an empty workspace reproduces exactly these results; `tests/test_onboarding.py` checks it. See [docs/demo.md](docs/demo.md) for a tool-by-tool morning review.

## Limits

- Single currency and a single PSP. Multi-currency FX and multi-acquirer routing are the obvious next steps.
- The international card surcharge and rolling reserve are stored but not yet applied, because exports rarely carry card country. Fee checks use the standard rate.
- Dispute evidence (3-D Secure, delivery proof) is not imported from CSV yet; imported orders triage on the evidence available.
- Bank statements: CAMT.053 and CSV. MT940 is not supported yet.
- Reason codes are simplified for triage. Always check current card network rules before responding to a dispute.
- Win likelihood is a transparent heuristic, not a trained model.

## Roadmap

- Approval-gated actions: an `issue_refund` tool that asks the person to confirm in the client before anything executes
- Read-only live connectors (PSP API, bank feed, order database) so no exports are needed
- An eval set of tricky breaks (partial captures, FX rounding, refunds netted from payouts) so matching changes are measured, not guessed
- Multi-currency settlement with FX tolerance; MT940 statements; evidence import

## License

MIT

TDQS

A4.1/5.0

Scored across 13 tools

Disambiguation5/5

Each tool targets a distinct resource and action: refund policy, reconciliation, break explanation, disputes, contracts, and import each have clearly separate tools with no functional overlap. Even the potentially confusable pairs (propose_contract_terms vs save_contract_terms, preview_import vs import_transactions) are explicitly staged with descriptions clarifying sequencing. Descriptions proactively prevent misselection (e.g. check_refund_policy 'Does NOT issue the refund').

Naming Consistency5/5

Every tool follows a consistent verb_noun snake_case pattern: check_refund_policy, list_contract_versions, explain_reconciliation_break, draft_evidence_pack, save_mapping_profile, import_transactions. There are no camelCase or other convention deviations, and verbs are used consistently for the same class of action (list_*, save_*, propose_*).

Tool Count5/5

13 tools fall squarely in the well-scoped range, and each maps to a real operational step (setup, ingest, reconcile, explain, dispute, contract). No redundant or filler tools are present; each earns its place in the payments-ops workflow.

Completeness4/5

Coverage is strong across ingestion (preview/save_mapping/import), reconciliation (reconcile + explain), disputes (list/triage/draft), and contract lifecycle (list/propose/save). Minor gaps: there is no refund issuance tool (check_refund_policy explicitly stops short), no dispute submission, and no contract update/delete, but these appear to be intentional human-in-the-loop handoffs that agents can route around.

Maintenance

ActivityMaintained
ResponsivenessSyncing