revclamp-mcp 1.20.10 → 1.20.12

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
@@ -5,18 +5,18 @@
5
5
  **`revclamp-mcp`** is a standalone, zero-dependency **Open-Source Model Context Protocol (MCP) Server & CLI** (`index.mjs` + `local_engine.mjs`) implementing **9 deterministic B2B FinOps, Stripe `2025-03-31.basil`, Visa CE 3.0, EU/XI VIES VAT, Shopify Plus B2B Net-15/30/60, and Webhook Security tools** in pure Node.js.
6
6
 
7
7
  - **100% Local In-Process Execution (Default — Zero Network / Zero API Key Required):** All 9 MCP tools (`initialize`, `tools/list`, and `tools/call`) execute locally in-process inside [`local_engine.mjs`](./local_engine.mjs) using pure Node.js (`node:crypto` HMAC-SHA256 verification, integer-cent double-entry accounting, 72-hour webhook replay state machines, and `18,000` UTF-16 code unit CE 3.0 linting). Zero network calls are ever made unless `REVCLAMP_API_KEY` or `REVCLAMP_MCP_URL` is explicitly configured.
8
- - **Optional Hosted Cloud Workspace Sync (`REVCLAMP_API_KEY`):** When `REVCLAMP_API_KEY` (`rg_live_...`) is configured, `revclamp-mcp` connects to [**RevClamp Enterprise**](https://revclamp.com) (`https://api.revclamp.com/api/mcp`) to unlock the **90-day SQLite WAL usage & audit ledger**, **24/7 autonomous Stripe dispute & entitlement webhook outbox**, and **real-time EU Commission VIES SOAP gateway consultation numbers**.
8
+ - **Optional Hosted Cloud Workspace Sync (`REVCLAMP_API_KEY`):** When `REVCLAMP_API_KEY` (`rg_live_...`) is configured, `revclamp-mcp` connects to [**RevClamp Enterprise**](https://revclamp.com) (`https://api.revclamp.com/api/mcp`) to unlock the **90-day durable transactional usage & audit ledger**, **24/7 autonomous Stripe dispute & entitlement webhook outbox**, and **real-time EU Commission VIES SOAP gateway consultation numbers**.
9
9
 
10
10
  ## Local Open-Core (`local_engine.mjs`) vs. Hosted Cloud (`REVCLAMP_API_KEY`)
11
11
 
12
12
  | Capability | Local Open-Core Default (Zero API Key) | Hosted Cloud (`REVCLAMP_API_KEY`) |
13
13
  | :--- | :--- | :--- |
14
14
  | **Execution & Network** | 100% in-process (`local_engine.mjs`), zero network calls | HTTPS JSON-RPC to `https://api.revclamp.com/api/mcp` (`redirect: "error"`) |
15
- | **Usage & Audit Storage** | Stateless evaluation of caller-supplied JSON snapshots | **Persistent 90-day SQLite WAL ledger** + Stripe historical backfill |
15
+ | **Usage & Audit Storage** | Stateless evaluation of caller-supplied JSON snapshots | **Persistent 90-day durable transactional ledger** + Stripe historical backfill |
16
16
  | **Dispute & Entitlement Action** | Returns non-destructive `submit: false` draft & `revoke_entitlement` decision | **24/7 autonomous Stripe webhook outbox** (`disputes.update` & signed revoke webhooks) |
17
17
  | **EU & `XI` B2B VAT (`VIES`)** | Deterministic syntax & `GR -> EL` normalization (`FORMAT_ONLY` default, `valid: null`) | **Live EU Commission VIES SOAP consultation IDs** + circuit-breaker retry queue (`viesMode: "LIVE"` + `REVCLAMP_API_KEY`) |
18
18
  | **Monthly Event Tiers** | Unlimited local in-process evaluations (0 network cost) | **Free Sandbox** (`5,000` events/mo) · **Starter $19/mo** (`100k`) · **Growth $59/mo** (`1M`) · **Scale $199/mo** (`5M`) |
19
- | **Data Privacy (`INV-SAAS-04`)** | Nothing ever leaves your machine | Only explicit `tools/call` arguments are sent over TLS after local live-secret scrubbing (`scanMcpClientPayloadForSecrets` in `index.mjs` blocks `sk_live_`, non-test `whsec_`, `shpat_` locally) |
19
+ | **Data Minimization & Privacy** | Nothing ever leaves your machine | Only explicit `tools/call` arguments are sent over TLS after local live-secret scrubbing (blocks `sk_live_`, non-test `whsec_`, and `shpat_` locally before any network request) |
20
20
 
21
21
  ## Open-Source MCP Tools Implemented in `local_engine.mjs` (9)
22
22
 
@@ -59,13 +59,13 @@ curl -sS -X POST https://api.revclamp.com/api/mcp \
59
59
 
60
60
  ```bash
61
61
  # Run a <60s local CLI smoke check (verifies all 9 tool schemas & executes a local_engine.mjs sample audit with zero API key)
62
- npx -y github:lhphong09t2/revclamp-mcp#v1.20.10 --self-test
62
+ npx -y github:lhphong09t2/revclamp-mcp#v1.20.12 --self-test
63
63
 
64
64
  # Provision a free Cloud Workspace (or reuse REVCLAMP_API_KEY) & send a 6-digit login OTP
65
- npx -y revclamp-mcp@1.20.10 --init-workspace you@company.com
65
+ npx -y revclamp-mcp@1.20.12 --init-workspace you@company.com
66
66
 
67
67
  # Verify the 6-digit OTP using REVCLAMP_API_KEY from environment
68
- REVCLAMP_API_KEY="rg_live_..." npx -y revclamp-mcp@1.20.10 --verify-otp you@company.com 123456
68
+ REVCLAMP_API_KEY="rg_live_..." npx -y revclamp-mcp@1.20.12 --verify-otp you@company.com 123456
69
69
 
70
70
  # List all 9 MCP tools and JSON schemas (runs locally in-process)
71
71
  node index.mjs --list-tools
package/index.mjs CHANGED
@@ -33,7 +33,7 @@ export {
33
33
  executeLocalMcpJsonRpc,
34
34
  };
35
35
 
36
- export const PACKAGE_VERSION = "1.20.10";
36
+ export const PACKAGE_VERSION = "1.20.12";
37
37
  export const DEFAULT_MCP_ENDPOINT = "https://api.revclamp.com/api/mcp";
38
38
  export const ALLOWED_MCP_ORIGINS = Object.freeze(
39
39
  new Set([
package/local_engine.mjs CHANGED
@@ -12,7 +12,7 @@
12
12
  * caller-supplied payloads. Never fabricates live consultation IDs or card-network
13
13
  * dispute evidence unless `demo: true` is explicitly passed (`sample: true`).
14
14
  * - Cloud Workspace Mode (`REVCLAMP_API_KEY` on https://api.revclamp.com/api/mcp):
15
- * Unlocks the 90-day SQLite WAL usage ledger, 24/7 autonomous Stripe dispute &
15
+ * Unlocks the 90-day durable transactional usage ledger, 24/7 autonomous Stripe dispute &
16
16
  * entitlement webhook outbox, and live European Commission VIES consultation IDs.
17
17
  */
18
18
 
@@ -58,6 +58,24 @@ const LOCAL_MCP_TOOL_ARG_ALIAS_GROUPS = Object.freeze({
58
58
  aliases: Object.freeze(["windowSec", "dedupWindowSec"]),
59
59
  }),
60
60
  ]),
61
+ revclamp_validate_eu_vat_vies: Object.freeze([
62
+ Object.freeze({
63
+ canonical: "sellerCountry",
64
+ aliases: Object.freeze(["sellerCountryCode", "seller_country", "seller_country_code"]),
65
+ }),
66
+ Object.freeze({
67
+ canonical: "buyerVatId",
68
+ aliases: Object.freeze(["vatId", "buyer_vat_id"]),
69
+ }),
70
+ Object.freeze({
71
+ canonical: "viesMode",
72
+ aliases: Object.freeze(["vies_mode"]),
73
+ }),
74
+ Object.freeze({
75
+ canonical: "supplyType",
76
+ aliases: Object.freeze(["supply_type"]),
77
+ }),
78
+ ]),
61
79
  });
62
80
 
63
81
  export function normalizeMcpToolArgs(toolName, rawArgs) {
@@ -145,7 +163,7 @@ export const LOCAL_MCP_RESOURCES = Object.freeze([
145
163
  uri: "revclamp://docs/open-core-capabilities",
146
164
  name: "RevClamp Open-Core vs Hosted Cloud Capabilities",
147
165
  description:
148
- "Reference summary of the 9 local deterministic MCP tools vs. hosted REVCLAMP_API_KEY capabilities (90-day SQLite WAL ledger, 24/7 Stripe webhook outbox, and live EU VIES consultation IDs).",
166
+ "Reference summary of the 9 local deterministic MCP tools vs. hosted REVCLAMP_API_KEY capabilities (90-day durable transactional ledger, 24/7 Stripe webhook outbox, and live EU VIES consultation IDs).",
149
167
  mimeType: "application/json",
150
168
  }),
151
169
  ]);
@@ -189,7 +207,7 @@ const EU_VIES_FORMAT_RULES = Object.freeze({
189
207
  DK: /^DK\d{8}$/,
190
208
  EE: /^EE\d{9}$/,
191
209
  EL: /^EL\d{9}$/,
192
- ES: /^ES[A-Z0-9]\d{7}[A-Z0-9]$/,
210
+ ES: /^ES(?:[A-Z]\d{7}[A-Z0-9]|[0-9]\d{7}[A-Z])$/,
193
211
  FI: /^FI\d{8}$/,
194
212
  FR: /^FR[A-HJ-NP-Z0-9]{2}\d{9}$/,
195
213
  HR: /^HR\d{11}$/,
@@ -210,6 +228,384 @@ const EU_VIES_FORMAT_RULES = Object.freeze({
210
228
  XI: /^XI(?:\d{9}|\d{12}|(?:GD|HA)\d{3})$/,
211
229
  });
212
230
 
231
+ export const EU_VIES_STATUTORY_TERMINOLOGY_MAP = Object.freeze({
232
+ AT: Object.freeze({
233
+ memberState: "AT",
234
+ countryNameEn: "Austria",
235
+ nativeCountryName: "Österreich",
236
+ taxIdAcronym: "UID",
237
+ nativeTaxIdName: "Umsatzsteuer-Identifikationsnummer",
238
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
239
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
240
+ statutoryReverseChargeClause:
241
+ "Steuerschuldnerschaft des Leistungsempfängers – Art. 196 & Art. 226 Nr. 11a MwStSystRL (Directive 2006/112/EC, § 19 UStG) / Reverse charge (B2B services)",
242
+ statutoryGoodsExemptionClause:
243
+ "Steuerfreie innergemeinschaftliche Lieferung – Art. 138 Abs. 1 & Art. 226 Nr. 11 MwStSystRL (Directive 2006/112/EC, Art. 6 Abs. 1 UStG) / Intra-Community exempt supply of goods",
244
+ }),
245
+ BE: Object.freeze({
246
+ memberState: "BE",
247
+ countryNameEn: "Belgium",
248
+ nativeCountryName: "België / Belgique",
249
+ taxIdAcronym: "N° TVA / BTW-nr.",
250
+ nativeTaxIdName: "Numéro de TVA / Btw-identificatienummer",
251
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
252
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
253
+ statutoryReverseChargeClause:
254
+ "Autoliquidation / Btw verlegd – Art. 196 & Art. 226(11a) Directive 2006/112/EC / Reverse charge (B2B services)",
255
+ statutoryGoodsExemptionClause:
256
+ "Livraison intracommunautaire exonérée / Vrijgestelde intracommunautaire levering – Art. 138(1) & Art. 226(11) Directive 2006/112/EC (Art. 39bis CTVA/WBTW) / Intra-Community exempt supply of goods",
257
+ }),
258
+ BG: Object.freeze({
259
+ memberState: "BG",
260
+ countryNameEn: "Bulgaria",
261
+ nativeCountryName: "България",
262
+ taxIdAcronym: "ДДС номер",
263
+ nativeTaxIdName: "Идентификационен номер по ДДС (ЗДДС)",
264
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
265
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
266
+ statutoryReverseChargeClause:
267
+ "Обратно начисляване – чл. 196 и чл. 226, т. 11а от Директива 2006/112/ЕО (чл. 82, ал. 2 ЗДДС) / Reverse charge (B2B services)",
268
+ statutoryGoodsExemptionClause:
269
+ "Освободена вътреобщностна доставка на стоки – чл. 138, пар. 1 и чл. 226, т. 11 от Директива 2006/112/ЕО (чл. 7 и чл. 53 ЗДДС) / Intra-Community exempt supply of goods",
270
+ }),
271
+ CY: Object.freeze({
272
+ memberState: "CY",
273
+ countryNameEn: "Cyprus",
274
+ nativeCountryName: "Κύπρος",
275
+ taxIdAcronym: "ΑΦΜ / ΦΠΑ",
276
+ nativeTaxIdName: "Αριθμός Εγγραφής ΦΠΑ",
277
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
278
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
279
+ statutoryReverseChargeClause:
280
+ "Αντίστροφη επιβάρυνση – Άρθρα 196 & 226(11α) Οδηγίας 2006/112/ΕΚ / Reverse charge (B2B services)",
281
+ statutoryGoodsExemptionClause:
282
+ "Απαλλασσόμενη ενδοκοινοτική παράδοση αγαθών – Άρθρα 138(1) & 226(11) Οδηγίας 2006/112/ΕΚ / Intra-Community exempt supply of goods",
283
+ }),
284
+ CZ: Object.freeze({
285
+ memberState: "CZ",
286
+ countryNameEn: "Czechia",
287
+ nativeCountryName: "Česká republika",
288
+ taxIdAcronym: "DIČ",
289
+ nativeTaxIdName: "Daňové identifikační číslo",
290
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
291
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
292
+ statutoryReverseChargeClause:
293
+ "Daň odvede zákazník – čl. 196 a čl. 226 bod 11a směrnice 2006/112/ES / Reverse charge (B2B services)",
294
+ statutoryGoodsExemptionClause:
295
+ "Osvobozené dodání zboží do jiného členského státu – čl. 138 odst. 1 a čl. 226 bod 11 směrnice 2006/112/ES (§ 64 ZDPH) / Intra-Community exempt supply of goods",
296
+ }),
297
+ DE: Object.freeze({
298
+ memberState: "DE",
299
+ countryNameEn: "Germany",
300
+ nativeCountryName: "Deutschland",
301
+ taxIdAcronym: "USt-IdNr.",
302
+ nativeTaxIdName: "Umsatzsteuer-Identifikationsnummer",
303
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
304
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
305
+ statutoryReverseChargeClause:
306
+ "Steuerschuldnerschaft des Leistungsempfängers – Art. 196 & Art. 226 Nr. 11a MwStSystRL (Directive 2006/112/EC, § 13b UStG) / Reverse charge (B2B services)",
307
+ statutoryGoodsExemptionClause:
308
+ "Steuerfreie innergemeinschaftliche Lieferung – Art. 138 Abs. 1 & Art. 226 Nr. 11 MwStSystRL (Directive 2006/112/EC, § 4 Nr. 1b i.V.m. § 6a UStG) / Intra-Community exempt supply of goods",
309
+ }),
310
+ DK: Object.freeze({
311
+ memberState: "DK",
312
+ countryNameEn: "Denmark",
313
+ nativeCountryName: "Danmark",
314
+ taxIdAcronym: "CVR / SE-nr.",
315
+ nativeTaxIdName: "Momsregistreringsnummer (CVR/SE)",
316
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
317
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
318
+ statutoryReverseChargeClause:
319
+ "Omvendt betalingspligt – Art. 196 & Art. 226, nr. 11a, i direktiv 2006/112/EF / Reverse charge (B2B services)",
320
+ statutoryGoodsExemptionClause:
321
+ "Momsfri EU-vareleverance – Art. 138, stk. 1, og Art. 226, nr. 11, i direktiv 2006/112/EF (ML § 34, stk. 1, nr. 1) / Intra-Community exempt supply of goods",
322
+ }),
323
+ EE: Object.freeze({
324
+ memberState: "EE",
325
+ countryNameEn: "Estonia",
326
+ nativeCountryName: "Eesti",
327
+ taxIdAcronym: "KMKR",
328
+ nativeTaxIdName: "Käibemaksukohustuslase registreerimisnumber",
329
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
330
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
331
+ statutoryReverseChargeClause:
332
+ "Pöördmaksustamine – direktiivi 2006/112/EÜ art 196 ja art 226 p 11a / Reverse charge (B2B services)",
333
+ statutoryGoodsExemptionClause:
334
+ "Ühendusesisene kauba käive (0% KM) – direktiivi 2006/112/EÜ art 138 lg 1 ja art 226 p 11 (KMS § 15 lg 3 p 2) / Intra-Community exempt supply of goods",
335
+ }),
336
+ EL: Object.freeze({
337
+ memberState: "EL",
338
+ countryNameEn: "Greece",
339
+ nativeCountryName: "Ελλάδα",
340
+ taxIdAcronym: "ΑΦΜ",
341
+ nativeTaxIdName: "Αριθμός Φορολογικού Μητρώου (ΦΠΑ)",
342
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
343
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
344
+ statutoryReverseChargeClause:
345
+ "Αντίστροφη επιβάρυνση – Άρθρα 196 & 226(11α) Οδηγίας 2006/112/ΕΚ / Reverse charge (B2B services)",
346
+ statutoryGoodsExemptionClause:
347
+ "Απαλλασσόμενη ενδοκοινοτική παράδοση αγαθών – Άρθρα 138(1) & 226(11) Οδηγίας 2006/112/ΕΚ (Άρθρο 28 Κώδικα ΦΠΑ) / Intra-Community exempt supply of goods",
348
+ }),
349
+ ES: Object.freeze({
350
+ memberState: "ES",
351
+ countryNameEn: "Spain",
352
+ nativeCountryName: "España",
353
+ taxIdAcronym: "NIF-IVA",
354
+ nativeTaxIdName: "Número de Identificación Fiscal (ROI / NIF-IVA)",
355
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
356
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
357
+ statutoryReverseChargeClause:
358
+ "Inversión del sujeto pasivo – Art. 196 y Art. 226.11 bis Directiva 2006/112/CE (Art. 84 LIVA) / Reverse charge (B2B services)",
359
+ statutoryGoodsExemptionClause:
360
+ "Entrega intracomunitaria exenta de bienes – Art. 138.1 y Art. 226.11 Directiva 2006/112/CE (Art. 25 LIVA) / Intra-Community exempt supply of goods",
361
+ }),
362
+ FI: Object.freeze({
363
+ memberState: "FI",
364
+ countryNameEn: "Finland",
365
+ nativeCountryName: "Suomi",
366
+ taxIdAcronym: "ALV-nro",
367
+ nativeTaxIdName: "Arvonlisäverotunniste (Y-tunnus)",
368
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
369
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
370
+ statutoryReverseChargeClause:
371
+ "Käännetty verovelvollisuus – direktiivin 2006/112/EY 196 art. ja 226 art. 11a kohta / Reverse charge (B2B services)",
372
+ statutoryGoodsExemptionClause:
373
+ "Veroton yhteisömyynti – direktiivin 2006/112/EY 138 art. 1 kohta ja 226 art. 11 kohta (AVL 72 a §) / Intra-Community exempt supply of goods",
374
+ }),
375
+ FR: Object.freeze({
376
+ memberState: "FR",
377
+ countryNameEn: "France",
378
+ nativeCountryName: "France",
379
+ taxIdAcronym: "N° TVA",
380
+ nativeTaxIdName: "Numéro de TVA intracommunautaire",
381
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
382
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
383
+ statutoryReverseChargeClause:
384
+ "Autoliquidation – Art. 196 et Art. 226, point 11 bis, de la Directive 2006/112/CE (CGI art. 283-2) / Reverse charge (B2B services)",
385
+ statutoryGoodsExemptionClause:
386
+ "Exonération de TVA – Livraison intracommunautaire de biens – Art. 138, par. 1, et Art. 226, point 11, Directive 2006/112/CE (CGI art. 262 ter I) / Intra-Community exempt supply of goods",
387
+ }),
388
+ HR: Object.freeze({
389
+ memberState: "HR",
390
+ countryNameEn: "Croatia",
391
+ nativeCountryName: "Hrvatska",
392
+ taxIdAcronym: "PDV ID / OIB",
393
+ nativeTaxIdName: "PDV identifikacijski broj (OIB)",
394
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
395
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
396
+ statutoryReverseChargeClause:
397
+ "Prijenos porezne obveze – čl. 196. i čl. 226. t. 11.a Direktive 2006/112/EZ / Reverse charge (B2B services)",
398
+ statutoryGoodsExemptionClause:
399
+ "Oslobođena isporuka dobara unutar EU – čl. 138. st. 1. i čl. 226. t. 11. Direktive 2006/112/EZ (čl. 41. st. 1. Zakona o PDV-u) / Intra-Community exempt supply of goods",
400
+ }),
401
+ HU: Object.freeze({
402
+ memberState: "HU",
403
+ countryNameEn: "Hungary",
404
+ nativeCountryName: "Magyarország",
405
+ taxIdAcronym: "Közösségi adószám",
406
+ nativeTaxIdName: "Közösségi adószám (EU ÁFA)",
407
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
408
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
409
+ statutoryReverseChargeClause:
410
+ "Fordított adózás – a 2006/112/EK irányelv 196. cikke és 226. cikkének 11a. pontja / Reverse charge (B2B services)",
411
+ statutoryGoodsExemptionClause:
412
+ "Adómentes Közösségen belüli termékértékesítés – a 2006/112/EK irányelv 138. cikk (1) bek. és 226. cikk 11. pontja (Áfa tv. 89. §) / Intra-Community exempt supply of goods",
413
+ }),
414
+ IE: Object.freeze({
415
+ memberState: "IE",
416
+ countryNameEn: "Ireland",
417
+ nativeCountryName: "Éire / Ireland",
418
+ taxIdAcronym: "VAT Reg No",
419
+ nativeTaxIdName: "Value Added Tax Registration Number",
420
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
421
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
422
+ statutoryReverseChargeClause:
423
+ "Reverse charge – Art. 196 & Art. 226(11a) Council Directive 2006/112/EC (B2B services)",
424
+ statutoryGoodsExemptionClause:
425
+ "Zero-rated intra-Community supply of goods – Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
426
+ }),
427
+ IT: Object.freeze({
428
+ memberState: "IT",
429
+ countryNameEn: "Italy",
430
+ nativeCountryName: "Italia",
431
+ taxIdAcronym: "P.IVA",
432
+ nativeTaxIdName: "Partita IVA intracomunitaria (VIES)",
433
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
434
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
435
+ statutoryReverseChargeClause:
436
+ "Inversione contabile – Art. 196 e Art. 226, punto 11-bis, Direttiva 2006/112/CE (Art. 17 DPR 633/72) / Reverse charge (B2B services)",
437
+ statutoryGoodsExemptionClause:
438
+ "Cessione intracomunitaria non imponibile di beni – Art. 138, par. 1, e Art. 226, punto 11, Direttiva 2006/112/CE (Art. 41 D.L. 331/1993) / Intra-Community exempt supply of goods",
439
+ }),
440
+ LT: Object.freeze({
441
+ memberState: "LT",
442
+ countryNameEn: "Lithuania",
443
+ nativeCountryName: "Lietuva",
444
+ taxIdAcronym: "PVM kodas",
445
+ nativeTaxIdName: "Pridėtinės vertės mokesčio mokėtojo kodas",
446
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
447
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
448
+ statutoryReverseChargeClause:
449
+ "Atvirkštinis apmokestinimas – Direktyvos 2006/112/EB 196 str. ir 226 str. 11a p. / Reverse charge (B2B services)",
450
+ statutoryGoodsExemptionClause:
451
+ "PVM neapmokestinamas prekių tiekimas į kitą ES valstybę narę – Direktyvos 2006/112/EB 138 str. 1 d. ir 226 str. 11 p. (PVMĮ 49 str.) / Intra-Community exempt supply of goods",
452
+ }),
453
+ LU: Object.freeze({
454
+ memberState: "LU",
455
+ countryNameEn: "Luxembourg",
456
+ nativeCountryName: "Lëtzebuerg / Luxembourg",
457
+ taxIdAcronym: "N° TVA",
458
+ nativeTaxIdName: "Numéro d'identification à la TVA",
459
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
460
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
461
+ statutoryReverseChargeClause:
462
+ "Autoliquidation – Art. 196 et Art. 226, point 11 bis, Directive 2006/112/CE / Reverse charge (B2B services)",
463
+ statutoryGoodsExemptionClause:
464
+ "Livraison intracommunautaire de biens exonérée – Art. 138, par. 1, et Art. 226, point 11, Directive 2006/112/CE (Art. 43 LTVA) / Intra-Community exempt supply of goods",
465
+ }),
466
+ LV: Object.freeze({
467
+ memberState: "LV",
468
+ countryNameEn: "Latvia",
469
+ nativeCountryName: "Latvija",
470
+ taxIdAcronym: "PVN Nr.",
471
+ nativeTaxIdName: "Pievienotās vērtības nodokļa reģistrācijas numurs",
472
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
473
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
474
+ statutoryReverseChargeClause:
475
+ "Nodokļa apgrieztā maksāšana – Direktīvas 2006/112/EK 196. pants un 226. panta 11.a punkts / Reverse charge (B2B services)",
476
+ statutoryGoodsExemptionClause:
477
+ "Ar 0% PVN likmi apliekama preču piegāde ES ietvaros – Direktīvas 2006/112/EK 138. panta 1. punkts un 226. panta 11. punkts (PVN likuma 43. pants) / Intra-Community exempt supply of goods",
478
+ }),
479
+ MT: Object.freeze({
480
+ memberState: "MT",
481
+ countryNameEn: "Malta",
482
+ nativeCountryName: "Malta",
483
+ taxIdAcronym: "VAT Reg. No.",
484
+ nativeTaxIdName: "Value Added Tax Registration Number",
485
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
486
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
487
+ statutoryReverseChargeClause:
488
+ "Reverse charge – Art. 196 & Art. 226(11a) Council Directive 2006/112/EC (B2B services)",
489
+ statutoryGoodsExemptionClause:
490
+ "Exempt intra-Community supply of goods – Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
491
+ }),
492
+ NL: Object.freeze({
493
+ memberState: "NL",
494
+ countryNameEn: "Netherlands",
495
+ nativeCountryName: "Nederland",
496
+ taxIdAcronym: "Btw-id",
497
+ nativeTaxIdName: "Btw-identificatienummer",
498
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
499
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
500
+ statutoryReverseChargeClause:
501
+ "Btw verlegd – Art. 196 & Art. 226 lid 11 bis Richtlijn 2006/112/EG / Reverse charge (B2B services)",
502
+ statutoryGoodsExemptionClause:
503
+ "Vrijgestelde intracommunautaire levering van goederen (0% btw) – Art. 138 lid 1 & Art. 226 lid 11 Richtlijn 2006/112/EG (Art. 9 lid 2 sub b Wet OB 1968 juncto Tabel II onderdeel a post 6) / Intra-Community exempt supply of goods",
504
+ }),
505
+ PL: Object.freeze({
506
+ memberState: "PL",
507
+ countryNameEn: "Poland",
508
+ nativeCountryName: "Polska",
509
+ taxIdAcronym: "NIP (VAT-UE)",
510
+ nativeTaxIdName: "Numer Identyfikacji Podatkowej (NIP UE)",
511
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
512
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
513
+ statutoryReverseChargeClause:
514
+ "Odwrotne obciążenie – art. 196 i art. 226 pkt 11a dyrektywy 2006/112/WE / Reverse charge (B2B services)",
515
+ statutoryGoodsExemptionClause:
516
+ "Wewnątrzwspólnotowa dostawa towarów (0% VAT) – art. 138 ust. 1 i art. 226 pkt 11 dyrektywy 2006/112/WE (art. 42 ust. 1 ustawy o VAT) / Intra-Community exempt supply of goods",
517
+ }),
518
+ PT: Object.freeze({
519
+ memberState: "PT",
520
+ countryNameEn: "Portugal",
521
+ nativeCountryName: "Portugal",
522
+ taxIdAcronym: "NIF / NIPC",
523
+ nativeTaxIdName: "Número de Identificação Fiscal (IVA)",
524
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
525
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
526
+ statutoryReverseChargeClause:
527
+ "Autoliquidação – Art. 196.º e Art. 226.º, n.º 11-A, da Diretiva 2006/112/CE / Reverse charge (B2B services)",
528
+ statutoryGoodsExemptionClause:
529
+ "Transmissão intracomunitária de bens isenta de IVA – Art. 138.º, n.º 1, e Art. 226.º, n.º 11, da Diretiva 2006/112/CE (Art. 14.º do RITI) / Intra-Community exempt supply of goods",
530
+ }),
531
+ RO: Object.freeze({
532
+ memberState: "RO",
533
+ countryNameEn: "Romania",
534
+ nativeCountryName: "România",
535
+ taxIdAcronym: "CIF / Cod TVA",
536
+ nativeTaxIdName: "Cod de înregistrare în scopuri de TVA",
537
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
538
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
539
+ statutoryReverseChargeClause:
540
+ "Taxare inversă – Art. 196 și Art. 226 pct. 11a din Directiva 2006/112/CE / Reverse charge (B2B services)",
541
+ statutoryGoodsExemptionClause:
542
+ "Livrare intracomunitară de bunuri scutită de TVA – Art. 138 alin. (1) și Art. 226 pct. 11 din Directiva 2006/112/CE (Art. 294 alin. (2) Codul Fiscal) / Intra-Community exempt supply of goods",
543
+ }),
544
+ SE: Object.freeze({
545
+ memberState: "SE",
546
+ countryNameEn: "Sweden",
547
+ nativeCountryName: "Sverige",
548
+ taxIdAcronym: "Momsnr",
549
+ nativeTaxIdName: "Momsregistreringsnummer (SE-nummer)",
550
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
551
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
552
+ statutoryReverseChargeClause:
553
+ "Omvänd betalningsskyldighet – Art. 196 & Art. 226.11a i direktiv 2006/112/EG / Reverse charge (B2B services)",
554
+ statutoryGoodsExemptionClause:
555
+ "Undantagen unionsintern leverans av varor – Art. 138.1 & Art. 226.11 i direktiv 2006/112/EG (10 kap. 42 § ML) / Intra-Community exempt supply of goods",
556
+ }),
557
+ SI: Object.freeze({
558
+ memberState: "SI",
559
+ countryNameEn: "Slovenia",
560
+ nativeCountryName: "Slovenija",
561
+ taxIdAcronym: "ID za DDV",
562
+ nativeTaxIdName: "Identifikacijska številka za DDV",
563
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
564
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
565
+ statutoryReverseChargeClause:
566
+ "Obrnjena davčna obveznost – člen 196 in člen 226(11a) Direktive 2006/112/ES / Reverse charge (B2B services)",
567
+ statutoryGoodsExemptionClause:
568
+ "Oproščena dobava blaga znotraj Unije – člen 138(1) in člen 226(11) Direktive 2006/112/ES (46. člen ZDDV-1) / Intra-Community exempt supply of goods",
569
+ }),
570
+ SK: Object.freeze({
571
+ memberState: "SK",
572
+ countryNameEn: "Slovakia",
573
+ nativeCountryName: "Slovensko",
574
+ taxIdAcronym: "IČ DPH",
575
+ nativeTaxIdName: "Identifikačné číslo pre daň z pridanej hodnoty",
576
+ directiveArticle: "Art. 196 & Art. 226(11a) Council Directive 2006/112/EC",
577
+ directiveGoodsArticle: "Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
578
+ statutoryReverseChargeClause:
579
+ "Prenesenie daňovej povinnosti – čl. 196 a čl. 226 bod 11a smernice 2006/112/ES / Reverse charge (B2B services)",
580
+ statutoryGoodsExemptionClause:
581
+ "Oslobodené dodanie tovaru do iného členského štátu – čl. 138 ods. 1 a čl. 226 bod 11 smernice 2006/112/ES (§ 43 zákona o DPH) / Intra-Community exempt supply of goods",
582
+ }),
583
+ XI: Object.freeze({
584
+ memberState: "XI",
585
+ countryNameEn: "Northern Ireland (Windsor Framework)",
586
+ nativeCountryName: "Northern Ireland (Windsor Framework)",
587
+ taxIdAcronym: "XI VAT No",
588
+ nativeTaxIdName: "Northern Ireland Protocol / Windsor Framework VAT Number (Goods Only)",
589
+ goodsOnlyProtocol: true,
590
+ directiveArticle:
591
+ "Windsor Framework (Goods Only — Services Not Covered by XI VIES) / Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
592
+ directiveGoodsArticle:
593
+ "Windsor Framework (Goods Only) / Art. 138(1) & Art. 226(11) Council Directive 2006/112/EC",
594
+ statutoryReverseChargeClause:
595
+ "N/A for B2B services under XI VIES (Windsor Framework applies to goods only under Art. 138(1) & Art. 226(11) Directive 2006/112/EC; UK/GB place-of-supply rules govern services)",
596
+ statutoryGoodsExemptionClause:
597
+ "Zero-rated intra-community supply of goods under Windsor Framework (Northern Ireland Protocol) – Art. 138(1) & Art. 226(11) Directive 2006/112/EC",
598
+ }),
599
+ });
600
+
601
+ export function getEuViesStatutoryTerminology(rawCode) {
602
+ const code = normalizeCountryCode(rawCode || "");
603
+ if (!code || !Object.prototype.hasOwnProperty.call(EU_VIES_STATUTORY_TERMINOLOGY_MAP, code)) {
604
+ return null;
605
+ }
606
+ return EU_VIES_STATUTORY_TERMINOLOGY_MAP[code];
607
+ }
608
+
213
609
  const REVCLAMP_START_MARKER = "--- BEGIN REVCLAMP CE3 EVIDENCE ---";
214
610
  const REVCLAMP_END_MARKER = "--- END REVCLAMP CE3 EVIDENCE ---";
215
611
  const REVCLAMP_BRACKET_START_MARKER = "[RevClamp Verified Product Usage Log]";
@@ -357,6 +753,13 @@ export const LOCAL_MCP_TOOLS = Object.freeze([
357
753
  properties: {
358
754
  sellerCountry: { type: "string", default: "DE" },
359
755
  buyerVatId: { type: "string" },
756
+ supplyType: {
757
+ type: "string",
758
+ enum: ["GOODS", "SERVICES"],
759
+ default: "GOODS",
760
+ description:
761
+ "Cross-border transaction supply category: 'GOODS' (Directive 2006/112/EC Art. 138(1) intra-Community supply, default; permitted for Northern Ireland XI under Windsor Framework) or 'SERVICES' (Directive 2006/112/EC Art. 196 B2B reverse charge; excluded from EU VIES for Northern Ireland XI).",
762
+ },
360
763
  viesMode: {
361
764
  type: "string",
362
765
  enum: [
@@ -655,14 +1058,20 @@ export function validateArgsAgainstSchema(schema, args) {
655
1058
  function normalizeCountryCode(raw) {
656
1059
  const clean = String(raw || "")
657
1060
  .trim()
658
- .toUpperCase();
659
- return clean === "GR" ? "EL" : clean;
1061
+ .toUpperCase()
1062
+ .replace(/[\s.\-/:_]+/g, "");
1063
+ if (clean === "GR") return "EL";
1064
+ if (clean === "GBNIR") return "XI";
1065
+ return clean;
660
1066
  }
661
1067
 
662
1068
  function normalizeVatId(rawVat) {
663
- const compact = String(rawVat || "")
1069
+ let compact = String(rawVat || "")
664
1070
  .toUpperCase()
665
- .replace(/[\s.\-/:]+/g, "");
1071
+ .replace(/[\s.\-/:_]+/g, "");
1072
+ if (compact.startsWith("GBNIR")) {
1073
+ compact = `XI${compact.slice(5)}`;
1074
+ }
666
1075
  if (compact.length < 4) {
667
1076
  return { validFormat: false, memberState: "", vatNumber: "", fullVatId: compact };
668
1077
  }
@@ -1008,14 +1417,37 @@ function evaluateLocalGhostUsage(subscriptionsEnv, usageEvent, dunningGracePerio
1008
1417
  reason: "UNMATCHED_CUSTOMER_ID",
1009
1418
  };
1010
1419
  }
1420
+ const hasPositiveCustomerIdMatch = Boolean(evCustomerId && subCus && subCus === evCustomerId);
1421
+ const hasPositiveEmailMatch = Boolean(evEmail && subEmail && subEmail === evEmail);
1422
+ if (!hasPositiveCustomerIdMatch && !hasPositiveEmailMatch) {
1423
+ return {
1424
+ ok: true,
1425
+ executionMode: "local_open_source_engine",
1426
+ isGhostUsage: false,
1427
+ decision: "HOLD_CUSTOMER_MISMATCH",
1428
+ reason: subCus ? "UNMATCHED_CUSTOMER_ID" : "UNMATCHED_CUSTOMER_EMAIL",
1429
+ };
1430
+ }
1011
1431
  const st = sub.status.trim();
1012
1432
  if (ENTITLED_SUB_STATUSES.has(st)) {
1433
+ const collectionPaused = Boolean(
1434
+ sub.pause_collection && typeof sub.pause_collection === "object"
1435
+ );
1013
1436
  return {
1014
1437
  ok: true,
1015
1438
  executionMode: "local_open_source_engine",
1016
1439
  isGhostUsage: false,
1017
1440
  decision: "ALLOW_ENTITLED",
1018
1441
  reason: "ACTIVE_SUBSCRIPTION_PRESENT",
1442
+ ...(collectionPaused
1443
+ ? {
1444
+ collectionPaused: true,
1445
+ pauseCollectionBehavior:
1446
+ typeof sub.pause_collection.behavior === "string"
1447
+ ? sub.pause_collection.behavior
1448
+ : "void",
1449
+ }
1450
+ : {}),
1019
1451
  };
1020
1452
  }
1021
1453
  if (sub.items?.has_more === true) {
@@ -1152,7 +1584,36 @@ function parseStrictIpv4Octets(str) {
1152
1584
 
1153
1585
  function normalizeIpForCe3Correlation(ip) {
1154
1586
  if (typeof ip !== "string") return null;
1155
- const clean = ip.trim().replace(/^\[|\]$/g, "").replace(/%[^\s%\]]+$/, "").trim().toLowerCase();
1587
+ let raw = ip.trim().toLowerCase();
1588
+ if (!raw || raw.includes(",")) return null;
1589
+ if (raw.startsWith("ipv4:")) {
1590
+ raw = raw.slice(5).trim();
1591
+ } else if (raw.startsWith("ipv6_64:")) {
1592
+ const v6Match = raw.match(
1593
+ /^ipv6_64:([0-9a-f]{1,4}):([0-9a-f]{1,4}):([0-9a-f]{1,4}):([0-9a-f]{1,4})$/
1594
+ );
1595
+ if (!v6Match) return null;
1596
+ return `ipv6_64:${v6Match
1597
+ .slice(1, 5)
1598
+ .map((w) => Number.parseInt(w, 16).toString(16).padStart(4, "0"))
1599
+ .join(":")}`;
1600
+ }
1601
+ const bracketPortMatch = raw.match(/^\[([^\]]+)\](?::(\d{1,5}))?$/);
1602
+ if (bracketPortMatch) {
1603
+ if (bracketPortMatch[2] !== undefined) {
1604
+ const portNum = Number(bracketPortMatch[2]);
1605
+ if (!Number.isInteger(portNum) || portNum < 1 || portNum > 65535) return null;
1606
+ }
1607
+ raw = bracketPortMatch[1];
1608
+ } else {
1609
+ const v4PortMatch = raw.match(/^(\d{1,3}(?:\.\d{1,3}){3}):(\d{1,5})$/);
1610
+ if (v4PortMatch) {
1611
+ const portNum = Number(v4PortMatch[2]);
1612
+ if (!Number.isInteger(portNum) || portNum < 1 || portNum > 65535) return null;
1613
+ raw = v4PortMatch[1];
1614
+ }
1615
+ }
1616
+ const clean = raw.replace(/^\[|\]$/g, "").replace(/%[^\s%\]]+$/, "").trim();
1156
1617
  if (!clean) return null;
1157
1618
  const directV4 = parseStrictIpv4Octets(clean);
1158
1619
  if (directV4) return `ipv4:${directV4.join(".")}`;
@@ -1283,14 +1744,30 @@ function extractNormalizedCe3Identifiers(tx) {
1283
1744
 
1284
1745
  function extractPaymentCredential(tx) {
1285
1746
  if (!tx || typeof tx !== "object") return "";
1286
- const raw =
1287
- tx.card_fingerprint ||
1288
- tx.payment_method_fingerprint ||
1289
- tx.payment_method ||
1290
- tx.payment_method_details?.card?.fingerprint ||
1291
- tx.card?.fingerprint ||
1292
- "";
1293
- return sanitizeLogToken(raw, 96);
1747
+ const fpCandidates = [
1748
+ tx.card_fingerprint,
1749
+ tx.payment_method_fingerprint,
1750
+ tx.payment_method_details?.card?.fingerprint,
1751
+ tx.payment_method && typeof tx.payment_method === "object"
1752
+ ? tx.payment_method.card?.fingerprint
1753
+ : "",
1754
+ tx.card?.fingerprint,
1755
+ tx.source?.card?.fingerprint,
1756
+ ];
1757
+ for (const cand of fpCandidates) {
1758
+ if (typeof cand === "string" && cand.trim()) {
1759
+ return sanitizeLogToken(cand.trim(), 96);
1760
+ }
1761
+ }
1762
+ const pmId =
1763
+ typeof tx.payment_method === "string"
1764
+ ? tx.payment_method
1765
+ : tx.payment_method &&
1766
+ typeof tx.payment_method === "object" &&
1767
+ typeof tx.payment_method.id === "string"
1768
+ ? tx.payment_method.id
1769
+ : "";
1770
+ return sanitizeLogToken(pmId, 96);
1294
1771
  }
1295
1772
 
1296
1773
  function evaluateLocalVisaCe3Qualification(disputeReason, disputedTransaction, priorTransactions) {
@@ -1436,7 +1913,7 @@ export const LOCAL_STATELESS_CLOUD_UPGRADE_HINT = Object.freeze({
1436
1913
  message:
1437
1914
  "Running in stateless local mode. Provision a free or paid Cloud Workspace for 90-day event persistence, automated webhook revocation, and Slack/Email alerts.",
1438
1915
  command: "npx --yes revclamp-mcp --init-workspace <work_email>",
1439
- cliActivateCommand: "npx -y revclamp-mcp@1.20.10 --init-workspace you@company.com",
1916
+ cliActivateCommand: "npx -y revclamp-mcp@1.20.12 --init-workspace you@company.com",
1440
1917
  upgradeUrl: "https://revclamp.com/pricing?source=mcp_cli",
1441
1918
  });
1442
1919
 
@@ -2447,11 +2924,10 @@ function executeLocalMcpToolCore(toolName, rawArgs = {}) {
2447
2924
  if (
2448
2925
  args.consultationNumber !== undefined &&
2449
2926
  (typeof args.consultationNumber !== "string" ||
2450
- args.consultationNumber.trim().length === 0 ||
2451
- args.consultationNumber.trim().length > 64)
2927
+ !/^[A-Za-z0-9_-]{1,64}$/.test(args.consultationNumber.trim()))
2452
2928
  ) {
2453
2929
  const err = new Error(
2454
- "Invalid params: consultationNumber must be a non-empty string up to 64 chars"
2930
+ "Invalid params: consultationNumber must be 1..64 alphanumeric, underscore, or hyphen characters [A-Za-z0-9_-]"
2455
2931
  );
2456
2932
  err.code = -32602;
2457
2933
  throw err;
@@ -2464,10 +2940,58 @@ function executeLocalMcpToolCore(toolName, rawArgs = {}) {
2464
2940
  err.code = -32602;
2465
2941
  throw err;
2466
2942
  }
2943
+ if (
2944
+ args.supplyType !== undefined &&
2945
+ (typeof args.supplyType !== "string" ||
2946
+ !["GOODS", "SERVICES"].includes(args.supplyType.trim().toUpperCase()))
2947
+ ) {
2948
+ const err = new Error("Invalid params: supplyType must be 'GOODS' or 'SERVICES'");
2949
+ err.code = -32602;
2950
+ throw err;
2951
+ }
2952
+ const supplyType =
2953
+ args.supplyType === undefined ? "GOODS" : args.supplyType.trim().toUpperCase();
2467
2954
  const norm = normalizeVatId(args.buyerVatId || "");
2468
2955
  const viesMode = String(args.viesMode || "FORMAT_ONLY").toUpperCase();
2469
2956
  const isDemo = args.demo === true;
2470
2957
 
2958
+ if (
2959
+ norm.validFormat &&
2960
+ sellerCountry !== norm.memberState &&
2961
+ supplyType === "SERVICES" &&
2962
+ (sellerCountry === "XI" || norm.memberState === "XI")
2963
+ ) {
2964
+ const statutoryTerminology = getEuViesStatutoryTerminology(norm.memberState);
2965
+ const sellerStatutoryTerminology = getEuViesStatutoryTerminology(sellerCountry);
2966
+ return {
2967
+ ok: true,
2968
+ executionMode: "local_open_source_engine",
2969
+ ...(isDemo ? { sample: true, simulatedViesLookup: true } : {}),
2970
+ valid: null,
2971
+ formatValid: true,
2972
+ supplyType,
2973
+ status: "HOLD_XI_SERVICES_OUTSIDE_EU_VIES",
2974
+ action: "APPLY_UK_OR_NON_EU_SERVICES_VAT_RULES",
2975
+ reason: "WINDSOR_FRAMEWORK_XI_B2B_SERVICES_EXCLUDED_FROM_VIES",
2976
+ sellerCountry,
2977
+ sellerStatutoryTerminology,
2978
+ normalizedVatId: norm.fullVatId,
2979
+ memberState: norm.memberState,
2980
+ statutoryTerminology,
2981
+ crossBorderSupply: true,
2982
+ domesticSameMemberState: false,
2983
+ reverseChargeEligible: false,
2984
+ zeroRateAllowed: false,
2985
+ statutoryReverseChargeClause: null,
2986
+ sellerStatutoryReverseChargeClause: null,
2987
+ statutoryGoodsExemptionClause: null,
2988
+ sellerStatutoryGoodsExemptionClause: null,
2989
+ applicableStatutoryClause: null,
2990
+ sellerApplicableStatutoryClause: null,
2991
+ consultationId: null,
2992
+ };
2993
+ }
2994
+
2471
2995
  if (viesMode === "LIVE") {
2472
2996
  const err = new Error(
2473
2997
  "LIVE_VIES_REQUIRES_CLOUD_ENDPOINT: Live European Commission VIES consultation requires cloud mode (https://api.revclamp.com/api/mcp with REVCLAMP_API_KEY)."
@@ -2488,9 +3012,10 @@ function executeLocalMcpToolCore(toolName, rawArgs = {}) {
2488
3012
  return {
2489
3013
  ok: true,
2490
3014
  executionMode: "local_open_source_engine",
2491
- ...(isDemo ? { sample: true } : {}),
3015
+ ...(isDemo ? { sample: true, simulatedViesLookup: true } : {}),
2492
3016
  valid: false,
2493
3017
  formatValid: false,
3018
+ supplyType,
2494
3019
  status: "HOLD_INVALID_VAT",
2495
3020
  reason: "INVALID_EU_VAT_FORMAT",
2496
3021
  sellerCountry,
@@ -2502,6 +3027,12 @@ function executeLocalMcpToolCore(toolName, rawArgs = {}) {
2502
3027
  }
2503
3028
 
2504
3029
  const crossBorder = sellerCountry !== norm.memberState;
3030
+ const statutoryTerminology = getEuViesStatutoryTerminology(norm.memberState);
3031
+ const sellerStatutoryTerminology = getEuViesStatutoryTerminology(sellerCountry);
3032
+ const callerConsultationId =
3033
+ typeof args.consultationNumber === "string" && args.consultationNumber.trim().length > 0
3034
+ ? args.consultationNumber.trim().slice(0, 64)
3035
+ : null;
2505
3036
 
2506
3037
  if (!isDemo || viesMode === "FORMAT_ONLY") {
2507
3038
  return {
@@ -2509,14 +3040,25 @@ function executeLocalMcpToolCore(toolName, rawArgs = {}) {
2509
3040
  executionMode: "local_open_source_engine",
2510
3041
  valid: null,
2511
3042
  formatValid: true,
3043
+ supplyType,
2512
3044
  status: "FORMAT_VALID_UNVERIFIED",
3045
+ action: crossBorder ? "FORMAT_VALID_UNVERIFIED" : "APPLY_DOMESTIC_STANDARD_VAT",
2513
3046
  reason: "LOCAL_FORMAT_CHECK_ONLY_NO_LIVE_VIES_CONSULTATION",
2514
3047
  sellerCountry,
3048
+ sellerStatutoryTerminology,
2515
3049
  normalizedVatId: norm.fullVatId,
2516
3050
  memberState: norm.memberState,
3051
+ statutoryTerminology,
2517
3052
  crossBorderSupply: crossBorder,
3053
+ domesticSameMemberState: !crossBorder,
2518
3054
  reverseChargeEligible: false,
2519
3055
  zeroRateAllowed: false,
3056
+ statutoryReverseChargeClause: null,
3057
+ sellerStatutoryReverseChargeClause: null,
3058
+ statutoryGoodsExemptionClause: null,
3059
+ sellerStatutoryGoodsExemptionClause: null,
3060
+ applicableStatutoryClause: null,
3061
+ sellerApplicableStatutoryClause: null,
2520
3062
  consultationId: null,
2521
3063
  limitations: ["NO_LIVE_VIES_CONSULTATION_NUMBER"],
2522
3064
  upgrade: {
@@ -2527,56 +3069,157 @@ function executeLocalMcpToolCore(toolName, rawArgs = {}) {
2527
3069
  };
2528
3070
  }
2529
3071
 
2530
- if (viesMode === "MS_UNAVAILABLE" || viesMode === "GLOBAL_MAX_CONCURRENT_REQ") {
3072
+ const TRANSIENT_SIM_MODES = new Set([
3073
+ "MS_UNAVAILABLE",
3074
+ "GLOBAL_MAX_CONCURRENT_REQ",
3075
+ "MS_MAX_CONCURRENT_REQ",
3076
+ "MS_MAX_CONCURRENT_REQ_TIME",
3077
+ "GLOBAL_MAX_CONCURRENT_REQ_TIME",
3078
+ "SERVICE_UNAVAILABLE",
3079
+ "TIMEOUT",
3080
+ "SERVER_BUSY",
3081
+ "NETWORK_ERROR",
3082
+ ]);
3083
+ if (TRANSIENT_SIM_MODES.has(viesMode)) {
2531
3084
  return {
2532
3085
  ok: true,
2533
3086
  executionMode: "local_open_source_engine",
2534
3087
  sample: true,
3088
+ simulatedViesLookup: true,
2535
3089
  valid: null,
2536
3090
  formatValid: true,
3091
+ supplyType,
2537
3092
  status: "PENDING_ASYNC_RETRY",
2538
3093
  reason: `VIES_SOFT_FAULT_${viesMode}`,
2539
3094
  sellerCountry,
3095
+ sellerStatutoryTerminology,
3096
+ normalizedVatId: norm.fullVatId,
3097
+ memberState: norm.memberState,
3098
+ statutoryTerminology,
3099
+ domesticSameMemberState: !crossBorder,
3100
+ reverseChargeEligible: false,
3101
+ zeroRateAllowed: false,
3102
+ consultationId: null,
3103
+ };
3104
+ }
3105
+
3106
+ if (viesMode === "INVALID_REQUESTER_INFO" || viesMode === "IP_BLOCKED") {
3107
+ return {
3108
+ ok: true,
3109
+ executionMode: "local_open_source_engine",
3110
+ sample: true,
3111
+ simulatedViesLookup: true,
3112
+ valid: null,
3113
+ formatValid: true,
3114
+ supplyType,
3115
+ status: "HOLD_UNVERIFIED_VIES_FAULT",
3116
+ reason: `VIES_GATEWAY_FAULT_${viesMode}`,
3117
+ sellerCountry,
3118
+ sellerStatutoryTerminology,
2540
3119
  normalizedVatId: norm.fullVatId,
2541
3120
  memberState: norm.memberState,
3121
+ statutoryTerminology,
3122
+ domesticSameMemberState: !crossBorder,
2542
3123
  reverseChargeEligible: false,
2543
3124
  zeroRateAllowed: false,
2544
3125
  consultationId: null,
2545
3126
  };
2546
3127
  }
2547
3128
 
2548
- if (viesMode === "INVALID") {
3129
+ if (viesMode === "INVALID" || viesMode === "VAT_BLOCKED" || viesMode === "INVALID_INPUT") {
2549
3130
  return {
2550
3131
  ok: true,
2551
3132
  executionMode: "local_open_source_engine",
2552
3133
  sample: true,
3134
+ simulatedViesLookup: true,
2553
3135
  valid: false,
2554
3136
  formatValid: true,
3137
+ supplyType,
2555
3138
  status: "HOLD_INVALID_VAT",
2556
- reason: "VIES_DEFINITE_INVALID",
3139
+ reason: viesMode === "INVALID" ? "VIES_DEFINITE_INVALID" : `VIES_${viesMode}`,
3140
+ sellerCountry,
3141
+ sellerStatutoryTerminology,
3142
+ normalizedVatId: norm.fullVatId,
3143
+ memberState: norm.memberState,
3144
+ statutoryTerminology,
3145
+ domesticSameMemberState: !crossBorder,
3146
+ reverseChargeEligible: false,
3147
+ zeroRateAllowed: false,
3148
+ consultationId: null,
3149
+ };
3150
+ }
3151
+
3152
+ if (viesMode !== "VALID" && viesMode !== "VERIFIED") {
3153
+ return {
3154
+ ok: true,
3155
+ executionMode: "local_open_source_engine",
3156
+ sample: true,
3157
+ simulatedViesLookup: true,
3158
+ valid: null,
3159
+ formatValid: true,
3160
+ supplyType,
3161
+ status: "HOLD_UNVERIFIED_VIES_FAULT",
3162
+ reason: "UNRECOGNIZED_VIES_SIMULATION_MODE",
2557
3163
  sellerCountry,
3164
+ sellerStatutoryTerminology,
2558
3165
  normalizedVatId: norm.fullVatId,
2559
3166
  memberState: norm.memberState,
3167
+ statutoryTerminology,
3168
+ domesticSameMemberState: !crossBorder,
2560
3169
  reverseChargeEligible: false,
2561
3170
  zeroRateAllowed: false,
2562
3171
  consultationId: null,
2563
3172
  };
2564
3173
  }
2565
3174
 
3175
+ const applicableStatutoryClause = crossBorder
3176
+ ? supplyType === "GOODS"
3177
+ ? statutoryTerminology?.statutoryGoodsExemptionClause || null
3178
+ : statutoryTerminology?.statutoryReverseChargeClause || null
3179
+ : null;
3180
+ const sellerApplicableStatutoryClause = crossBorder
3181
+ ? supplyType === "GOODS"
3182
+ ? sellerStatutoryTerminology?.statutoryGoodsExemptionClause || null
3183
+ : sellerStatutoryTerminology?.statutoryReverseChargeClause || null
3184
+ : null;
3185
+
2566
3186
  return {
2567
3187
  ok: true,
2568
3188
  executionMode: "local_open_source_engine",
2569
3189
  sample: true,
3190
+ simulatedViesLookup: true,
2570
3191
  valid: true,
2571
3192
  formatValid: true,
3193
+ supplyType,
2572
3194
  status: crossBorder ? "VERIFIED_ZERO_RATED" : "DOMESTIC_TAXABLE_SUPPLY",
3195
+ action: crossBorder ? "ALLOW_ZERO_RATED_REVERSE_CHARGE" : "APPLY_DOMESTIC_STANDARD_VAT",
2573
3196
  reason: crossBorder ? "VALID_CROSS_BORDER_REVERSE_CHARGE" : "SAME_MEMBER_STATE_DOMESTIC",
2574
3197
  sellerCountry,
3198
+ sellerStatutoryTerminology,
2575
3199
  normalizedVatId: norm.fullVatId,
2576
3200
  memberState: norm.memberState,
3201
+ statutoryTerminology,
3202
+ domesticSameMemberState: !crossBorder,
2577
3203
  reverseChargeEligible: crossBorder,
2578
3204
  zeroRateAllowed: crossBorder,
2579
- consultationId: "DEMO_SAMPLE_NOT_FOR_TAX_AUDIT",
3205
+ statutoryReverseChargeClause: crossBorder
3206
+ ? statutoryTerminology?.statutoryReverseChargeClause || null
3207
+ : null,
3208
+ sellerStatutoryReverseChargeClause: crossBorder
3209
+ ? sellerStatutoryTerminology?.statutoryReverseChargeClause || null
3210
+ : null,
3211
+ statutoryGoodsExemptionClause: crossBorder
3212
+ ? statutoryTerminology?.statutoryGoodsExemptionClause || null
3213
+ : null,
3214
+ sellerStatutoryGoodsExemptionClause: crossBorder
3215
+ ? sellerStatutoryTerminology?.statutoryGoodsExemptionClause || null
3216
+ : null,
3217
+ applicableStatutoryClause,
3218
+ sellerApplicableStatutoryClause,
3219
+ consultationId: callerConsultationId || "DEMO_SAMPLE_NOT_FOR_TAX_AUDIT",
3220
+ consultationIdSource: callerConsultationId
3221
+ ? "CALLER_SUPPLIED_UNVERIFIED"
3222
+ : "DEMO_SAMPLE_DEFAULT",
2580
3223
  };
2581
3224
  }
2582
3225
 
@@ -2670,20 +3313,21 @@ function executeLocalMcpToolCore(toolName, rawArgs = {}) {
2670
3313
 
2671
3314
  const effectiveTotalCents = Math.max(0, orderTotalCents - creditNotesCents);
2672
3315
  const hasExplicitDepositCents = args.requiredDepositCents !== undefined;
2673
- const requiredDepositCents = hasExplicitDepositCents
3316
+ const rawRequiredDepositCents = hasExplicitDepositCents
2674
3317
  ? args.requiredDepositCents
2675
3318
  : Math.ceil((effectiveTotalCents * requiredDepositPercent) / 100);
2676
3319
  if (
2677
- !Number.isSafeInteger(requiredDepositCents) ||
2678
- requiredDepositCents < 0 ||
2679
- requiredDepositCents > effectiveTotalCents
3320
+ !Number.isSafeInteger(rawRequiredDepositCents) ||
3321
+ rawRequiredDepositCents < 0 ||
3322
+ rawRequiredDepositCents > orderTotalCents
2680
3323
  ) {
2681
3324
  const err = new Error(
2682
- "INVALID_REQUIRED_DEPOSIT_CENTS: requiredDepositCents must be an integer between 0 and effectiveTotalCents."
3325
+ "INVALID_REQUIRED_DEPOSIT_CENTS: requiredDepositCents must be an integer between 0 and totalOrderCents."
2683
3326
  );
2684
3327
  err.code = -32602;
2685
3328
  throw err;
2686
3329
  }
3330
+ const requiredDepositCents = Math.min(rawRequiredDepositCents, effectiveTotalCents);
2687
3331
 
2688
3332
  const shortfallRawCents = Math.max(0, effectiveTotalCents - paidAmountCents);
2689
3333
  const overpaidCents = Math.max(0, paidAmountCents - effectiveTotalCents);
@@ -3341,7 +3985,7 @@ function toSafeLocalRpcId(rawId) {
3341
3985
 
3342
3986
  export function executeLocalMcpJsonRpc(
3343
3987
  rpcRequest,
3344
- packageVersion = "1.20.10",
3988
+ packageVersion = "1.20.12",
3345
3989
  options = {}
3346
3990
  ) {
3347
3991
  if (!rpcRequest || typeof rpcRequest !== "object" || Array.isArray(rpcRequest)) {
@@ -3457,7 +4101,7 @@ export function executeLocalMcpJsonRpc(
3457
4101
  version: packageVersion,
3458
4102
  localExecution: "9 deterministic tools in local_engine.mjs (0 network calls by default)",
3459
4103
  cloudCapabilities: [
3460
- "90-day SQLite WAL usage & audit ledger",
4104
+ "90-day durable transactional usage & audit ledger",
3461
4105
  "24/7 autonomous Stripe dispute & entitlement webhook outbox",
3462
4106
  "Live EU Commission VIES SOAP consultation numbers (viesMode: 'LIVE')",
3463
4107
  ],
package/mcp-config.json CHANGED
@@ -26,7 +26,7 @@
26
26
  },
27
27
  "manifest": {
28
28
  "name": "revclamp-mcp",
29
- "version": "1.20.10",
29
+ "version": "1.20.12",
30
30
  "tools": [
31
31
  "revclamp_audit_revenue_leakage",
32
32
  "revclamp_evaluate_ghost_usage",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "revclamp-mcp",
3
- "mcpName": "io.github.revclamp/revclamp-mcp",
4
- "version": "1.20.10",
3
+ "mcpName": "com.revclamp/revclamp-mcp",
4
+ "version": "1.20.12",
5
5
  "description": "Model Context Protocol (MCP) server and CLI for Stripe 2025-03-31.basil entitlement checks, Visa CE 3.0 dispute staging (submit: false), EU/XI VIES VAT validation, Shopify Plus B2B Net-15/30/60 reconciliation, webhook HMAC-SHA256 verification, 0% take-rate ROI calculation, 72-hour webhook replay & out-of-order state-machine simulation, and Stripe dispute evidence 18,000 UTF-16 code unit & CE 3.0 completeness linting.",
6
6
  "type": "module",
7
7
  "main": "./index.mjs",
@@ -46,6 +46,6 @@
46
46
  "node": ">=20.0.0"
47
47
  },
48
48
  "revclamp": {
49
- "engineSha256": "c18e79d00a51b23cc4745868a7371968709dca8c6385b7c27cca5e23e67dbb1f"
49
+ "engineSha256": "c67f214211284a479fbe10857dfef984b45e3c3403c37d5d834dcd5a5b326b60"
50
50
  }
51
51
  }
package/server.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
- "name": "io.github.revclamp/revclamp-mcp",
3
+ "name": "com.revclamp/revclamp-mcp",
4
4
  "title": "RevClamp MCP Server",
5
5
  "description": "Zero-take-rate Stripe 2025-03-31.basil, Visa CE 3.0 & EU/XI VIES VAT guardrails MCP server.",
6
6
  "repository": {
7
7
  "url": "https://github.com/lhphong09t2/revclamp-mcp",
8
8
  "source": "github"
9
9
  },
10
- "version": "1.20.10",
10
+ "version": "1.20.12",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "registryBaseUrl": "https://registry.npmjs.org",
15
15
  "identifier": "revclamp-mcp",
16
- "version": "1.20.10",
16
+ "version": "1.20.12",
17
17
  "transport": {
18
18
  "type": "stdio"
19
19
  },