vat-validator-mcp 2.0.2 → 2.0.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/package.json +1 -1
- package/server.json +2 -2
- package/src/server.js +36 -41
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vat-validator-mcp",
|
|
3
3
|
"mcpName": "io.github.OjasKord/vat-validator-mcp",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.3",
|
|
5
5
|
"description": "VAT number validator for AI agents. EU VIES, UK HMRC, AU ABR — auto-detects jurisdiction. Fraud risk scoring and invoice name cross-check in one call.",
|
|
6
6
|
"main": "src/server.js",
|
|
7
7
|
"scripts": {
|
package/server.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "io.github.OjasKord/vat-validator-mcp",
|
|
4
4
|
"title": "VAT Validator MCP",
|
|
5
5
|
"description": "Validate EU, UK, AU VAT numbers for AI agents. EU ViDA e-invoicing compliance.",
|
|
6
|
-
"version": "2.0.
|
|
6
|
+
"version": "2.0.2",
|
|
7
7
|
"websiteUrl": "https://kordagencies.com",
|
|
8
8
|
"repository": {
|
|
9
9
|
"url": "https://github.com/OjasKord/vat-validator-mcp",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
{
|
|
14
14
|
"registryType": "npm",
|
|
15
15
|
"identifier": "vat-validator-mcp",
|
|
16
|
-
"version": "2.0.
|
|
16
|
+
"version": "2.0.2",
|
|
17
17
|
"transport": { "type": "stdio" },
|
|
18
18
|
"environmentVariables": [
|
|
19
19
|
{ "name": "ANTHROPIC_API_KEY", "description": "Anthropic API key for AI-powered fraud risk analysis", "isRequired": true, "isSecret": true },
|
package/src/server.js
CHANGED
|
@@ -7,7 +7,7 @@ const Stripe = require('stripe');
|
|
|
7
7
|
const stripe = Stripe(process.env.STRIPE_SECRET_KEY);
|
|
8
8
|
|
|
9
9
|
const PERSIST_FILE = '/tmp/vat_stats.json';
|
|
10
|
-
const VERSION = '2.0.
|
|
10
|
+
const VERSION = '2.0.3';
|
|
11
11
|
|
|
12
12
|
// Persistent device ID for HMRC fraud prevention headers (BATCH_PROCESS_DIRECT)
|
|
13
13
|
const DEVICE_ID_FILE = path.join(__dirname, '..', 'device-id.txt');
|
|
@@ -211,6 +211,15 @@ async function validateVIES(countryCode, vatNumber) {
|
|
|
211
211
|
});
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
async function hmrcFetchWithRetry(url, options, maxRetries = 3) {
|
|
215
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
216
|
+
const response = await fetch(url, options);
|
|
217
|
+
if (response.status !== 429) return response;
|
|
218
|
+
if (attempt === maxRetries) return response;
|
|
219
|
+
await new Promise(resolve => setTimeout(resolve, attempt * 1000));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
214
223
|
function getFraudPreventionHeaders() {
|
|
215
224
|
return {
|
|
216
225
|
'Gov-Client-Connection-Method': 'BATCH_PROCESS_DIRECT',
|
|
@@ -223,7 +232,7 @@ function getFraudPreventionHeaders() {
|
|
|
223
232
|
'Gov-Client-User-IDs': 'os=railway-service',
|
|
224
233
|
'Gov-Vendor-License-IDs': 'vat-validator-mcp=not-applicable',
|
|
225
234
|
'Gov-Vendor-Product-Name': 'VAT%20Validator%20MCP',
|
|
226
|
-
'Gov-Vendor-Version': 'vat-validator-mcp=2.0.
|
|
235
|
+
'Gov-Vendor-Version': 'vat-validator-mcp=2.0.3'
|
|
227
236
|
};
|
|
228
237
|
}
|
|
229
238
|
|
|
@@ -245,32 +254,23 @@ async function getHMRCToken() {
|
|
|
245
254
|
|
|
246
255
|
const body = `client_secret=${encodeURIComponent(clientSecret)}&client_id=${encodeURIComponent(clientId)}&grant_type=client_credentials&scope=read%3Avat`;
|
|
247
256
|
|
|
248
|
-
|
|
249
|
-
const
|
|
250
|
-
hostname,
|
|
251
|
-
path: '/oauth/token',
|
|
257
|
+
try {
|
|
258
|
+
const response = await hmrcFetchWithRetry(`https://${hostname}/oauth/token`, {
|
|
252
259
|
method: 'POST',
|
|
253
|
-
headers: { 'Content-Type': 'application/x-www-form-urlencoded',
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
res.on('end', () => {
|
|
257
|
-
try {
|
|
258
|
-
const json = JSON.parse(d);
|
|
259
|
-
if (json.access_token) {
|
|
260
|
-
hmrcToken = json.access_token;
|
|
261
|
-
hmrcTokenExpiry = now + (json.expires_in || 14400) * 1000;
|
|
262
|
-
resolve(hmrcToken);
|
|
263
|
-
} else {
|
|
264
|
-
resolve(null);
|
|
265
|
-
}
|
|
266
|
-
} catch(e) { resolve(null); }
|
|
267
|
-
});
|
|
260
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded', ...getFraudPreventionHeaders() },
|
|
261
|
+
body,
|
|
262
|
+
signal: AbortSignal.timeout(8000)
|
|
268
263
|
});
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
264
|
+
const json = await response.json();
|
|
265
|
+
if (json.access_token) {
|
|
266
|
+
hmrcToken = json.access_token;
|
|
267
|
+
hmrcTokenExpiry = now + (json.expires_in || 14400) * 1000;
|
|
268
|
+
return hmrcToken;
|
|
269
|
+
}
|
|
270
|
+
return null;
|
|
271
|
+
} catch(e) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
async function validateHMRC(vatNumber) {
|
|
@@ -281,23 +281,18 @@ async function validateHMRC(vatNumber) {
|
|
|
281
281
|
const sandbox = process.env.HMRC_SANDBOX === 'true';
|
|
282
282
|
const hostname = sandbox ? 'test-api.service.hmrc.gov.uk' : 'api.service.hmrc.gov.uk';
|
|
283
283
|
|
|
284
|
-
|
|
285
|
-
const
|
|
286
|
-
hostname,
|
|
287
|
-
path: '/organisations/vat/check-vat-number/lookup/' + clean,
|
|
284
|
+
try {
|
|
285
|
+
const response = await hmrcFetchWithRetry(`https://${hostname}/organisations/vat/check-vat-number/lookup/${clean}`, {
|
|
288
286
|
method: 'GET',
|
|
289
|
-
headers: { 'Accept': 'application/vnd.hmrc.2.0+json', 'Authorization': 'Bearer ' + token, ...getFraudPreventionHeaders() }
|
|
290
|
-
|
|
291
|
-
let d = ''; res.on('data', c => d += c);
|
|
292
|
-
res.on('end', () => {
|
|
293
|
-
try { resolve({ source: 'HMRC', status: res.statusCode, data: JSON.parse(d) }); }
|
|
294
|
-
catch(e) { resolve({ source: 'HMRC', error: 'Parse error' }); }
|
|
295
|
-
});
|
|
287
|
+
headers: { 'Accept': 'application/vnd.hmrc.2.0+json', 'Authorization': 'Bearer ' + token, ...getFraudPreventionHeaders() },
|
|
288
|
+
signal: AbortSignal.timeout(8000)
|
|
296
289
|
});
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
290
|
+
const data = await response.json();
|
|
291
|
+
return { source: 'HMRC', status: response.status, data };
|
|
292
|
+
} catch(e) {
|
|
293
|
+
if (e.name === 'TimeoutError' || e.name === 'AbortError') return { source: 'HMRC', error: 'Timeout' };
|
|
294
|
+
return { source: 'HMRC', error: e.message };
|
|
295
|
+
}
|
|
301
296
|
}
|
|
302
297
|
|
|
303
298
|
async function validateABN(abn) {
|