Skip to main content

Language Server Protocol (LSP) server for authoring camt053 ISO 20022 camt.053 reversing-entry data files.

Project description

camt053-lsp: A Language Server for Authoring ISO 20022 Reversing-Entry Files

camt053-lsp logo

PyPI Version Python Versions License Tests Quality OpenSSF Scorecard OpenSSF Best Practices Documentation

Real-time editor help for ISO 20022 reversing-entry files — diagnostics, completion, and hover as you author the JSON records that drive camt.053 reversal generation.

Latest release: v0.0.7 — supply-chain hardening: every GitHub Action SHA-pinned, all CI/release pip installs hash-pinned, least-privilege workflow tokens, and continuous fuzzing (Atheris + ClusterFuzzLite) of the document-processing entry points — earning the OpenSSF Best Practices gold badge (100%). Built on the pygls-based Language Server with schema + IBAN/BIC diagnostics, field and message-type completion, schema-description hover, code actions, document symbols, and formatting — all backed by camt053.services. See what's new →

Contents

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, …). camt053-lsp is that backend for reversing-entry data JSON files: the JSON arrays of flat reversing-entry records that drive ISO 20022 camt.053 reversal generation in the camt053 suite.

It gives editors three features as you type, all backed by camt053.services 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 camt message types.
  • Hover — the schema description for the field under the cursor.

The intended message type defaults to camt.053.001.14 (Bank to Customer Statement); the pure helpers accept a message_type argument so a different type can be configured.

camt053-lsp is part of the camt053 suite — a set of independently installable packages (all Python 3.10+) sharing the camt053.services layer:

Package Role
camt053 Core library + Click CLI + FastAPI REST API
camt053-mcp Model Context Protocol server (for AI agents)
camt053-lsp Language Server Protocol server (this package)
flowchart LR
    A["Editor (VS Code / Neovim / …)"] -->|LSP over stdio| B["camt053-lsp"]
    B -->|compute_diagnostics / completion_items / hover_text| C["camt053.services"]
    C -->|schema + IBAN/BIC validation| B
    B -->|diagnostics · completion · hover| A

Install

camt053-lsp runs on macOS, Linux, and Windows and requires Python 3.10+ and pip. It pulls in the core camt053 library and pygls automatically.

python -m pip install camt053-lsp

Verify the installation:

python -c "import camt053_lsp; print('camt053-lsp', camt053_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 camt053-lsp

Quick Start

For the 10-minute install → editor wiring → first reversing-entry edit tutorial, see docs/quickstart.md.

The package installs a camt053-lsp console entry point that starts the language server over stdio:

camt053-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 reversing-entry data files and you get diagnostics, completion, and hover as you type.

Editor wiring

Register camt053-lsp as the server cmd for JSON files in your editor's LSP client.

Neovim (built-in vim.lsp.config)
vim.lsp.config["camt053"] = {
  cmd = { "camt053-lsp" },
  filetypes = { "json" },
  root_markers = { ".git" },
}
vim.lsp.enable("camt053")
VS Code (generic LSP client)

Configure a generic LSP client extension to spawn the camt053-lsp command over stdio for the json language, or wrap it in a small extension whose serverOptions is { command: "camt053-lsp", transport: TransportKind.stdio }.

