Conformo
Conformo lets you create, validate, convert, and inspect European e-invoices locally, generate Factur-X/ZUGFeRD PDFs, and look up rules and country requirements without transmitting invoices.
Create e-invoice XML in CII, UBL, XRechnung, Peppol BIS, and limited KSeF FA(3) from structured JSON.
Generate Factur-X/ZUGFeRD PDF/A-3 invoices with embedded XML, returned as base64 or written to an allowed
.pdfpath.Validate XML or PDF invoices against XSD and official EN 16931/XRechnung/Peppol rule sets, with optional FR/DE country layers and detailed failures/explanations.
Convert invoices between supported syntaxes.
Parse supported XML/PDF invoices into the structured JSON invoice model.
Get country e-invoicing requirements for BE, DE, ES, FR, IT, NL, and PL, including what Conformo can generate/read/validate.
Explain validation rule IDs with official wording and plain-language guidance.
Run via stdio or stateless HTTP; tools do not transmit invoices or make network calls, and unsupported formats include FatturaPA, Facturae, and reading KSeF FA(3).
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ConformoValidate this e-invoice XML against German XRechnung rules"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@conformo/mcp-server
Let Claude, Cursor or any MCP client make and check European e-invoices: XRechnung, ZUGFeRD / Factur-X PDF, Peppol BIS Billing 3.0, plain CII and UBL.
Runs on your machine. No account, no API key, no usage limits. Invoices never leave your computer; no tool makes a network call.
Same verdict as the official validator.
validate_invoiceruns the official KoSIT, CEN and Peppol rules plus the XSDs. Its verdicts match the official KoSIT validator 100% on the official test invoices, and the full comparison is public.Explains what to fix. Every failed rule comes back with the publisher's message, and the common ones also with a plain-language explanation and fix.
Free and open source (Apache-2.0). Rule sets are pinned and a daily job tracks KoSIT, CEN and Peppol releases (how).
Quick start for Claude Code: claude mcp add conformo -- npx -y @conformo/mcp-server. Other clients are below.
Needs Node.js 20 or newer. MCP Registry name: io.github.arsalmurad/conformo.
Then ask your agent things like:
"Make an XRechnung for Stadt Musterstadt, Leitweg-ID 04011000-1234512345-06, 10 hours of consulting at 95 EUR, and check it."
"Is this invoice valid? Explain every error and fix it." (paste the XML, or give a ZUGFeRD PDF)
"Turn this UBL invoice into a ZUGFeRD PDF."
"What does BR-DE-15 mean?"
Every tool is a thin wrapper over @conformo/toolkit. Two transports: stdio (default, for desktop clients) and
stateless Streamable HTTP (for a shared deployment).
Tools
Tool | What it does | Read-only |
| Structured invoice (JSON object) to XML: | yes |
| Same input to a Factur-X / ZUGFeRD PDF/A-3 ( | no |
| XML text or base64 PDF. Detects syntax and profile, runs XSD and the matching rule sets, reports which ran. Optional | yes |
| XML or PDF in, another syntax out. | yes |
| XML or PDF to the invoice JSON model. | yes |
| Mandates, dates, thresholds and sources per country, plus what Conformo itself supports. | yes |
| A rule id such as | yes |
All tools declare an outputSchema and return structuredContent plus a text fallback. Money is always integer minor
units (EUR 12.34 is 1234). The input schema of create_invoice documents every field with its BT/BG identifier.
Input problems come back as an isError result listing every issue (path, BT id, message), never a stack trace.
Related MCP server: Fintom8 E-Invoice MCP Server
Install and configure
The commands below use the published package name. From a checkout, replace npx -y @conformo/mcp-server with
npx tsx /absolute/path/to/conformo/packages/mcp-server/src/server.ts.
Claude Desktop
Add to claude_desktop_config.json (Settings, Developer, Edit Config):
{
"mcpServers": {
"conformo": {
"command": "npx",
"args": ["-y", "@conformo/mcp-server"]
}
}
}On Windows, if npx is not found, use "command": "cmd" with "args": ["/c", "npx", "-y", "@conformo/mcp-server"].
Claude Code
claude mcp add conformo -- npx -y @conformo/mcp-server
# or against a remote deployment
claude mcp add --transport http conformo https://mcp.example.com/mcpCursor
.cursor/mcp.json in the project, or ~/.cursor/mcp.json for all projects:
{
"mcpServers": {
"conformo": {
"command": "npx",
"args": ["-y", "@conformo/mcp-server"]
}
}
}Working directory and outputPath
create_invoice_pdf can write a file instead of returning base64. The path must end in .pdf, stay inside the server's
working directory, and not exist yet unless overwrite: true. Set CONFORMO_MCP_ALLOW_ANY_PATH=1 to lift the directory
limit.
HTTP mode
conformo-mcp --http --port 8787 --host 127.0.0.1 --max-body-bytes 8388608Flag | Env | Default |
|
|
|
|
|
|
|
|
|
Endpoints: POST /mcp (JSON-RPC, JSON responses), GET /healthz (liveness), GET/DELETE /mcp answer 405.
The server is stateless: a fresh server and transport per request, no session ids, no data kept between calls.
It has no authentication and no TLS.
Remote deployment
Do not expose the port directly. Run it on a private interface and put a reverse proxy with TLS and authentication in
front (a bearer token check, mTLS, or your identity-aware proxy). Because it is stateless you can run any number of
replicas behind a load balancer with no sticky sessions. Bind to 0.0.0.0 only inside a container or private network.
Dockerfile:
FROM node:22-slim
WORKDIR /app
RUN npm install -g @conformo/mcp-server
ENV CONFORMO_MCP_HOST=0.0.0.0 CONFORMO_MCP_PORT=8787
EXPOSE 8787
USER node
HEALTHCHECK CMD node -e "fetch('http://127.0.0.1:8787/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
CMD ["conformo-mcp", "--http"]Caddy example (token auth and TLS in front):
mcp.example.com {
@authed header Authorization "Bearer {env.MCP_TOKEN}"
handle @authed {
reverse_proxy 127.0.0.1:8787
}
respond "unauthorized" 401
}Note that invoices contain personal and commercial data: whoever can reach the endpoint can send invoices through it, and you carry the usual obligations for the traffic your proxy logs.
What it does not do
It does not transmit invoices: no Peppol access point, no French PA/PDP, no KSeF, no SdI. It produces and checks documents only.
It does not support FatturaPA or Facturae (no serializer, reader or validator). KSeF FA(3) is limited to writing domestic PLN invoices and checking them against the Ministry of Finance XSD; it cannot read them.
A
valid: truemeans the rule sets listed inruleSetsand the XSD passed. It is not a statement that any tax authority, buyer or network will accept the invoice.It does not compute anything you did not supply beyond totals and the VAT breakdown; exchange rates (BT-111) and exemption reasons are your input.
get_country_requirementsreports a sourced dataset; entries markedunverifiedare not confirmed from an official source. It is not legal advice.No authentication, authorisation, rate limiting or persistence in the server itself.
Local PDF writing is limited to the working directory unless you opt out; there is no network access from any tool.
Design decisions are recorded in DECISIONS.txt.
Available Tools
7 toolsconvert_invoiceConvert an e-invoice between syntaxesARead-onlyIdempotent
Rewrites an existing e-invoice in another syntax, for example CII to UBL, or plain EN 16931 to XRechnung or Peppol BIS. Use it when you already hold an invoice document. To build one from data use create_invoice; to get a PDF from XML use parse_invoice, then create_invoice_pdf. Accepts XML or a Factur-X / ZUGFeRD PDF. Nothing is invented: a target such as XRechnung may need data the source lacks, so read warnings and run validate_invoice on the result. A document it cannot read comes back as an error result with the reason. Runs locally; nothing is sent anywhere.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | Output syntax. "cii" = UN/CEFACT CII, EN 16931 (Factur-X / ZUGFeRD EN 16931 profile, a.k.a. COMFORT); "cii-extended" = UN/CEFACT CII declared as Factur-X / ZUGFeRD EXTENDED (EN 16931 content only; no EXTENDED-only fields); "ubl" = UBL 2.1 Invoice or CreditNote, EN 16931; "xrechnung-cii" = XRechnung 3.x in CII syntax (German CIUS); "xrechnung-ubl" = XRechnung 3.x in UBL syntax (German CIUS); "peppol-ubl" = Peppol BIS Billing 3.0 (UBL); "ksef-fa3" = Polish KSeF FA(3), PLN domestic invoices only; written and schema-checked, never submitted. | |
| xml | No | The invoice as XML text (CII, UBL Invoice/CreditNote, XRechnung, Peppol BIS). Provide this OR pdfBase64. | |
| pdfBase64 | No | A Factur-X / ZUGFeRD PDF/A-3 as base64; the embedded XML is used. Provide this OR xml. |
Output Schema
| Name | Required | Description |
|---|---|---|
| xml | Yes | The invoice in the target syntax. |
| from | Yes | Syntax of the source: cii, ubl-invoice or ubl-credit-note. |
| format | Yes | The syntax that was written. |
| warnings | Yes | Non-fatal findings, e.g. data the target requires that the source does not have. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the readOnly/idempotent/non-destructive annotations: it warns that conversion invents nothing, that a target profile like XRechnung may lack required source data and surfaces `warnings`, and that unreadable documents return an error result with a reason. It also discloses local execution ("nothing is sent anywhere"), corroborating openWorldHint=false.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads what the tool does, then alternatives, then input forms, then behavioral caveats and failure mode — a logical escalation with no filler. Each sentence supplies information the agent would otherwise have to infer.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even though an output schema exists and return values needn't be spelled out, the description covers the parts that matter for a conversion tool: input acceptance, lossy-conversion risk, warning inspection, and error behavior. Nothing an agent needs in order to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the enum and per-parameter descriptions already carry the load, and the description correctly does not repeat them. It still adds useful framing that only one of xml or pdfBase64 is supplied and that Factur-X/ZUGFeRD PDFs are accepted as input, plus concrete example target syntaxes.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Rewrites an existing e-invoice in another syntax") and grounds it with concrete conversions (CII to UBL, EN 16931 to XRechnung or Peppol BIS). An agent can immediately tell this apart from create_invoice or parse_invoice without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly scopes usage to when the caller "already hold[s] an invoice document" and routes the other cases: build from data → create_invoice, XML to PDF → parse_invoice then create_invoice_pdf. It also names the follow-up step (validate_invoice on the result) and the accepted input forms.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_invoiceCreate an e-invoice (XML)ARead-onlyIdempotent
Builds e-invoice XML from structured invoice data: EN 16931 CII or UBL, XRechnung (CII or UBL) or Peppol BIS Billing 3.0, chosen by format. Use it for a new invoice that software will read. For a printable PDF with the XML inside, use create_invoice_pdf; to change the syntax of an invoice you already have, use convert_invoice. Pass invoice as a JSON object, not a string. Every money field ends in "Minor" and is an integer in minor units (EUR 12.34 = 1234); totals and the VAT breakdown are computed, so do not send them. If fields are missing or wrong it returns an error listing every problem (path, BT id, message) and produces nothing; fix them all and call again. It runs locally and does not send the invoice anywhere. It does not run the official rule sets: call validate_invoice on the XML before it goes out.
| Name | Required | Description | Default |
|---|---|---|---|
| format | Yes | Output syntax. "cii" = UN/CEFACT CII, EN 16931 (Factur-X / ZUGFeRD EN 16931 profile, a.k.a. COMFORT); "cii-extended" = UN/CEFACT CII declared as Factur-X / ZUGFeRD EXTENDED (EN 16931 content only; no EXTENDED-only fields); "ubl" = UBL 2.1 Invoice or CreditNote, EN 16931; "xrechnung-cii" = XRechnung 3.x in CII syntax (German CIUS); "xrechnung-ubl" = XRechnung 3.x in UBL syntax (German CIUS); "peppol-ubl" = Peppol BIS Billing 3.0 (UBL); "ksef-fa3" = Polish KSeF FA(3), PLN domestic invoices only; written and schema-checked, never submitted. | |
| invoice | Yes | The invoice. Required: number, issueDate, currency, seller, buyer, lines. |
Output Schema
| Name | Required | Description |
|---|---|---|
| xml | Yes | The e-invoice XML, ready to send or to pass to validate_invoice. |
| format | Yes | The syntax that was written. |
| warnings | Yes | Non-fatal findings, e.g. a missing XRechnung precondition. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/local, and the description adds substantive behavior beyond them: the tool runs locally and sends nothing, a failure is atomic ("produces nothing") and returns an error enumerating every problem by path, BT id and message. It also discloses a real limitation not in any annotation — the official rule sets are not run, so validate_invoice must be called separately.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Six tight sentences, front-loaded with purpose then routing then input conventions then failure behavior. No filler, though the minor-units and computed-totals guidance partially repeats per-field schema descriptions and could be trimmed to one clause.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter tool wrapping a very large nested schema with an output schema available, the description covers the essentials: format choice, input conventions, atomic failure, locality, and the validation handoff. It does not mention format-specific field requirements (XRechnung mandatory seller contact, Peppol/France electronic address), but those are documented in the schema itself.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description earns an extra point by stating conventions that matter at call time but are easy to miss across a 100-field schema: `invoice` is an object not a JSON string, every money field is an integer in minor units, and totals/VAT breakdown must not be sent because they are computed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource ("Builds e-invoice XML from structured invoice data") and enumerates the supported syntaxes (EN 16931 CII/UBL, XRechnung, Peppol BIS 3.0) selected by `format`. It explicitly differentiates itself from create_invoice_pdf and convert_invoice, so the agent can choose without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States the use case ("for a new invoice that software will read") and names three alternatives with the exact condition that selects each: create_invoice_pdf for PDF, convert_invoice for changing syntax, validate_invoice before sending. When-to-use, when-not-to-use, and alternatives are all present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_invoice_pdfCreate a Factur-X / ZUGFeRD PDFADestructiveIdempotent
Builds a Factur-X / ZUGFeRD invoice: a PDF/A-3b page a person can read, with the EN 16931 XML embedded for software. Use it when the invoice goes to a person or by e-mail. For XML only, such as an XRechnung uploaded to a German public-sector portal, use create_invoice. Takes the same invoice object as create_invoice, money in integer minor units. language changes only the printed labels; the embedded XML is identical in every language. By default the PDF comes back as base64, which can be large; pass outputPath to write the file instead. Writing stays inside the server's working directory and never replaces an existing file unless overwrite is true. The same input always gives the same bytes, and nothing is sent anywhere. Check the result with validate_invoice (pass pdfBase64).
| Name | Required | Description | Default |
|---|---|---|---|
| invoice | Yes | The invoice. Required: number, issueDate, currency, seller, buyer, lines. | |
| profile | No | Factur-X / ZUGFeRD profile. Default en16931. | |
| language | No | Language of the printed labels: en, de or fr. Default en. Presentation only; the XML does not change. | |
| template | No | Page layout. Default classic. | |
| overwrite | No | Allow replacing an existing file at outputPath. Default false. | |
| outputPath | No | Write the PDF here instead of returning base64. Relative to the server working directory; must end in .pdf. |
Output Schema
| Name | Required | Description |
|---|---|---|
| sha256 | Yes | SHA-256 of the PDF bytes, hex; equal for equal input. |
| profile | Yes | The Factur-X / ZUGFeRD profile written. |
| warnings | Yes | Non-fatal findings about the invoice data. |
| pdfBase64 | No | The PDF, base64. Absent when outputPath was given. |
| byteLength | Yes | Size of the PDF in bytes. |
| outputPath | No | Absolute path written, when outputPath was given. |
| xmlFilename | Yes | Name of the embedded XML attachment. |
| conformanceLevel | Yes | Conformance level declared in the PDF metadata, e.g. EN 16931. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, but the description adds concrete behavior the agent could not otherwise know: writes are confined to the server working directory, an existing file is never replaced unless overwrite is true, output is byte-deterministic, nothing leaves the process, and the default base64 payload can be large enough to warrant outputPath. These are exactly the operational facts a caller needs before invoking a file-writing tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence is front-loaded with purpose and carries a distinct fact: what it builds, when to use it, when not to, input contract, language behavior, output channel, overwrite safety, determinism, and verification. No sentence repeats the schema or the annotations, and nothing is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a six-parameter tool with a deeply nested invoice schema and an output schema already present, the description covers the decision-relevant surface: artifact choice, input reuse, output channel trade-off, filesystem safety, determinism, and next-step validation. Return-value shape is correctly left to the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline would be 3, but the description adds real meaning: it explains that `language` affects only printed labels while the embedded XML is identical, that `outputPath` switches the return channel from base64 to a file, that writes are sandboxed to the working directory, and that the `invoice` object is shared with create_invoice and uses integer minor units. Only per-parameter details like profile/template semantics are left to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence names the exact artifact (a Factur-X / ZUGFeRD PDF/A-3b page with EN 16931 XML embedded), which is far more specific than the name alone, and the second sentence distinguishes it from the sibling create_invoice (XML only). An agent can tell instantly which of the two produces a human-readable document.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the positive trigger ("when the invoice goes to a person or by e-mail") and the negative one ("For XML only, such as an XRechnung uploaded to a German public-sector portal, use create_invoice"), naming the alternative explicitly. It also routes post-generation verification to validate_invoice with the pdfBase64 argument.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explain_validation_ruleExplain a validation ruleARead-onlyIdempotent
Explains one validation rule id, such as BR-CO-15, BR-DE-15, PEPPOL-EN16931-R003 or BR-FR-05: the publisher's official wording from the compiled rule sets and, where available, a plain-language summary, the reason for the rule and how to fix it. Use it after validate_invoice reports a rule you need to explain or fix, or when a user asks what a rule means. It does not check an invoice; call validate_invoice for that. An unknown id is not an error: the result has found false and an empty official list; say so and do not guess. Reads the bundled rule sets; no network.
| Name | Required | Description | Default |
|---|---|---|---|
| ruleId | Yes | The rule id, e.g. BR-CO-15. |
Output Schema
| Name | Required | Description |
|---|---|---|
| found | Yes | False when no compiled rule set knows this id. |
| ruleId | Yes | The rule id as looked up. |
| official | Yes | Official wording, one entry per rule set that defines the id. |
| plainLanguage | No | Plain-language explanation, when one exists for this rule. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, closed-world and non-destructive, so the safety profile is covered. The description still adds real behavioral context beyond them: unknown ids are not errors but yield `found` false with an empty `official` list, and the tool reads bundled rule sets with no network access. That said, it does not describe result sizing or how large the official wording list can get, so it is useful but not exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense paragraph, front-loaded with the verb/resource and the id formats, then usage, then the negative case, then data sourcing. Every clause earns its place; the 'does not check an invoice' sentence is a deliberate disambiguation rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter, read-only lookup with an output schema, the description covers purpose, routing, edge-case behavior and data provenance. Return values are backed by the output schema, and the description goes further by naming the `found`/`official` fields for the miss case so an agent knows what to report to the user.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single `ruleId` parameter is already documented with its own example, so the schema carries the parameter burden. The description reinforces the id format with several additional naming conventions (PEPPOL-EN16931-R003, BR-FR-05), which helps an agent recognize valid ids but adds no new constraints. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Explains one validation rule id') and immediately grounds it with concrete id examples (BR-CO-15, BR-DE-15, PEPPOL-EN16931-R003, BR-FR-05), making clear it is a lookup/explanation tool, not a validator. It explicitly distinguishes itself from validate_invoice, so an agent can route correctly without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit triggering conditions ('after validate_invoice reports a rule you need to explain or fix, or when a user asks what a rule means') and an explicit exclusion ('It does not check an invoice; call validate_invoice for that'). The alternative sibling and the condition that selects it are named outright, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_country_requirementsE-invoicing requirements for a countryARead-onlyIdempotent
Looks up the e-invoicing rules for one country in a sourced dataset: B2G and B2B mandates for issuing and receiving, start dates, turnover thresholds, required formats and official sources. Use it before create_invoice to decide which format a buyer in that country needs, or to answer when a mandate applies. It says nothing about a specific invoice; use validate_invoice to check one. Covers BE, DE, ES, FR, IT, NL, PL. conformoSupport says per format whether this server can create, read and validate it. Entries marked unverified are not confirmed from an official source; say so. Information, not legal advice. Reads a bundled dataset; no network.
| Name | Required | Description | Default |
|---|---|---|---|
| country | Yes | ISO 3166-1 alpha-2 country code, e.g. DE, FR. |
Output Schema
| Name | Required | Description |
|---|---|---|
| country | Yes | ISO 3166-1 alpha-2 code of the country returned. |
| conformoSupport | Yes | Per required format, what this server can do with it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly, idempotent and the closed-world nature, but the description adds real context beyond them: a data-quality caveat that 'unverified' entries are not confirmed from an official source and must be disclosed, plus the meaning of the `conformoSupport` field. Minor overlap exists in restating 'no network', which duplicates openWorldHint=false.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then alternatives, then caveats; nearly every sentence carries distinct information. Slight redundancy in 'Reads a bundled dataset; no network' echoing the openWorldHint annotation, but overall tight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values needn't be explained, yet the description still clarifies the key embedded field (`conformoSupport`) and the trust caveat for unverified entries. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; however the description adds the supported country domain (BE, DE, ES, FR, IT, NL, PL) that the schema does not encode via enum. That materially constrains valid inputs beyond the ISO-code description in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence gives a precise verb and resource ('Looks up the e-invoicing rules for one country in a sourced dataset') and enumerates the returned content (B2G/B2B mandates, start dates, thresholds, formats, sources). It is immediately distinguishable from siblings like validate_invoice and create_invoice.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use it ('before create_invoice to decide which format a buyer needs') and draws a clear exclusion boundary ('It says nothing about a specific invoice; use validate_invoice to check one'). This is the when/when-not/alternative pattern done fully.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
parse_invoiceParse an e-invoice into JSONARead-onlyIdempotent
Reads an e-invoice (CII, UBL, XRechnung or Peppol XML, or a Factur-X / ZUGFeRD PDF) into the structured invoice object that create_invoice accepts, with money in integer minor units. Use it to answer questions about a received invoice, to edit one, or to re-issue it with create_invoice. It does not check any rules, so use validate_invoice for that, and convert_invoice to change syntax directly. For a PDF, visibleTotals shows whether the totals printed on the page match the embedded XML, which exposes a tampered or mismatched PDF. A document it cannot read comes back as an error result with the reason. Runs locally.
| Name | Required | Description | Default |
|---|---|---|---|
| xml | No | The invoice as XML text (CII, UBL Invoice/CreditNote, XRechnung, Peppol BIS). Provide this OR pdfBase64. | |
| pdfBase64 | No | A Factur-X / ZUGFeRD PDF/A-3 as base64; the embedded XML is used. Provide this OR xml. |
Output Schema
| Name | Required | Description |
|---|---|---|
| format | Yes | Syntax of the source document. |
| origin | Yes | Whether the input was XML or a PDF. |
| invoice | Yes | The Invoice object, in the shape of the create_invoice input schema. |
| visibleTotals | No | PDF only: comparison of the printed totals with the embedded XML. |
| embeddedFilename | No | PDF only: name of the embedded XML that was read. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/idempotent/non-destructive, and the description adds behavior beyond them: output is the same object create_invoice accepts with money in integer minor units, unreadable documents return an error result with a reason, and it runs locally. The visibleTotals disclosure for PDFs (page totals vs embedded XML, exposing tampering) is precisely the kind of non-obvious behavioral detail an agent cannot get from annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and accepted formats are front-loaded in the first clause, then usage, sibling routing, PDF caveat, and error behavior follow in descending priority. Every sentence carries distinct information; the 'exposes a tampered or mismatched PDF' clause is a short payoff, not padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter read tool with a full output schema and complete annotations, the description supplies everything else an agent needs: accepted syntaxes, output contract, failure mode, and the three sibling-routing decisions. Nothing material is left to inference.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both parameters already document the 'provide this OR pdfBase64' exclusivity, so the baseline is 3. The description reinforces that a PDF path exists and explains what the embedded XML yields, but it adds no format or precedence detail beyond what the schema states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource (reads an e-invoice into a structured invoice object) and enumerates the exact accepted syntaxes (CII, UBL, XRechnung, Peppol XML, Factur-X/ZUGFeRD PDF). It goes further by tying the output to create_invoice's input shape with integer minor units, which lets an agent distinguish it from validate_invoice and convert_invoice without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit use cases (answer questions about a received invoice, edit one, re-issue it with create_invoice) and explicit exclusions with named alternatives: no rule checking, so use validate_invoice; to change syntax directly, use convert_invoice. This is the full when/when-not/alternative triad.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validate_invoiceValidate an e-invoiceARead-onlyIdempotent
Checks an e-invoice against the official rule sets on this machine: the XSD, the EN 16931 Schematron from CEN, and the KoSIT XRechnung or Peppol BIS rules when the document declares them. Use it before sending an invoice you created and when you receive one. To read the invoice's data use parse_invoice; to explain one failed rule in depth use explain_validation_rule. Accepts XML or a Factur-X / ZUGFeRD PDF, whose embedded XML is checked; syntax and profile are detected from the document. A valid result means the listed ruleSets passed, not that a tax authority or buyer will accept the invoice, so report which rule sets ran and never claim more. Each failure carries the publisher's message and, for common rules, a plain-language fix. Input that is not an invoice comes back as an error result, not as invalid. The check runs offline; nothing is uploaded.
| Name | Required | Description | Default |
|---|---|---|---|
| xml | No | The invoice as XML text (CII, UBL Invoice/CreditNote, XRechnung, Peppol BIS). Provide this OR pdfBase64. | |
| xsd | No | Run XSD validation too. Default true. | |
| country | No | Add a country layer: "FR" runs the French CTC rules (CII only); "DE" reports whether the profile is acceptable for German B2B (MINIMUM and BASIC WL are not). | |
| profile | No | Force the rule set instead of reading it from BT-24. | |
| pdfBase64 | No | A Factur-X / ZUGFeRD PDF/A-3 as base64; the embedded XML is used. Provide this OR xml. |
Output Schema
| Name | Required | Description |
|---|---|---|
| xsd | Yes | XML Schema check. |
| valid | Yes | True only when no error-level rule failed, the XSD did not fail, and no error-level notice was raised. |
| origin | Yes | Whether the input was XML or a PDF. |
| notices | Yes | Findings about the document that are not Schematron rules, e.g. an unrecognised profile, or (with country DE) a profile not acceptable for German B2B. An error-level notice makes valid false. |
| detected | Yes | What the document declares about itself. |
| failures | Yes | Error-level rules that failed; any entry makes valid false. |
| ruleSets | Yes | Exactly the rule sets that ran. Report these; do not claim checks that are not listed. |
| advisories | Yes | Warning or info rules that fired; they do not make the invoice invalid. |
| firedCount | Yes | Schematron rules that fired across all rule sets. |
| embeddedFilename | No | PDF only: name of the embedded XML that was checked. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive and closed-world, and the description still adds substantial context: rule-set detection from the document, that `valid` only means the listed `ruleSets` passed and implies no tax-authority acceptance, that non-invoice input yields an error rather than an invalid verdict, and that the check is offline with no upload. This is exactly the kind of scope-limiting detail annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded and each sentence carries information — the valid/ruleSets caveat and the error-vs-invalid distinction are high-value. It is somewhat dense and the accepted-input sentence sits mid-paragraph rather than next to the purpose, but nothing is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values needn't be explained, yet the description still pre-empts the main misinterpretation risk (over-claiming acceptance) and notes that failures carry the publisher's message plus plain-language fixes. Nothing an agent needs in order to call it and report results correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real meaning: it clarifies that syntax and profile are auto-detected unless overridden, and that for a Factur-X/ZUGFeRD PDF the embedded XML is what gets checked. The remaining parameters (xsd, country) are left entirely to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — checking an e-invoice against named rule sets (XSD, EN 16931 Schematron, KoSIT XRechnung/Peppol BIS) — and explicitly distinguishes itself from parse_invoice and explain_validation_rule. An agent can identify the tool without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use guidance (before sending an invoice you created, and when receiving one) and names both alternatives with the condition that selects them. No inference required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
- Changed
validate_invoice4 fields changed- added
Output schema / properties / failures / items / properties / elementAdded value: +{ + "description": "The offending element without namespaces, e.g. LineTotalAmount.", + "type": "string" +} - added
Output schema / properties / failures / items / properties / lineAdded value: +{ + "description": "1-based invoice line number when the node is inside an invoice line.", + "type": "integer" +} - added
Output schema / properties / failures / items / properties / pathAdded value: +{ + "description": "A short readable path, e.g. \"line 1 > NetPriceProductTradePrice > ChargeAmount\". xpath is the exact location.", + "type": "string" +} - changed
Output schema / properties / failures / items / properties / plainLanguage / descriptionPrevious value: -"Plain-language explanation and fix, present for common rules."New value: +"Plain-language explanation and fix, present for common rules and for the syntax rules (CII-DT, CII-SR, UBL-CR, UBL-DT, UBL-SR)."
7 tool updates
- Changed
convert_invoice3 fields changed- added
Output schema / properties / format / descriptionAdded value: +"The syntax that was written." - added
Output schema / properties / warnings / descriptionAdded value: +"Non-fatal findings, e.g. data the target requires that the source does not have." - added
Output schema / properties / xml / descriptionAdded value: +"The invoice in the target syntax."
- Changed
create_invoice2 fields changed- added
Output schema / properties / format / descriptionAdded value: +"The syntax that was written." - added
Output schema / properties / xml / descriptionAdded value: +"The e-invoice XML, ready to send or to pass to validate_invoice."
- Changed
create_invoice_pdf5 fields changed- added
Output schema / properties / byteLength / descriptionAdded value: +"Size of the PDF in bytes." - added
Output schema / properties / conformanceLevel / descriptionAdded value: +"Conformance level declared in the PDF metadata, e.g. EN 16931." - added
Output schema / properties / profile / descriptionAdded value: +"The Factur-X / ZUGFeRD profile written." - added
Output schema / properties / sha256 / descriptionAdded value: +"SHA-256 of the PDF bytes, hex; equal for equal input." - added
Output schema / properties / warnings / descriptionAdded value: +"Non-fatal findings about the invoice data."
- Changed
explain_validation_rule9 fields changed- added
Output schema / properties / found / descriptionAdded value: +"False when no compiled rule set knows this id." - added
Output schema / properties / official / descriptionAdded value: +"Official wording, one entry per rule set that defines the id." - added
Output schema / properties / official / items / properties / ruleSet / descriptionAdded value: +"Rule set containing the rule." - added
Output schema / properties / official / items / properties / text / descriptionAdded value: +"The publisher's wording of the rule." - added
Output schema / properties / plainLanguage / descriptionAdded value: +"Plain-language explanation, when one exists for this rule." - added
Output schema / properties / plainLanguage / properties / fix / descriptionAdded value: +"How to change the invoice so the rule passes." - added
Output schema / properties / plainLanguage / properties / summary / descriptionAdded value: +"What the rule requires, in plain language." - added
Output schema / properties / plainLanguage / properties / why / descriptionAdded value: +"Why the rule exists or why it typically fires." - added
Output schema / properties / ruleId / descriptionAdded value: +"The rule id as looked up."
- Changed
get_country_requirements6 fields changed- added
Output schema / properties / conformoSupport / additionalProperties / properties / generate / descriptionAdded value: +"This server can create the format." - added
Output schema / properties / conformoSupport / additionalProperties / properties / note / descriptionAdded value: +"Limits that apply." - added
Output schema / properties / conformoSupport / additionalProperties / properties / read / descriptionAdded value: +"This server can read the format." - added
Output schema / properties / conformoSupport / additionalProperties / properties / validate / descriptionAdded value: +"This server can validate the format." - added
Output schema / properties / conformoSupport / descriptionAdded value: +"Per required format, what this server can do with it." - added
Output schema / properties / country / descriptionAdded value: +"ISO 3166-1 alpha-2 code of the country returned."
- Changed
parse_invoice3 fields changed- added
Output schema / properties / embeddedFilename / descriptionAdded value: +"PDF only: name of the embedded XML that was read." - added
Output schema / properties / format / descriptionAdded value: +"Syntax of the source document." - added
Output schema / properties / origin / descriptionAdded value: +"Whether the input was XML or a PDF."
- Changed
validate_invoice36 fields changed- changed
Input schema / properties / country / descriptionPrevious value: -"Add a country layer on top of EN 16931."New value: +"Add a country layer: \"FR\" runs the French CTC rules (CII only); \"DE\" reports whether the profile is acceptable for German B2B (MINIMUM and BASIC WL are not)." - added
Output schema / properties / advisories / descriptionAdded value: +"Warning or info rules that fired; they do not make the invoice invalid." - added
Output schema / properties / detected / descriptionAdded value: +"What the document declares about itself." - added
Output schema / properties / detected / properties / businessProcess / descriptionAdded value: +"BT-23 business process, when present." - added
Output schema / properties / detected / properties / customizationId / descriptionAdded value: +"The BT-24 specification identifier as written in the document." - added
Output schema / properties / detected / properties / profile / descriptionAdded value: +"Profile read from BT-24: en16931, xrechnung, peppol, extended, minimum, basicwl or unknown." - added
Output schema / properties / detected / properties / syntax / descriptionAdded value: +"cii, ubl-invoice or ubl-credit-note." - added
Output schema / properties / detected / properties / variant / descriptionAdded value: +"XRechnung only: standard, extension or cvd." - added
Output schema / properties / embeddedFilename / descriptionAdded value: +"PDF only: name of the embedded XML that was checked." - added
Output schema / properties / failures / descriptionAdded value: +"Error-level rules that failed; any entry makes valid false." - added
Output schema / properties / failures / items / properties / fields / descriptionAdded value: +"BT and BG ids named in the official message, in order." - added
Output schema / properties / failures / items / properties / message / descriptionAdded value: +"The publisher's own message for this rule." - added
Output schema / properties / failures / items / properties / plainLanguage / descriptionAdded value: +"Plain-language explanation and fix, present for common rules." - added
Output schema / properties / failures / items / properties / plainLanguage / properties / fix / descriptionAdded value: +"How to change the invoice so the rule passes." - added
Output schema / properties / failures / items / properties / plainLanguage / properties / summary / descriptionAdded value: +"What the rule requires, in plain language." - added
Output schema / properties / failures / items / properties / plainLanguage / properties / why / descriptionAdded value: +"Why the rule exists or why it typically fires." - added
Output schema / properties / failures / items / properties / ruleId / descriptionAdded value: +"Rule id from the publisher, e.g. BR-CO-15 or BR-DE-15." - added
Output schema / properties / failures / items / properties / ruleSet / descriptionAdded value: +"Id of the rule set the rule belongs to (see ruleSets)." - added
Output schema / properties / failures / items / properties / severity / descriptionAdded value: +"error and fatal fail the invoice; warning and info do not. Effective level after the publisher's own re-levelling." - added
Output schema / properties / failures / items / properties / xpath / descriptionAdded value: +"Where in the XML the rule fired." - added
Output schema / properties / notices / descriptionAdded value: +"Findings about the document that are not Schematron rules, e.g. an unrecognised profile, or (with country DE) a profile not acceptable for German B2B. An error-level notice makes valid false." - added
Output schema / properties / origin / descriptionAdded value: +"Whether the input was XML or a PDF." - added
Output schema / properties / ruleSets / descriptionAdded value: +"Exactly the rule sets that ran. Report these; do not claim checks that are not listed." - added
Output schema / properties / ruleSets / items / properties / advisory / descriptionAdded value: +"Warning or info rules that fired without failing the invoice." - added
Output schema / properties / ruleSets / items / properties / failed / descriptionAdded value: +"Error-level rules that failed." - added
Output schema / properties / ruleSets / items / properties / fired / descriptionAdded value: +"Rules of this set that applied to the document." - added
Output schema / properties / ruleSets / items / properties / id / descriptionAdded value: +"Rule set id, e.g. en16931-cii or xrechnung-cii." - added
Output schema / properties / ruleSets / items / properties / label / descriptionAdded value: +"Human-readable name." - added
Output schema / properties / ruleSets / items / properties / source / descriptionAdded value: +"Publisher and version of the official artefact that ran." - added
Output schema / properties / valid / descriptionAdded value: +"True only when no error-level rule failed, the XSD did not fail, and no error-level notice was raised." - added
Output schema / properties / xsd / descriptionAdded value: +"XML Schema check." - added
Output schema / properties / xsd / properties / errors / descriptionAdded value: +"XSD errors, empty when valid." - added
Output schema / properties / xsd / properties / ran / descriptionAdded value: +"Whether XSD validation ran." - added
Output schema / properties / xsd / properties / schema / descriptionAdded value: +"The XSD used." - added
Output schema / properties / xsd / properties / skippedReason / descriptionAdded value: +"Why XSD did not run, when it did not." - added
Output schema / properties / xsd / properties / valid / descriptionAdded value: +"XSD verdict, when it ran."
7 tool updates
v0.2.1- First observed
convert_invoice - First observed
create_invoice - First observed
create_invoice_pdf - First observed
explain_validation_rule - First observed
get_country_requirements - First observed
parse_invoice - First observed
validate_invoice
TDQS
Scored across 7 tools
Each tool has a narrowly distinct purpose, and the descriptions explicitly cross-reference siblings to steer selection (create_invoice vs create_invoice_pdf vs convert_invoice; validate_invoice vs explain_validation_rule vs parse_invoice; get_country_requirements is clearly advisory only). There is no pair an agent could plausibly confuse.
All seven names follow a consistent snake_case verb_noun pattern (create_, validate_, convert_, parse_, explain_, get_). The single compound suffix create_invoice_pdf follows the same convention and reads naturally alongside create_invoice.
Seven tools is tightly scoped to the e-invoicing lifecycle, with each tool earning its place: two creation targets (XML, PDF), parsing, conversion, validation, rule explanation, and country requirements. Nothing looks redundant or padded.
The surface covers the full document lifecycle: build (XML/PDF), read (parse), transform (convert), check (validate), explain failures, and decide format per country. Minor gaps remain, such as no tool to enumerate supported rule sets/profiles or to bulk-validate, but parse → edit → create covers the update case.
Maintenance
Related MCP Connectors
Validate, generate & convert EU e-invoices (UBL, CII, XRechnung, Factur-X) — EN 16931 pre-validated.
Create, validate, convert & extract compliant e-invoices (UBL, Factur-X, ZUGFeRD, XRechnung)
Generate & validate EN 16931 e-invoices (Factur-X, ZUGFeRD, XRechnung); verification certificates
Validate, generate, convert and extract EN 16931 e-invoices for businesses.
Related MCP Servers
AlicenseNot gradedqualityBmaintenanceInvoiceXML brings e-invoice compliance to your AI agent. Create, validate, convert, render, and extract structured invoices across UBL (Peppol BIS Billing 3.0, used worldwide), CII, Factur-X, ZUGFeRD, and XRechnung, all checked against the EN 16931 standard and official Schematron rules. Ask your assistant to generate a compliant invoice, validate one for errors, or convert between formats, with n5MIT- AlicenseNot gradedqualityDmaintenanceEnables autonomous agents to validate, audit, and correct e-invoices against European standards (EN16931) and Peppol regulations.1MIT
- AlicenseAqualityDmaintenanceValidates EU electronic invoices (Peppol, XRechnung, FatturaPA, etc.) and explains validation error codes, enabling AI coding agents to check invoice validity and get fixes before rejection.339 npmMIT
- FlicenseNot gradedqualityBmaintenanceEnables AI agents to create and manage e-invoices through natural language, supporting EU compliance formats like ZUGFeRD and XRechnung, as well as US plain PDF invoices.7-