data-compliance-mcp 1.0.0 → 1.0.2
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/CHANGELOG.md +8 -0
- package/package.json +15 -5
- package/server.json +7 -25
- package/src/server.js +62 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.0.2] - 2026-04-26
|
|
4
|
+
### Changed
|
|
5
|
+
- Added `agent_action` field to all error responses (PROVIDE_REQUIRED_FIELD, DO_NOT_PROCESS_UNTIL_CLASSIFIED, RETRY_IN_2_MIN)
|
|
6
|
+
- Added `source_url` to validate_data_safety results
|
|
7
|
+
- Added stdio transport for Claude Desktop / npm usage
|
|
8
|
+
- Fixed em-dash in analysis_type string (ASCII --)
|
|
9
|
+
- VERSION constant introduced as single source of truth
|
|
10
|
+
|
|
3
11
|
## [1.0.0] - 2026-04-21
|
|
4
12
|
### Added
|
|
5
13
|
- Initial release
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "data-compliance-mcp",
|
|
3
|
-
"
|
|
3
|
+
"mcpName": "io.github.OjasKord/data-compliance-mcp",
|
|
4
|
+
"version": "1.0.2",
|
|
4
5
|
"description": "Classify data safety before your agent stores or shares it. GDPR, HIPAA, PCI-DSS, CCPA. AI-powered.",
|
|
5
6
|
"main": "src/server.js",
|
|
6
7
|
"scripts": {
|
|
@@ -21,15 +22,24 @@
|
|
|
21
22
|
"privacy",
|
|
22
23
|
"data-privacy",
|
|
23
24
|
"sensitive-data",
|
|
24
|
-
"validator"
|
|
25
|
+
"validator",
|
|
26
|
+
"data-governance",
|
|
27
|
+
"ai-safety",
|
|
28
|
+
"regulation",
|
|
29
|
+
"eu-ai-act"
|
|
25
30
|
],
|
|
26
|
-
"author": "
|
|
31
|
+
"author": "Kord Agencies Pte Ltd <ojas@kordagencies.com>",
|
|
27
32
|
"license": "UNLICENSED",
|
|
28
33
|
"homepage": "https://kordagencies.com",
|
|
29
34
|
"repository": {
|
|
30
35
|
"type": "git",
|
|
31
|
-
"url": "https://github.com/OjasKord/data-compliance-mcp"
|
|
36
|
+
"url": "git+https://github.com/OjasKord/data-compliance-mcp.git"
|
|
37
|
+
},
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/OjasKord/data-compliance-mcp/issues"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18.0.0"
|
|
32
43
|
},
|
|
33
|
-
"mcpName": "io.github.OjasKord/data-compliance-mcp",
|
|
34
44
|
"dependencies": {}
|
|
35
45
|
}
|
package/server.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
3
|
"name": "io.github.OjasKord/data-compliance-mcp",
|
|
4
|
-
"version": "1.0.0",
|
|
5
|
-
"description": "Classify data safety before storing or sharing. GDPR, HIPAA, PCI-DSS, CCPA. AI-powered.",
|
|
6
4
|
"title": "Data Compliance Classifier MCP",
|
|
5
|
+
"description": "Classify data safety before storing or sharing. GDPR, HIPAA, PCI-DSS, CCPA. AI-powered.",
|
|
6
|
+
"version": "1.0.2",
|
|
7
7
|
"websiteUrl": "https://kordagencies.com",
|
|
8
8
|
"repository": {
|
|
9
9
|
"url": "https://github.com/OjasKord/data-compliance-mcp",
|
|
@@ -12,32 +12,14 @@
|
|
|
12
12
|
"packages": [
|
|
13
13
|
{
|
|
14
14
|
"registryType": "npm",
|
|
15
|
-
"registryBaseUrl": "https://registry.npmjs.org",
|
|
16
15
|
"identifier": "data-compliance-mcp",
|
|
17
|
-
"version": "1.0.
|
|
18
|
-
"transport": {
|
|
19
|
-
"type": "stdio"
|
|
20
|
-
},
|
|
16
|
+
"version": "1.0.2",
|
|
17
|
+
"transport": { "type": "stdio" },
|
|
21
18
|
"environmentVariables": [
|
|
22
|
-
{
|
|
23
|
-
|
|
24
|
-
"description": "Anthropic API key for AI classification",
|
|
25
|
-
"isRequired": true,
|
|
26
|
-
"isSecret": true
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
"name": "ABUSEIPDB_API_KEY",
|
|
30
|
-
"description": "AbuseIPDB API key for threat intelligence (optional - disables IP threat checks if not set)",
|
|
31
|
-
"isRequired": false,
|
|
32
|
-
"isSecret": true
|
|
33
|
-
}
|
|
19
|
+
{ "name": "ANTHROPIC_API_KEY", "description": "Anthropic API key for AI classification", "isRequired": true, "isSecret": true },
|
|
20
|
+
{ "name": "ABUSEIPDB_API_KEY", "description": "AbuseIPDB API key for threat intelligence (optional)", "isRequired": false, "isSecret": true }
|
|
34
21
|
]
|
|
35
22
|
}
|
|
36
23
|
],
|
|
37
|
-
"remotes": [
|
|
38
|
-
{
|
|
39
|
-
"type": "streamable-http",
|
|
40
|
-
"url": "https://data-compliance-mcp-production.up.railway.app"
|
|
41
|
-
}
|
|
42
|
-
]
|
|
24
|
+
"remotes": [{ "type": "streamable-http", "url": "https://data-compliance-mcp-production.up.railway.app" }]
|
|
43
25
|
}
|
package/src/server.js
CHANGED
|
@@ -3,7 +3,7 @@ const https = require('https');
|
|
|
3
3
|
const crypto = require('crypto');
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
|
|
6
|
-
const VERSION = '1.0.
|
|
6
|
+
const VERSION = '1.0.2';
|
|
7
7
|
const PERSIST_FILE = '/tmp/datacompliance_stats.json';
|
|
8
8
|
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY || '';
|
|
9
9
|
const ABUSEIPDB_API_KEY = process.env.ABUSEIPDB_API_KEY || '';
|
|
@@ -17,6 +17,8 @@ const FREE_TIER_LIMIT = 20;
|
|
|
17
17
|
const FREE_TIER_WARNING = 16;
|
|
18
18
|
const apiKeys = new Map();
|
|
19
19
|
const PLAN_LIMITS = { pro: 5000, enterprise: Infinity };
|
|
20
|
+
const STRIPE_PRO_URL = 'https://buy.stripe.com/8x24gy9Ah3iZ8W04xiebu0c';
|
|
21
|
+
const STRIPE_ENTERPRISE_URL = 'https://buy.stripe.com/cNi7sKeUB8Dj7RW7Juebu0d';
|
|
20
22
|
|
|
21
23
|
const LEGAL_DISCLAIMER = 'Classification is AI-powered and for informational purposes only. Does not constitute legal advice and does not guarantee regulatory compliance. We do not store or log your data payload — it is analysed in memory and immediately discarded. Jurisdiction detection uses IPinfo (ipinfo.io). Credential checks use the Pwned Passwords k-anonymity API (haveibeenpwned.com) — your credentials are never transmitted in full. Threat checks use AbuseIPDB (abuseipdb.com). Provider maximum liability is limited to subscription fees paid in the preceding 3 months. Full terms: kordagencies.com/terms.html';
|
|
22
24
|
|
|
@@ -253,7 +255,7 @@ function extractCredentials(payload) {
|
|
|
253
255
|
const tools = [
|
|
254
256
|
{
|
|
255
257
|
name: 'validate_data_safety',
|
|
256
|
-
description: 'Call this tool BEFORE your agent stores, transmits, logs, or passes any data payload to another system.
|
|
258
|
+
description: 'Call this tool BEFORE your agent stores, transmits, logs, or passes any data payload to another system. Returns one of four machine-readable verdicts your agent can act on immediately: SAFE_TO_PROCESS, REDACT_BEFORE_PASSING, DO_NOT_STORE, or ESCALATE -- no human interpretation needed. Prevents GDPR, HIPAA, and PCI-DSS violations before they happen, not after. Use when your agent has just received data from a user, form, API, webhook, or external source. Also use for: classifying customer records before database writes, screening scraped content before storage, checking API responses before caching. AI-powered -- NOT a simple pattern match. Combines Claude reasoning with live jurisdiction detection (IPinfo) and credential breach checking (HaveIBeenPwned k-anonymity). LEGAL NOTICE: Classification is informational only, not legal advice. We do not store your data payload. Full terms: kordagencies.com/terms.html. Free tier: first 20 classifications/month, no API key needed.',
|
|
257
259
|
inputSchema: {
|
|
258
260
|
type: 'object',
|
|
259
261
|
properties: {
|
|
@@ -267,7 +269,7 @@ const tools = [
|
|
|
267
269
|
},
|
|
268
270
|
{
|
|
269
271
|
name: 'get_safety_report',
|
|
270
|
-
description: 'Call this tool when your agent needs to classify
|
|
272
|
+
description: 'Call this tool when your agent needs to classify multiple data payloads at once or generate audit documentation for a dataset. BATCH mode: classify up to 50 payloads with full AI reasoning per payload -- use for bulk onboarding flows, pre-migration audits, or any workflow processing multiple records. AUDIT mode: generate a structured compliance report for a dataset description -- use when your agent needs documentation a human compliance officer can review and sign off. Returns threat actor detection via AbuseIPDB for any IP addresses found. A company that processes data at scale without batch classification is one breach away from a regulator fine. AI-powered -- NOT a simple database lookup. LEGAL NOTICE: Classification is informational only. We do not store your data payloads. Full terms: kordagencies.com/terms.html. Paid API key required -- upgrade at kordagencies.com.',
|
|
271
273
|
inputSchema: {
|
|
272
274
|
type: 'object',
|
|
273
275
|
properties: {
|
|
@@ -289,7 +291,7 @@ async function executeTool(name, args, tier) {
|
|
|
289
291
|
// ── validate_data_safety ──────────────────────────────────────────────────
|
|
290
292
|
if (name === 'validate_data_safety') {
|
|
291
293
|
const { payload, context, data_origin_ip, jurisdiction } = args;
|
|
292
|
-
if (!payload) return { error: 'payload is required', _disclaimer: LEGAL_DISCLAIMER };
|
|
294
|
+
if (!payload) return { error: 'payload is required', agent_action: 'PROVIDE_REQUIRED_FIELD', _disclaimer: LEGAL_DISCLAIMER };
|
|
293
295
|
|
|
294
296
|
// Step 1: Pattern detection (fast, no API call)
|
|
295
297
|
const patterns = detectPatterns(payload);
|
|
@@ -373,7 +375,8 @@ async function executeTool(name, args, tier) {
|
|
|
373
375
|
classification = JSON.parse(clean);
|
|
374
376
|
} catch(e) {
|
|
375
377
|
return {
|
|
376
|
-
error: 'AI classification temporarily unavailable
|
|
378
|
+
error: 'AI classification temporarily unavailable -- manual review recommended before processing this data.',
|
|
379
|
+
agent_action: 'DO_NOT_PROCESS_UNTIL_CLASSIFIED',
|
|
377
380
|
patterns_detected: patterns,
|
|
378
381
|
checked_at: checkedAt,
|
|
379
382
|
_disclaimer: LEGAL_DISCLAIMER
|
|
@@ -390,7 +393,8 @@ async function executeTool(name, args, tier) {
|
|
|
390
393
|
jurisdiction_detected: detectedCountry || jurisdiction || null,
|
|
391
394
|
patterns_detected: patterns,
|
|
392
395
|
credential_check: credentialCheck,
|
|
393
|
-
analysis_type: 'AI-powered classification
|
|
396
|
+
analysis_type: 'AI-powered classification -- NOT a simple pattern match',
|
|
397
|
+
source_url: 'api.anthropic.com + ipinfo.io + api.pwnedpasswords.com',
|
|
394
398
|
checked_at: checkedAt,
|
|
395
399
|
_disclaimer: LEGAL_DISCLAIMER
|
|
396
400
|
};
|
|
@@ -403,7 +407,7 @@ async function executeTool(name, args, tier) {
|
|
|
403
407
|
audit_report: 'Pro plan generates structured audit-ready compliance reports',
|
|
404
408
|
threat_intelligence: 'Pro plan checks IP addresses in payload against AbuseIPDB threat database',
|
|
405
409
|
full_reasoning: 'Pro plan includes full AI reasoning per verdict for compliance documentation',
|
|
406
|
-
upgrade_url:
|
|
410
|
+
upgrade_url: STRIPE_PRO_URL
|
|
407
411
|
};
|
|
408
412
|
} else {
|
|
409
413
|
result.reasoning = classification.reasoning;
|
|
@@ -416,7 +420,7 @@ async function executeTool(name, args, tier) {
|
|
|
416
420
|
// ── get_safety_report ─────────────────────────────────────────────────────
|
|
417
421
|
if (name === 'get_safety_report') {
|
|
418
422
|
const { mode, payloads, dataset_description, context } = args;
|
|
419
|
-
if (!mode) return { error: 'mode is required: BATCH or AUDIT', _disclaimer: LEGAL_DISCLAIMER };
|
|
423
|
+
if (!mode) return { error: 'mode is required: BATCH or AUDIT', agent_action: 'PROVIDE_REQUIRED_FIELD', _disclaimer: LEGAL_DISCLAIMER };
|
|
420
424
|
|
|
421
425
|
// Free tier preview — run count analysis without full classification
|
|
422
426
|
if (tier === 'free') {
|
|
@@ -439,7 +443,7 @@ async function executeTool(name, args, tier) {
|
|
|
439
443
|
'Audit-ready compliance report',
|
|
440
444
|
'Redaction targets per flagged payload'
|
|
441
445
|
],
|
|
442
|
-
upgrade_url:
|
|
446
|
+
upgrade_url: STRIPE_PRO_URL,
|
|
443
447
|
checked_at: checkedAt,
|
|
444
448
|
_disclaimer: LEGAL_DISCLAIMER
|
|
445
449
|
};
|
|
@@ -448,7 +452,7 @@ async function executeTool(name, args, tier) {
|
|
|
448
452
|
mode: mode,
|
|
449
453
|
status: 'PREVIEW — paid plan required',
|
|
450
454
|
message: 'Pro plan required for ' + mode + ' reports. Upgrade at kordagencies.com.',
|
|
451
|
-
upgrade_url:
|
|
455
|
+
upgrade_url: STRIPE_PRO_URL,
|
|
452
456
|
checked_at: checkedAt,
|
|
453
457
|
_disclaimer: LEGAL_DISCLAIMER
|
|
454
458
|
};
|
|
@@ -457,7 +461,7 @@ async function executeTool(name, args, tier) {
|
|
|
457
461
|
// ── PAID: BATCH mode ──
|
|
458
462
|
if (mode === 'BATCH') {
|
|
459
463
|
if (!payloads || !Array.isArray(payloads) || payloads.length === 0) {
|
|
460
|
-
return { error: 'payloads array is required for BATCH mode', _disclaimer: LEGAL_DISCLAIMER };
|
|
464
|
+
return { error: 'payloads array is required for BATCH mode', agent_action: 'PROVIDE_REQUIRED_FIELD', _disclaimer: LEGAL_DISCLAIMER };
|
|
461
465
|
}
|
|
462
466
|
const batch = payloads.slice(0, 50);
|
|
463
467
|
const results = [];
|
|
@@ -534,7 +538,7 @@ async function executeTool(name, args, tier) {
|
|
|
534
538
|
// ── PAID: AUDIT mode ──
|
|
535
539
|
if (mode === 'AUDIT') {
|
|
536
540
|
if (!dataset_description) {
|
|
537
|
-
return { error: 'dataset_description is required for AUDIT mode', _disclaimer: LEGAL_DISCLAIMER };
|
|
541
|
+
return { error: 'dataset_description is required for AUDIT mode', agent_action: 'PROVIDE_REQUIRED_FIELD', _disclaimer: LEGAL_DISCLAIMER };
|
|
538
542
|
}
|
|
539
543
|
|
|
540
544
|
const prompt = 'You are a data compliance auditor. Generate a structured compliance audit report for the following dataset.\n\n' +
|
|
@@ -556,14 +560,14 @@ async function executeTool(name, args, tier) {
|
|
|
556
560
|
_disclaimer: LEGAL_DISCLAIMER
|
|
557
561
|
};
|
|
558
562
|
} catch(e) {
|
|
559
|
-
return { error: 'Audit report generation failed. Please retry.', checked_at: checkedAt, _disclaimer: LEGAL_DISCLAIMER };
|
|
563
|
+
return { error: 'Audit report generation failed. Please retry.', agent_action: 'RETRY_IN_2_MIN', checked_at: checkedAt, _disclaimer: LEGAL_DISCLAIMER };
|
|
560
564
|
}
|
|
561
565
|
}
|
|
562
566
|
|
|
563
|
-
return { error: 'Invalid mode. Use BATCH or AUDIT.', _disclaimer: LEGAL_DISCLAIMER };
|
|
567
|
+
return { error: 'Invalid mode. Use BATCH or AUDIT.', agent_action: 'PROVIDE_REQUIRED_FIELD', _disclaimer: LEGAL_DISCLAIMER };
|
|
564
568
|
}
|
|
565
569
|
|
|
566
|
-
return { error: 'Unknown tool: ' + name };
|
|
570
|
+
return { error: 'Unknown tool: ' + name, agent_action: 'RETRY_IN_2_MIN' };
|
|
567
571
|
}
|
|
568
572
|
|
|
569
573
|
// ─── ACCESS CONTROL ───────────────────────────────────────────────────────────
|
|
@@ -585,7 +589,7 @@ function checkAccess(req, toolName) {
|
|
|
585
589
|
return {
|
|
586
590
|
allowed: false,
|
|
587
591
|
reason: 'Free tier limit of ' + FREE_TIER_LIMIT + ' classifications/month reached. You have seen it work — upgrade to Pro ($49/month) at kordagencies.com for 5,000 classifications/month.',
|
|
588
|
-
upgrade_url:
|
|
592
|
+
upgrade_url: STRIPE_PRO_URL,
|
|
589
593
|
tier: 'free_limit_reached'
|
|
590
594
|
};
|
|
591
595
|
}
|
|
@@ -740,7 +744,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
740
744
|
|
|
741
745
|
if (!access.allowed) {
|
|
742
746
|
res.writeHead(200, { ...cors, 'Content-Type': 'application/json' });
|
|
743
|
-
res.end(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { content: [{ type: 'text', text: JSON.stringify({ error: access.reason,
|
|
747
|
+
res.end(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { content: [{ type: 'text', text: JSON.stringify({ error: access.reason, agent_action: 'Inform user free tier quota is exhausted. Upgrade required at kordagencies.com', upgrade_url: STRIPE_PRO_URL, _disclaimer: LEGAL_DISCLAIMER }) }] } }));
|
|
744
748
|
return;
|
|
745
749
|
}
|
|
746
750
|
|
|
@@ -776,6 +780,47 @@ const server = http.createServer(async (req, res) => {
|
|
|
776
780
|
res.writeHead(404, cors); res.end(JSON.stringify({ error: 'Not found' }));
|
|
777
781
|
});
|
|
778
782
|
|
|
783
|
+
function setupStdio() {
|
|
784
|
+
if (process.stdin.isTTY) return;
|
|
785
|
+
let buf = '';
|
|
786
|
+
process.stdin.setEncoding('utf8');
|
|
787
|
+
process.stdin.on('data', chunk => {
|
|
788
|
+
buf += chunk;
|
|
789
|
+
const lines = buf.split('\n');
|
|
790
|
+
buf = lines.pop();
|
|
791
|
+
lines.forEach(async line => {
|
|
792
|
+
if (!line.trim()) return;
|
|
793
|
+
let req;
|
|
794
|
+
try { req = JSON.parse(line); } catch(e) { return; }
|
|
795
|
+
let response;
|
|
796
|
+
if (req.method === 'initialize') {
|
|
797
|
+
response = { jsonrpc: '2.0', id: req.id, result: { protocolVersion: '2024-11-05', capabilities: { tools: {}, resources: {}, prompts: {} }, serverInfo: { name: 'data-compliance-mcp', version: VERSION, description: 'Classify data safety before your agent stores or shares it. GDPR, HIPAA, PCI-DSS, CCPA. Free tier: 20/month, no API key needed.' } } };
|
|
798
|
+
} else if (req.method === 'notifications/initialized') {
|
|
799
|
+
return;
|
|
800
|
+
} else if (req.method === 'tools/list') {
|
|
801
|
+
response = { jsonrpc: '2.0', id: req.id, result: { tools } };
|
|
802
|
+
} else if (req.method === 'resources/list') {
|
|
803
|
+
response = { jsonrpc: '2.0', id: req.id, result: { resources: [] } };
|
|
804
|
+
} else if (req.method === 'prompts/list') {
|
|
805
|
+
response = { jsonrpc: '2.0', id: req.id, result: { prompts: [] } };
|
|
806
|
+
} else if (req.method === 'tools/call') {
|
|
807
|
+
try {
|
|
808
|
+
const result = await executeTool(req.params.name, req.params.arguments || {}, 'paid');
|
|
809
|
+
response = { jsonrpc: '2.0', id: req.id, result: { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] } };
|
|
810
|
+
} catch(e) {
|
|
811
|
+
response = { jsonrpc: '2.0', id: req.id, error: { code: -32603, message: e.message, agent_action: 'RETRY_IN_2_MIN' } };
|
|
812
|
+
}
|
|
813
|
+
} else {
|
|
814
|
+
response = { jsonrpc: '2.0', id: req.id, error: { code: -32601, message: 'Method not found: ' + req.method } };
|
|
815
|
+
}
|
|
816
|
+
process.stdout.write(JSON.stringify(response) + '\n');
|
|
817
|
+
});
|
|
818
|
+
});
|
|
819
|
+
process.stdin.resume();
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
setupStdio();
|
|
823
|
+
|
|
779
824
|
server.listen(PORT, () => {
|
|
780
825
|
loadStats();
|
|
781
826
|
console.log('Data Compliance Classifier MCP v' + VERSION + ' running on port ' + PORT);
|