Open a JSON array of reversing-entry 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 reversing-entry data JSON files (a JSON array of flat reversing-entry 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 (account_id, account_servicer_bic, counterparty_account) 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 camt message type.
  • Hover — the schema description for the field name under the cursor, or the human-readable name when the token is a supported camt.05x message type (e.g. camt.053.001.14 — Bank To Customer Statement).
  • Code actions — for each record missing required fields, a quick-fix inserts the missing keys (with empty placeholder values) into that record. Valid records and malformed JSON propose no action.
  • Document symbols (outline) — one symbol per record (named Record N, with its statement_msg_id / entry_ref as the detail) and a child symbol for every field, so editors can render an outline / breadcrumb. Malformed JSON yields an empty outline.
  • Formatting — pretty-prints the whole document with a stable 2-space indent while preserving key order, returned as a single full-document edit. Invalid JSON leaves the document unchanged.
  • JSONC tolerance// line comments and trailing commas are stripped before parsing, so all of the above work on JSONC data files. Clean JSON is unaffected. (YAML data files are a planned future enhancement.)

The feature logic lives in pure, importable helpers (compute_diagnostics, completion_items, hover_text, hover_markup, message_type_name, code_actions, document_symbols, format_text) backed by the shared camt053.services layer, 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 camt053_lsp.server import (
    code_actions,
    completion_items,
    compute_diagnostics,
    document_symbols,
    format_text,
    hover_markup,
    hover_text,
)

# A complete, valid reversing-entry record produces no diagnostics.
valid_doc = json.dumps(
    [
        {
            "statement_msg_id": "RVSL-STMT-0001",
            "creation_date_time": "2026-06-15T08:00:00",
            "statement_id": "RVSL-STMT-0001",
            "account_id": "GB29NWBK60161331926819",
            "account_currency": "EUR",
            "account_servicer_bic": "NWBKGB2LXXX",
            "amount": "1500.00",
            "currency": "EUR",
            "credit_debit": "DBIT",
            "reason_code": "AC04",
            "counterparty_account": "DE89370400440532013000",
        }
    ]
)
assert compute_diagnostics(valid_doc) == []

# Missing required fields are reported as errors.
missing = json.dumps([{"statement_msg_id": "ONLY-ID"}])
print(len(compute_diagnostics(missing)), "issue(s)")

# An invalid BIC is flagged as a warning.
bad_bic = json.dumps([{"account_servicer_bic": "INVALID"}])
print(compute_diagnostics(bad_bic)[: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("account_servicer_bic"))   # -> the field's schema description
print(hover_text("nope"))                    # -> None

# Hover markup also names a message type under the cursor.
print(hover_markup("camt.053.001.14"))       # -> "camt.053.001.14 — Bank ..."

# Code actions propose inserting a record's missing required fields.
fixes = code_actions(missing)
print(fixes[0]["title"])                     # -> "Insert missing required ..."
print(code_actions(valid_doc))               # -> [] (nothing to fix)

# Document symbols build an outline: one symbol per record, fields as children.
outline = document_symbols(valid_doc)
print(outline[0]["name"], "->", len(outline[0]["children"]), "fields")

# Formatting pretty-prints the document (2-space indent, key order preserved).
print(format_text('[{"b":1,"a":2}]'))        # -> formatted JSON string
print(format_text("[{not json}]"))           # -> None (left unchanged)

# JSONC sugar (// comments, trailing commas) is tolerated everywhere.
jsonc = '[\n  // a record\n  {"statement_msg_id": "ID-1",},\n]'
print(compute_diagnostics(jsonc)[:1])        # parses fine

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/lsp_helpers.py for the full runnable script.

Examples

The examples/ directory contains a self-contained, runnable script for the helper API:

Example Demonstrates
lsp_helpers.py The LSP diagnostics / completion / hover helpers
git clone https://github.com/sebastienrousseau/camt053-lsp.git && cd camt053-lsp
python examples/lsp_helpers.py

The camt053 suite

camt053-lsp is part of a set of independently installable packages built around the camt053 library — pick whichever ones your stack needs:

Package Role
camt053 Core library + CLI + FastAPI REST API
camt053-mcp Model Context Protocol server (for AI agents)
camt053-lsp Language Server Protocol server (this package)
camt053-writer-xlsx Excel .xlsx writer for parsed statements
camt053-loader-mt940 SWIFT MT940 → camt.053 loader

Every helper here is a thin typed wrapper over camt053.services — the same facade the CLI, REST API, and MCP server use — so all four interfaces behave identically.

When not to use camt053-lsp

  • You have no LSP-capable editor. This server only makes sense paired with an LSP client (VS Code, Neovim, Helix, Sublime LSP, etc.). Scripted / CI use is better served by the camt053 CLI and REST API.
  • You are authoring camt.053 XML statements (rather than the reversing-entry JSON the LSP targets). The CBPR+ Nov 2026 diagnostics added in v0.0.6 do fire on opened XML files (auto- detected by content), but full XML-authoring features (completion, schema-aware hover) are not the LSP's primary mode.
  • You need single-file linting outside an editor. Use the CLI: camt053 check-cbpr-readiness statement.xml covers the same ground the LSP surfaces on save.
  • You need to generate pain.001 outbound payment files. Out of scope; use the pain001-lsp for that workflow.

Development

camt053-lsp uses Poetry and mise.

git clone https://github.com/sebastienrousseau/camt053-lsp.git && cd camt053-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 (100% line + branch coverage enforced)
make lint         # ruff + black
make type-check   # mypy --strict
make security     # bandit
make examples     # run the example scripts
make fuzz         # run the Atheris fuzz harness locally
make pip-compile  # regenerate the hash-pinned requirements/*.txt

CI installs are hash-pinned: each job installs from a requirements/*.txt lockfile (compiled from requirements/*.in with uv pip compile --generate-hashes) using pip install --require-hashes. Regenerate them with make pip-compile after changing a .in file.

Security

camt053-lsp is a thin wrapper — every helper delegates to camt053.services, where the defence-in-depth (defusedxml + xml_guard byte cap + DOCTYPE / ENTITY pre-flight) lives. The LSP itself does no network I/O and treats the open document as untrusted text. The text-driven entry points are continuously fuzzed with Atheris under ClusterFuzzLite (see fuzz/ and .clusterfuzzlite/) so malformed JSON/JSONC/XML cannot crash the server. Supply-chain hardening — SHA-pinned Actions, hash-pinned pip installs, and least-privilege workflow tokens — is tracked by OpenSSF Scorecard. Reporting practice, supported versions, and the full posture are documented in SECURITY.md. Vulnerabilities go via GitHub Private Vulnerability Reporting, not public issues.

Documentation

License

Licensed under the Apache License, Version 2.0. 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 pygls and lsprotocol by the Open Law Library, and on the core camt053 library that powers the shared service layer.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

camt053_lsp-0.0.8.tar.gz (24.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

camt053_lsp-0.0.8-py3-none-any.whl (20.7 kB view details)

Uploaded Python 3

File details

Details for the file camt053_lsp-0.0.8.tar.gz.

File metadata

  • Download URL: camt053_lsp-0.0.8.tar.gz
  • Upload date:
  • Size: 24.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for camt053_lsp-0.0.8.tar.gz
Algorithm Hash digest
SHA256 6b17befa50e16202ac38d0877ce1da2ebac29b0af2d768a0f429735f0fc3453f
MD5 97285f79c4ef30d0b58d86cfd75d859f
BLAKE2b-256 937703fc2a82802a5cb922470e5b4b59eec5c9d937e9713b81b81a8f8398c8e9

See more details on using hashes here.

Provenance

The following attestation bundles were made for camt053_lsp-0.0.8.tar.gz:

Publisher: release.yml on sebastienrousseau/camt053-lsp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file camt053_lsp-0.0.8-py3-none-any.whl.

File metadata

  • Download URL: camt053_lsp-0.0.8-py3-none-any.whl
  • Upload date:
  • Size: 20.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for camt053_lsp-0.0.8-py3-none-any.whl
Algorithm Hash digest
SHA256 7fd1178aa252eada619e5f9c82f956264d3c11e1e5d8907a6237aedb9b4337f9
MD5 158b9900e4a6054729d28d08c5c7f0c2
BLAKE2b-256 cd56c9e76841c22a766e179c7934d5862acecbfab5287264d18c23a9560a530f

See more details on using hashes here.

Provenance

The following attestation bundles were made for camt053_lsp-0.0.8-py3-none-any.whl:

Publisher: release.yml on sebastienrousseau/camt053-lsp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page