Language Server Protocol (LSP) server for authoring pain001 ISO 20022 Customer Credit Transfer Initiation data files.
Project description
pain001-lsp
Language Server Protocol server for authoring pain001 ISO 20022 Customer Credit Transfer Initiation data files.
Real-time editor help for ISO 20022 pain.001 data files - diagnostics,
completion, and hover as you author the JSON records that drive
pain.001 Customer Credit Transfer Initiation message generation.
Latest release: v0.0.52 - a pygls-based Language Server with schema + IBAN/BIC diagnostics, field and message-type completion, and schema-description hover, all backed by the
pain001public API. See what's new →
Contents
- Overview
- Install
- Quick Start
- Features
- Using the helpers
- Examples
- Development
- Licence
- Contribution
- Acknowledgements
Overview
A Language Server speaks the
Language Server Protocol (LSP) - the editor-agnostic protocol that
lets a single backend deliver diagnostics, completion, hover, and more to
any LSP client (VS Code, Neovim, Helix, Emacs, …). pain001-lsp is that
backend for payment-data JSON files: the JSON arrays of flat payment
records that drive ISO 20022 pain.001 message generation in the
pain001 suite.
- Website: https://pain001.com
- Source code: https://github.com/sebastienrousseau/pain001-lsp
- Bug reports: https://github.com/sebastienrousseau/pain001-lsp/issues
It gives editors four features as you type, all backed by the pain001
public API so they behave identically to the CLI, REST API, and MCP server:
- Diagnostics - each record is validated against a message type's input JSON Schema, and any IBAN / BIC identifier values are additionally checked with the dedicated validators.
- Completion - every input field (with its description) plus the list
of supported
pain.001/pain.008message types. - Hover - the schema description for the field under the cursor.
- Code actions - a single quick-fix that inserts JSON
"field": …lines for every schema-required field missing from the first record, using type-appropriate placeholders.
The intended message type defaults to pain.001.001.09 (Customer Credit
Transfer Initiation V09); the pure helpers accept a message_type argument
so a different type can be configured. Editors can override the default
per-workspace by sending
initializationOptions: {"messageType": "pain.001.001.11"} when they spawn
the server.
pain001-lsp is part of the pain001 suite - a set of independently
installable packages (all Python 3.10+) built around the pain001 library:
| Package | Role |
|---|---|
pain001 |
Core library + Click CLI + FastAPI REST API |
pain001-mcp |
Model Context Protocol server (for AI agents) |
pain001-lsp |
Language Server Protocol server (this package) |
flowchart LR
A["Editor (VS Code / Neovim / …)"] -->|LSP over stdio| B["pain001-lsp"]
B -->|compute_diagnostics / completion_items / hover_text| C["pain001"]
C -->|schema + IBAN/BIC validation| B
B -->|diagnostics · completion · hover| A
Install
pain001-lsp runs on macOS, Linux, and Windows and requires Python 3.10+
and pip. It pulls in the core pain001 library and
pygls automatically.
python -m pip install pain001-lsp
Verify the installation:
python -c "import pain001_lsp; print('pain001-lsp', pain001_lsp.__version__)"
Using an isolated virtual environment (recommended)
python -m venv venv
source venv/bin/activate # macOS/Linux
venv\Scripts\activate # Windows
python -m pip install -U pain001-lsp
Quick Start
The package installs a pain001-lsp console entry point that starts the
language server over stdio:
pain001-lsp
The command speaks LSP on stdin/stdout - it is meant to be launched by your editor's LSP client, not used interactively. Point your editor at it for JSON payment-data files and you get diagnostics, completion, and hover as you type.
Editor wiring
Register pain001-lsp as the server cmd for JSON files in your editor's
LSP client.
Neovim (built-in vim.lsp.config)
vim.lsp.config["pain001"] = {
cmd = { "pain001-lsp" },
filetypes = { "json" },
root_markers = { ".git" },
}
vim.lsp.enable("pain001")
VS Code (generic LSP client)
Configure a generic LSP client extension to spawn the pain001-lsp command
over stdio for the json language, or wrap it in a small extension whose
serverOptions is { command: "pain001-lsp", transport: TransportKind.stdio }.
Open a JSON array of payment records and the server validates each record on open and on every change, surfaces completion for field names and message types, and shows schema descriptions on hover.
Features
For payment-data JSON files (a JSON array of flat payment records, or a single record object treated as one record):
- Diagnostics - schema validation reports missing required fields,
wrong types, and pattern/length violations; identifier fields
(
debtor_account_IBAN,creditor_account_IBAN,charge_account_IBAN,debtor_agent_BIC,creditor_agent_BIC,forwarding_agent_BIC) are additionally checked as IBAN / BIC. Malformed JSON yields a single syntax diagnostic at the offending position. - Completion - every input field for the message type (with its schema
description as the detail) plus every supported
pain.001/pain.008message type. - Hover - the schema
descriptionfor the field name under the cursor. - Code actions -
missing_required_fields(record, message_type)lists the schema-required fields absent from a record;build_insert_text(...)renders type-appropriate placeholder lines (""for strings,0for numbers,falsefor booleans). The LSP server stitches these together into a single "Add missing required fields" quick-fix.
The feature logic lives in pure, importable helpers (compute_diagnostics,
completion_items, hover_text, missing_required_fields,
build_insert_text) backed by the pain001 public API, so editor
behaviour stays in lockstep with the CLI, REST API, and MCP server. The
LSP handlers are thin glue that map those plain dicts to lsprotocol
types.
Using the helpers
Because the feature logic is pure, you can call it directly - no editor or server process required. This is exactly what the server runs on each edit:
import json
from pain001_lsp.server import (
completion_items,
compute_diagnostics,
hover_text,
)
# A complete, valid payment record produces no diagnostics.
valid_doc = json.dumps(
[
{
"id": "MSG-0001",
"date": "2026-01-15T10:30:00",
"nb_of_txs": 1,
"ctrl_sum": 100.00,
"initiator_name": "Acme Embedded Finance Ltd",
"payment_information_id": "PMT-INFO-0001",
"payment_method": "TRF",
"batch_booking": False,
"service_level_code": "SEPA",
"requested_execution_date": "2026-01-20",
"debtor_name": "Acme Embedded Finance Ltd",
"debtor_account_IBAN": "DE89370400440532013000",
"debtor_agent_BIC": "DEUTDEFFXXX",
"charge_bearer": "SLEV",
"payment_id": "PAY-0001",
"payment_amount": 100.00,
"currency": "EUR",
"creditor_agent_BIC": "NWBKGB2LXXX",
"creditor_name": "National Westminster Bank",
"creditor_account_IBAN": "GB29NWBK60161331926819",
"remittance_information": "Invoice 0001",
}
]
)
assert compute_diagnostics(valid_doc) == []
# Missing required fields are reported as errors.
missing = json.dumps([{"id": "ONLY-ID"}])
print(len(compute_diagnostics(missing)), "issue(s)")
# An invalid IBAN is flagged as a warning.
bad_iban = json.dumps([{"debtor_account_IBAN": "INVALID"}])
print(compute_diagnostics(bad_iban)[:1])
# Completion offers field names and message types; hover shows descriptions.
items = completion_items()
print(len(items), "completion items, e.g.", items[0]["label"])
print(hover_text("debtor_account_IBAN")) # -> the field's schema description
print(hover_text("nope")) # -> None
Each diagnostic is a plain dict -
{"line": int, "character": int, "severity": "error" | "warning", "message": str} -
which the server maps to lsprotocol Diagnostic objects before publishing.
See examples/01_lsp_helpers.py for the full
runnable script.
Examples
The examples/ directory contains three self-contained,
runnable scripts:
| Example | Demonstrates |
|---|---|
01_lsp_helpers.py |
The LSP diagnostics / completion / hover helpers |
02_quick_fix.py |
The "Add missing required fields" code action - missing_required_fields + build_insert_text |
03_configure_message_type.py |
Overriding the default message type via initializationOptions |
git clone https://github.com/sebastienrousseau/pain001-lsp.git && cd pain001-lsp
python examples/01_lsp_helpers.py
Development
pain001-lsp uses Poetry and mise.
git clone https://github.com/sebastienrousseau/pain001-lsp.git && cd pain001-lsp
mise install
poetry install
poetry shell
A 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 --strict
make examples # run the example script
Licence
Licensed under the Apache Licence, Version 2.0. Any contribution submitted for inclusion shall be licensed as above, without additional terms.
Contribution
Contributions are welcome - see the contributing instructions. Thanks to all contributors.
Acknowledgements
Built on pygls and lsprotocol by the
Open Law Library, and on the core
pain001 library that powers the validators and schemas.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pain001_lsp-0.0.52.tar.gz.
File metadata
- Download URL: pain001_lsp-0.0.52.tar.gz
- Upload date:
- Size: 20.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
71049992ec69794ee367415da19a0c8ba5c9f38390ac5263399330baf32f5e22
|
|
| MD5 |
ead79c0b2cad96a5889cab9c9e647796
|
|
| BLAKE2b-256 |
7055e317b7695ae209716aa8acbe54d5c11da72dd4a74039be7556c15ad5bfd3
|
Provenance
The following attestation bundles were made for pain001_lsp-0.0.52.tar.gz:
Publisher:
release.yml on sebastienrousseau/pain001-lsp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pain001_lsp-0.0.52.tar.gz -
Subject digest:
71049992ec69794ee367415da19a0c8ba5c9f38390ac5263399330baf32f5e22 - Sigstore transparency entry: 1867845162
- Sigstore integration time:
-
Permalink:
sebastienrousseau/pain001-lsp@cb373b51cf55a9beaa64a1e964ff81ab50df833d -
Branch / Tag:
refs/tags/v0.0.52 - Owner: https://github.com/sebastienrousseau
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cb373b51cf55a9beaa64a1e964ff81ab50df833d -
Trigger Event:
push
-
Statement type:
File details
Details for the file pain001_lsp-0.0.52-py3-none-any.whl.
File metadata
- Download URL: pain001_lsp-0.0.52-py3-none-any.whl
- Upload date:
- Size: 18.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28e247f84c2e65086e2deb5c97440d30bfc0eebbb21cc08ca917ec8afd3957f4
|
|
| MD5 |
f8533d7092a7db2c9c2d4831b856c0c4
|
|
| BLAKE2b-256 |
62e6e9f032a2df13c4decc92bcc8020e79ec993e441f61eea69e1bfa68a6aee1
|
Provenance
The following attestation bundles were made for pain001_lsp-0.0.52-py3-none-any.whl:
Publisher:
release.yml on sebastienrousseau/pain001-lsp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pain001_lsp-0.0.52-py3-none-any.whl -
Subject digest:
28e247f84c2e65086e2deb5c97440d30bfc0eebbb21cc08ca917ec8afd3957f4 - Sigstore transparency entry: 1867845233
- Sigstore integration time:
-
Permalink:
sebastienrousseau/pain001-lsp@cb373b51cf55a9beaa64a1e964ff81ab50df833d -
Branch / Tag:
refs/tags/v0.0.52 - Owner: https://github.com/sebastienrousseau
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cb373b51cf55a9beaa64a1e964ff81ab50df833d -
Trigger Event:
push
-
Statement type: