vatnode-mcp 0.1.0 → 0.2.0
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/LICENSE +21 -0
- package/README.md +25 -0
- package/dist/index.js +26 -825
- package/package.json +18 -16
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 vatnode
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# vatnode-mcp
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/vatnode-mcp)
|
|
4
|
+
[](https://github.com/vatnode/vatnode-mcp/actions/workflows/test.yml)
|
|
4
5
|
[](LICENSE)
|
|
5
6
|
|
|
6
7
|
Official [Model Context Protocol](https://modelcontextprotocol.io) server for **[vatnode](https://vatnode.dev)** — VAT validation and EU tax data for AI agents.
|
|
@@ -119,6 +120,30 @@ Any MCP-compatible client can connect — point it at `npx -y vatnode-mcp` and (
|
|
|
119
120
|
|
|
120
121
|
---
|
|
121
122
|
|
|
123
|
+
## Contributing
|
|
124
|
+
|
|
125
|
+
Bug reports and PRs welcome. Open an issue first for non-trivial changes so we can align on direction.
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
git clone https://github.com/vatnode/vatnode-mcp.git
|
|
129
|
+
cd vatnode-mcp
|
|
130
|
+
npm install
|
|
131
|
+
npm test
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Releasing
|
|
135
|
+
|
|
136
|
+
Releases are published to npm via [Trusted Publishing](https://docs.npmjs.com/trusted-publishers) — no NPM_TOKEN secret, every release signed with [npm provenance](https://docs.npmjs.com/generating-provenance-statements).
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# bump version in package.json (and VERSION in src/index.ts), commit, then:
|
|
140
|
+
git tag v0.2.1
|
|
141
|
+
git push --tags
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
CI on `.github/workflows/release.yml` picks up the tag and publishes.
|
|
145
|
+
|
|
122
146
|
## License
|
|
123
147
|
|
|
124
148
|
MIT
|
|
149
|
+
|
package/dist/index.js
CHANGED
|
@@ -3,818 +3,15 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
-
import { z as z2 } from "zod";
|
|
7
|
-
|
|
8
|
-
// ../../packages/eu-vat-rates/dist/index.js
|
|
9
|
-
var eu_vat_rates_default = {
|
|
10
|
-
version: "2026-05-19",
|
|
11
|
-
source: "European Commission TEDB",
|
|
12
|
-
rates: {
|
|
13
|
-
AD: {
|
|
14
|
-
country: "Andorra",
|
|
15
|
-
currency: "EUR",
|
|
16
|
-
eu_member: false,
|
|
17
|
-
vat_name: "Impost General Indirecte",
|
|
18
|
-
vat_abbr: "IGI",
|
|
19
|
-
standard: 4.5,
|
|
20
|
-
reduced: [
|
|
21
|
-
1,
|
|
22
|
-
2.5
|
|
23
|
-
],
|
|
24
|
-
super_reduced: null,
|
|
25
|
-
parking: null,
|
|
26
|
-
format: "1 letter + 6 digits + 1 letter",
|
|
27
|
-
pattern: "^[A-Z]\\d{6}[A-Z]$"
|
|
28
|
-
},
|
|
29
|
-
AL: {
|
|
30
|
-
country: "Albania",
|
|
31
|
-
currency: "ALL",
|
|
32
|
-
eu_member: false,
|
|
33
|
-
vat_name: "Tatimi mbi vler\xEBn e shtuar",
|
|
34
|
-
vat_abbr: "TVSH",
|
|
35
|
-
standard: 20,
|
|
36
|
-
reduced: [
|
|
37
|
-
6,
|
|
38
|
-
10
|
|
39
|
-
],
|
|
40
|
-
super_reduced: null,
|
|
41
|
-
parking: null,
|
|
42
|
-
format: "1 letter + 8 digits + 1 letter",
|
|
43
|
-
pattern: "^[A-Z]\\d{8}[A-Z]$"
|
|
44
|
-
},
|
|
45
|
-
AT: {
|
|
46
|
-
country: "Austria",
|
|
47
|
-
currency: "EUR",
|
|
48
|
-
eu_member: true,
|
|
49
|
-
vat_name: "Umsatzsteuer",
|
|
50
|
-
vat_abbr: "USt",
|
|
51
|
-
standard: 20,
|
|
52
|
-
reduced: [
|
|
53
|
-
10,
|
|
54
|
-
13,
|
|
55
|
-
19
|
|
56
|
-
],
|
|
57
|
-
super_reduced: null,
|
|
58
|
-
parking: null,
|
|
59
|
-
format: "ATU + 8 digits",
|
|
60
|
-
pattern: "^ATU\\d{8}$"
|
|
61
|
-
},
|
|
62
|
-
BA: {
|
|
63
|
-
country: "Bosnia and Herzegovina",
|
|
64
|
-
currency: "BAM",
|
|
65
|
-
eu_member: false,
|
|
66
|
-
vat_name: "Porez na dodanu vrijednost",
|
|
67
|
-
vat_abbr: "PDV",
|
|
68
|
-
standard: 17,
|
|
69
|
-
reduced: [],
|
|
70
|
-
super_reduced: null,
|
|
71
|
-
parking: null,
|
|
72
|
-
format: "12 digits",
|
|
73
|
-
pattern: "^\\d{12}$"
|
|
74
|
-
},
|
|
75
|
-
BE: {
|
|
76
|
-
country: "Belgium",
|
|
77
|
-
currency: "EUR",
|
|
78
|
-
eu_member: true,
|
|
79
|
-
vat_name: "Belasting over de toegevoegde waarde",
|
|
80
|
-
vat_abbr: "BTW",
|
|
81
|
-
standard: 21,
|
|
82
|
-
reduced: [
|
|
83
|
-
6,
|
|
84
|
-
12
|
|
85
|
-
],
|
|
86
|
-
super_reduced: null,
|
|
87
|
-
parking: 12,
|
|
88
|
-
format: "BE + 0/1 + 9 digits",
|
|
89
|
-
pattern: "^BE[01]\\d{9}$"
|
|
90
|
-
},
|
|
91
|
-
BG: {
|
|
92
|
-
country: "Bulgaria",
|
|
93
|
-
currency: "EUR",
|
|
94
|
-
eu_member: true,
|
|
95
|
-
vat_name: "\u0414\u0430\u043D\u044A\u043A \u0432\u044A\u0440\u0445\u0443 \u0434\u043E\u0431\u0430\u0432\u0435\u043D\u0430\u0442\u0430 \u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442",
|
|
96
|
-
vat_abbr: "\u0414\u0414\u0421",
|
|
97
|
-
standard: 20,
|
|
98
|
-
reduced: [
|
|
99
|
-
9
|
|
100
|
-
],
|
|
101
|
-
super_reduced: null,
|
|
102
|
-
parking: null,
|
|
103
|
-
format: "BG + 9\u201310 digits",
|
|
104
|
-
pattern: "^BG\\d{9,10}$"
|
|
105
|
-
},
|
|
106
|
-
CH: {
|
|
107
|
-
country: "Switzerland",
|
|
108
|
-
currency: "CHF",
|
|
109
|
-
eu_member: false,
|
|
110
|
-
vat_name: "Mehrwertsteuer",
|
|
111
|
-
vat_abbr: "MWST",
|
|
112
|
-
standard: 8.1,
|
|
113
|
-
reduced: [
|
|
114
|
-
2.6,
|
|
115
|
-
3.8
|
|
116
|
-
],
|
|
117
|
-
super_reduced: null,
|
|
118
|
-
parking: null,
|
|
119
|
-
format: "CHE-NNN.NNN.NNN (+ MWST/TVA/IVA)",
|
|
120
|
-
pattern: "^CHE-?\\d{3}\\.?\\d{3}\\.?\\d{3}[ ]?(MWST|TVA|IVA)?$"
|
|
121
|
-
},
|
|
122
|
-
CY: {
|
|
123
|
-
country: "Cyprus",
|
|
124
|
-
currency: "EUR",
|
|
125
|
-
eu_member: true,
|
|
126
|
-
vat_name: "\u03A6\u03CC\u03C1\u03BF\u03C2 \u03A0\u03C1\u03BF\u03C3\u03C4\u03B9\u03B8\u03AD\u03BC\u03B5\u03BD\u03B7\u03C2 \u0391\u03BE\u03AF\u03B1\u03C2",
|
|
127
|
-
vat_abbr: "\u03A6\u03A0\u0391",
|
|
128
|
-
standard: 19,
|
|
129
|
-
reduced: [
|
|
130
|
-
5,
|
|
131
|
-
9
|
|
132
|
-
],
|
|
133
|
-
super_reduced: 3,
|
|
134
|
-
parking: null,
|
|
135
|
-
format: "CY + 8 digits + 1 letter",
|
|
136
|
-
pattern: "^CY\\d{8}[A-Z]$"
|
|
137
|
-
},
|
|
138
|
-
CZ: {
|
|
139
|
-
country: "Czech Republic",
|
|
140
|
-
currency: "CZK",
|
|
141
|
-
eu_member: true,
|
|
142
|
-
vat_name: "Da\u0148 z p\u0159idan\xE9 hodnoty",
|
|
143
|
-
vat_abbr: "DPH",
|
|
144
|
-
standard: 21,
|
|
145
|
-
reduced: [
|
|
146
|
-
12
|
|
147
|
-
],
|
|
148
|
-
super_reduced: null,
|
|
149
|
-
parking: null,
|
|
150
|
-
format: "CZ + 8\u201310 digits",
|
|
151
|
-
pattern: "^CZ\\d{8,10}$"
|
|
152
|
-
},
|
|
153
|
-
DE: {
|
|
154
|
-
country: "Germany",
|
|
155
|
-
currency: "EUR",
|
|
156
|
-
eu_member: true,
|
|
157
|
-
vat_name: "Mehrwertsteuer",
|
|
158
|
-
vat_abbr: "MwSt",
|
|
159
|
-
standard: 19,
|
|
160
|
-
reduced: [
|
|
161
|
-
7
|
|
162
|
-
],
|
|
163
|
-
super_reduced: null,
|
|
164
|
-
parking: null,
|
|
165
|
-
format: "DE + 9 digits",
|
|
166
|
-
pattern: "^DE\\d{9}$"
|
|
167
|
-
},
|
|
168
|
-
DK: {
|
|
169
|
-
country: "Denmark",
|
|
170
|
-
currency: "DKK",
|
|
171
|
-
eu_member: true,
|
|
172
|
-
vat_name: "Moms",
|
|
173
|
-
vat_abbr: "moms",
|
|
174
|
-
standard: 25,
|
|
175
|
-
reduced: [],
|
|
176
|
-
super_reduced: null,
|
|
177
|
-
parking: null,
|
|
178
|
-
format: "DK + 8 digits",
|
|
179
|
-
pattern: "^DK\\d{8}$"
|
|
180
|
-
},
|
|
181
|
-
EE: {
|
|
182
|
-
country: "Estonia",
|
|
183
|
-
currency: "EUR",
|
|
184
|
-
eu_member: true,
|
|
185
|
-
vat_name: "K\xE4ibemaks",
|
|
186
|
-
vat_abbr: "km",
|
|
187
|
-
standard: 24,
|
|
188
|
-
reduced: [
|
|
189
|
-
9,
|
|
190
|
-
13
|
|
191
|
-
],
|
|
192
|
-
super_reduced: null,
|
|
193
|
-
parking: null,
|
|
194
|
-
format: "EE + 9 digits",
|
|
195
|
-
pattern: "^EE\\d{9}$"
|
|
196
|
-
},
|
|
197
|
-
ES: {
|
|
198
|
-
country: "Spain",
|
|
199
|
-
currency: "EUR",
|
|
200
|
-
eu_member: true,
|
|
201
|
-
vat_name: "Impuesto sobre el Valor A\xF1adido",
|
|
202
|
-
vat_abbr: "IVA",
|
|
203
|
-
standard: 21,
|
|
204
|
-
reduced: [
|
|
205
|
-
10
|
|
206
|
-
],
|
|
207
|
-
super_reduced: 4,
|
|
208
|
-
parking: null,
|
|
209
|
-
format: "ES + letter/digit + 7 digits + letter/digit",
|
|
210
|
-
pattern: "^ES[A-Z0-9]\\d{7}[A-Z0-9]$"
|
|
211
|
-
},
|
|
212
|
-
FI: {
|
|
213
|
-
country: "Finland",
|
|
214
|
-
currency: "EUR",
|
|
215
|
-
eu_member: true,
|
|
216
|
-
vat_name: "Arvonlis\xE4vero",
|
|
217
|
-
vat_abbr: "ALV",
|
|
218
|
-
standard: 25.5,
|
|
219
|
-
reduced: [
|
|
220
|
-
10,
|
|
221
|
-
13.5
|
|
222
|
-
],
|
|
223
|
-
super_reduced: null,
|
|
224
|
-
parking: null,
|
|
225
|
-
format: "FI + 8 digits",
|
|
226
|
-
pattern: "^FI\\d{8}$"
|
|
227
|
-
},
|
|
228
|
-
FR: {
|
|
229
|
-
country: "France",
|
|
230
|
-
currency: "EUR",
|
|
231
|
-
eu_member: true,
|
|
232
|
-
vat_name: "Taxe sur la valeur ajout\xE9e",
|
|
233
|
-
vat_abbr: "TVA",
|
|
234
|
-
standard: 20,
|
|
235
|
-
reduced: [
|
|
236
|
-
0.9,
|
|
237
|
-
1.05,
|
|
238
|
-
5.5,
|
|
239
|
-
8.5,
|
|
240
|
-
10,
|
|
241
|
-
13
|
|
242
|
-
],
|
|
243
|
-
super_reduced: 2.1,
|
|
244
|
-
parking: null,
|
|
245
|
-
format: "FR + 2 alphanumeric + 9 digits",
|
|
246
|
-
pattern: "^FR[A-HJ-NP-Z0-9]{2}\\d{9}$"
|
|
247
|
-
},
|
|
248
|
-
GB: {
|
|
249
|
-
country: "United Kingdom",
|
|
250
|
-
currency: "GBP",
|
|
251
|
-
eu_member: false,
|
|
252
|
-
vat_name: "Value Added Tax",
|
|
253
|
-
vat_abbr: "VAT",
|
|
254
|
-
standard: 20,
|
|
255
|
-
reduced: [
|
|
256
|
-
5
|
|
257
|
-
],
|
|
258
|
-
super_reduced: null,
|
|
259
|
-
parking: null,
|
|
260
|
-
format: "GB + 9 digits, 12 digits, or GD/HA + 3 digits",
|
|
261
|
-
pattern: "^GB(\\d{9}|\\d{12}|GD\\d{3}|HA\\d{3})$"
|
|
262
|
-
},
|
|
263
|
-
GE: {
|
|
264
|
-
country: "Georgia",
|
|
265
|
-
currency: "GEL",
|
|
266
|
-
eu_member: false,
|
|
267
|
-
vat_name: "\u10D3\u10D0\u10DB\u10D0\u10E2\u10D4\u10D1\u10E3\u10DA\u10D8 \u10E6\u10D8\u10E0\u10D4\u10D1\u10E3\u10DA\u10D4\u10D1\u10D8\u10E1 \u10D2\u10D0\u10D3\u10D0\u10E1\u10D0\u10EE\u10D0\u10D3\u10D8",
|
|
268
|
-
vat_abbr: "\u10D3\u10E6\u10D2",
|
|
269
|
-
standard: 18,
|
|
270
|
-
reduced: [],
|
|
271
|
-
super_reduced: null,
|
|
272
|
-
parking: null,
|
|
273
|
-
format: "9 digits",
|
|
274
|
-
pattern: "^\\d{9}$"
|
|
275
|
-
},
|
|
276
|
-
GR: {
|
|
277
|
-
country: "Greece",
|
|
278
|
-
currency: "EUR",
|
|
279
|
-
eu_member: true,
|
|
280
|
-
vat_name: "\u03A6\u03CC\u03C1\u03BF\u03C2 \u03A0\u03C1\u03BF\u03C3\u03C4\u03B9\u03B8\u03AD\u03BC\u03B5\u03BD\u03B7\u03C2 \u0391\u03BE\u03AF\u03B1\u03C2",
|
|
281
|
-
vat_abbr: "\u03A6\u03A0\u0391",
|
|
282
|
-
standard: 24,
|
|
283
|
-
reduced: [
|
|
284
|
-
6,
|
|
285
|
-
13,
|
|
286
|
-
17
|
|
287
|
-
],
|
|
288
|
-
super_reduced: 4,
|
|
289
|
-
parking: 13,
|
|
290
|
-
format: "EL + 9 digits",
|
|
291
|
-
pattern: "^EL\\d{9}$"
|
|
292
|
-
},
|
|
293
|
-
HR: {
|
|
294
|
-
country: "Croatia",
|
|
295
|
-
currency: "EUR",
|
|
296
|
-
eu_member: true,
|
|
297
|
-
vat_name: "Porez na dodanu vrijednost",
|
|
298
|
-
vat_abbr: "PDV",
|
|
299
|
-
standard: 25,
|
|
300
|
-
reduced: [
|
|
301
|
-
5,
|
|
302
|
-
13
|
|
303
|
-
],
|
|
304
|
-
super_reduced: null,
|
|
305
|
-
parking: null,
|
|
306
|
-
format: "HR + 11 digits",
|
|
307
|
-
pattern: "^HR\\d{11}$"
|
|
308
|
-
},
|
|
309
|
-
HU: {
|
|
310
|
-
country: "Hungary",
|
|
311
|
-
currency: "HUF",
|
|
312
|
-
eu_member: true,
|
|
313
|
-
vat_name: "\xC1ltal\xE1nos forgalmi ad\xF3",
|
|
314
|
-
vat_abbr: "\xC1FA",
|
|
315
|
-
standard: 27,
|
|
316
|
-
reduced: [
|
|
317
|
-
5,
|
|
318
|
-
18
|
|
319
|
-
],
|
|
320
|
-
super_reduced: null,
|
|
321
|
-
parking: null,
|
|
322
|
-
format: "HU + 8 digits",
|
|
323
|
-
pattern: "^HU\\d{8}$"
|
|
324
|
-
},
|
|
325
|
-
IE: {
|
|
326
|
-
country: "Ireland",
|
|
327
|
-
currency: "EUR",
|
|
328
|
-
eu_member: true,
|
|
329
|
-
vat_name: "Value Added Tax",
|
|
330
|
-
vat_abbr: "VAT",
|
|
331
|
-
standard: 23,
|
|
332
|
-
reduced: [
|
|
333
|
-
9,
|
|
334
|
-
13.5
|
|
335
|
-
],
|
|
336
|
-
super_reduced: null,
|
|
337
|
-
parking: null,
|
|
338
|
-
format: "IE + 7 digits + 1\u20132 letters",
|
|
339
|
-
pattern: "^IE\\d{7}[A-W][A-IW]?$|^IE\\d[A-Z+*]\\d{5}[A-W]$"
|
|
340
|
-
},
|
|
341
|
-
IS: {
|
|
342
|
-
country: "Iceland",
|
|
343
|
-
currency: "ISK",
|
|
344
|
-
eu_member: false,
|
|
345
|
-
vat_name: "Vir\xF0isaukaskattur",
|
|
346
|
-
vat_abbr: "VSK",
|
|
347
|
-
standard: 24,
|
|
348
|
-
reduced: [
|
|
349
|
-
11
|
|
350
|
-
],
|
|
351
|
-
super_reduced: null,
|
|
352
|
-
parking: null,
|
|
353
|
-
format: "5\u20136 digits",
|
|
354
|
-
pattern: "^\\d{5,6}$"
|
|
355
|
-
},
|
|
356
|
-
IT: {
|
|
357
|
-
country: "Italy",
|
|
358
|
-
currency: "EUR",
|
|
359
|
-
eu_member: true,
|
|
360
|
-
vat_name: "Imposta sul valore aggiunto",
|
|
361
|
-
vat_abbr: "IVA",
|
|
362
|
-
standard: 22,
|
|
363
|
-
reduced: [
|
|
364
|
-
5,
|
|
365
|
-
10
|
|
366
|
-
],
|
|
367
|
-
super_reduced: 4,
|
|
368
|
-
parking: null,
|
|
369
|
-
format: "IT + 11 digits",
|
|
370
|
-
pattern: "^IT\\d{11}$"
|
|
371
|
-
},
|
|
372
|
-
LI: {
|
|
373
|
-
country: "Liechtenstein",
|
|
374
|
-
currency: "CHF",
|
|
375
|
-
eu_member: false,
|
|
376
|
-
vat_name: "Mehrwertsteuer",
|
|
377
|
-
vat_abbr: "MWST",
|
|
378
|
-
standard: 8.1,
|
|
379
|
-
reduced: [
|
|
380
|
-
2.6,
|
|
381
|
-
3.8
|
|
382
|
-
],
|
|
383
|
-
super_reduced: null,
|
|
384
|
-
parking: null,
|
|
385
|
-
format: "5 digits",
|
|
386
|
-
pattern: "^\\d{5}$"
|
|
387
|
-
},
|
|
388
|
-
LT: {
|
|
389
|
-
country: "Lithuania",
|
|
390
|
-
currency: "EUR",
|
|
391
|
-
eu_member: true,
|
|
392
|
-
vat_name: "Prid\u0117tin\u0117s vert\u0117s mokestis",
|
|
393
|
-
vat_abbr: "PVM",
|
|
394
|
-
standard: 21,
|
|
395
|
-
reduced: [
|
|
396
|
-
5,
|
|
397
|
-
12
|
|
398
|
-
],
|
|
399
|
-
super_reduced: null,
|
|
400
|
-
parking: null,
|
|
401
|
-
format: "LT + 9 or 12 digits",
|
|
402
|
-
pattern: "^LT(\\d{9}|\\d{12})$"
|
|
403
|
-
},
|
|
404
|
-
LU: {
|
|
405
|
-
country: "Luxembourg",
|
|
406
|
-
currency: "EUR",
|
|
407
|
-
eu_member: true,
|
|
408
|
-
vat_name: "Taxe sur la valeur ajout\xE9e",
|
|
409
|
-
vat_abbr: "TVA",
|
|
410
|
-
standard: 17,
|
|
411
|
-
reduced: [
|
|
412
|
-
8,
|
|
413
|
-
14
|
|
414
|
-
],
|
|
415
|
-
super_reduced: 3,
|
|
416
|
-
parking: 14,
|
|
417
|
-
format: "LU + 8 digits",
|
|
418
|
-
pattern: "^LU\\d{8}$"
|
|
419
|
-
},
|
|
420
|
-
LV: {
|
|
421
|
-
country: "Latvia",
|
|
422
|
-
currency: "EUR",
|
|
423
|
-
eu_member: true,
|
|
424
|
-
vat_name: "Pievienot\u0101s v\u0113rt\u012Bbas nodoklis",
|
|
425
|
-
vat_abbr: "PVN",
|
|
426
|
-
standard: 21,
|
|
427
|
-
reduced: [
|
|
428
|
-
5,
|
|
429
|
-
12
|
|
430
|
-
],
|
|
431
|
-
super_reduced: null,
|
|
432
|
-
parking: null,
|
|
433
|
-
format: "LV + 11 digits",
|
|
434
|
-
pattern: "^LV\\d{11}$"
|
|
435
|
-
},
|
|
436
|
-
MC: {
|
|
437
|
-
country: "Monaco",
|
|
438
|
-
currency: "EUR",
|
|
439
|
-
eu_member: false,
|
|
440
|
-
vat_name: "Taxe sur la valeur ajout\xE9e",
|
|
441
|
-
vat_abbr: "TVA",
|
|
442
|
-
standard: 20,
|
|
443
|
-
reduced: [
|
|
444
|
-
5.5,
|
|
445
|
-
10
|
|
446
|
-
],
|
|
447
|
-
super_reduced: 2.1,
|
|
448
|
-
parking: null,
|
|
449
|
-
format: "FR + 2 alphanumeric + 9 digits",
|
|
450
|
-
pattern: "^FR[A-HJ-NP-Z0-9]{2}\\d{9}$"
|
|
451
|
-
},
|
|
452
|
-
MD: {
|
|
453
|
-
country: "Moldova",
|
|
454
|
-
currency: "MDL",
|
|
455
|
-
eu_member: false,
|
|
456
|
-
vat_name: "Taxa pe valoarea ad\u0103ugat\u0103",
|
|
457
|
-
vat_abbr: "TVA",
|
|
458
|
-
standard: 20,
|
|
459
|
-
reduced: [
|
|
460
|
-
8
|
|
461
|
-
],
|
|
462
|
-
super_reduced: null,
|
|
463
|
-
parking: null,
|
|
464
|
-
format: "7 digits",
|
|
465
|
-
pattern: "^\\d{7}$"
|
|
466
|
-
},
|
|
467
|
-
ME: {
|
|
468
|
-
country: "Montenegro",
|
|
469
|
-
currency: "EUR",
|
|
470
|
-
eu_member: false,
|
|
471
|
-
vat_name: "Porez na dodatu vrijednost",
|
|
472
|
-
vat_abbr: "PDV",
|
|
473
|
-
standard: 21,
|
|
474
|
-
reduced: [
|
|
475
|
-
7,
|
|
476
|
-
15
|
|
477
|
-
],
|
|
478
|
-
super_reduced: null,
|
|
479
|
-
parking: null,
|
|
480
|
-
format: "8 digits",
|
|
481
|
-
pattern: "^\\d{8}$"
|
|
482
|
-
},
|
|
483
|
-
MK: {
|
|
484
|
-
country: "North Macedonia",
|
|
485
|
-
currency: "MKD",
|
|
486
|
-
eu_member: false,
|
|
487
|
-
vat_name: "\u0414\u0430\u043D\u043E\u043A \u043D\u0430 \u0434\u043E\u0434\u0430\u0434\u0435\u043D\u0430 \u0432\u0440\u0435\u0434\u043D\u043E\u0441\u0442",
|
|
488
|
-
vat_abbr: "\u0414\u0414\u0412",
|
|
489
|
-
standard: 18,
|
|
490
|
-
reduced: [
|
|
491
|
-
5,
|
|
492
|
-
10
|
|
493
|
-
],
|
|
494
|
-
super_reduced: null,
|
|
495
|
-
parking: null,
|
|
496
|
-
format: "MK + 13 digits",
|
|
497
|
-
pattern: "^MK\\d{13}$"
|
|
498
|
-
},
|
|
499
|
-
MT: {
|
|
500
|
-
country: "Malta",
|
|
501
|
-
currency: "EUR",
|
|
502
|
-
eu_member: true,
|
|
503
|
-
vat_name: "Taxxa tal-Valur Mi\u017Cjud",
|
|
504
|
-
vat_abbr: "VAT",
|
|
505
|
-
standard: 18,
|
|
506
|
-
reduced: [
|
|
507
|
-
5,
|
|
508
|
-
7
|
|
509
|
-
],
|
|
510
|
-
super_reduced: null,
|
|
511
|
-
parking: 12,
|
|
512
|
-
format: "MT + 8 digits",
|
|
513
|
-
pattern: "^MT\\d{8}$"
|
|
514
|
-
},
|
|
515
|
-
NL: {
|
|
516
|
-
country: "Netherlands",
|
|
517
|
-
currency: "EUR",
|
|
518
|
-
eu_member: true,
|
|
519
|
-
vat_name: "Belasting over de toegevoegde waarde",
|
|
520
|
-
vat_abbr: "btw",
|
|
521
|
-
standard: 21,
|
|
522
|
-
reduced: [
|
|
523
|
-
9
|
|
524
|
-
],
|
|
525
|
-
super_reduced: null,
|
|
526
|
-
parking: null,
|
|
527
|
-
format: "NL + 9 digits + B + 2 digits",
|
|
528
|
-
pattern: "^NL\\d{9}B\\d{2}$"
|
|
529
|
-
},
|
|
530
|
-
NO: {
|
|
531
|
-
country: "Norway",
|
|
532
|
-
currency: "NOK",
|
|
533
|
-
eu_member: false,
|
|
534
|
-
vat_name: "Merverdiavgift",
|
|
535
|
-
vat_abbr: "MVA",
|
|
536
|
-
standard: 25,
|
|
537
|
-
reduced: [
|
|
538
|
-
12,
|
|
539
|
-
15
|
|
540
|
-
],
|
|
541
|
-
super_reduced: null,
|
|
542
|
-
parking: null,
|
|
543
|
-
format: "9 digits + MVA",
|
|
544
|
-
pattern: "^\\d{9}MVA$"
|
|
545
|
-
},
|
|
546
|
-
PL: {
|
|
547
|
-
country: "Poland",
|
|
548
|
-
currency: "PLN",
|
|
549
|
-
eu_member: true,
|
|
550
|
-
vat_name: "Podatek od towar\xF3w i us\u0142ug",
|
|
551
|
-
vat_abbr: "VAT",
|
|
552
|
-
standard: 23,
|
|
553
|
-
reduced: [
|
|
554
|
-
5,
|
|
555
|
-
8
|
|
556
|
-
],
|
|
557
|
-
super_reduced: 8,
|
|
558
|
-
parking: null,
|
|
559
|
-
format: "PL + 10 digits",
|
|
560
|
-
pattern: "^PL\\d{10}$"
|
|
561
|
-
},
|
|
562
|
-
PT: {
|
|
563
|
-
country: "Portugal",
|
|
564
|
-
currency: "EUR",
|
|
565
|
-
eu_member: true,
|
|
566
|
-
vat_name: "Imposto sobre o Valor Acrescentado",
|
|
567
|
-
vat_abbr: "IVA",
|
|
568
|
-
standard: 23,
|
|
569
|
-
reduced: [
|
|
570
|
-
6,
|
|
571
|
-
13,
|
|
572
|
-
16,
|
|
573
|
-
22
|
|
574
|
-
],
|
|
575
|
-
super_reduced: 6,
|
|
576
|
-
parking: 13,
|
|
577
|
-
format: "PT + 9 digits",
|
|
578
|
-
pattern: "^PT\\d{9}$"
|
|
579
|
-
},
|
|
580
|
-
RO: {
|
|
581
|
-
country: "Romania",
|
|
582
|
-
currency: "RON",
|
|
583
|
-
eu_member: true,
|
|
584
|
-
vat_name: "Taxa pe valoarea ad\u0103ugat\u0103",
|
|
585
|
-
vat_abbr: "TVA",
|
|
586
|
-
standard: 21,
|
|
587
|
-
reduced: [
|
|
588
|
-
11
|
|
589
|
-
],
|
|
590
|
-
super_reduced: null,
|
|
591
|
-
parking: null,
|
|
592
|
-
format: "RO + 2\u201310 digits",
|
|
593
|
-
pattern: "^RO\\d{2,10}$"
|
|
594
|
-
},
|
|
595
|
-
RS: {
|
|
596
|
-
country: "Serbia",
|
|
597
|
-
currency: "RSD",
|
|
598
|
-
eu_member: false,
|
|
599
|
-
vat_name: "Porez na dodatu vrednost",
|
|
600
|
-
vat_abbr: "PDV",
|
|
601
|
-
standard: 20,
|
|
602
|
-
reduced: [
|
|
603
|
-
10
|
|
604
|
-
],
|
|
605
|
-
super_reduced: null,
|
|
606
|
-
parking: null,
|
|
607
|
-
format: "9 digits",
|
|
608
|
-
pattern: "^\\d{9}$"
|
|
609
|
-
},
|
|
610
|
-
SE: {
|
|
611
|
-
country: "Sweden",
|
|
612
|
-
currency: "SEK",
|
|
613
|
-
eu_member: true,
|
|
614
|
-
vat_name: "Merv\xE4rdesskatt",
|
|
615
|
-
vat_abbr: "moms",
|
|
616
|
-
standard: 25,
|
|
617
|
-
reduced: [
|
|
618
|
-
6,
|
|
619
|
-
12
|
|
620
|
-
],
|
|
621
|
-
super_reduced: null,
|
|
622
|
-
parking: null,
|
|
623
|
-
format: "SE + 10 digits + 01",
|
|
624
|
-
pattern: "^SE\\d{10}01$"
|
|
625
|
-
},
|
|
626
|
-
SI: {
|
|
627
|
-
country: "Slovenia",
|
|
628
|
-
currency: "EUR",
|
|
629
|
-
eu_member: true,
|
|
630
|
-
vat_name: "Davek na dodano vrednost",
|
|
631
|
-
vat_abbr: "DDV",
|
|
632
|
-
standard: 22,
|
|
633
|
-
reduced: [
|
|
634
|
-
5,
|
|
635
|
-
9.5
|
|
636
|
-
],
|
|
637
|
-
super_reduced: null,
|
|
638
|
-
parking: null,
|
|
639
|
-
format: "SI + 8 digits",
|
|
640
|
-
pattern: "^SI\\d{8}$"
|
|
641
|
-
},
|
|
642
|
-
SK: {
|
|
643
|
-
country: "Slovakia",
|
|
644
|
-
currency: "EUR",
|
|
645
|
-
eu_member: true,
|
|
646
|
-
vat_name: "Da\u0148 z pridanej hodnoty",
|
|
647
|
-
vat_abbr: "DPH",
|
|
648
|
-
standard: 23,
|
|
649
|
-
reduced: [
|
|
650
|
-
5,
|
|
651
|
-
19
|
|
652
|
-
],
|
|
653
|
-
super_reduced: null,
|
|
654
|
-
parking: null,
|
|
655
|
-
format: "SK + 10 digits",
|
|
656
|
-
pattern: "^SK\\d{10}$"
|
|
657
|
-
},
|
|
658
|
-
TR: {
|
|
659
|
-
country: "Turkey",
|
|
660
|
-
currency: "TRY",
|
|
661
|
-
eu_member: false,
|
|
662
|
-
vat_name: "Katma De\u011Fer Vergisi",
|
|
663
|
-
vat_abbr: "KDV",
|
|
664
|
-
standard: 20,
|
|
665
|
-
reduced: [
|
|
666
|
-
1,
|
|
667
|
-
10
|
|
668
|
-
],
|
|
669
|
-
super_reduced: null,
|
|
670
|
-
parking: null,
|
|
671
|
-
format: "10 digits",
|
|
672
|
-
pattern: "^\\d{10}$"
|
|
673
|
-
},
|
|
674
|
-
UA: {
|
|
675
|
-
country: "Ukraine",
|
|
676
|
-
currency: "UAH",
|
|
677
|
-
eu_member: false,
|
|
678
|
-
vat_name: "\u041F\u043E\u0434\u0430\u0442\u043E\u043A \u043D\u0430 \u0434\u043E\u0434\u0430\u043D\u0443 \u0432\u0430\u0440\u0442\u0456\u0441\u0442\u044C",
|
|
679
|
-
vat_abbr: "\u041F\u0414\u0412",
|
|
680
|
-
standard: 20,
|
|
681
|
-
reduced: [
|
|
682
|
-
7,
|
|
683
|
-
14
|
|
684
|
-
],
|
|
685
|
-
super_reduced: null,
|
|
686
|
-
parking: null,
|
|
687
|
-
format: "9 digits",
|
|
688
|
-
pattern: "^\\d{9}$"
|
|
689
|
-
},
|
|
690
|
-
XI: {
|
|
691
|
-
country: "Northern Ireland",
|
|
692
|
-
currency: "GBP",
|
|
693
|
-
eu_member: false,
|
|
694
|
-
vat_name: "Value Added Tax",
|
|
695
|
-
vat_abbr: "VAT",
|
|
696
|
-
standard: 20,
|
|
697
|
-
reduced: [
|
|
698
|
-
5
|
|
699
|
-
],
|
|
700
|
-
super_reduced: null,
|
|
701
|
-
parking: null,
|
|
702
|
-
format: "XI + 9 digits, 12 digits, or GD/HA + 3 digits",
|
|
703
|
-
pattern: "^XI(\\d{9}|\\d{12}|(GD|HA)\\d{3})$"
|
|
704
|
-
},
|
|
705
|
-
XK: {
|
|
706
|
-
country: "Kosovo",
|
|
707
|
-
currency: "EUR",
|
|
708
|
-
eu_member: false,
|
|
709
|
-
vat_name: "Tatimi mbi Vler\xEBn e Shtuar",
|
|
710
|
-
vat_abbr: "TVSH",
|
|
711
|
-
standard: 18,
|
|
712
|
-
reduced: [
|
|
713
|
-
8
|
|
714
|
-
],
|
|
715
|
-
super_reduced: null,
|
|
716
|
-
parking: null,
|
|
717
|
-
format: "9 digits",
|
|
718
|
-
pattern: "^\\d{9}$"
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
};
|
|
722
|
-
var dataset = eu_vat_rates_default;
|
|
723
|
-
function getRate(code) {
|
|
724
|
-
return dataset.rates[code];
|
|
725
|
-
}
|
|
726
|
-
function getAllRates() {
|
|
727
|
-
return dataset.rates;
|
|
728
|
-
}
|
|
729
|
-
var dataVersion = dataset.version;
|
|
730
|
-
|
|
731
|
-
// ../../packages/shared/src/validators/index.ts
|
|
732
6
|
import { z } from "zod";
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
"EE",
|
|
742
|
-
"FI",
|
|
743
|
-
"FR",
|
|
744
|
-
"DE",
|
|
745
|
-
"GR",
|
|
746
|
-
"HU",
|
|
747
|
-
"IE",
|
|
748
|
-
"IT",
|
|
749
|
-
"LV",
|
|
750
|
-
"LT",
|
|
751
|
-
"LU",
|
|
752
|
-
"MT",
|
|
753
|
-
"NL",
|
|
754
|
-
"PL",
|
|
755
|
-
"PT",
|
|
756
|
-
"RO",
|
|
757
|
-
"SK",
|
|
758
|
-
"SI",
|
|
759
|
-
"ES",
|
|
760
|
-
"SE",
|
|
761
|
-
"XI"
|
|
762
|
-
];
|
|
763
|
-
var _rates = getAllRates();
|
|
764
|
-
var VAT_PATTERNS = {};
|
|
765
|
-
for (const code of EU_COUNTRY_CODES) {
|
|
766
|
-
const entry = _rates[code];
|
|
767
|
-
if (entry?.pattern) {
|
|
768
|
-
VAT_PATTERNS[code] = new RegExp(entry.pattern);
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
function normalizeVatId(vatId) {
|
|
772
|
-
const upper = vatId.trim().toUpperCase().replace(/[\s\-.]/g, "");
|
|
773
|
-
return upper.startsWith("GR") ? "EL" + upper.slice(2) : upper;
|
|
774
|
-
}
|
|
775
|
-
function extractCountryCode(vatId) {
|
|
776
|
-
const normalized = normalizeVatId(vatId);
|
|
777
|
-
if (normalized.startsWith("EL")) return "GR";
|
|
778
|
-
const code = normalized.slice(0, 2);
|
|
779
|
-
return EU_COUNTRY_CODES.includes(code) ? code : null;
|
|
780
|
-
}
|
|
781
|
-
function validateVatIdFormat(vatId) {
|
|
782
|
-
const normalized = normalizeVatId(vatId);
|
|
783
|
-
if (normalized.length < 4) {
|
|
784
|
-
return { valid: false, error: "VAT ID too short" };
|
|
785
|
-
}
|
|
786
|
-
const countryCode = extractCountryCode(normalized);
|
|
787
|
-
if (!countryCode) {
|
|
788
|
-
return { valid: false, error: "Invalid country code" };
|
|
789
|
-
}
|
|
790
|
-
const pattern = VAT_PATTERNS[countryCode];
|
|
791
|
-
if (pattern && !pattern.test(normalized)) {
|
|
792
|
-
return { valid: false, error: `Invalid VAT ID format for ${countryCode}` };
|
|
793
|
-
}
|
|
794
|
-
return { valid: true };
|
|
795
|
-
}
|
|
796
|
-
var vatIdSchema = z.string().min(4).max(20).transform(normalizeVatId);
|
|
797
|
-
var countryCodeSchema = z.enum(EU_COUNTRY_CODES);
|
|
798
|
-
var createSubscriptionSchema = z.object({
|
|
799
|
-
vatId: vatIdSchema,
|
|
800
|
-
webhookId: z.string().uuid().optional(),
|
|
801
|
-
emailEnabled: z.boolean().default(false)
|
|
802
|
-
});
|
|
803
|
-
var updateSubscriptionSchema = z.object({
|
|
804
|
-
status: z.enum(["active", "paused"]).optional(),
|
|
805
|
-
webhookId: z.string().uuid().nullable().optional(),
|
|
806
|
-
emailEnabled: z.boolean().optional()
|
|
807
|
-
});
|
|
808
|
-
var createWebhookSchema = z.object({
|
|
809
|
-
url: z.string().url()
|
|
810
|
-
});
|
|
811
|
-
var paginationSchema = z.object({
|
|
812
|
-
page: z.coerce.number().int().positive().default(1),
|
|
813
|
-
limit: z.coerce.number().int().min(1).max(100).default(20)
|
|
814
|
-
});
|
|
815
|
-
|
|
816
|
-
// src/index.ts
|
|
817
|
-
var VERSION = "0.1.0";
|
|
7
|
+
import {
|
|
8
|
+
getAllRates,
|
|
9
|
+
getRate,
|
|
10
|
+
validateFormat,
|
|
11
|
+
isEUMember,
|
|
12
|
+
dataVersion
|
|
13
|
+
} from "eu-vat-rates-data";
|
|
14
|
+
var VERSION = "0.2.0";
|
|
818
15
|
var API_BASE = process.env.VATNODE_API_URL ?? "https://api.vatnode.dev";
|
|
819
16
|
var API_KEY = process.env.VATNODE_API_KEY;
|
|
820
17
|
var USER_AGENT = `vatnode-mcp/${VERSION} (+https://vatnode.dev)`;
|
|
@@ -834,6 +31,9 @@ Hint: ${hint}` : message
|
|
|
834
31
|
}
|
|
835
32
|
]
|
|
836
33
|
});
|
|
34
|
+
function normalizeVatId(vatId) {
|
|
35
|
+
return vatId.toUpperCase().replace(/[\s-]/g, "");
|
|
36
|
+
}
|
|
837
37
|
function buildRate(countryCode) {
|
|
838
38
|
const r = getRate(countryCode);
|
|
839
39
|
if (!r) return null;
|
|
@@ -852,11 +52,13 @@ function buildRate(countryCode) {
|
|
|
852
52
|
updatedAt: dataVersion
|
|
853
53
|
};
|
|
854
54
|
}
|
|
55
|
+
var isVIESEligible = (code) => isEUMember(code) || code === "XI";
|
|
56
|
+
var EU_COUNTRY_CODES = Object.keys(getAllRates()).filter(isVIESEligible).sort();
|
|
855
57
|
server.registerTool(
|
|
856
58
|
"list_eu_vat_rates",
|
|
857
59
|
{
|
|
858
60
|
title: "List EU VAT rates",
|
|
859
|
-
description: 'Returns current VAT rates for all
|
|
61
|
+
description: 'Returns current VAT rates for all EU member states (plus XI for Northern Ireland). Use when the user asks for an overview, a comparison across countries, or "all EU VAT rates". For a single country prefer get_country_vat_rates. Data is sourced from the EU Commission TEDB and updated daily. Free, no API key required.',
|
|
860
62
|
inputSchema: {}
|
|
861
63
|
},
|
|
862
64
|
async () => {
|
|
@@ -870,7 +72,7 @@ server.registerTool(
|
|
|
870
72
|
title: "Get VAT rates for a country",
|
|
871
73
|
description: 'Returns the standard, reduced, super-reduced and parking VAT rates for a single European country, plus the VAT number format and regex. Accepts ISO 3166-1 alpha-2 codes (DE, FR, IT, \u2026); also covers non-EU European jurisdictions where available (NO, CH, GB, UA, TR, \u2026). Use when the user asks "what is the VAT rate in X" or needs the VAT number format for a country. Free, no API key required.',
|
|
872
74
|
inputSchema: {
|
|
873
|
-
countryCode:
|
|
75
|
+
countryCode: z.string().length(2).describe('ISO 3166-1 alpha-2 country code, e.g. "DE", "FR", "IT".')
|
|
874
76
|
}
|
|
875
77
|
},
|
|
876
78
|
async ({ countryCode }) => {
|
|
@@ -885,21 +87,21 @@ server.registerTool(
|
|
|
885
87
|
title: "Check VAT number format",
|
|
886
88
|
description: "Performs an offline syntactic check of a VAT number against the country-specific regex pattern. Does NOT verify the VAT with VIES \u2014 use validate_vat_number for that. Use when the user wants a quick sanity check on the shape of a VAT ID without burning a quota call. Free, no API key required.",
|
|
887
89
|
inputSchema: {
|
|
888
|
-
vatId:
|
|
90
|
+
vatId: z.string().min(3).describe(
|
|
889
91
|
'A VAT number, with or without spaces/dashes, with or without country prefix (e.g. "DE123456789", "IE 6388047 V").'
|
|
890
92
|
)
|
|
891
93
|
}
|
|
892
94
|
},
|
|
893
95
|
async ({ vatId }) => {
|
|
894
96
|
const normalized = normalizeVatId(vatId);
|
|
895
|
-
const country =
|
|
896
|
-
const
|
|
97
|
+
const country = normalized.slice(0, 2);
|
|
98
|
+
const valid = validateFormat(normalized);
|
|
897
99
|
return ok({
|
|
898
100
|
input: vatId,
|
|
899
101
|
normalized,
|
|
900
|
-
countryCode: country,
|
|
901
|
-
validFormat:
|
|
902
|
-
error:
|
|
102
|
+
countryCode: getRate(country) ? country : null,
|
|
103
|
+
validFormat: valid,
|
|
104
|
+
error: valid ? null : `${normalized} does not match the expected VAT number format for ${country}.`
|
|
903
105
|
});
|
|
904
106
|
}
|
|
905
107
|
);
|
|
@@ -912,12 +114,11 @@ server.registerTool(
|
|
|
912
114
|
},
|
|
913
115
|
async () => {
|
|
914
116
|
const all = getAllRates();
|
|
915
|
-
const euSet = new Set(EU_COUNTRY_CODES);
|
|
916
117
|
const countries = Object.entries(all).map(([code, r]) => ({
|
|
917
118
|
countryCode: code,
|
|
918
119
|
countryName: r.country,
|
|
919
|
-
isEUMember:
|
|
920
|
-
viesValidationSupported:
|
|
120
|
+
isEUMember: isVIESEligible(code),
|
|
121
|
+
viesValidationSupported: isVIESEligible(code)
|
|
921
122
|
})).sort((a, b) => a.countryCode.localeCompare(b.countryCode));
|
|
922
123
|
return ok({
|
|
923
124
|
countries,
|
|
@@ -960,13 +161,13 @@ server.registerTool(
|
|
|
960
161
|
title: "Validate EU VAT number",
|
|
961
162
|
description: "Verifies an EU VAT number against the official VIES service and returns validity, company name, address, registration date and other metadata. When the requester (your own VAT) is configured on the vatnode account, also returns a VIES consultation number \u2014 audit-grade proof of validation. Use whenever the user wants to confirm a VAT is real, look up the company behind a VAT, or needs evidence for accounting/compliance. Requires a vatnode API key (free tier available). Only EU-27 + XI (Northern Ireland) are supported by VIES.",
|
|
962
163
|
inputSchema: {
|
|
963
|
-
vatId:
|
|
164
|
+
vatId: z.string().min(3).describe(
|
|
964
165
|
'EU VAT number, with country prefix. Spaces and dashes are stripped. Examples: "DE123456789", "IE6388047V", "FR12345678901".'
|
|
965
166
|
),
|
|
966
|
-
requesterCountryCode:
|
|
167
|
+
requesterCountryCode: z.string().length(2).optional().describe(
|
|
967
168
|
"Optional: 2-letter country code of the party doing the check. Together with requesterVatNumber, asks VIES to issue an audit consultation number."
|
|
968
169
|
),
|
|
969
|
-
requesterVatNumber:
|
|
170
|
+
requesterVatNumber: z.string().min(1).optional().describe(
|
|
970
171
|
"Optional: VAT number of the party doing the check. Pair with requesterCountryCode to get a consultation number."
|
|
971
172
|
)
|
|
972
173
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vatnode-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Official Model Context Protocol (MCP) server for vatnode — EU VAT validation, rates, and format checks for AI agents (Claude, Cursor, ChatGPT).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -15,11 +15,14 @@
|
|
|
15
15
|
],
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"author": "vatnode",
|
|
18
|
-
"homepage": "https://vatnode.dev",
|
|
18
|
+
"homepage": "https://vatnode.dev/docs/mcp",
|
|
19
19
|
"repository": {
|
|
20
20
|
"type": "git",
|
|
21
|
-
"url": "https://github.com/vatnode/vatnode.git"
|
|
22
|
-
|
|
21
|
+
"url": "git+https://github.com/vatnode/vatnode-mcp.git"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/vatnode/vatnode-mcp/issues",
|
|
25
|
+
"email": "support@vatnode.dev"
|
|
23
26
|
},
|
|
24
27
|
"type": "module",
|
|
25
28
|
"bin": {
|
|
@@ -29,24 +32,23 @@
|
|
|
29
32
|
"dist",
|
|
30
33
|
"README.md"
|
|
31
34
|
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"dev": "tsx watch src/index.ts",
|
|
37
|
+
"build": "tsup",
|
|
38
|
+
"start": "node dist/index.js",
|
|
39
|
+
"typecheck": "tsc --noEmit",
|
|
40
|
+
"test": "npm run build && node test/smoke.mjs",
|
|
41
|
+
"prepublishOnly": "npm run build"
|
|
42
|
+
},
|
|
32
43
|
"dependencies": {
|
|
33
44
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"eu-vat-rates-data": "2026.3.27"
|
|
45
|
+
"eu-vat-rates-data": "^2026.5.20",
|
|
46
|
+
"zod": "^3.24.0"
|
|
37
47
|
},
|
|
38
48
|
"devDependencies": {
|
|
39
49
|
"@types/node": "^22.10.0",
|
|
40
50
|
"tsup": "^8.3.0",
|
|
41
51
|
"tsx": "^4.19.0",
|
|
42
52
|
"typescript": "^5.7.0"
|
|
43
|
-
},
|
|
44
|
-
"scripts": {
|
|
45
|
-
"dev": "tsx watch src/index.ts",
|
|
46
|
-
"build": "tsup",
|
|
47
|
-
"start": "node dist/index.js",
|
|
48
|
-
"lint": "eslint src/",
|
|
49
|
-
"typecheck": "tsc --noEmit",
|
|
50
|
-
"test": "pnpm build && node test/smoke.mjs"
|
|
51
53
|
}
|
|
52
|
-
}
|
|
54
|
+
}
|