pactus-mcp 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pactus_mcp-1.0.0/.gitattributes +6 -0
- pactus_mcp-1.0.0/.github/dependabot.yml +40 -0
- pactus_mcp-1.0.0/.github/workflows/ci.yml +150 -0
- pactus_mcp-1.0.0/.github/workflows/release.yml +96 -0
- pactus_mcp-1.0.0/.gitignore +17 -0
- pactus_mcp-1.0.0/.python-version +1 -0
- pactus_mcp-1.0.0/.xsdata.xml +18 -0
- pactus_mcp-1.0.0/LICENSE +21 -0
- pactus_mcp-1.0.0/PKG-INFO +264 -0
- pactus_mcp-1.0.0/README.md +238 -0
- pactus_mcp-1.0.0/SECURITY.md +34 -0
- pactus_mcp-1.0.0/architecture.md +24 -0
- pactus_mcp-1.0.0/pyproject.toml +98 -0
- pactus_mcp-1.0.0/scripts/generate_models.py +71 -0
- pactus_mcp-1.0.0/src/pactus/__init__.py +1 -0
- pactus_mcp-1.0.0/src/pactus/core/__init__.py +1 -0
- pactus_mcp-1.0.0/src/pactus/core/domain/__init__.py +26 -0
- pactus_mcp-1.0.0/src/pactus/core/domain/camt053.py +173 -0
- pactus_mcp-1.0.0/src/pactus/core/domain/common.py +103 -0
- pactus_mcp-1.0.0/src/pactus/core/domain/pacs002.py +126 -0
- pactus_mcp-1.0.0/src/pactus/core/domain/pacs008.py +99 -0
- pactus_mcp-1.0.0/src/pactus/core/domain/pain001.py +136 -0
- pactus_mcp-1.0.0/src/pactus/core/parsers.py +515 -0
- pactus_mcp-1.0.0/src/pactus/generated/.gitkeep +0 -0
- pactus_mcp-1.0.0/src/pactus/generated/GENERATED_HASHES.txt +5 -0
- pactus_mcp-1.0.0/src/pactus/generated/__init__.py +1031 -0
- pactus_mcp-1.0.0/src/pactus/generated/camt_053_001_08.py +6228 -0
- pactus_mcp-1.0.0/src/pactus/generated/pacs_002_001_10.py +3322 -0
- pactus_mcp-1.0.0/src/pactus/generated/pacs_008_001_08.py +3302 -0
- pactus_mcp-1.0.0/src/pactus/generated/pain_001_001_09.py +3293 -0
- pactus_mcp-1.0.0/src/pactus/mcp_server.py +170 -0
- pactus_mcp-1.0.0/src/pactus/py.typed +0 -0
- pactus_mcp-1.0.0/src/pactus/schemas/SCHEMAS.md +76 -0
- pactus_mcp-1.0.0/src/pactus/schemas/camt.053.001.08.xsd +2070 -0
- pactus_mcp-1.0.0/src/pactus/schemas/pacs.002.001.10.xsd +1127 -0
- pactus_mcp-1.0.0/src/pactus/schemas/pacs.008.001.08.xsd +1120 -0
- pactus_mcp-1.0.0/src/pactus/schemas/pain.001.001.09.xsd +1114 -0
- pactus_mcp-1.0.0/tests/__init__.py +0 -0
- pactus_mcp-1.0.0/tests/conftest.py +75 -0
- pactus_mcp-1.0.0/tests/fixtures/test_camt053.xml +102 -0
- pactus_mcp-1.0.0/tests/fixtures/test_camt053_balances.xml +34 -0
- pactus_mcp-1.0.0/tests/fixtures/test_camt053_batched.xml +58 -0
- pactus_mcp-1.0.0/tests/fixtures/test_camt053_single.xml +55 -0
- pactus_mcp-1.0.0/tests/fixtures/test_mt103.txt +14 -0
- pactus_mcp-1.0.0/tests/fixtures/test_pacs002_multi.xml +30 -0
- pactus_mcp-1.0.0/tests/fixtures/test_pacs002_rejected.xml +33 -0
- pactus_mcp-1.0.0/tests/fixtures/test_pacs002_single.xml +21 -0
- pactus_mcp-1.0.0/tests/fixtures/test_pacs008.xml +38 -0
- pactus_mcp-1.0.0/tests/fixtures/test_pacs008_multi.xml +88 -0
- pactus_mcp-1.0.0/tests/fixtures/test_pain001.xml +78 -0
- pactus_mcp-1.0.0/tests/fixtures/test_pain001_minimal.xml +26 -0
- pactus_mcp-1.0.0/tests/fixtures/test_pain001_multi_pmt_inf.xml +65 -0
- pactus_mcp-1.0.0/tests/fixtures/test_pain001_single.xml +71 -0
- pactus_mcp-1.0.0/tests/test_camt053_parser.py +237 -0
- pactus_mcp-1.0.0/tests/test_mcp_integration.py +163 -0
- pactus_mcp-1.0.0/tests/test_pacs002_parser.py +122 -0
- pactus_mcp-1.0.0/tests/test_pacs008_parser.py +237 -0
- pactus_mcp-1.0.0/tests/test_pacs008_security.py +85 -0
- pactus_mcp-1.0.0/tests/test_pain001_parser.py +141 -0
- pactus_mcp-1.0.0/uv.lock +2606 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# Python dependencies via uv (Dependabot reads pyproject.toml + uv.lock natively)
|
|
4
|
+
- package-ecosystem: "uv"
|
|
5
|
+
directory: "/"
|
|
6
|
+
schedule:
|
|
7
|
+
interval: "weekly"
|
|
8
|
+
day: "monday"
|
|
9
|
+
time: "07:00"
|
|
10
|
+
timezone: "Europe/Kyiv"
|
|
11
|
+
open-pull-requests-limit: 5
|
|
12
|
+
labels:
|
|
13
|
+
- "dependencies"
|
|
14
|
+
- "python"
|
|
15
|
+
commit-message:
|
|
16
|
+
prefix: "deps"
|
|
17
|
+
include: "scope"
|
|
18
|
+
groups:
|
|
19
|
+
# Group all dev-tooling updates into one PR per week
|
|
20
|
+
dev-tooling:
|
|
21
|
+
patterns:
|
|
22
|
+
- "ruff"
|
|
23
|
+
- "mypy"
|
|
24
|
+
- "pytest*"
|
|
25
|
+
|
|
26
|
+
# GitHub Actions — keeps the SHAs we pinned from rotting
|
|
27
|
+
- package-ecosystem: "github-actions"
|
|
28
|
+
directory: "/"
|
|
29
|
+
schedule:
|
|
30
|
+
interval: "weekly"
|
|
31
|
+
day: "monday"
|
|
32
|
+
time: "07:00"
|
|
33
|
+
timezone: "Europe/Kyiv"
|
|
34
|
+
open-pull-requests-limit: 5
|
|
35
|
+
labels:
|
|
36
|
+
- "dependencies"
|
|
37
|
+
- "github-actions"
|
|
38
|
+
commit-message:
|
|
39
|
+
prefix: "ci"
|
|
40
|
+
include: "scope"
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
quality:
|
|
19
|
+
name: Lint, type-check, tests
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout
|
|
23
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
24
|
+
with:
|
|
25
|
+
persist-credentials: false
|
|
26
|
+
|
|
27
|
+
- name: Install uv
|
|
28
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
29
|
+
with:
|
|
30
|
+
enable-cache: true
|
|
31
|
+
|
|
32
|
+
- name: Install Python 3.12
|
|
33
|
+
run: uv python install 3.12
|
|
34
|
+
|
|
35
|
+
- name: Check lockfile is in sync with pyproject.toml
|
|
36
|
+
run: uv lock --check
|
|
37
|
+
|
|
38
|
+
- name: Sync dependencies (including [semantic] extras)
|
|
39
|
+
run: uv sync --frozen --all-extras
|
|
40
|
+
|
|
41
|
+
- name: Generate xsdata Pydantic models
|
|
42
|
+
run: uv run python scripts/generate_models.py
|
|
43
|
+
|
|
44
|
+
- name: Verify generated models match canonical hashes
|
|
45
|
+
working-directory: src/pactus/generated
|
|
46
|
+
run: sha256sum -c GENERATED_HASHES.txt
|
|
47
|
+
|
|
48
|
+
- name: Ruff lint
|
|
49
|
+
run: uv run ruff check
|
|
50
|
+
|
|
51
|
+
- name: Ruff format check
|
|
52
|
+
run: uv run ruff format --check
|
|
53
|
+
|
|
54
|
+
- name: Mypy strict
|
|
55
|
+
run: uv run mypy
|
|
56
|
+
|
|
57
|
+
- name: Run pytest with coverage gate
|
|
58
|
+
run: uv run pytest -q
|
|
59
|
+
|
|
60
|
+
sbom:
|
|
61
|
+
name: SBOM generation
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
permissions:
|
|
64
|
+
contents: read
|
|
65
|
+
steps:
|
|
66
|
+
- name: Checkout
|
|
67
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
68
|
+
with:
|
|
69
|
+
persist-credentials: false
|
|
70
|
+
|
|
71
|
+
- name: Generate SBOM (CycloneDX 1.6)
|
|
72
|
+
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
|
|
73
|
+
with:
|
|
74
|
+
format: cyclonedx-json
|
|
75
|
+
output-file: pactus-mcp.cdx.json
|
|
76
|
+
upload-artifact: false
|
|
77
|
+
|
|
78
|
+
- name: Generate SBOM (SPDX 3.0.1)
|
|
79
|
+
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
|
|
80
|
+
with:
|
|
81
|
+
format: spdx-json
|
|
82
|
+
output-file: pactus-mcp.spdx.json
|
|
83
|
+
upload-artifact: false
|
|
84
|
+
|
|
85
|
+
- name: Upload SBOM artifacts
|
|
86
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
87
|
+
with:
|
|
88
|
+
name: sbom
|
|
89
|
+
path: |
|
|
90
|
+
pactus-mcp.cdx.json
|
|
91
|
+
pactus-mcp.spdx.json
|
|
92
|
+
|
|
93
|
+
vuln-scan:
|
|
94
|
+
name: Grype vulnerability scan
|
|
95
|
+
needs: sbom
|
|
96
|
+
runs-on: ubuntu-latest
|
|
97
|
+
permissions:
|
|
98
|
+
contents: read
|
|
99
|
+
steps:
|
|
100
|
+
- name: Download SBOM artifact
|
|
101
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
102
|
+
with:
|
|
103
|
+
name: sbom
|
|
104
|
+
|
|
105
|
+
# Grype scans the full SBOM including dev dependencies; there is no
|
|
106
|
+
# mechanism to exclude dev-only packages at this layer. A finding in a
|
|
107
|
+
# dev dep (e.g. pytest, ruff) will fail this job.
|
|
108
|
+
- name: Grype scan (fail on high+)
|
|
109
|
+
uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 # v7.4.0
|
|
110
|
+
with:
|
|
111
|
+
sbom: pactus-mcp.cdx.json
|
|
112
|
+
severity-cutoff: high
|
|
113
|
+
fail-build: true
|
|
114
|
+
|
|
115
|
+
workflow-audit:
|
|
116
|
+
name: Workflow audit (zizmor)
|
|
117
|
+
runs-on: ubuntu-latest
|
|
118
|
+
permissions:
|
|
119
|
+
contents: read
|
|
120
|
+
steps:
|
|
121
|
+
- name: Checkout
|
|
122
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
123
|
+
with:
|
|
124
|
+
persist-credentials: false
|
|
125
|
+
|
|
126
|
+
- name: Install zizmor
|
|
127
|
+
run: pipx install zizmor
|
|
128
|
+
|
|
129
|
+
- name: Verify zizmor version
|
|
130
|
+
run: zizmor --version
|
|
131
|
+
|
|
132
|
+
- name: Audit workflows
|
|
133
|
+
run: zizmor .github/workflows/
|
|
134
|
+
|
|
135
|
+
dependency-review:
|
|
136
|
+
name: Dependency review
|
|
137
|
+
if: github.event_name == 'pull_request'
|
|
138
|
+
runs-on: ubuntu-latest
|
|
139
|
+
permissions:
|
|
140
|
+
contents: read
|
|
141
|
+
steps:
|
|
142
|
+
- name: Checkout
|
|
143
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
144
|
+
with:
|
|
145
|
+
persist-credentials: false
|
|
146
|
+
|
|
147
|
+
- name: Dependency review
|
|
148
|
+
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
|
|
149
|
+
with:
|
|
150
|
+
fail-on-severity: high
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
target:
|
|
10
|
+
description: 'Publish target'
|
|
11
|
+
required: true
|
|
12
|
+
type: choice
|
|
13
|
+
options:
|
|
14
|
+
- testpypi
|
|
15
|
+
- pypi
|
|
16
|
+
|
|
17
|
+
# Deny all permissions at the workflow level; each job grants only what it needs.
|
|
18
|
+
permissions: {}
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
build:
|
|
22
|
+
name: Build distribution
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
permissions:
|
|
25
|
+
contents: read
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout
|
|
28
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
29
|
+
with:
|
|
30
|
+
persist-credentials: false
|
|
31
|
+
|
|
32
|
+
- name: Install uv
|
|
33
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
34
|
+
with:
|
|
35
|
+
enable-cache: false
|
|
36
|
+
|
|
37
|
+
- name: Install Python 3.12
|
|
38
|
+
run: uv python install 3.12
|
|
39
|
+
|
|
40
|
+
- name: Build
|
|
41
|
+
run: uv build
|
|
42
|
+
|
|
43
|
+
- name: Upload dist artifact
|
|
44
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
45
|
+
with:
|
|
46
|
+
name: dist
|
|
47
|
+
path: dist/
|
|
48
|
+
|
|
49
|
+
publish-testpypi:
|
|
50
|
+
name: Publish to TestPyPI
|
|
51
|
+
needs: build
|
|
52
|
+
if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
|
|
53
|
+
runs-on: ubuntu-latest
|
|
54
|
+
environment: testpypi
|
|
55
|
+
permissions:
|
|
56
|
+
contents: read
|
|
57
|
+
id-token: write
|
|
58
|
+
steps:
|
|
59
|
+
- name: Download dist artifact
|
|
60
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
61
|
+
with:
|
|
62
|
+
name: dist
|
|
63
|
+
path: dist/
|
|
64
|
+
|
|
65
|
+
- name: Publish to TestPyPI
|
|
66
|
+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
|
|
67
|
+
with:
|
|
68
|
+
repository-url: https://test.pypi.org/legacy/
|
|
69
|
+
|
|
70
|
+
publish-pypi:
|
|
71
|
+
name: Publish to PyPI
|
|
72
|
+
needs: build
|
|
73
|
+
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.target == 'pypi')
|
|
74
|
+
runs-on: ubuntu-latest
|
|
75
|
+
environment: pypi
|
|
76
|
+
permissions:
|
|
77
|
+
contents: write
|
|
78
|
+
id-token: write
|
|
79
|
+
steps:
|
|
80
|
+
- name: Download dist artifact
|
|
81
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
82
|
+
with:
|
|
83
|
+
name: dist
|
|
84
|
+
path: dist/
|
|
85
|
+
|
|
86
|
+
# id-token: write above enables OIDC; pypa/gh-action-pypi-publish generates
|
|
87
|
+
# Sigstore attestations automatically when that permission is set.
|
|
88
|
+
- name: Publish to PyPI
|
|
89
|
+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
|
|
90
|
+
|
|
91
|
+
- name: Create GitHub Release
|
|
92
|
+
if: github.event_name == 'push'
|
|
93
|
+
env:
|
|
94
|
+
GH_TOKEN: ${{ github.token }}
|
|
95
|
+
TAG: ${{ github.ref_name }}
|
|
96
|
+
run: gh release create "$TAG" dist/* --title "$TAG"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<Config xmlns="http://pypi.org/project/xsdata">
|
|
3
|
+
<Output maxLineLength="100" subscriptableTypes="true" unionType="true">
|
|
4
|
+
<Package>pactus.generated</Package>
|
|
5
|
+
<Format repr="true" eq="true" order="false" unsafeHash="false" frozen="false" slots="false" kwOnly="false">pydantic</Format>
|
|
6
|
+
<Structure>filenames</Structure>
|
|
7
|
+
<DocstringStyle>reStructuredText</DocstringStyle>
|
|
8
|
+
<RelativeImports>true</RelativeImports>
|
|
9
|
+
<CompoundFields defaultName="choice"/>
|
|
10
|
+
</Output>
|
|
11
|
+
<Conventions>
|
|
12
|
+
<ClassName case="pascalCase" safePrefix="type"/>
|
|
13
|
+
<FieldName case="snakeCase" safePrefix="value"/>
|
|
14
|
+
<ConstantName case="screamingSnakeCase" safePrefix="value"/>
|
|
15
|
+
<ModuleName case="snakeCase" safePrefix="mod"/>
|
|
16
|
+
<PackageName case="snakeCase" safePrefix="pkg"/>
|
|
17
|
+
</Conventions>
|
|
18
|
+
</Config>
|
pactus_mcp-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Denis Karlinsky
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pactus-mcp
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Production-grade MCP server for ISO 20022 payment message processing
|
|
5
|
+
Project-URL: Repository, https://github.com/deniskarlinsky/iso20022-mcp
|
|
6
|
+
Project-URL: Documentation, https://github.com/deniskarlinsky/iso20022-mcp#readme
|
|
7
|
+
Author: Denis Karlinsky
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: camt053,fintech,iso20022,mcp,pacs008,pain001,payments,swift
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
16
|
+
Requires-Python: >=3.12
|
|
17
|
+
Requires-Dist: fastmcp>=2.0
|
|
18
|
+
Requires-Dist: lxml>=5.0
|
|
19
|
+
Requires-Dist: pydantic>=2.6
|
|
20
|
+
Requires-Dist: xsdata-pydantic>=24.5
|
|
21
|
+
Requires-Dist: xsdata[cli,lxml]>=26.2
|
|
22
|
+
Provides-Extra: semantic
|
|
23
|
+
Requires-Dist: numpy>=1.26; extra == 'semantic'
|
|
24
|
+
Requires-Dist: sentence-transformers>=3.0; extra == 'semantic'
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# Pactus
|
|
28
|
+
|
|
29
|
+
[](https://github.com/deniskarlinsky/iso20022-mcp/actions/workflows/ci.yml)
|
|
30
|
+
|
|
31
|
+
Pactus is an MCP server for parsing ISO 20022 payment messages directly from chat. It exposes five tools that let AI assistants inspect `pacs.008`, `pacs.002`, `pain.001`, and `camt.053` messages — the message types at the centre of the CBPR+ migration — without leaving the conversation. It is aimed at developers and bank-integration teams who need to read, debug, or explain ISO 20022 traffic during the transition away from MT messages.
|
|
32
|
+
|
|
33
|
+
## Status
|
|
34
|
+
|
|
35
|
+
Stable. Version 1.0.0 is on PyPI.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install pactus-mcp
|
|
39
|
+
# or
|
|
40
|
+
uv add pactus-mcp
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Quick start
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
git clone https://github.com/deniskarlinsky/iso20022-mcp
|
|
47
|
+
cd iso20022-mcp
|
|
48
|
+
uv sync
|
|
49
|
+
uv run pytest
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Connecting to Claude Desktop
|
|
53
|
+
|
|
54
|
+
Add Pactus to your Claude Desktop config:
|
|
55
|
+
|
|
56
|
+
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
57
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
58
|
+
- **Linux:** `~/.config/Claude/claude_desktop_config.json`
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"mcpServers": {
|
|
63
|
+
"pactus": {
|
|
64
|
+
"command": "uv",
|
|
65
|
+
"args": ["run", "--directory", "/absolute/path/to/iso20022-mcp", "pactus-mcp"]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Restart Claude Desktop. The Pactus tools will appear in the tools menu.
|
|
72
|
+
|
|
73
|
+
## Available tools
|
|
74
|
+
|
|
75
|
+
| Tool | Message type | Purpose |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| `ping` | — | Health check; returns service name and version. |
|
|
78
|
+
| `parse_pacs008` | `pacs.008.001.08` | Parse a FI-to-FI Customer Credit Transfer. |
|
|
79
|
+
| `parse_pacs002` | `pacs.002.001.10` | Parse a FI-to-FI Payment Status Report. |
|
|
80
|
+
| `parse_pain001` | `pain.001.001.09` | Parse a Customer Credit Transfer Initiation. |
|
|
81
|
+
| `parse_camt053` | `camt.053.001.08` | Parse a Bank-to-Customer Account Statement. |
|
|
82
|
+
|
|
83
|
+
All four parse tools return a structured Pydantic model on success, or `{"error": "..."}` on failure. Errors never raise; the agent can explain what went wrong.
|
|
84
|
+
|
|
85
|
+
## Tool reference
|
|
86
|
+
|
|
87
|
+
### parse_pacs008
|
|
88
|
+
|
|
89
|
+
`pacs.008` is the primary interbank credit transfer message and the mandatory format for all CBPR+ cross-border traffic from November 2025. It carries one or more credit transfer instructions between financial institutions, each with settlement amount, charge bearer, debtor, and creditor agents.
|
|
90
|
+
|
|
91
|
+
<details>
|
|
92
|
+
<summary>Example response</summary>
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"group_header": {
|
|
97
|
+
"message_id": "MSG20240508001",
|
|
98
|
+
"creation_datetime": "2024-05-08T10:00:00",
|
|
99
|
+
"number_of_transactions": 1,
|
|
100
|
+
"settlement_method": "CLRG"
|
|
101
|
+
},
|
|
102
|
+
"transactions": [
|
|
103
|
+
{
|
|
104
|
+
"end_to_end_id": "E2E20240508001",
|
|
105
|
+
"transaction_id": "TX20240508001",
|
|
106
|
+
"settlement_amount": {"value": "1000.00", "currency": "USD"},
|
|
107
|
+
"charge_bearer": "SHAR",
|
|
108
|
+
"debtor": {"name": "Acme Corporation"},
|
|
109
|
+
"debtor_agent": {"bic": "CHASUS33"},
|
|
110
|
+
"creditor": {"name": "Global Supplies Ltd"},
|
|
111
|
+
"creditor_agent": {"bic": "DEUTDEDB"}
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
</details>
|
|
118
|
+
|
|
119
|
+
### parse_pacs002
|
|
120
|
+
|
|
121
|
+
`pacs.002` is the status report sent in response to a `pacs.008`. It reports whether each transaction was accepted, rejected, or is in an intermediate state. Rejections carry one or more structured reason codes (e.g. `AC01` incorrect account, `AG01` transaction forbidden) that explain the outcome.
|
|
122
|
+
|
|
123
|
+
<details>
|
|
124
|
+
<summary>Example response</summary>
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"group_header": {
|
|
129
|
+
"message_id": "STS20260510001",
|
|
130
|
+
"creation_datetime": "2026-05-10T14:30:00"
|
|
131
|
+
},
|
|
132
|
+
"original_group_info": {
|
|
133
|
+
"original_message_id": "MSG20240508001",
|
|
134
|
+
"original_message_name_id": "pacs.008.001.08",
|
|
135
|
+
"original_creation_datetime": "2024-05-08T10:00:00",
|
|
136
|
+
"group_status": "ACSC"
|
|
137
|
+
},
|
|
138
|
+
"transaction_statuses": [
|
|
139
|
+
{
|
|
140
|
+
"original_end_to_end_id": "E2E-001",
|
|
141
|
+
"original_transaction_id": "TX-001",
|
|
142
|
+
"status": "ACSC",
|
|
143
|
+
"status_reasons": [],
|
|
144
|
+
"acceptance_datetime": "2026-05-10T14:29:45"
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
</details>
|
|
151
|
+
|
|
152
|
+
### parse_pain001
|
|
153
|
+
|
|
154
|
+
`pain.001` is the initiating message in a credit transfer flow, sent by a corporate or customer to their bank. It groups transactions into one or more `PaymentInformation` batches that share a debtor account, execution date, and service level. The LLM sees the full hierarchy: group header → batches → transactions.
|
|
155
|
+
|
|
156
|
+
<details>
|
|
157
|
+
<summary>Example response</summary>
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"group_header": {
|
|
162
|
+
"message_id": "PAIN20260510-001",
|
|
163
|
+
"creation_datetime": "2026-05-10T09:00:00",
|
|
164
|
+
"number_of_transactions": 1,
|
|
165
|
+
"control_sum": "1500.00",
|
|
166
|
+
"initiating_party_name": "ACME Corp"
|
|
167
|
+
},
|
|
168
|
+
"payment_informations": [
|
|
169
|
+
{
|
|
170
|
+
"payment_information_id": "BATCH-2026-05-10-A",
|
|
171
|
+
"payment_method": "TRF",
|
|
172
|
+
"requested_execution_date": "2026-05-12",
|
|
173
|
+
"debtor": {"name": "ACME Corp"},
|
|
174
|
+
"debtor_account_iban": "DE89370400440532013000",
|
|
175
|
+
"debtor_agent": {"bic": "DEUTDEFFXXX"},
|
|
176
|
+
"charge_bearer": "SLEV",
|
|
177
|
+
"service_level_code": "SEPA",
|
|
178
|
+
"transactions": [
|
|
179
|
+
{
|
|
180
|
+
"end_to_end_id": "E2E-PAIN-001",
|
|
181
|
+
"amount": {"value": "1500.00", "currency": "EUR"},
|
|
182
|
+
"creditor": {"name": "Acme Supplier SARL"},
|
|
183
|
+
"creditor_account_iban": "FR1420041010050500013M02606",
|
|
184
|
+
"remittance_info": ["Invoice 2026-0042"]
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
]
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
</details>
|
|
193
|
+
|
|
194
|
+
### parse_camt053
|
|
195
|
+
|
|
196
|
+
`camt.053` is the structured account statement sent by a bank to its customer. It reports opening and closing balances and individual debit/credit entries for a period, each optionally broken down to individual transaction details. It is the primary source for automated bank reconciliation.
|
|
197
|
+
|
|
198
|
+
<details>
|
|
199
|
+
<summary>Example response</summary>
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"group_header": {
|
|
204
|
+
"message_id": "CAMT053-SINGLE-001",
|
|
205
|
+
"creation_datetime": "2026-05-10T08:00:00"
|
|
206
|
+
},
|
|
207
|
+
"statements": [
|
|
208
|
+
{
|
|
209
|
+
"statement_id": "STMT-2026-05-09-001",
|
|
210
|
+
"account_iban": "DE89370400440532013000",
|
|
211
|
+
"account_currency": "EUR",
|
|
212
|
+
"balances": [
|
|
213
|
+
{
|
|
214
|
+
"type_code": "OPBD",
|
|
215
|
+
"amount": {"value": "10000.00", "currency": "EUR"},
|
|
216
|
+
"credit_debit": "CRDT",
|
|
217
|
+
"balance_date": "2026-05-09"
|
|
218
|
+
}
|
|
219
|
+
],
|
|
220
|
+
"entries": [
|
|
221
|
+
{
|
|
222
|
+
"entry_ref": "NTRY-001",
|
|
223
|
+
"amount": {"value": "1500.00", "currency": "EUR"},
|
|
224
|
+
"credit_debit": "DBIT",
|
|
225
|
+
"status": "BOOK",
|
|
226
|
+
"booking_date": "2026-05-09",
|
|
227
|
+
"bank_tx_domain": "PMNT",
|
|
228
|
+
"bank_tx_family": "ICDT",
|
|
229
|
+
"bank_tx_subfamily": "ESCT"
|
|
230
|
+
}
|
|
231
|
+
]
|
|
232
|
+
}
|
|
233
|
+
]
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
</details>
|
|
238
|
+
|
|
239
|
+
## Security model
|
|
240
|
+
|
|
241
|
+
- **XXE and entity-expansion hardening:** All four parsers reject input containing `<!DOCTYPE>` or `<!ENTITY>` declarations before any XML parsing occurs. This blocks XXE file-read, SSRF, and billion-laughs DoS patterns.
|
|
242
|
+
- **Build integrity:** Generated xsdata models are SHA-256 verified in CI on every commit (`sha256sum -c GENERATED_HASHES.txt`). Regeneration is reproducible from the vendored XSDs.
|
|
243
|
+
- **Supply chain:** GitHub Actions workflows use SHA-pinned action references (commit-hash `@` pins, not mutable tags).
|
|
244
|
+
- **Distribution integrity:** PyPI artifacts are published via OIDC Trusted Publishing and signed with Sigstore. SBOMs (CycloneDX and SPDX) are generated and vulnerability-scanned on every CI run; release artifacts include the SBOM.
|
|
245
|
+
- **Vulnerability disclosure:** See [SECURITY.md](SECURITY.md).
|
|
246
|
+
|
|
247
|
+
## Architecture
|
|
248
|
+
|
|
249
|
+
Pactus uses a hexagonal layout: `pactus/core/` is pure business logic with no MCP awareness, `mcp_server.py` is a thin FastMCP wrapper, and the generated xsdata models live in `pactus/generated/` and never escape `parsers.py`. See [architecture.md](architecture.md) for the diagram.
|
|
250
|
+
|
|
251
|
+
## Development
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
uv run ruff check
|
|
255
|
+
uv run ruff format
|
|
256
|
+
uv run mypy
|
|
257
|
+
uv run pytest
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
The project targets `mypy --strict`.
|
|
261
|
+
|
|
262
|
+
## License
|
|
263
|
+
|
|
264
|
+
MIT
|