beliq-mcp 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -71,9 +71,26 @@ Add to `~/.cursor/mcp.json` (or a project `.cursor/mcp.json`) using the same `mc
71
71
 
72
72
  `beliq_parse_einvoice` returns the detected `format` and `profileDetected` plus the extracted `invoice` object (EN 16931 fields: number, dates, currency, seller, buyer, lines, totals, and any national extensions present).
73
73
 
74
- `beliq_generate_einvoice` returns the `output` kind (`xml` or `pdf`), the `contentType`, and the `schematronVersion` the document was checked against. An XML document is also returned inline as `xml`; a PDF (and an XML when you set `outputPath`) is written to disk, and the call reports `outputPath` and `bytesWritten`. It does not overwrite an existing file: pick a path that does not exist.
75
-
76
- `beliq_convert_einvoice` returns the `output` kind, the resolved `sourceFormat` and `targetFormat`, and `lostElementsCount`/`lostElements` for anything the conversion could not carry across. An XML target comes back inline as `xml`; a PDF target (facturx / zugferd) is written to `outputPath`. Like generate, it never overwrites an existing file.
74
+ `beliq_generate_einvoice` returns a short text summary (with the XML document appended for XML output) plus a structured result:
75
+
76
+ - `output` is `xml` or `pdf`, as requested, and `contentType` is the matching media type (`application/xml` or `application/pdf`).
77
+ - `xml` is the generated document inline, present only for XML output.
78
+ - `outputPath` and `bytesWritten` are set when the document was written to disk: always for a PDF, and for XML when you set `outputPath`. The call never overwrites an existing file, so pick a path that does not exist.
79
+ - `pdfKind` is present only for PDF output: `hybrid` (a PDF/A-3 with the XML embedded, for facturx and zugferd) or `visualization` (rendered pages with no XML inside, for xrechnung and peppol-bis, whose legal document stays the XML).
80
+ - `schematronVersion` is the ruleset (Schematron) revision the document was checked against.
81
+ - `sha256` is the lowercase-hex SHA-256 of the returned document bytes, so `sha256sum` on the file at `outputPath` reproduces it.
82
+ - `rulesetSha256` is one combined fingerprint of the rule artifacts the document was checked against, present when a ruleset ran.
83
+ - `livemode` is true for a `blq_live_` key and false for a `blq_test_` sandbox key, whose output is [marked as a specimen](https://docs.beliq.eu/api-reference/test-mode/#sandbox-markers) and is not a production invoice.
84
+ - `validationResult` is the verdict on the generated document: `valid`, the `schematronVersion` it ran, and `errors[]`/`warnings[]` in the same shape as validate returns. With the default `verify: true`, a document that fails validation comes back as a tool error instead of a result. With `verify: false` no ruleset runs: `valid` is false and `errors`/`warnings` are empty because nothing checked the document, not because it failed.
85
+
86
+ `beliq_convert_einvoice` returns a short text summary (with the XML document appended for an XML target) plus a structured result:
87
+
88
+ - `output` is `pdf` for a facturx or zugferd target and `xml` for the others, and `contentType` is the matching media type (`application/pdf` or `application/xml`).
89
+ - `xml` is the converted document inline, present only for an XML target.
90
+ - `outputPath` and `bytesWritten` are set when the document was written to disk: always for a PDF target, and for an XML target when you set `outputPath`. Like generate, it never overwrites an existing file.
91
+ - `sourceFormat` is the format the engine read, and `targetFormat` the format it produced (the `targetFormat` you asked for when the API does not name one).
92
+ - `profileDetected` is the profile the engine recognised on the source document, when it recognised one.
93
+ - `lostElementsCount` and `lostElements` count and name the source elements that had no equivalent in the target format; `0` means nothing was lost at the element level.
77
94
 
78
95
  A PDF (Factur-X / ZUGFeRD) must be passed by `documentPath` for validate, parse, and convert, not inlined as text.
79
96
 
@@ -83,7 +100,7 @@ A PDF (Factur-X / ZUGFeRD) must be passed by `documentPath` for validate, parse,
83
100
 
84
101
  ## Development
85
102
 
86
- This server depends on the published [`@beliq/sdk`](https://www.npmjs.com/package/@beliq/sdk), which carries the request, transport, and result-shaping logic. No lockfile is committed; `@beliq/sdk` is resolved fresh at install time.
103
+ This server depends on the published [`@beliq/sdk`](https://www.npmjs.com/package/@beliq/sdk), which carries the request, transport, and result-shaping logic. `package-lock.json` is committed, and CI and the release build install from it with `npm ci`.
87
104
 
88
105
  - `npm install`
89
106
  - `npm run build` - compile to `dist/`
package/dist/schema.js CHANGED
@@ -117,11 +117,11 @@ export const generateInputShape = {
117
117
  output: z
118
118
  .enum(['xml', 'pdf'])
119
119
  .optional()
120
- .describe("'xml' (default) returns the document inline. 'pdf' produces a Factur-X / ZUGFeRD hybrid PDF and needs outputPath to write it to."),
120
+ .describe("'xml' (default) returns the document inline. 'pdf' needs outputPath to write it to: for facturx and zugferd it is a hybrid PDF/A-3 with the XML embedded; xrechnung and peppol-bis have no hybrid form, so it is a visualization with no XML inside it, and their legal document stays the XML."),
121
121
  facturxProfile: z
122
122
  .enum(LIVE_PROFILES)
123
123
  .optional()
124
- .describe('Profile for a Factur-X / ZUGFeRD PDF; applies only when standard is facturx or zugferd.'),
124
+ .describe('Profile for a Factur-X / ZUGFeRD document; ignored for xrechnung and peppol-bis. extended-ctc-fr is Factur-X only: zugferd accepts basicwl, en16931 and extended.'),
125
125
  verify: z
126
126
  .boolean()
127
127
  .optional()
@@ -199,7 +199,3 @@ export const convertOutputShape = {
199
199
  bytesWritten: z.number().optional(),
200
200
  xml: z.string().optional(),
201
201
  };
202
- const validateInputSchema = z.object(validateInputShape);
203
- const parseInputSchema = z.object(parseInputShape);
204
- const generateInputSchema = z.object(generateInputShape);
205
- const convertInputSchema = z.object(convertInputShape);
@@ -3,7 +3,7 @@ import { runGenerate } from './shared.js';
3
3
  const description = [
4
4
  'Generate a compliant EU electronic invoice from an EN 16931 invoice object.',
5
5
  'Set standard to the target (xrechnung, zugferd, facturx, or peppol-bis) and pass the invoice fields.',
6
- "output 'xml' (default) returns the document inline; 'pdf' produces a Factur-X / ZUGFeRD hybrid PDF, which needs outputPath to write it to.",
6
+ "output 'xml' (default) returns the document inline; 'pdf' needs outputPath to write it to, and is a hybrid PDF/A-3 with the XML embedded for facturx and zugferd, or a visualization with no embedded XML for xrechnung and peppol-bis (whose legal document stays the XML).",
7
7
  'By default the result is validated before it is returned (verify), so a non-compliant document fails rather than coming back.',
8
8
  'beliq produces the compliant document; transmission (Peppol, PDP, KSeF, SDI), archiving, and tax-authority reporting stay with your access point.',
9
9
  ].join(' ');
@@ -1,5 +1,5 @@
1
1
  import { readFile, writeFile } from 'node:fs/promises';
2
- import { BeliqApiError } from '@beliq/sdk';
2
+ import { BeliqApiError, isProfileAllowedForStandard, profilesForStandard, } from '@beliq/sdk';
3
3
  import { summarizeConvert, summarizeGenerate, summarizeParse, summarizeValidation } from '../summary.js';
4
4
  function errorResult(message) {
5
5
  return { content: [{ type: 'text', text: message }], isError: true };
@@ -153,6 +153,15 @@ export async function runGenerate(input, deps) {
153
153
  if (output === 'pdf' && !outputPath) {
154
154
  return errorResult('A pdf output needs outputPath: the file path to write the generated PDF to.');
155
155
  }
156
+ // The SDK drops facturxProfile outside the Factur-X / ZUGFeRD family. Inside
157
+ // it the pair is still pinned: extended-ctc-fr is Factur-X only, and the API
158
+ // answers it on zugferd with 422 PROFILE_STANDARD_MISMATCH. Name the legal
159
+ // values rather than spend a call on a pair that cannot succeed.
160
+ const hybrid = input.standard === 'facturx' || input.standard === 'zugferd';
161
+ if (hybrid && input.facturxProfile && !isProfileAllowedForStandard(input.standard, input.facturxProfile)) {
162
+ return errorResult(`facturxProfile '${input.facturxProfile}' is not available for ${input.standard}. ` +
163
+ `Use one of: ${profilesForStandard(input.standard).join(', ')}.`);
164
+ }
156
165
  let result;
157
166
  try {
158
167
  result = await deps.client.generate({
@@ -160,6 +169,10 @@ export async function runGenerate(input, deps) {
160
169
  invoice: input.invoice,
161
170
  output,
162
171
  facturxProfile: input.facturxProfile,
172
+ // XRechnung and Peppol BIS have no hybrid PDF, and the API refuses PDF
173
+ // for them unless the request names a visual to render. Factur-X and
174
+ // ZUGFeRD render theirs either way, so this is inert for them.
175
+ template: output === 'pdf' ? 'standard' : undefined,
163
176
  verify: input.verify ?? true,
164
177
  // Always seal so the tool can hand back the document sha256 and the
165
178
  // validation verdict for the model to cite.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beliq-mcp",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "beliq MCP server: validate, parse, generate, and convert EU e-invoices (XRechnung, ZUGFeRD, Factur-X, Peppol BIS) against authority-pinned, drift-checked rules, for MCP clients.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -56,16 +56,16 @@
56
56
  "prepublishOnly": "npm run build"
57
57
  },
58
58
  "dependencies": {
59
- "@beliq/sdk": "^0.3.0",
59
+ "@beliq/sdk": "^0.4.0",
60
60
  "@modelcontextprotocol/sdk": "^1.29.0",
61
61
  "zod": "^4.4.3"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@types/node": "^20.14.0",
65
- "@typescript-eslint/eslint-plugin": "^7.18.0",
66
- "@typescript-eslint/parser": "^7.18.0",
65
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
66
+ "@typescript-eslint/parser": "^8.0.0",
67
67
  "eslint": "^8.57.0",
68
68
  "typescript": "^5.5.4",
69
- "vitest": "^3.2.6"
69
+ "vitest": "^4.0.0"
70
70
  }
71
71
  }