@attestwire/mcp
v1.1.2
Published
stdio bridge to the Attestwire MCP server — nine EN 16931 e-invoicing compliance tools: validate invoice data, or a UBL 2.1 / UN-CEFACT CII invoice file, against XRechnung and Peppol BIS 3 rules, and emit UBL or CII XML. XML only: it does not read or writ
Maintainers
Readme
@attestwire/mcp
European e-invoicing compliance as MCP tools — EN 16931, XRechnung, Peppol BIS 3.0 and Factur-X. Ask what a rule means, validate a real invoice, emit invoice XML, check whether VIES is up, look up a French company against the 2026-2027 mandate.
Five of the nine tools need no API key at all. Connect with no credential and they work immediately — start there, add a key later.
npx -y @attestwire/mcpAt a glance
| | |
|---|---|
| Tools | 9 — 5 keyless, 3 keyed and metered, 1 keyed and free |
| Hosted at | https://api.attestwire.com/mcp — streamable HTTP, stateless, no session id |
| This package | npx -y @attestwire/mcp — a stdio bridge to that endpoint, for clients that cannot speak remote HTTP |
| Deterministic | The compliance tools are a rule engine, not a model. The same document against the same ruleset returns the same verdicts, in the same order, every time — no sampling, no temperature, nothing generated. The ruleset is pinned per engine release; GET https://api.attestwire.com/v1/versions names the one that is live. |
| Rules | EN 16931 plus the national CIUS: XRechnung (UBL and CII), Peppol BIS 3.0. 270 rule ids explained in plain English — most, not all, of what the validator checks. |
| Reads / writes | UBL 2.1 Invoice, UBL 2.1 CreditNote, UN/CEFACT CII CrossIndustryInvoice, in both directions |
| Auth | Optional Authorization: Bearer aw_live_... — a bearer API key, not OAuth |
| Free tier | 100 documents/month, no card. issue_api_key mints a key from inside the session — but minting does not authenticate the connection it was minted on: save it, configure it, reconnect (§3). |
| Runtime | Zero dependencies, Node ≥ 20, MIT |
The disclaimer, up front, because it is the thing people get wrong: this is a pre-flight, not a clearing house. It handles XML and never PDF — a Factur-X or ZUGFeRD file is CII XML inside a PDF/A-3 container, and this server neither opens that container nor builds one. And a document that passes here can still be rejected by KoSIT or by a receiving platform: rules that constrain the XML itself do not run on a file this server read. Nothing here is legal or tax advice. The four limits are spelled out in full below.
Quickstart
1. Connect
If your client speaks streamable HTTP — Claude Code, Claude Desktop custom connectors, Cursor — point it at the hosted endpoint and skip this package entirely:
claude mcp add --transport http attestwire https://api.attestwire.com/mcpIf your client can only spawn a local process, this package is a stdio bridge to
that same endpoint. Paste into claude_desktop_config.json, .cursor/mcp.json,
or whatever your client calls its MCP config:
{
"mcpServers": {
"attestwire": {
"command": "npx",
"args": ["-y", "@attestwire/mcp"]
}
}
}No env block, no key, nothing to sign up for. See
most people do not need this package
for which of the two to pick.
2. Make a call, with no credential
Ask the agent, in these words or your own:
Use the attestwire MCP server: explain rule BR-DE-15.
explain_rule is keyless, so this answers on a fresh connection — the rule's
requirement, the business term it constrains, a fix and an example. Four other
tools work the same way with no key: check_vies_status,
check_french_readiness, list_approved_platforms and issue_api_key.
That is the whole first run. Everything below is either the key (§3), the full tool list, or the limits.
3. Add a key — two stages, and the second one is not optional
Authentication is supplied when the client connects: this bridge reads
ATTESTWIRE_API_KEY once, at process start, and sends it as an
Authorization: Bearer header; a client on the remote HTTP transport sends the
header from its own config. Minting a key does not authenticate the connection
it was minted on — nothing a tool returns changes a live session's credential,
and there is no automatic reauthentication to wait for.
So it is two stages, not one call:
Stage one — get a key.
- Mint it. Ask the agent to call
issue_api_keywith your email address, or fill in the browser form at attestwire.com/#keyform — same endpoint, same instant key. It is free, there is no signup flow and no card. - Save it. The key is shown once and cannot be recovered — only its SHA-256 hash is stored. Put it in a password manager or a secret store, not in the chat you are typing into. The browser form is the better route when you would rather a one-time secret never entered a transcript at all.
Stage two — make the connection carry it.
Configure it.
ATTESTWIRE_API_KEYin theenvblock for this stdio bridge:{ "mcpServers": { "attestwire": { "command": "npx", "args": ["-y", "@attestwire/mcp"], "env": { "ATTESTWIRE_API_KEY": "aw_live_..." } } } }Or an
Authorization: Bearer aw_live_...header if your client speaks remote HTTP.addover an existing name is the step people skip, so remove first:claude mcp remove attestwire claude mcp add --transport http attestwire https://api.attestwire.com/mcp \ --header "Authorization: Bearer aw_live_..."Restart or reconnect the MCP server. Editing the config of a running client changes nothing until it reconnects.
Verify with one metered call —
validate_invoiceon any invoice.
Four of the nine tools need a key, not three: the three document tools —
validate_invoice, validate_invoice_xml and generate_invoice, which are the
metered ones — plus get_upgrade_link, which is keyed but free, because it has
to know which key it is quoting an upgrade for. Called without one, the three
document tools return an error naming issue_api_key as the remedy and spelling
out these steps.
Do not mint twice: the limit is one free key per email address, so a second call
answers 409 rather than issuing a replacement. If a metered call still fails
after the reconnect, the problem is the config, not the key.
| Variable | |
|---|---|
| ATTESTWIRE_API_KEY | Optional. Needed by validate_invoice, validate_invoice_xml, generate_invoice and get_upgrade_link; the other five tools ignore it. |
| ATTESTWIRE_MCP_URL | Optional endpoint override. Defaults to https://api.attestwire.com/mcp. |
Tools
You can hand these tools a JSON invoice model or an XML invoice file.
Both of the syntaxes EN 16931 is written in are read and written: UBL 2.1
Invoice, UBL 2.1 CreditNote and UN/CEFACT CII CrossIndustryInvoice, which
carries invoices and credit notes alike. What is not read or written is a PDF.
See what this does not do.
| Tool | Key? | |
|---|---|---|
| explain_rule | free | One rule id (BR-DE-15, BR-CO-15, PEPPOL-EN16931-R010…) in plain English: what it requires, the business term it constrains, a fix and an example. 270 rules explained at time of writing — most, not all, of what the validator checks; the live number is in the tool's own description. |
| check_vies_status | free | Is VIES (EU VAT number validation) up? Overall or per member state, with latency and 24h/7d uptime. Tells a bad VAT number apart from a down endpoint. |
| check_french_readiness | free | Look up a French company by SIREN, SIRET or name in INSEE SIRENE open data. |
| list_approved_platforms | free | The DGFiP-approved French platforms (Plateformes Agréées, ex-PDP). |
| issue_api_key | free | Mint a free key — 100 documents/month, no signup flow, no card. Minting alone does not authenticate the connection: save, configure, reconnect (§3). |
| validate_invoice | key · 1 doc | Check a JSON invoice object against EN 16931 plus the national CIUS. Every failure comes back as a teaching error: rule id, business term, what the rule requires, a concrete fix, and the XPath the rule would have landed on. |
| validate_invoice_xml | key · 1 doc | Check an invoice file the user already has — a UBL 2.1 Invoice, a UBL 2.1 CreditNote, or a UN/CEFACT CII CrossIndustryInvoice (invoice or credit note alike). Same teaching errors, plus which syntax it read, the document's BT-24/BT-23, and everything in the file that did not reach the invoice model. Send the file as-is: the reader and the document type are both chosen from the root element. A credit note is not refused. Not a PDF reader. |
| generate_invoice | key · 1 doc | Emit compliant XML from a JSON invoice object. The profile chooses the syntax: xrechnung-cii and facturx-en16931 come back as CII, everything else as UBL 2.1. invoiceTypeCode 381 emits a credit note in either syntax. Refuses an invalid invoice rather than emitting XML that passes nothing. |
| get_upgrade_link | key · free | A checkout link (Paddle-hosted) for a paid plan. Returns a link; a human still has to open it. |
Four honest limits, stated up front
- XML, never PDF — in either direction. Factur-X and ZUGFeRD are CII XML
inside a PDF/A-3 container. These tools handle the XML. They do not parse
a Factur-X or ZUGFeRD PDF, and they do not build one: no container, no
factur-x.xmlattachment, no/AFRelationship. If you have a PDF, extract the XML from it first. If you need a PDF, pass our XML to a Factur-X packaging library. Afacturx-en16931result is the payload, not a Factur-X document. - The two CII profiles are not equally evidenced, and neither is checked per
call. The generator's
xrechnung-ciifixture documents are run through the official KoSIT validator on release and accepted. Thefacturx-en16931ones are not: that profile's BT-24 is the core EN 16931 one, which matches no XRechnung scenario, so KoSIT answers "no scenario matched" rather than passing or failing them — and an absence of a verdict is not a pass. Neither case says anything about the document you generate: nothing is sent to KoSIT at call time. - Credit notes yes; debit notes no, and one business term does not survive
one. A credit note is a first-class document in both syntaxes now:
invoiceTypeCode: "381"emits a UBLCreditNoteor a CII document withram:TypeCode381, the reader picks the document type off the root element, and the whole rule set runs on it unchanged. What is still refused isubl:DebitNote, for which EN 16931 has no binding at all. And BT-11, the project reference, has no element inUBL-CreditNote-2.1.xsd, so no conformant UBL credit note can carry one: it is dropped and reported rather than emitted somewhere it does not belong. Reading a file is also a pre-flight, not a verdict from the receiver:validate_invoice_xmlchecks the model it read, not the XML a receiving platform judges, so a file that passes can still be rejected. check_french_readinesscannot confirm that a company has registered with an approved platform — that lives only in the CAPTCHA-protected DGFiP annuaire, which has no open API. The tool says so in every response.
One smaller gap, for completeness: the 25 arithmetic and decimal-precision rules
the validator fires (BR-45/46/48, BR-CO-18, BR-DEC-19/20/23, and
the per-category -01 and -09 families) have no plain-English write-up yet.
BR-12–BR-15 were on that list until @attestwire/en16931 0.6.0 and are not
any more: a document read from XML can omit a total it is required to state, so
the four presence rules became reachable and now have harvested write-ups like
any other rule. None of them can be tripped by anything a caller
sends: they constrain the library's own computed arithmetic, which is what they
are for. explain_rule says so for those ids and links
the rule reference, which does cover them.
Most people do not need this package
Attestwire is a remote MCP server at https://api.attestwire.com/mcp. Any
client that speaks streamable HTTP should point at it directly — that is the
claude mcp add --transport http line in the quickstart.
This package exists for clients that can only spawn a local stdio process. It moves JSON-RPC messages between stdio and HTTPS and does nothing else: no schema validation, no caching, no interpretation. New tools appear without updating it.
Notes
- The key is never a tool argument on a metered tool — it is read from the
connection.
get_upgrade_linkis the one exception: it accepts an optionalkey, so a key minted a minute ago can be upgraded before it has been configured anywhere. Prefer the header even there, because an argument is written into the agent's transcript. - Zero runtime dependencies. Node ≥ 20.
- Diagnostics go to stderr; stdout carries protocol messages only.
--help,--version.- Free tier is 100 documents/month.
validate_invoice,validate_invoice_xmlandgenerate_invoicecost one document each; nothing else costs anything. A file that cannot be read at all — a PDF, aubl:DebitNote, malformed bytes — never reaches the rules and costs nothing.
MIT · attestwire.com · docs · changelog · [email protected]
