Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased¶
0.0.16 - 2026-10-27¶
Python 3.11 floor and release-evidence release, in lockstep with
pacs008 0.0.16. Python 3.10 is no longer supported (see Removed).
Changed¶
pacs008 >= 0.0.16, < 1andpacs008-loader-mt103 >= 0.0.16, < 1: the suite members of the same release, so an older core or loader and the advisory floors they declare cannot resolve under this one. The hash-pinnedrequirements/trees are re-locked against them.The GitHub release is titled
pacs008-mcp X.Y.Z(the project name and the bare version), not the tag.validate_xmlanswers a document whose date has a year past what the validator can represent with{"message_type": ..., "is_valid": false}, not an{"error": "refused XML: OverflowError(...)"}payload: pacs008 0.0.16 reports that date as invalid instead of letting elementpath’sOverflowErrorescape, so the tool no longer catches it.
Security¶
The release SBOMs (CycloneDX and the pip-licenses manifest) describe the shipped runtime set: the hash-pinned
requirements/docker.txtthe image installs, plus the package as a local wheel, in a venv of their own.poetry installhad resolved afresh (nopoetry.lockis committed here), andpoetry runpointed the SBOM tools at their own interpreter, so the SBOM listed the tooling, not the runtime set.The MCP Inspector conformance job pins
@modelcontextprotocol/inspectorto 2.10.1, so a new npm publish cannot change what CI runs.
Removed¶
Python 3.10 is no longer supported: the floor is 3.11 (
python = ">=3.11,<4.0"), in step with thepacs008core, as 3.10 reaches end of life in October 2026. CI tests 3.11 to 3.14; ruff, black and mypy target 3.11. Thetomlifallback inscripts/check_suite_consistency.pyandtests/test_package_version.pygoes, with its dev dependency, andrequirements/ci.txtandsbom.txtare compiled for 3.11, dropping their 3.10-only lines (exceptiongroup, toml,tomliinsbom.txt, and the older httpx2, httpcore2, hypothesis, starlette, websockets, platformdirs and rpds-py pins).
0.0.15 - 2026-10-24¶
Security¶
mcpis constrained to>=1.30.0,!=2.0.*,!=2.1.*,<3, so no release affected by GHSA-84m7-p3x7-pcfv (unbounded streamable HTTP session accumulation: mcp>=1.8.0,<1.30.0and>=2.0.0,<2.2.0) can resolve. The previous>=1.2,<3admitted them.Security floors on mcp’s transitive stack, matching pain001-mcp:
anyio >= 4.14.2,httpx2 >= 2.12.0,httpcore2 >= 2.10.0,pyjwt[crypto] >= 2.15.0,opentelemetry-api >= 1.45.1(GHSA-xcq7-p3pf-p88h) andcertifi >= 2026.10.19(PYSEC-2026-4320).The release toolchain (
requirements/build.txt, installed only by the release workflow on Python 3.12) floorsfilelock >= 4.2.1(GHSA-9vhv-jxww-xfm5, GHSA-567q-5qvw-pf92, GHSA-v4x8-3wr5-3wq8); it had pinned 4.0.10. That release needs Python 3.11, so the tree is compiled for 3.12.The same tree floors
virtualenv >= 21.14.13(GHSA-cx6f-vjhg-g3cc: from 21.14.9, the bash activator leaves--promptunescaped inPS1); it had pinned 21.14.11.
Fixed¶
validate_xmlanswers a document that declares DTD entities (XXE, billion laughs) with an{"error": "refused XML: EntitiesForbidden(...)"}payload. defusedxml’s refusal used to escape the tool, so the client saw only an opaque “Error executing tool validate_xml”.validate_xmlanswers a date whose year is past what the validator can represent (for example<CreDtTm>99999999999-01-15T10:30:00</CreDtTm>) with an{"error": "refused XML: OverflowError('year overflow')"}payload. elementpath’sOverflowErrorused to escape the tool; the Atheris job found it.scripts/check_suite_consistency.pycompares this tree with the publishedpacs008-mcp, not with thepacs008core it was copied from, so the scheduled Suite Consistency job no longer reports a never-released bump that does not exist.
Added¶
Coverage-guided fuzzing:
fuzz/fuzz_tools.py(Atheris) feeds arbitrary text tovalidate_xml,parse_messageandconvert_mt103, run by theFuzzworkflow on every change and for 30 minutes weekly;tests/test_untrusted_text.pyholds the fixed and property-based cases of the same contract.A complexity gate in the lint job:
scripts/check_complexity.py(cyclomatic, Halstead, function and file length) andcomplexipy(cognitive), each against a committed baseline of the offenders that predate it, which may only shrink.docs/POLICIES.md, the toolchain policy the README’s Python badge links to.
Changed¶
Requires
pacs008 >= 0.0.15, < 1andpacs008-loader-mt103 >= 0.0.15, < 1(were>= 0.0.10and>= 0.0.1): the suite releases in lockstep, and the loader’s 0.0.15 parses SWIFT block 4 in linear time (GHSA-4f6g-425r-ff5p). The hash-pinned trees move both from 0.0.12 to 0.0.15.Every
pip installin CI, the docs build and the container image is hash-pinned:requirements/ci.txt,docs.txt,fuzz.txtanddocker.txt. The package goes on top with--no-deps --no-build-isolation, so its build backend (poetry-core) comes from those trees too instead of an unpinned isolated build; where the install is not editable (the docs build, the MCP Inspector job and the image), a wheel is built first and installed with--no-deps.The container image runs Python 3.14 (
python:3.14-slim, pinned by digest) and drops thePACS008_PIP_SPECbuild argument and the git client it needed; the runtime dependencies come fromrequirements/docker.txt.GitHub Actions updated and pinned by commit SHA: checkout 7.0.1, setup-python 7.0.0, setup-node 7.1.0, upload-artifact 7.0.2, attest-build-provenance 4.2.2, gh-action-pypi-publish 1.14.3, sbom-action 0.24.3, scorecard-action 2.5.0, codeql-action 4.39.0.
Development tools: ruff
>=0.1,<0.18, mypy>=1.11,<3.0; the release tooling floorsvirtualenv>=21.14.8.The README badge row follows the portfolio template: Build, Registry, Docs, OpenSSF Scorecard, License and Python floor, then Glama.
scripts/verify_versions.pychecks each manifest in its own helper; the output and exit codes are unchanged.CITATION.cffandSECURITY.mdcarry the current version again (both had been left at 0.0.12).
0.0.14 - 2026-10-04¶
Changed¶
Standardize license section heading in README to License for Glama directory and registry matcher consistency.
Update locked dependencies to resolve transitive vulnerabilities.
0.0.13 - 2026-10-04¶
Added¶
Added framework adapters (
as_langchain_tools,as_crewai_tools,as_llamaindex_tools) inpacs008_mcp.adaptersfor seamless agent integration.Added animated terminal demo (
.github/demo.gif) and.github/demo.tapewithmake demotarget.Added normalized dual-licensing structure with
LICENSES/Apache-2.0.txtandLICENSES/MIT.txt.Mutation testing of the tool handlers (mutmut 3):
make mutateand theMutants of the tool handlersworkflow run every mutant ofpacs008_mcpagainst the fast handler tests and fail below the floor in the Makefile (90%; measured 98.6%, 479 of 486 checked mutants, on 2026-09-19).Property-based tests (
tests/test_properties.py, Hypothesis) over the invariants the handlers keep for any input their schemas admit: error envelopes always carry a non-emptyerror, every result is JSON-serialisable, report summaries agree with their rows, the BIC normaliser’s parts re-join to the code, and the repaired address is itself a validclassify_addressinput. Deterministic, with a trimmedmutationprofile for the mutant runs.A docstring gate:
interrogateat 100% over the package, run bymake doc-coverageand the lint job.A rendered documentation site (Sphinx, Furo, MyST) at https://sebastienrousseau.github.io/pacs008-mcp/: README, API reference, benchmarks, ADRs, roadmap and changelog. Built with warnings as errors on every pull request and deployed from
main.tests/test_examples.pyexecutesexamples/mcp_tools.py, so the example fails the build instead of rotting.ADR 0002 records why tools are registered explicitly.
Fixed¶
validate_addressesreturned the library’sValueErroras an exception when a row’s address column broke a field rule (an over-lengthbldg_nb, say) instead of the{"error": ...}envelope its docstring promises. Found by the property tests.--transport streamable-httpand--transport sse, with--hostand--port. Streamable HTTP serves both current protocol revisions (2026-07-28 stateless withserver/discover, and 2025-11-25 with theinitializehandshake) on one endpoint and streams responses as server-sent events;sseserves the older HTTP+SSE transport. stdio stays the default and is unchanged.--versionprints the version. ADR 0001 records the decision.
Changed¶
Tools, resources and the prompt are registered in one explicit block before
main()instead of with decorators: mutmut never mutates a decorated function, so the decorator form kept every handler outside mutation testing. The catalogue a client sees is unchanged (dumped and diffed before and after; ADR 0002).The server is built through a small compatibility shim so it runs on both supported majors of the
mcpSDK: 2.x (MCPServer, the 2026-07-28 stateless revision withserver/discover) and 1.x (FastMCP). The dependency range is nowmcp>=1.2,<3, so a fresh install gets 2.x and speaks the current protocol revision.
0.0.12 - 2026-08-29¶
Aligns the pacs008 suite on one version number, and adds the gates this
repository was missing.
Added¶
benches/bench_tool_dispatch.pymeasures what an agent waits for: the dispatch floor, the payment pipeline across batch sizes, and the address tools. Two results are worth having on the record — validation costs about seven times what generation does, and address screening is roughly 155× cheaper per item than record validation, which is what makes a million-address cutover check a twelve-second job rather than a scheduled one.docs/benchmarks.mdwith the measured tables.scripts/check_suite_consistency.pyand a scheduledSuite Consistencyworkflow comparing this tree, and every published member, against PyPI.tests/test_suite_conformance.py, the shared suite conformance gate.SECURITY.md, written for an MCP server: stdio has no authentication of its own, tool inputs arrive from a model rather than someone who read the docs, andverify_bic_onlineis the one tool that egresses.
Changed¶
Version aligned to
0.0.12acrosspacs008,pacs008-mcpandpacs008-loader-mt103, which had drifted to0.0.11,0.0.9and0.0.3.
0.0.9 - 2026-08-28¶
Swift deferred the CBPR+ structured-address start date; the descriptions a model reads still named it as in force.
Fixed¶
The
address_policyparameter description, theclassify_addressdocstring and the workflow guidance all said the CBPR+ structured-address rule takes force on 14 November 2026. Swift deferred that on 27 August 2026 and confirms replacement timing by December at the latest. These strings are what an assistant reads to decide what to tell a user, so a stale date here is repeated to whoever asked as though it were authoritative.The descriptions now say the deferral is Swift’s and covers CBPR+; HVPS+, T2 RTGS, CHAPS, Lynx and Fedwire set their own timing and are unaffected.
Unchanged¶
No tool behaviour changes. Descriptions only.
0.0.8 - 2026-08-16¶
Release the work that accumulated on main after v0.0.7 was tagged,
and take the pacs008 release that makes the cryptography floor
resolvable.
Fixed¶
pacs008is now>=0.0.9. Both0.0.7and0.0.8ofpacs008capcryptography<50.0.0, so requiring the patchedcryptography 50.0.0against them is not merely unsatisfied — it is unresolvable:ERROR: Cannot install cryptography>=50.0.0, pacs008==0.0.7 and pacs008==0.0.8 because these package versions have conflicting dependencies.
cryptographyis floored at>=50.0.0. It arrives transitively viamcp->pyjwt[crypto]and nothing constrained it, so a resolver could pick a version in the range GHSA flags as high severity.
Added¶
Online BIC directory verification tool (#10).
MCP prompts and resources for Trinity parity (#9).
tests/test_package_version.py, tying__version__topyproject.tomland the newestCHANGELOG.mdheading. Its absence is why0.0.7shipped without a changelog entry and why thecryptographybump in #12 — whose commit message says(v0.0.7)— landed after thev0.0.7tag and was never published.
0.0.7 - 2026-07-30¶
Backfilled: this version was released and tagged, but no changelog entry was written at the time.
Changed¶
Required
pacs008>=0.0.7(was>=0.0.5) for the 0.0.7 validation bug fix.
0.0.6 - 2026-07-26¶
Added¶
PEP 561
py.typedmarker (pacs008_mcp/py.typed), wired into the Poetryincludelist and verified present in the built wheel. The server ismypy --strictclean but previously shipped no marker, so downstream consumers received none of its annotations.Regression test (
tests/test_py_typed_marker.py) that fails before a release ships if the marker is dropped from source or packaging.
Changed¶
Version
0.0.5→0.0.6.
0.0.5 - 2026-07-18¶
Changed¶
chore(deps): require
pacs008>=0.0.7(was>=0.0.5) to pick up the 0.0.7 validation bug fix. No tool signatures or behaviour change in this server.
0.0.4 - 2026-07-12¶
Added¶
convert_mt103tool — convert a legacy SWIFT MT103 (single customer credit transfer) into pacs.008-ready flat records that can be fed straight intovalidate_records/generate_message. This is the SWIFT MT-to-MX migration path (correspondent-banking MT103 coexistence with ISO 20022 ends November 2025). The tool is a thin wrapper over thepacs008-loader-mt103library’sparse_mt103; it does no file I/O and returns{"message_type": "pacs.008.001.08", "records": [...]}, or an{"error": ...}payload on a missing-mandatory-field / malformed MT103.
Changed¶
The MCP server now exposes 15 tools (was 14).
Added a runtime dependency on
pacs008-loader-mt103(>=0.0.1).
0.0.3 - 2026-07-12¶
Security¶
Require pacs008 >= 0.0.5, which relaxes the cryptography constraint to
<49.0.0(patched>=48.0.1), clearing the inherited Dependabot advisory.
0.0.2 - 2026-07-12¶
Added¶
Four November 2026 structured-address cliff tools, each a thin wrapper over the
pacs008library’sstandards.addressmodule. From 14 November 2026, fully unstructured postal addresses are rejected across SWIFT CBPR+, HVPS+, T2 RTGS, CHAPS, Fedwire and Lynx; these tools let agents get ahead of the deadline:classify_address— classify a postal address as structured / hybrid / unstructured (wrapsPostalAddress.classifyand itsis_*predicates)validate_address— validate one address against an address policy, defaulting to the 14 November 2026 cliff rule (wrapsPostalAddress.validate)repair_address— country-aware upgrade of legacy unstructured address lines toward hybrid/structured form (wrapsfrom_unstructured)validate_addresses— batch-validate every party address across payment rows (wrapsvalidate_addresses)
policyvalue-constraint enum on the address tools, surfaced as JSON Schemaenummetadata derived from the library’sAddressPolicyenum (unstructured_ok,hybrid_or_structured,structured_only), defaulting tohybrid_or_structured— the cliff policy.
Changed¶
The MCP server now exposes 14 tools (was 10).
Bumped the minimum
pacs008dependency to>=0.0.4— the first published PyPI release whosestandards.addressmodule backs the new tools.
0.0.1 - 2026-07-11¶
Added¶
Initial release of
pacs008-mcp, a Model Context Protocol (MCP) server that exposes thepacs008ISO 20022 FI-to-FI Customer Credit Transfer library as tools for AI agents and assistants.pacs008-mcpconsole script that runs the FastMCP server over stdio.Ten MCP tools, each a thin wrapper over the
pacs008library so they behave identically to the CLI and REST API:list_message_types— list the 20 supported pacs message types with nameslist_schemes— list the registered scheme / usage-guideline profilesget_scheme— inspect a scheme profile’s rulesget_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 type’s schemavalidate_scheme— validate records against a scheme’s usage guidelinesgenerate_message— generate a validated pacs XML messagevalidate_xml— validate a raw XML string against the bundled XSDparse_message— parse & classify an inbound ISO 20022 message
Value-constraint enums on closed-set tool parameters (
message_type,scheme), surfaced as JSON Schemaenummetadata derived from thepacs008library’s own constants and profile registry so accepted values never drift.MCP tool annotations (
readOnlyHint/idempotentHint/…) and tool titles for richer client/Glama introspection.Graceful error handling: tools return an
{"error": ...}payload on failure rather than raising.100% statement + branch test coverage, enforced inline via
--cov-fail-under=100.Python 3.10+ support; depends on
pacs008(>=0.0.1) andmcp(>=1.2).Runnable example (
examples/mcp_tools.py) invoking the tools in-process.glama.json,server.json(MCP Registry metadata), and aDockerfilefor directory listing, registry publication, and container deployment.