{
  "markdown": "# reconcile-mcp: An MCP Server for ISO 20022 Cash Reconciliation\n\n**A [Model Context Protocol][mcp] server that matches *expected* payments\n(from `pain.001` credit transfers) against *observed* booked entries (from a\n`camt.053` statement) and returns an explainable reconciliation** — exact\nmatches, short/over payments, split settlements (one-to-many), batch credits\n(many-to-one), and the residual unmatched items on each side, every match\ncarrying a score and the reasons it was made.\n\n> **Latest release: v0.0.1** — 7 MCP tools over stdio, pure-Python matching\n> engine, deterministic sandbox test-mode, for Python 3.10+. Part of the\n> [ISO 20022 MCP suite](#the-iso-20022-mcp-suite): you own both sides of the\n> match.\n\n## Why this exists\n\nReconciliation is the treasury team's daily pain: did the money we *expected*\nactually *arrive*, and which invoice does each credit belong to? It is rarely\none-to-one — customers underpay, settle an invoice in instalments, or a payout\naggregator sends one lump covering a dozen receivables. `reconcile-mcp` does\nthis matching as an agent tool, and — critically for finance — **shows its\nwork**: every pairing comes with a numeric score and a plain list of the\nsignals (reference, amount, date, counterparty) that drove it.\n\n## The ISO 20022 MCP Suite\n\n`reconcile-mcp` is the **reconciliation workflow** of eight coordinated,\nvendor-neutral MCP servers that together cover the ISO 20022 bank-statement\nworkflow and the November 2026 structured-address cutover, plus a high-level orchestration layer — readiness scoring, clearing-profile linting, and audit evidence — statement depth,\nwhole-catalogue routing, reconciliation, multi-format ingestion, and address\nremediation. Dependency ranges are kept aligned across the suite,\nso the servers co-install cleanly in a single Python environment: start with\none, add the rest as your workflow grows.\n\n| Server | Scope | Surface | Install | Use it when |\n| --- | --- | --- | --- | --- |\n| [`camt053-mcp`][camt053-mcp] | ISO 20022 `camt.053`/`camt.052` bank statements: parse, validate, filter, reverse; MT940/MT942 migration; CBPR+ readiness; journal export | 22 MCP tools · 4 prompts · 3 resources | `pip install camt053-mcp` | You work with bank-to-customer statements end to end — the suite's flagship |\n| [`iso20022-mcp`][iso20022-mcp] | Unified gateway: `search` / `describe` / `validate` / `generate` / `parse` meta-tools routed across the `pain` · `pacs` · `camt` · `acmt` families | 7 meta-tools | `pip install \"iso20022-mcp[all]\"` | You want one entry point to every message family |\n| [`reconcile-mcp`](#install) | Matches expected `pain.001` payments against observed `camt.053` entries — exact, partial, one-to-many, many-to-one, every match scored and explained | 7 MCP tools | `pip install reconcile-mcp` | You need explainable statement/payment reconciliation — **this package** |\n| [`bankstatementparser-mcp`][bsp-mcp] | Multi-format statement ingestion: ISO 20022 CAMT.053 and pain.001, SWIFT MT940, OFX/QFX, CSV | 5 MCP tools · 1 prompt · 1 resource | `pip install bankstatementparser-mcp` | Your statements arrive in mixed or legacy formats |\n| [`structured-address-fix-mcp`][saf-mcp] | ISO 20022 postal-address classification, assessment & remediation for the November 2026 structured-address cutover (`pacs.008` / `pain.001` debtor & creditor addresses) | 9 MCP tools | `pip install structured-address-fix-mcp` | You need debtor/creditor addresses cliff-ready ahead of 14 Nov 2026 |\n| [`iso20022-readiness-suite-mcp`](https://github.com/sebastienrousseau/iso20022-readiness-suite-mcp) | Orchestration gateway: detect → structurally validate → clearing-profile lint → readiness score, plus automated remediation and `pacs.002` bank-response simulation — a meta-client over the foundational servers | 4 MCP tools | `pip install iso20022-readiness-suite-mcp` | You want one high-level readiness / orchestration entry point over the suite |\n| [`iso20022-bank-profile-mcp`](https://github.com/sebastienrousseau/iso20022-bank-profile-mcp) | Manages, validates and serves bank-specific clearing profiles / rule packs (CBPR+, SEPA_Instant, FedNow, Generic); premium rule-pack entitlement gating | 4 MCP tools | `pip install iso20022-bank-profile-mcp` | You lint payments against your own institution's market practice |\n| [`iso20022-evidence-pack-mcp`](https://github.com/sebastienrousseau/iso20022-evidence-pack-mcp) | Compiles readiness findings, remediation diffs and simulated responses into a sealed, Ed25519-signable audit evidence pack | 6 MCP tools | `pip install iso20022-evidence-pack-mcp` | You need tamper-evident audit / certification artifacts |\n\nIn one line each: **`camt053-mcp`** is the bank-statement flagship (deepest\ncamt.05x surface, stdio + authenticated streamable HTTP);\n**`iso20022-mcp`** is the generic message toolkit (a handful of verbs over\nthe whole catalogue); **`reconcile-mcp`** is the reconciliation workflow\n(did the money we expected actually arrive?);\n**`bankstatementparser-mcp`** is the ingestion layer (many formats in, one\ntransaction shape out); and **`structured-address-fix-mcp`** is the\npostal-address specialist (debtor/creditor addresses cliff-ready for the\nNov 2026 cutover).\n\nThe suite also includes per-family servers — [`pain001-mcp`][pain001-mcp]\n(credit transfer initiation), [`pacs008-mcp`][pacs008-mcp] (FI-to-FI credit\ntransfers), and [`acmt001-mcp`][acmt001-mcp] (account management) — whose\nparsed output feeds straight into this server's `normalize_*` adapters.\n\n## Install\n\n```sh\npip install reconcile-mcp\n# or run without installing:\nuvx reconcile-mcp\n```\n\nMCP client config (e.g. Claude Desktop `claude_desktop_config.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"reconcile\": {\n      \"command\": \"reconcile-mcp\"\n    }\n  }\n}\n```\n\n## Quick start (zero real data)\n\nThe server ships a **sandbox test-mode**: deterministic scenarios so you can\nrun the whole flow with no setup and no real cash data. One call gets you a\nfull, explainable result:\n\n```\nrun_sandbox_scenario(name=\"month_end\")\n```\n\nreturns a realistic mixed close — one clean match, one short payment, one split\nsettlement, and an unexpected credit correctly left unmatched:\n\n```jsonc\n{\n  \"summary\": {\n    \"expected_count\": 3, \"observed_count\": 5,\n    \"matched_expected\": 3, \"unmatched_observed\": 1,\n    \"matches_by_type\": {\"exact\": 1, \"amount_mismatch\": 1, \"one_to_many\": 1},\n    \"fully_reconciled\": false\n  },\n  \"matches\": [\n    {\"type\": \"amount_mismatch\", \"expected\": [\"INV-6002\"], \"observed\": [\"ENT-52\"],\n     \"amount_delta\": \"-99.99\", \"confidence\": \"high\",\n     \"reasons\": [\"reference exact\", \"amount close (delta -99.99)\", \"date +/-0d\", \"counterparty exact\"]},\n    {\"type\": \"exact\", \"expected\": [\"INV-6001\"], \"observed\": [\"ENT-51\"], \"amount_delta\": \"0.00\"},\n    {\"type\": \"one_to_many\", \"expected\": [\"INV-6003\"], \"observed\": [\"ENT-53\", \"ENT-54\"],\n     \"reasons\": [\"amount sum of 2 entries\"]}\n  ],\n  \"unmatched_observed\": [\"ENT-55\"]\n}\n```\n\nList every scenario with `list_sandbox_scenarios`; load one to inspect or edit\nits inputs with `load_sandbox_scenario`.\n\n## Bring your own data\n\nRecords are small canonical objects — `id` and `amount` required, everything\nelse optional and used to sharpen matching:\n\n```jsonc\n{\n  \"id\": \"INV-1001\",            // your reference / end-to-end id\n  \"amount\": 1200.00,\n  \"currency\": \"EUR\",           // ISO 4217\n  \"date\": \"2026-03-02\",        // ISO-8601\n  \"counterparty\": \"Acme Ltd\",\n  \"reference\": \"INV-1001\"      // remittance / structured reference\n}\n```\n\nAlready using the rest of the suite? Feed parsed output straight in — the\nadapters map it for you:\n\n- `normalize_pain001(document)` → the *expected* side, from\n  [`pain001-mcp`][pain001-mcp].\n- `normalize_camt053(document)` → the *observed* side, from\n  [`camt053-mcp`][camt053-mcp].\n\nThen call `reconcile(expected, observed)`.\n\n## Tools\n\n- `reconcile` — Match expected payments against observed entries; full explainable report.\n- `explain_match` — Score a single expected/observed pair with a per-signal breakdown (tuning aid).\n- `normalize_pain001` — Adapt parsed `pain.001` output into canonical *expected* records.\n- `normalize_camt053` — Adapt parsed `camt.053` output into canonical *observed* records.\n- `list_sandbox_scenarios` — List the built-in test-mode scenarios and magic references.\n- `load_sandbox_scenario` — Return one scenario's expected/observed inputs to inspect or edit.\n- `run_sandbox_scenario` — Load a scenario and reconcile it in one call — the fastest first run.\n\n## How matching works\n\nEach candidate pair is scored on four weighted signals, then classified:\n\n- **Reference** (0.45) — exact / partial equality of references and end-to-end\n  ids, normalised to bare alphanumerics.\n- **Amount** (0.35) — exact within tolerance, or a linearly-decaying closeness\n  with the delta reported.\n- **Date** (0.10) — proximity within a configurable window; neutral if unknown.\n- **Counterparty** (0.10) — token-set overlap of names; neutral if unknown.\n\nAssignment is greedy, highest-score-first and fully deterministic (a total\ntiebreak order), so the same inputs always produce the same result. Residuals\nare then tested for **one-to-many** (a bounded subset-sum: one expected settled\nby several entries) and **many-to-one** (one entry covering several expected).\n\nTune any of it via the `options` argument: `abs_tol` / `rel_tol`,\n`date_window_days`, `high_threshold`, `review_threshold`, `currency_strict`,\n`enable_one_to_many`, `max_combination`.\n\n## Development\n\n```sh\ngit clone https://github.com/sebastienrousseau/reconcile-mcp\ncd reconcile-mcp\npython -m venv .venv && . .venv/bin/activate\npip install -e . && pip install pytest pytest-cov ruff black mypy\npytest                      # 100% branch coverage gate\nruff check reconcile_mcp tests && black --check reconcile_mcp tests && mypy reconcile_mcp\n```\n\n## Licence\n\nLicensed under the [Apache License, Version 2.0](LICENSE).\n\n---\n\n`mcp-name: io.github.sebastienrousseau/reconcile-mcp`\n\n[mcp]: https://modelcontextprotocol.io\n[iso20022-mcp]: https://github.com/sebastienrousseau/iso20022-mcp\n[pain001-mcp]: https://github.com/sebastienrousseau/pain001-mcp\n[pacs008-mcp]: https://github.com/sebastienrousseau/pacs008-mcp\n[camt053-mcp]: https://github.com/sebastienrousseau/camt053-mcp\n[acmt001-mcp]: https://github.com/sebastienrousseau/acmt001-mcp\n[bsp-mcp]: https://github.com/sebastienrousseau/bankstatementparser-mcp\n[saf-mcp]: https://github.com/sebastienrousseau/structured-address-fix-mcp\n",
  "bytes": 10488,
  "sha": "b71b33ef5f61385b57defdbae29cfca0da3b6ff717193dfc85e802e65f718794",
  "repo_slug": "sebastienrousseau/reconcile-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_sebastienrousseau_reconcile_mc_d6026d9f/readme"
}