camt053-mcp
Summary: This MCP server lets AI agents work with ISO 20022 camt.05x bank statements end-to-end, from discovery and validation through parsing, conversion, anomaly screening, reversal generation, and accounting export.
Discover supported camt message types, return reason codes, rulebook clauses, export targets, and default classification categories.
Inspect message-type required fields and full input JSON Schemas.
Validate IBANs, BICs, LEIs, flat records, and camt.05x XML statements against XSD schemas.
Check CBPR+ November 2026 readiness and retrieve the official cutover date.
Parse camt.05x statements into structured JSON-serializable data.
Convert legacy SWIFT MT940 to camt.053 and MT942 to camt.052 structures.
List and paginate all statement entries, or filter entries by ISO return reason code.
Detect deterministic statement anomalies such as duplicate references, unusual fees, and velocity spikes.
Generate validated camt.053.001.14 reversing-entry XML for entries matching a return reason.
Export booked entries as Xero BankTransactions or QuickBooks Online JournalEntry payloads.
Cite and search curated SEPA, CBPR+, and HVPS+ rulebook clauses by exact id or lexical-vector similarity.
Classify statement entries via MCP Sampling using the client’s LLM, and report multi-tenant scoping context.
Provides tools for exporting bank statement entries as Xero BankTransactions or QuickBooks Online JournalEntry payloads, enabling integration with accounting platforms.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@camt053-mcp Parse this camt.053 statement and create a reversal for closed account entries."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
camt053-mcp: An MCP Server for ISO 20022 Bank Statements
A Model Context Protocol server that exposes the camt053
ISO 20022 Bank Statement library as tools for AI agents and assistants —
discover message types and return reasons, inspect input schemas, validate
records and financial identifiers, parse incoming statements, and generate
validated reversing-entry XML, all from your favourite MCP client.
Latest release: v0.0.26: released with the camt053 suite 0.0.26 (core, loaders, writer, language server and this server on one version). Declares uvicorn, starlette and pydantic, which it imports directly, and takes the development-tool updates; 24 MCP tools over stdio, streamable HTTP, SSE or authenticated streamable HTTP.
Contents
Transports — stdio, streamable HTTP (2026-07-28 and 2025-11-25), SSE and authenticated HTTP from one command line
Related MCP server: Pactus
Overview
The Model Context Protocol (MCP) is an open standard that lets AI agents
and assistants discover and call external tools in a uniform way. camt053-mcp
is an MCP server that turns the camt053 library into a set of
first-class agent tools, so an assistant can read and reverse ISO 20022
camt.05x cash-management messages — the standardised bank-to-customer
account reports, statements, and debit/credit notifications — directly from a
conversation.
The headline capability is the one-shot reversing-entry workflow: read an incoming camt.053 statement, find the entries carrying a return reason code (e.g. AC04 Closed Account), and emit a validated reversing entry.
Every tool is a thin, typed wrapper over camt053.services — the single shared
facade also used by the CLI and REST API — so all interfaces behave identically.
Tools return JSON-serialisable data; on an error they return an
{"error": ...} payload rather than raising.
Source code: https://github.com/sebastienrousseau/camt053-mcp
Bug reports: https://github.com/sebastienrousseau/camt053-mcp/issues
This package is part of the camt053 suite — a set of independently
installable packages that share the camt053.services layer:
camt053— the core library (CLI + REST API)camt053-mcp— this package, the Model Context Protocol servercamt053-lsp— the Language Server Protocol server for editors
flowchart LR
A["MCP client<br/>(Claude Desktop, IDE, agent)"] -->|stdio| B["camt053-mcp"]
B -->|delegates to| C["camt053.services"]
C -->|parse + reverse + validate| D["ISO 20022 camt.053 XML"]The ISO 20022 MCP Suite
camt053-mcp is the bank-statement flagship of eight coordinated,
vendor-neutral MCP servers that together cover the ISO 20022
bank-statement workflow and the November 2026 structured-address
cutover — statement depth, whole-catalogue routing, reconciliation,
multi-format ingestion, and address remediation. Dependency ranges are kept
aligned across the suite, so the servers co-install cleanly in a single
Python environment: start with one, add the rest as your workflow grows.
Server | Scope | Surface | Install | Use it when |
ISO 20022 | 24 MCP tools · 4 prompts · 3 resources |
| You work with bank-to-customer statements end to end — this package, the suite's flagship | |
Unified gateway: | 7 meta-tools |
| You want one entry point to every message family | |
Matches expected | 7 MCP tools |
| You need explainable statement/payment reconciliation | |
ISO 20022 postal-address classification, assessment & remediation for the November 2026 structured-address cutover, plus a high-level orchestration layer — readiness scoring, clearing-profile linting, and audit evidence ( | 9 MCP tools |
| You need debtor/creditor addresses cliff-ready ahead of 14 Nov 2026 | |
Orchestration gateway: detect → structurally validate → clearing-profile lint → readiness score, plus automated remediation and | 4 MCP tools |
| You want one high-level readiness / orchestration entry point over the suite | |
Manages, validates and serves bank-specific clearing profiles / rule packs (CBPR+, SEPA_Instant, FedNow, Generic); premium rule-pack entitlement gating | 4 MCP tools |
| You lint payments against your own institution's market practice | |
Compiles readiness findings, remediation diffs and simulated responses into a sealed, Ed25519-signable audit evidence pack | 6 MCP tools |
| You need tamper-evident audit / certification artifacts |
In one line each: camt053-mcp is the bank-statement flagship
(deepest camt.05x surface, stdio, streamable HTTP, SSE and authenticated
streamable HTTP);
iso20022-mcp is the generic message toolkit (a handful of verbs
over the whole catalogue); reconcile-mcp is the reconciliation
workflow (did the money we expected actually arrive?);
bankstatementparser-mcp is the ingestion layer (many formats in,
one transaction shape out); and structured-address-fix-mcp is the
postal-address specialist (debtor/creditor addresses cliff-ready for the
Nov 2026 cutover).
The suite also includes per-family servers —
pain001-mcp
(credit transfer initiation),
pacs008-mcp
(FI-to-FI credit transfers), and
acmt001-mcp
(account management) — reachable through the iso20022-mcp gateway.
Install
camt053-mcp runs on macOS, Linux, and Windows and requires Python 3.11+
and pip. It pulls in the core camt053 library and the MCP SDK
automatically.
python -m pip install camt053-mcppython -m venv venv
source venv/bin/activate # macOS/Linux
venv\Scripts\activate # Windows
python -m pip install -U camt053-mcpQuick Start
For the 10-minute install → MCP client config → first conversation
tutorial, see docs/quickstart.md.
Launch the server over stdio (the FastMCP default transport):
camt053-mcpRegister it with any MCP client (e.g. Claude Desktop) by adding it to the client's configuration:
{
"mcpServers": {
"camt053": { "command": "camt053-mcp" }
}
}The agent can then call the tools below to parse incoming statements and generate validated reversing entries on demand.
For a shared, multi-tenant deployment, the server can also serve
streamable HTTP with mandatory bearer-token auth and optional
per-request Camt053-Account tenant scoping:
CAMT053_MCP_TOKEN=<secret> camt053-mcp --transport=http --bind=0.0.0.0:8080See Multi-tenant HTTP deployment and the deployment cookbook.
Transports
One command line, four transports:
Command | Transport | Endpoint | Protocol revisions |
| stdio | the client spawns the process | 2026-07-28, 2025-11-25 |
| Streamable HTTP |
| 2026-07-28 (stateless, |
| HTTP+SSE (2024-11-05) |
| for clients that still expect the older transport |
| Authenticated streamable HTTP (see |
| bearer token or OAuth 2.1, |
--host and --port change the bind address of streamable-http and
sse (defaults 127.0.0.1 and 8000). Those two carry no
authentication of their own: bind loopback, or put the server behind a
gateway you trust before binding a routable address; --transport http
is the authenticated option. Every release is verified over streamable
HTTP with scout in both
protocol eras and over SSE with the MCP SDK client; see
ADR 0001.
{
"mcpServers": {
"camt053": { "url": "http://127.0.0.1:8000/mcp" }
}
}Tools
All tools delegate to the shared camt053.services layer, so they behave
identically to the CLI and REST API.
list_message_types— List the 3 supported camt.05x message typeslist_return_reasons— List the ISO external return reason codesget_required_fields— Required input fields for a message typeget_input_schema— Full input JSON Schema for a message typevalidate_records— Validate flat records against a message typevalidate_identifier— Validate an IBAN, BIC, or LEIvalidate_statement— Validate a statement against its XSD and detect its typeconvert_mt940_to_camt053— MT940 → camt.053 migration: convert legacy SWIFT MT940 statement text into a camt.053 structureconvert_mt942— MT942 → camt.052 migration: convert legacy SWIFT MT942 interim transaction report text into a camt.052 structurecheck_cbpr_readiness— Flag CBPR+ Nov 2026 cliff issues in a statementget_cbpr_cutover_date— Return the official CBPR+ cutover date (2026-11-16)cite_rulebook— Quote a curated SEPA / CBPR+ / HVPS+ rulebook clauselist_rulebook_clauses— List the available rulebook citations (optionally filtered)search_rulebook_vector— Find rulebook clauses by natural-language similarity when you do not know the clause id (needs the[vector]extra)export_journal— Export statement entries as XeroBankTransactionsor QBOJournalEntrypayloadslist_export_journal_targets— List the accounting-platform targetsexport_journalsupportsclassify_entry— Classify a statement entry via MCP Sampling (uses the client's LLM)list_classify_entry_categories— List the default categoriesclassify_entryusesget_tenant_context— Report the multi-tenant scope of the call (theCamt053-Accountheader on the HTTP transport;Noneover stdio)parse_statement— Parse an incoming camt.05x statement into datadetect_statement_anomalies— Screen a statement for duplicate references, unusual fee deductions, and velocity spikes (deterministic rules, no model or network)list_entries— List every entry across all statements (paginated)filter_entries— Return entries carrying a return reason code (paginated)generate_reversal— Generate a validated reversing-entry XML document
Pagination
list_entries and filter_entries accept optional offset (default 0) and
limit (default None) parameters. When limit is omitted they return the
full list, exactly as before. When limit is given they return a paginated
envelope instead:
{"total": 42, "offset": 10, "limit": 5, "entries": [/* ... */]}A negative offset or limit returns an {"error": ...} payload, consistent
with the rest of the server's error convention.
Prompts
Prompt | Purpose |
| Guide an agent through a safe, confirm-before-generate reversal workflow |
| Match booked statement entries to the originating pain.001 batch on |
| Flag exact + suspected duplicates on a statement with confidence and next-action hints |
| Match incoming credits to an AR invoice ledger (exact + remittance + partial / multi-invoice tiers) |
reversal_preview takes an optional reason_code (default "AC04") and
returns a four-step message template: parse the statement, preview the matching
entries with filter_entries, confirm with the operator, then call
generate_reversal. The other three prompts take no parameters and return a
two-message user-prompt + assistant-walkthrough template the agent can replay
verbatim.
Resources
Resources give an agent read-only reference context it can load without calling a tool. Each resource returns a JSON payload.
Resource URI | Contents |
| The ISO external return-reason catalog — a list of |
| The supported camt.05x message types — a list of |
| Templated per-(session, bank) context: parsed BIC country/kind, recommended SEPA / CBPR+ / HVPS+ rulebook clauses, Nov 2026 cutover date |
Both back onto the shared camt053.services layer, so they stay in sync with
the equivalent list_return_reasons / list_message_types tools. On an error
they return a serialised {"error": ...} payload.
Rulebook search
cite_rulebook needs a scheme, version and clause id. When you know
what a rule is about but not what it is called,
search_rulebook_vector closes that gap:
search_rulebook_vector("structured address requirement", top_k=3)
{
"query": "structured address requirement",
"returned": 3,
"results": [
{
"scheme": "HVPS+",
"version": "2026",
"clause": "structured-address-alignment",
"title": "HVPS+ aligns with CBPR+ structured-address rule",
"score": 0.702729,
// ...
}
]
}Take the winning scheme/version/clause and pass it to
cite_rulebook for the full citation.
It is not a neural embedding model. Retrieval is a deterministic
lexical-vector cosine search: each clause and the query are hashed into a
fixed 256-dimension term-frequency vector — whole words plus character
3- and 4-grams, so address matches addresses without a stemmer —
bucketed with BLAKE2b rather than Python's salted hash, and ranked with
sqlite-vec. That has three consequences worth knowing:
The same query always returns the same ranking, in every process and every CI run.
Nothing is downloaded and no network call happens at query time.
It matches wording, not meaning. A query sharing no vocabulary with a clause will not find it, however related the concepts are.
Only the curated summaries are indexed — the same ones behind
cite_rulebook. No external, copyrighted, or auth-gated rulebook text is
stored or searched.
Installing it
sqlite-vec ships in an optional extra and is imported lazily, so the
base install pulls in nothing:
python -m pip install 'camt053-mcp[vector]'Without it the tool returns a plain error payload naming the extra rather than raising, so a client that calls it on a base install gets a usable message instead of a stack trace.
There is a second requirement that is easy to miss: your Python must be
built with loadable SQLite extension support. The python.org macOS
installers and several distribution packages ship it disabled, in which
case sqlite-vec installs perfectly and still cannot load. The tool
detects that and says so, naming the build flag
(--enable-loadable-sqlite-extensions) to look for. Homebrew, uv and
pyenv builds normally have it enabled.
See docs/vector-search.md for the retrieval design and its limits.
Using the tools
You can invoke the tools in-process — without a transport — straight through the
FastMCP instance. This mirrors what an agent receives over stdio. The runnable
version of this snippet lives in examples/mcp_tools.py.
import asyncio
from camt053_mcp.server import server
# A complete camt.053 statement with one entry returned AC04 (Closed Account).
statement_xml = """<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.14">
<BkToCstmrStmt>
<GrpHdr><MsgId>STMT-MSG-0001</MsgId><CreDtTm>2026-06-15T08:00:00</CreDtTm></GrpHdr>
<Stmt>
<Id>STMT-0001</Id><CreDtTm>2026-06-15T08:00:00</CreDtTm>
<Acct><Id><IBAN>GB29NWBK60161331926819</IBAN></Id><Ccy>EUR</Ccy></Acct>
<Bal><Tp><CdOrPrtry><Cd>CLBD</Cd></CdOrPrtry></Tp>
<Amt Ccy="EUR">10000.00</Amt><CdtDbtInd>CRDT</CdtDbtInd>
<Dt><Dt>2026-06-15</Dt></Dt></Bal>
<Ntry>
<NtryRef>NTRY-0001</NtryRef>
<Amt Ccy="EUR">1500.00</Amt><CdtDbtInd>CRDT</CdtDbtInd>
<Sts><Cd>BOOK</Cd></Sts>
<NtryDtls><TxDtls>
<RtrInf><Rsn><Cd>AC04</Cd></Rsn></RtrInf>
</TxDtls></NtryDtls>
</Ntry>
</Stmt>
</BkToCstmrStmt>
</Document>"""
async def main() -> None:
async def call(name, args):
result = await server.call_tool(name, args)
# mcp 2.x returns a CallToolResult (read .content); 1.x
# returns the content list, or a (content, meta) tuple.
content = getattr(result, "content", None)
if content is None:
# mcp 2.x returns a CallToolResult (read .content); 1.x
# returns the content list, or a (content, meta) tuple.
content = getattr(result, "content", None)
if content is None:
content = result[0] if isinstance(result, tuple) else result
return content[0].text if content else ""
# Validate an identifier.
print(await call("validate_identifier",
{"kind": "bic", "value": "NWBKGB2LXXX"}))
# -> {"kind": "bic", "value": "NWBKGB2LXXX", "valid": true}
# Page through the matching entries (paginated envelope).
print(await call("filter_entries",
{"xml": statement_xml, "reason_code": "AC04",
"offset": 0, "limit": 5}))
# -> {"total": 1, "offset": 0, "limit": 5, "entries": [...]}
# Generate a validated reversing-entry document for the AC04 entries.
xml = await call("generate_reversal",
{"xml": statement_xml, "reason_code": "AC04"})
print(xml[:46]) # -> <?xml version="1.0" encoding="UTF-8"?> ...
asyncio.run(main())Run it directly:
python examples/mcp_tools.pyThe camt053 suite
camt053-mcp is part of a set of independently installable packages
built around the camt053 library — pick whichever ones
your stack needs:
Package | Role |
Core library + CLI + FastAPI REST API | |
Model Context Protocol server (this package) | |
Language Server Protocol server (for editors) | |
Excel | |
SWIFT MT940 → camt.053 loader |
Every tool here is a thin typed wrapper over camt053.services —
the same facade the CLI, REST API, and LSP use — so all four
interfaces behave identically.
When not to use camt053-mcp
You have no MCP client. This server only makes sense paired with an MCP-aware host (Claude Desktop, the IDE plugins, an agent framework). For scripted / CI use, the camt053 CLI and REST API cover the same ground without the stdio protocol overhead.
You need to run as a long-lived daemon without an MCP client. The server does run persistently over the streamable HTTP transport (
--transport=http), but every consumer must still speak MCP JSON-RPC. For plain REST semantics, use the camt053 FastAPI service.You need streaming responses. Tool calls return whole values, not streams. Large statements are paginated through the existing
list_entries(xml, offset, limit)envelope, not chunked over multiple responses.You need per-user OAuth flows brokered for you. The HTTP transport authenticates callers (OAuth 2.1 resource server with RFC 9728 metadata, or a static bearer token in dev mode) and scopes requests via the
Camt053-Accounttenant header, but it does not run an authorization server: bring your own IdP.You need to generate pain.001 outbound payment files. Out of scope; use
pain001-mcp.
Development
camt053-mcp uses Poetry and mise.
git clone https://github.com/sebastienrousseau/camt053-mcp.git && cd camt053-mcp
mise install
poetry install
poetry shellA Makefile orchestrates the quality gates (kept in lockstep with CI):
make check # all gates (REQUIRED before commit)
make test # pytest
make lint # ruff + black
make type-check # mypy --strictSecurity
camt053-mcp is a thin wrapper — every tool delegates to
camt053.services, where the defence-in-depth (defusedxml +
xml_guard byte cap + DOCTYPE / ENTITY pre-flight) lives. Tools
catch (ValueError, Camt053Error) and return an {"error": ...}
envelope per the suite convention; they never propagate raw
exceptions to the MCP client. Reporting practice, supported
versions, and the full supply-chain posture are documented in
SECURITY.md. Vulnerabilities go via GitHub Private
Vulnerability Reporting, not public issues.
Documentation
README.md— this fileCHANGELOG.md— release notesSECURITY.md— disclosure + supported versionsSUPPORT.md— how to get helpMAINTAINERS.md— who can mergeexamples/— runnable scriptsglama.json— Glama directory manifestdocs/iso20022-mcp-servers-compared.md— ISO 20022 MCP servers compared (2026)docs/BENCHMARKS.md— measured HTTP load benchmarksGlama listing: https://glama.ai/mcp/servers/sebastienrousseau/camt053-mcp
Related MCP Servers
Part of the ISO 20022 MCP Suite — open-source, Apache-2.0 licensed MCP servers for banking and financial-services AI agents:
Server | Purpose |
Generate & validate ISO 20022 pain.001 payment files (v03–v12, pain.008, SEPA) with rulebook checks | |
Generate, validate, parse & scheme-check ISO 20022 pacs.008 FI-to-FI credit transfers + Nov-2026 address linting | |
Generate & validate ISO 20022 acmt account-management messages | |
Lossless YAML 1.2 parsing, formatting & validation (Rust, 100% spec compliance) |
MCP Registry
mcp-name: io.github.sebastienrousseau/camt053-mcp
License
Dual-licensed under the Apache License, Version 2.0 or the MIT License. Any contribution submitted for inclusion shall be licensed as above, without additional terms.
Contributing
Contributions are welcome — see the contributing instructions. Thanks to all contributors.
Acknowledgements
Built on the camt053 ISO 20022 Bank Statement library and the
Model Context Protocol Python SDK.
Available Tools
24 toolscheck_cbpr_readinessCheck CBPR+ Nov 2026 readinessARead-onlyIdempotent
Check a camt.053 statement against the CBPR+ Nov 2026 acceptance rules.
Use this to audit a statement for the business-rule changes (schema
version, structured postal addresses) enforced from the Nov 2026 cutover.
For plain XSD schema validity use ``validate_statement`` instead; for just
the cutover date use ``get_cbpr_cutover_date``.
A coordinated CBPR+ / Fedwire / CHAPS / T2 cutover lands on
**14-16 November 2026**: unstructured-only postal addresses get rejected,
``camt.110/111`` exceptions and investigations become mandatory, and T2S
R2026.NOV upgrades camt.053 / 054 to schema revision MR2026.
This tool walks the supplied payload and reports every issue that will
fail the Nov 2026 acceptance rules:
* **Schema version** vs the CBPR+ current set (``camt.053.001.08`` /
``camt.053.001.13``); ``.02``-``.07`` are flagged as deprecated
warnings; unknown / non-camt.053 namespaces as errors.
* **Postal addresses**: every ``<PstlAdr>`` is classified as fully
structured, hybrid, or **unstructured-only** (``<AdrLine>`` without
``<TwnNm>`` + ``<Ctry>`` siblings, the Nov 2026 reject case).
Returns a dictionary ``{"cbpr_ready": bool, "schema_version": str | None,
"checked_at": ISO-8601 UTC, "cutover_date": "2026-11-16",
"issues": [...], "summary": {...}}``. ``cbpr_ready`` is ``True`` iff no
``severity="error"`` issue was raised. An ``{"error": ...}`` envelope
is returned instead if the XML is malformed or refused by the
hardened pre-flight (DOCTYPE / ENTITY / oversized payload).
Args:
xml: The raw camt.05x statement XML as a string.
Inputs: xml (required).
cite_rulebookCite payments rulebook clauseARead-onlyIdempotent
Return a curated payments-rulebook citation for a single clause.
Use this to quote one specific rule (with its canonical source URL) once
you know the ``scheme``/``version``/``clause``. To discover which clauses
exist first, call ``list_rulebook_clauses``.
Looks up one well-known rule across the SEPA, CBPR+, and HVPS+
rulebooks and returns a short summary together with the canonical
source URL so an agent can quote the rule and the operator can
verify it against the official document.
The registry is a curated convenience layer, not a verbatim
reproduction of copyrighted text. Always defer to ``source_url``
for authoritative wording before relying on a citation for
compliance or contractual decisions; the returned ``disclaimer``
field repeats this for the calling agent.
Args:
scheme: One of ``"SEPA"``, ``"CBPR+"``, or ``"HVPS+"`` (case
sensitive).
version: The rulebook version (e.g. ``"2025"`` or ``"2026"``).
clause: A kebab-case clause identifier from
``list_rulebook_clauses``.
Returns:
A citation dict ``{"scheme", "version", "clause", "title",
"summary", "source_url", "as_of", "disclaimer"}`` or an
``{"error": ...}`` payload if the citation is not in the
registry.
Inputs: clause (required), scheme (required), version (required).
classify_entryClassify entry via LLM samplingARead-only
Classify one statement entry into a category via MCP LLM Sampling.
Use this when you want a semantic, model-driven label for an entry (payroll,
fee, refund, …) rather than a deterministic rule match. Because it delegates
an LLM completion to the client it is open-world and non-idempotent; for the
fixed candidate categories it chooses from, call
``list_classify_entry_categories`` first.
Uses the **MCP Sampling** protocol primitive: the server (this
process) asks the *client* (the agent's host application) to
perform an LLM completion on the server's behalf, then receives
the model's structured response. Keeps every LLM call in the
operator's existing model contract (privacy, billing, audit).
The model is asked to choose exactly one category from
``categories`` (or :data:`camt053_mcp.classify.DEFAULT_CATEGORIES`
if ``None`` is passed) and return a structured
``{category, confidence, explanation}`` payload.
Clients that do not support Sampling will get an
``{"error": "..."}`` envelope and can fall back to a rules-only
classifier.
Args:
ctx: The MCPServer Context (auto-injected; provides
``session.create_message``).
entry: A statement entry dict (the shape returned by
``parse_statement`` / ``list_entries``).
categories: The candidate categories. ``None`` uses the
built-in default list (12 common payment buckets).
Returns:
``{"category", "confidence", "explanation"}`` on success or
``{"error": "..."}`` on Sampling failure / malformed model
response / out-of-vocabulary category.
Inputs: entry (required), categories.
convert_mt940_to_camt053Convert legacy MT940 to camt.053ARead-onlyIdempotent
Convert a legacy SWIFT MT940 statement into a camt.053 structure.
Use this as the Phase-1 migration wedge: SWIFT MT940 customer statements
retire in **November 2028**, so this tool bridges the gap by turning raw
MT940 text into the same JSON-serialisable camt.053 document shape that
``parse_statement`` returns (group header plus statements, each with its
account, balances, and entries). Downstream tools (``list_entries``,
``filter_entries``, ``classify_entry``, ``export_journal``) then work on the
result unchanged.
Wraps the ``camt053-loader-mt940`` library's ``parse_mt940``; the MT parsing
itself is delegated (no MT grammar is reimplemented here). The resulting
``ParsedDocument`` is serialised with the same ``to_dict()`` the server's
other parse tools use, so agents get a consistent structure. Nothing is read
from or written to disk.
Returns the converted document as a JSON-serialisable dict, or an
``{"error": ...}`` payload if the MT940 text cannot be parsed (e.g. a
missing ``:20:`` reference or a malformed balance / statement line).
Args:
mt940_text: The raw MT940 statement text as a string.
Inputs: mt940_text (required).
convert_mt942Convert legacy MT942 to camt.052ARead-onlyIdempotent
Convert a legacy SWIFT MT942 interim report into a camt.052 structure.
Use this as the Phase-1 migration wedge for intraday reporting: SWIFT MT94x
messages retire in **November 2028**, so this tool bridges the gap by
turning raw MT942 *Interim Transaction Report* text into the same
JSON-serialisable camt.052 (Bank-to-Customer Account **Report**) document
shape the server's parse tools return (group header plus statements, each
with its account, balances, and entries). MT942 is the intraday sibling of
MT940: where MT940 maps to camt.053 (end-of-day statement), MT942 maps to
camt.052, so the resulting ``message_type`` is ``camt.052.001.08``.
Downstream tools (``list_entries``, ``filter_entries``, ``classify_entry``,
``export_journal``) then work on the result unchanged.
Wraps the ``camt053-loader-mt942`` library's ``parse_mt942``; the MT parsing
itself is delegated (no MT grammar is reimplemented here). The resulting
``ParsedDocument`` is serialised with the same ``to_dict()`` the server's
other parse tools use, so agents get a consistent structure. Nothing is read
from or written to disk.
**Documented model limitation.** The ``camt053`` typed model is
camt.053-statement-oriented: it has no dedicated field for camt.052's
floor-limit (``<Lmt>``) or transaction-summary (``<TxsSummry>``) blocks.
Rather than drop that data, the loader surfaces it on the balance list using
clearly proprietary ``type_code`` values so consumers can recognise and
filter them: ``:34F:`` floor limits become ``FLIMD`` / ``FLIMC`` balances,
and ``:90D:`` / ``:90C:`` entry-count summaries become ``SUMD:<count>`` /
``SUMC:<count>`` balances (the ISO ``NbOfNtries`` count is encoded after the
colon; the sum is the balance ``amount``). See the loader's README.
Returns the converted document as a JSON-serialisable dict, or an
``{"error": ...}`` payload if the MT942 text cannot be parsed (e.g. a
missing ``:20:`` reference or a malformed floor-limit / summary / statement
line).
Args:
mt942_text: The raw MT942 interim transaction report text as a string.
Inputs: mt942_text (required).
detect_statement_anomaliesDetect statement anomaliesARead-onlyIdempotent
Screen a camt.05x statement for deterministic, rule-based anomalies.
Use this as a fast, explainable first pass over an incoming statement
before deeper review or reversal. It applies three fixed heuristics over
the parsed entry list (see ``list_entries``) and never calls out to a model
or the network, so the same statement always yields the same result:
* **Duplicate references** (severity ``HIGH``) -- two or more entries share
an end-to-end id (or, absent one, an entry reference), a classic
double-payment signal.
* **Unusual fee deductions** (severity ``MEDIUM``) -- a fee/charge debit
whose amount exceeds a fixed fraction (25%) of the largest ordinary
transaction amount on the statement.
* **Velocity spikes** (severity ``LOW``/``MEDIUM``) -- a booking-date window
whose entry count runs far above the statement's median per-window count.
Returns ``{"anomalies": [{"type", "severity", "detail", "entry_refs"}],
"checked_entries": <int>}``; ``anomalies`` is empty for a clean statement.
Returns an ``{"error": ...}`` payload instead if the XML cannot be parsed.
Args:
statement_xml: The raw statement XML as a string.
Inputs: statement_xml (required).
export_journalExport statement to journal entriesARead-onlyIdempotent
Export a camt.053 statement as accounting-platform journal-entry payloads.
Use this to reshape a statement's booked entries into ready-to-POST Xero or
QuickBooks payloads (the tool builds the payloads only; it does not call any
external API or write files). To discover the valid ``target`` values first,
call ``list_export_journal_targets``.
Parses the supplied statement and re-shapes every booked entry
into a target-specific journal-entry payload ready for direct
POST to the accounting platform's REST API.
Supported targets (see ``camt053_mcp.export_journal.SUPPORTED_TARGETS``):
* ``"xero"`` - returns a list of Xero ``BankTransactions``
payloads. Each entry maps to ``{Type, Reference, Date,
BankAccount, Contact, LineAmountTypes, CurrencyCode,
LineItems}``; CRDT entries become ``Type=RECEIVE`` and DBIT
entries ``Type=SPEND``.
* ``"qbo"`` - returns a list of QuickBooks Online
``JournalEntry`` payloads. Each entry produces a balanced
two-line journal (one to the bank account, one to a clearing
account; sign flipped on debit entries).
Operator-specific values (account codes, contact identifiers,
realm IDs) appear as ``"OPERATOR_FILL"`` placeholders so the
operator knows exactly what still needs wiring. The response's
``placeholder_count`` field reports the total.
NetSuite + SAP S/4HANA targets are tracked as a follow-up in #17.
Args:
xml: The raw camt.053 statement XML as a string.
target: One of ``"xero"`` or ``"qbo"`` (default ``"xero"``).
Returns:
``{"target", "entries", "placeholder_count", "placeholder_field"}``
on success, or ``{"error": ...}`` on failure (unsupported
target / malformed XML / parse refusal).
Inputs: xml (required), target.
filter_entriesFilter entries by reason codeARead-onlyIdempotent
List only the statement entries carrying a given return reason code.
Use this to preview exactly which entries a reversal would touch before
calling ``generate_reversal`` with the same ``reason_code``. For every entry
regardless of reason code use ``list_entries`` instead.
When ``limit`` is ``None`` (the default) the full list of matching entries
is returned, preserving the behaviour expected by existing callers. When
``limit`` is given, a paginated envelope ``{"total", "offset", "limit",
"entries"}`` is returned instead, exposing the ``offset:offset + limit``
slice. A negative ``offset`` or ``limit`` yields an ``{"error": ...}``
payload.
Args:
xml: The raw statement XML as a string.
reason_code: The ISO external return reason to match (default
``"AC04"`` Closed Account).
offset: The zero-based index of the first entry to return (paginated
mode only; default ``0``).
limit: The maximum number of entries to return, or ``None`` for the
full list (default ``None``).
Inputs: xml (required), limit, offset, reason_code. Returns: result
generate_reversalGenerate reversal documentARead-onlyIdempotent
Generate a validated camt.053.001.14 reversal document from a statement.
This is the headline one-shot workflow: pass an incoming statement and a
return-reason code and get back the reversal XML (nothing is written to
disk). Preview which entries will be reversed first with ``filter_entries``
using the same ``reason_code``.
This is the headline one-shot workflow: parse the incoming camt.053, pick
the entries with the requested return reason (e.g. AC04 Closed Account),
and emit a validated camt.053.001.14 reversal statement.
Returns the validated XML document as a string, or an ``{"error": ...}``
payload (serialized) if generation fails.
Args:
xml: The raw incoming statement XML as a string.
reason_code: The ISO external return reason to reverse (default
``"AC04"``).
Inputs: xml (required), reason_code. Returns: result
get_cbpr_cutover_dateGet CBPR+ cutover dateARead-onlyIdempotent
Return the official CBPR+ / Nov 2026 cutover date as ISO 8601.
Use this to quote the enforcement date directly, without parsing a
document. To actually audit a statement against the rules that take effect
on that date, call ``check_cbpr_readiness`` instead.
The cutover (``2026-11-16``) is the date after which the rules checked
by ``check_cbpr_readiness`` are enforced by the major clearing systems;
payments that fail will be rejected at receive-time. Surfaced as a
discrete tool so agents can quote it directly without having to call
a readiness check first.
Inputs: no named parameters.
get_input_schemaGet input JSON SchemaARead-onlyIdempotent
Return the full JSON Schema for a message type's flat input record.
Use this to learn every field, its type, and its constraints before
assembling records, or to drive a form/UI. For just the required-field
names use ``get_required_fields``; to actually check records against this
schema use ``validate_records``.
Args:
message_type: A supported ISO 20022 camt.05x message type.
Inputs: message_type (required).
get_required_fieldsGet required input fieldsARead-onlyIdempotent
List only the required input field names for a camt message type.
Use this for a quick checklist of the mandatory columns before building
reversing-entry records. When you need full type/format constraints (not
just which fields are required), call ``get_input_schema`` instead.
Args:
message_type: A supported ISO 20022 camt.05x message type.
Inputs: message_type (required). Returns: result
get_tenant_contextGet tenant scoping contextARead-onlyIdempotent
Return the multi-tenant scoping context of the current call.
Use this to confirm which tenant/account scope the server attributes
the session to. On the streamable-HTTP transport (D7, #42) the
``tenant`` field carries the value of the optional
``Camt053-Account`` request header the caller sent; over stdio (or
when the caller sent no header) it is ``None``. The same value is
stamped as the ``scope`` on the server's audit log, so an agent can
verify its calls are attributed to the right tenant.
The lookup is read-only and deterministic for a given request:
nothing is validated or mutated, and no external system is touched.
Args:
ctx: The MCPServer Context (auto-injected; carries the underlying
HTTP request, when there is one).
Returns:
``{"service": "camt053-mcp", "tenant": str | None}``.
Inputs: no named parameters.
list_classify_entry_categoriesList classifier categoriesARead-onlyIdempotent
List the default candidate categories the classify_entry tool uses.
Use this to quote the built-in category vocabulary to a user before running
the LLM classifier. This is a static list lookup (no model call); to
actually classify an entry, call ``classify_entry``.
Operators can override the list per call; this tool exposes the
default the prompt template ships with so an agent can quote them
to the user before invoking the classifier.
Inputs: no named parameters. Returns: result
list_entriesList all statement entriesARead-onlyIdempotent
List every booked entry across all statements in a camt.05x document.
Use this to get the flat, paginable entry list from a statement. To keep
only the entries carrying a given return-reason code use ``filter_entries``;
for the full nested document structure use ``parse_statement``.
When ``limit`` is ``None`` (the default) the full list of entries is
returned. When ``limit`` is given, a paginated envelope ``{"total",
"offset", "limit", "entries"}`` is returned instead, exposing the
``offset:offset + limit`` slice. A negative ``offset`` or ``limit`` yields
an ``{"error": ...}`` payload.
Args:
xml: The raw statement XML as a string.
offset: The zero-based index of the first entry to return (paginated
mode only; default ``0``).
limit: The maximum number of entries to return, or ``None`` for the
full list (default ``None``).
Inputs: xml (required), limit, offset. Returns: result
list_export_journal_targetsList journal export targetsARead-onlyIdempotent
List the accounting-platform targets the export_journal tool supports.
Use this to tell a user which ``target`` values ``export_journal`` accepts
before invoking it. This lists export destinations only; for the LLM
classifier's category vocabulary use ``list_classify_entry_categories``.
Returns the sorted list of valid ``target`` arguments accepted by
``export_journal`` (``["qbo", "xero"]`` today). NetSuite and SAP
S/4HANA support is a tracked follow-up.
Inputs: no named parameters. Returns: result
list_message_typesList camt.05x message typesARead-onlyIdempotent
List every supported ISO 20022 camt.05x message type and its name.
Use this first, before any validation or generation call, to discover the
exact ``message_type`` strings this server accepts. For the return-reason
codes rather than message types, call ``list_return_reasons`` instead.
Returns a list of ``{"message_type": ..., "name": ...}`` dictionaries, one
per supported message type (e.g. ``camt.053.001.14``).
Inputs: no named parameters. Returns: result
list_return_reasonsList ISO return reason codesARead-onlyIdempotent
List every known ISO external return reason code with its name.
Use this to discover the ``reason_code`` values that ``filter_entries`` and
``generate_reversal`` accept (e.g. ``AC04`` Closed Account). For the
supported message types rather than reason codes, use ``list_message_types``.
Returns a list of ``{"code": ..., "name": ...}`` dictionaries (e.g.
``{"code": "AC04", "name": "Closed Account Number"}``).
Inputs: no named parameters. Returns: result
list_rulebook_clausesList rulebook clausesARead-onlyIdempotent
List the curated rulebook clauses the server can cite, optionally filtered.
Use this to browse the citation registry and pick a ``clause`` id; then pass
that id to ``cite_rulebook`` to fetch the full summary and source URL.
Returns the full registry, optionally filtered by ``scheme`` and /
or ``version``. Use the resulting ``clause`` values as input to
``cite_rulebook``.
Args:
scheme: Restrict to one scheme (e.g. ``"SEPA"``). ``None``
returns all schemes.
version: Restrict to one version (e.g. ``"2026"``). ``None``
returns all versions.
Inputs: scheme, version. Returns: result
parse_statementParse camt.05x statement XMLARead-onlyIdempotent
Parse an incoming camt.05x statement XML string into structured data.
Use this to turn a raw statement into a navigable dict (header, statements,
accounts, balances, entries). To pull just the flat entry list use
``list_entries``; to only check the document is schema-valid use
``validate_statement``.
Returns the parsed document as a JSON-serialisable dict (group header plus
statements, each with its account, balances, and entries), or an
``{"error": ...}`` payload if the XML cannot be parsed.
Args:
xml: The raw statement XML as a string.
Inputs: xml (required).
search_rulebook_vectorSearch rulebook clauses by similarityARead-onlyIdempotent
Search the curated rulebook clauses by lexical-vector similarity.
Use this when you know *what* a rule is about but not its exact
``scheme``/``version``/``clause`` id: describe it in natural language and
get back the closest curated clauses, each with a similarity ``score``.
Then pass the winning ``scheme``/``version``/``clause`` to
``cite_rulebook`` for the full citation, or browse everything with
``list_rulebook_clauses``.
Retrieval is a **deterministic lexical-vector cosine** search over the
same curated SEPA / CBPR+ / HVPS+ summaries that back ``cite_rulebook``
(no external, copyrighted, or auth-gated rulebook text is indexed). Each
clause and the query are hashed into a fixed 256-dimension term-frequency
vector (whole words plus character 3/4-grams, BLAKE2b-bucketed so results
are reproducible across processes) and ranked by cosine distance with
``sqlite-vec``. It is offline and does **not** use a large neural
embedding model, so the same query always yields the same ranking and no
model download or network call happens at query time.
``sqlite-vec`` ships in the optional ``[vector]`` extra and is imported
lazily; when it is not installed this returns a graceful
``{"error": ...}`` payload asking the operator to
``pip install 'camt053-mcp[vector]'`` rather than failing to import.
Args:
query: The natural-language search string.
top_k: The maximum number of clauses to return (default ``5``,
clamped to the corpus size).
Returns:
``{"query", "top_k", "returned", "method", "results", "disclaimer"}``
where ``results`` is the ranked list of clause dicts (each with an
added ``score``), or an ``{"error": ...}`` payload on a bad argument
or a missing ``[vector]`` extra.
Inputs: query (required), top_k.
validate_identifierValidate IBAN, BIC or LEIARead-onlyIdempotent
Validate a single financial identifier (IBAN, BIC, or LEI).
Use this for a one-off identifier check with a clear pass/fail. To validate
identifiers embedded across a whole batch of records, prefer
``validate_records`` rather than calling this per field.
Returns ``{"kind": str, "value": str, "valid": bool}``.
Args:
kind: One of ``"iban"``, ``"bic"``, or ``"lei"`` (case-insensitive).
value: The identifier value to check.
Inputs: kind (required), value (required).
validate_recordsValidate records against schemaARead-onlyIdempotent
Validate flat records against a message type's input JSON Schema.
Use this on in-memory reversing-entry records to catch structural/type
errors per row before generation. To validate a whole camt.05x *document*
(XML) against its XSD instead, use ``validate_statement``.
Returns a report ``{"valid": bool, "total": int, "valid_count": int,
"errors": [...]}``.
Args:
message_type: A supported ISO 20022 camt.05x message type.
records: One or more flat reversing-entry records to validate.
Inputs: records (required), message_type (required).
validate_statementValidate statement against XSDARead-onlyIdempotent
Validate an incoming camt.05x statement XML against its XSD schema.
Use this to confirm a document is well-formed and schema-valid before
processing it. This checks XSD conformance only; for the Nov 2026 CBPR+
business rules use ``check_cbpr_readiness``, and to extract the data use
``parse_statement``.
Detects the document's message type, validates it against the matching
ISO 20022 schema, and returns a report ``{"valid": bool, "message_type":
str, "errors": [...]}``. A well-formed but schema-invalid document yields
``valid=False`` with a populated ``errors`` list (and the detected
``message_type``); a valid one yields ``valid=True`` with no errors.
Returns an ``{"error": ...}`` payload instead if the XML cannot be parsed
(e.g. it is malformed or is not a camt ``Document``).
Args:
xml: The raw statement XML as a string.
Inputs: xml (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 24 tools
Each tool targets a distinct resource or action, with parse, validate, convert, list/filter, reverse, export, classify, CBPR, and rulebook tools cleanly separated. The only mild risk is distinguishing convert_mt942 from convert_mt940_to_camt053 and validate_records from validate_statement, but the descriptions remove the ambiguity.
Nearly every tool follows a consistent snake_case verb_noun pattern such as list_*, get_*, validate_*, and generate_*. The minor deviation is convert_mt942 lacking the explicit target suffix that convert_mt940_to_camt053 includes.
At 24 tools the server sits in the heavy 16–25 band, and while the broad scope covers migration, validation, CBPR, rulebook lookup, export, and classification, several small list-lookup and constant-returning helpers inflate the count. The size is defensible but borders on over-scoping for a single MCP server.
The core statement workflow is well covered: parsing, validating, listing/filtering entries, detecting anomalies, generating reversals, exporting journals, classifying entries, and checking CBPR readiness. A minor gap is that get_input_schema and validate_records prepare flat records for generation, but no tool directly consumes those records since generate_reversal takes XML instead.
Maintenance
Related MCP Connectors
Remote MCP server for UETR tracking and SWIFT payment tracking. Read bank-reported transfer status and manage monitoring from your AI app, within your uetr.ai plan and team rights. Connect at https://uetr.ai/mcp with OAuth or an API key. A free uetr.ai account is enough to connect. uetr.ai is an independent information service and does not move or hold funds.
MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
MCP server for building and testing AI agents with multi-model experimentation and insights.
Related MCP Servers
- AlicenseAqualityDmaintenanceAn MCP server that gives AI agents deterministic, verified access to ISO 8583 field specs, MTI decoding, jPOS packager XML generation, deploy descriptor validation, message building, and jPOS documentation search.74MIT
- AlicenseAqualityDmaintenancePactus is an MCP server for parsing and validating ISO 20022 payment messages directly from chat. It exposes nine tools that let AI assistants inspect or validate pacs.008, pacs.002, pain.001, and camt.053 messages — the message types at the centre of the CBPR+ migration — without leaving the conversation.92MIT
- AlicenseAqualityBmaintenanceA Model Context Protocol server that exposes the pain001 ISO 20022 Customer Credit Transfer Initiation library as agent tools, enabling AI assistants to generate and validate standardized payment XML messages.30953 PyPI1Apache 2.0
- AlicenseAqualityBmaintenanceAn MCP server that exposes the pacs008 ISO 20022 FI-to-FI Customer Credit Transfer library as tools for AI agents and assistants, enabling generation, validation, and parsing of pacs.008 credit transfer XML messages.1649 PyPI1Apache 2.0