swift-iso20022-mcp
swift-iso20022-mcp
An MCP (Model Context Protocol) server that gives any AI agent — Claude, ChatGPT, Cursor, Windsurf, or any other MCP-compatible client, local or remote — tools to validate SWIFT MT and ISO 20022 MX payment messages, check BIC/IBAN correctness, and map between MT and MX formats, without the agent hallucinating message-format rules.
Built from real SWIFT MT/ISO 20022 test-automation experience in banking and payments (SWIFT MT/MX, ACH, SEPA, RTGS, FEDWIRE).
Why this exists
Generic AI agents get SWIFT/ISO 20022 formatting wrong constantly — mandatory fields, BIC shape, IBAN checksums, charges codes, and (as of the SWIFT CBPR+ milestone in November 2026) structured vs. unstructured postal addresses. This server gives an agent ground truth instead of a guess.
Two transports — this is what makes it "universal"
MCP itself is the cross-vendor standard (Anthropic, OpenAI, Google, and Microsoft all support it), but a server still has to expose the right transport to be reachable by every kind of client:
Transport | Entrypoint | Who connects this way |
stdio |
| Local clients that spawn your process directly: Claude Desktop, Cursor, Windsurf, Cline |
Streamable HTTP |
| Remote clients that connect over a URL: hosted connectors, web-based agents, anything that can't spawn a local process |
Same tools, same logic (src/server-factory.js is shared by both) — only
the wire format differs. Run whichever one matches where you want to be
reachable, or both at once on different machines.
Tools exposed
Tool | What it does |
| Validates an MT103 or MT202 message body: mandatory fields, date/currency/amount format, BIC shape, IBAN checksum, charges code |
| Validates a pacs.008/pacs.009 XML message: MsgId presence, currency shape, BICFI validity, IBAN checksum, unstructured-address warning |
| Structural BIC/SWIFT code check (8 or 11 chars) |
| IBAN shape + ISO 7064 mod-97 checksum |
| Maps MT103 fields to pacs.008 (customer credit transfer, has Dbtr/Cdtr) |
| Maps MT202 fields to pacs.009 (bank-to-bank transfer, has InstgAgt/InstdAgt BICs instead of customer parties) |
| Reverse direction: maps pacs.008 XML back to MT103 field tags, for coexistence-period systems that still expect MT |
Install & test
cd swift-mcp
npm installThere are three ways to verify it works, in order of speed:
1. Unit tests — checks the logic in isolation
npm testRuns 18 assertions against swift-core.js directly. No MCP protocol
involved — fastest signal that the validation/mapping logic is correct.
2. Manual protocol test — checks the stdio server
npm run test:manualSpawns the actual stdio server and talks to it over real JSON-RPC (the same transport Claude Desktop uses), calling all 7 tools with realistic data.
You can also inspect either transport interactively with the official MCP Inspector:
npx @modelcontextprotocol/inspector node src/index.js3. Manual test for the HTTP transport
npm run start:http
# in another terminal:
curl http://localhost:3000/health
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"validate_bic","arguments":{"bic":"DEUTDEFF"}}}'4. Live test in a real client
Add the config below for whichever client you're using, and try prompts like:
"Validate this MT103: :20:REF123...\n:23B:CRED\n:32A:250115USD1000,00..." "Is DE89370400440532013000 a valid IBAN?" "Convert this MT202 to pacs.009: ..."
Watch for the tool-use block in the client's UI — that confirms it's calling your server instead of guessing.
Connect it — local clients (stdio)
Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json
on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows):
{
"mcpServers": {
"swift-iso20022": {
"command": "node",
"args": ["/absolute/path/to/swift-mcp/src/index.js"]
}
}
}Cursor, Windsurf, and Cline use the same shape in their own MCP config files
— just the command/args pair pointing at src/index.js.
Connect it — remote clients (Streamable HTTP)
Run the HTTP server:
npm run start:http # listens on PORT env var, default 3000Deploy it anywhere Node.js runs — Render, Railway, Fly.io, a VPS — and point any HTTP-based MCP client at:
https://your-deployed-host/mcpSecuring the public endpoint
Set MCP_API_KEY in the deployment environment to require a bearer token on
every request. If it's unset, the endpoint stays open (fine for local/manual
testing, not for a public deploy):
MCP_API_KEY=your-secret-key npm run start:httpClients must then send:
Authorization: Bearer your-secret-keyThis is what lets a client that can't spawn a local process (a hosted connector, a web app, a teammate who doesn't have your code checked out) reach the same tools. It runs statelessly — every request gets a fresh server instance, so there's no session state to lose on a restart, which also makes it trivial to run on serverless platforms.
Roadmap (next steps if you take this further)
MT202 -> pacs.009 mapping
Reverse MX -> MT mapping (pacs.008 -> MT103)
Streamable HTTP transport for remote/universal access
Reverse pacs.009 -> MT202 mapping (currently only pacs.008 -> MT103 exists)
Full XSD schema validation for MX messages (current MX check is structural, not schema-complete)
Auth (API key) on the HTTP endpoint via
MCP_API_KEY— optional, off by default for local testingPublish to npm as
@bikramdas1/swift-iso20022-mcpso it can be installed withnpxSubmit to the MCP server directory / registry once it has real usage
Wire this same
src/swift-core.jslogic into Coexist as a shared package, so the SaaS UI and the MCP server never drift apart
License
MIT