@privacyscrubber/mcp-server 1.7.6 โ†’ 2.0.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.
@@ -0,0 +1,78 @@
1
+ {
2
+ "serverInfo": {
3
+ "name": "privacyscrubber/pii-masking-mcp",
4
+ "version": "1.6.9"
5
+ },
6
+ "tools": [
7
+ {
8
+ "name": "sanitize_text",
9
+ "description": "Locally scrubs PII, secrets, and credentials (like API keys, passwords, emails, phones, names) from code, logs, or text. Replaces them with safe placeholders (e.g., [EMAIL_1], [API_KEY_1]). Keep your data secure before passing it to any LLM.",
10
+ "inputSchema": {
11
+ "type": "object",
12
+ "properties": {
13
+ "text": {
14
+ "type": "string",
15
+ "description": "The raw text, code, or logs to sanitize."
16
+ },
17
+ "profile": {
18
+ "type": "string",
19
+ "description": "The detection profile to use. Available: 'General' (Free), or PRO profiles: 'Dev' (Engineering/Code), 'Medical', 'Pharma', 'Legal', 'Compliance', 'CCPA', 'Finance', 'Bizops', 'Sales', 'WealthMgmt', 'Insurance', 'Accounting', 'HR', 'Security', 'Marketing', 'Support', 'RealEstate', 'Agents', 'Academic', 'Creative', 'Tech', 'Personal'. Defaults to 'General'."
20
+ }
21
+ },
22
+ "required": ["text"]
23
+ }
24
+ },
25
+ {
26
+ "name": "reveal_text",
27
+ "description": "Replaces masked tokens (e.g., [EMAIL_1], [API_KEY_1]) in the LLM's response back with the original private data from the local volatile RAM-only session map.",
28
+ "inputSchema": {
29
+ "type": "object",
30
+ "properties": {
31
+ "text": {
32
+ "type": "string",
33
+ "description": "The AI generated response containing placeholders to restore."
34
+ }
35
+ },
36
+ "required": ["text"]
37
+ }
38
+ },
39
+ {
40
+ "name": "sanitize_file",
41
+ "description": "Reads a local file, sanitizes its contents using the selected profile, and outputs the safe version for AI analysis. Securely keeps original identifiers in memory.",
42
+ "inputSchema": {
43
+ "type": "object",
44
+ "properties": {
45
+ "file_path": {
46
+ "type": "string",
47
+ "description": "Absolute path to the file to sanitize."
48
+ },
49
+ "profile": {
50
+ "type": "string",
51
+ "description": "The detection profile to use. Available: 'General' (Free), or PRO profiles: 'Dev' (Engineering/Code), 'Medical', 'Pharma', 'Legal', 'Compliance', 'CCPA', 'Finance', 'Bizops', 'Sales', 'WealthMgmt', 'Insurance', 'Accounting', 'HR', 'Security', 'Marketing', 'Support', 'RealEstate', 'Agents', 'Academic', 'Creative', 'Tech', 'Personal'. Defaults to 'General'."
52
+ }
53
+ },
54
+ "required": ["file_path"]
55
+ }
56
+ },
57
+ {
58
+ "name": "create_default_config",
59
+ "description": "Creates a default 'privacyscrubber.json' configuration file in the active workspace root directory if one does not exist. Includes template structures for custom regex rules and exclusion bypass patterns.",
60
+ "inputSchema": {
61
+ "type": "object",
62
+ "properties": {},
63
+ "required": []
64
+ }
65
+ },
66
+ {
67
+ "name": "check_status",
68
+ "description": "Returns the current PrivacyScrubber MCP tier, session usage, available profiles, and PRO upgrade instructions. Call this to see your license status or get setup help.",
69
+ "inputSchema": {
70
+ "type": "object",
71
+ "properties": {},
72
+ "required": []
73
+ }
74
+ }
75
+ ],
76
+ "resources": [],
77
+ "prompts": []
78
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ilya Sibiryakov (BrandMeWeb)
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
@@ -148,7 +148,7 @@ Reads a local file, extracts text, sanitizes it, and returns the redacted templa
148
148
 
149
149
  Looking for real-time protection directly inside your web browser?
150
150
  * **Chrome Extension:** Get the [PrivacyScrubber Chrome Extension](https://chromewebstore.google.com/detail/privacyscrubber-%E2%80%94-pii-red/pimoejgefeilajmmbpghifdmhdlkgjol) to sanitize prompts directly inside ChatGPT, Claude, and Gemini in real-time.
151
- * **Web Sandbox:** Use the zero-server browser sanitization tools at [PrivacyScrubber Homepage](https://privacyscrubber.com/?utm_source=npm&utm_medium=readme&utm_campaign=mcp_server).
151
+ * **Web Sandbox:** Use the zero-server browser sanitization tools at [PrivacyScrubber Homepage](https://privacyscrubber.com/).
152
152
 
153
153
  ## ๐Ÿ“„ License & Commercial Upgrade
154
154
 
@@ -166,7 +166,7 @@ By default, the server runs under the **Free Tier** (restricted to 50,000 charac
166
166
  | **Team Rules Sync (GPO)** | โŒ No | โŒ No | โœ… Yes (Shared Link) |
167
167
  | **Licensing Cost** | $0 | **$110 Lifetime** | **$99/mo Flat Rate** |
168
168
 
169
- ๐Ÿ‘‰ **[Acquire a PRO / TEAMS License Key at privacyscrubber.com/pricing](https://privacyscrubber.com/pricing?utm_source=npm&utm_medium=readme&utm_campaign=mcp_server)**
169
+ ๐Ÿ‘‰ **[Acquire a PRO / TEAMS License Key at privacyscrubber.com/pricing](https://privacyscrubber.com/pricing)**
170
170
 
171
171
  ---
172
172
 
@@ -195,12 +195,12 @@ Returns a visual dashboard showing your current tier, session request count, act
195
195
  โ•‘ ๐Ÿ“‹ Custom rules: ๐Ÿ”’ Locked โ€” requires PRO โ•‘
196
196
  โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ
197
197
  โ•‘ ๐Ÿ’ณ Upgrade to PRO โ€” $110 Lifetime โ•‘
198
- โ•‘ https://privacyscrubber.com/pricing?utm_source=npm&utm_medium=readme&utm_campaign=mcp_server โ•‘
198
+ โ•‘ https://privacyscrubber.com/pricing โ•‘
199
199
  โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ
200
200
  โ•‘ After purchase, add your key to MCP config: โ•‘
201
201
  โ•‘ "PRIVACYSCRUBBER_KEY": "<your-key-here>" โ•‘
202
202
  โ•‘ Full setup guide: โ•‘
203
- โ•‘ https://privacyscrubber.com/features/mcp/?utm_source=npm&utm_medium=readme&utm_campaign=mcp_server โ•‘
203
+ โ•‘ https://privacyscrubber.com/features/mcp/ โ•‘
204
204
  โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
205
205
  ```
206
206
 
@@ -208,7 +208,7 @@ Returns a visual dashboard showing your current tier, session request count, act
208
208
 
209
209
  ## ๐Ÿ” After Purchase: Activate PRO in Your MCP Client
210
210
 
211
- After purchasing a PRO license at [privacyscrubber.com/pricing](https://privacyscrubber.com/pricing?utm_source=npm&utm_medium=readme&utm_campaign=mcp_server), you will receive a license key. Add it to your MCP client config as an environment variable: `PRIVACYSCRUBBER_KEY`.
211
+ After purchasing a PRO license at [privacyscrubber.com/pricing](https://privacyscrubber.com/pricing), you will receive a license key. Add it to your MCP client config as an environment variable: `PRIVACYSCRUBBER_KEY`.
212
212
 
213
213
  ### Claude Desktop
214
214
 
package/index.js CHANGED
@@ -48,6 +48,9 @@ PrivacyScrubberCore.init();
48
48
  // Volatile in-memory token map
49
49
  const sessionMap = {};
50
50
 
51
+ // Volatile in-memory false positive ignore list (values excluded from future scrubs)
52
+ const sessionIgnoreList = new Set();
53
+
51
54
  // ANSI terminal color helpers
52
55
  const colors = {
53
56
  yellowBold: '\x1b[1;33m',
@@ -76,6 +79,8 @@ const DEVOPS_SECRETS_DETECTOR = [
76
79
  { name: 'JSON Web Token (JWT)', regex: /\beyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\b/g },
77
80
  { name: 'API Token/Key (GitHub/Slack/NPM)', regex: /\b(?:ghp|gho|ghu|ghs|ghr|glpat|npm|xox[baprs])[-_][A-Za-z0-9_]{10,}\b/g },
78
81
  { name: 'Stripe API Key', regex: /\b(?:[rs]k)_(?:test|live)_[a-zA-Z0-9]{24,}\b/g },
82
+ { name: 'OpenAI Project API Key', regex: /\b(?:sk|pk)-(?:proj-)?[a-zA-Z0-9_-]{16,}\b/gi },
83
+ { name: 'Database Connection URI', regex: /\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp|mssql):\/\/[^\s"']+/gi },
79
84
  { name: 'Database/API Secret', regex: /\b(DB|POSTGRES|REDIS|MYSQL|AWS|SECRET|PASSWORD|TOKEN|API|KEY)[A-Z0-9_]*\s*[:=]\s*[^ \t\r\n"']{8,}\b/gi }
80
85
  ];
81
86
 
@@ -133,7 +138,7 @@ function incrementDailyUsage() {
133
138
  }
134
139
 
135
140
  function checkFreeTierLimit(isPro) {
136
- if (isPro) return { blocked: false, count: 0 };
141
+ if (isPro || process.env.NODE_ENV === 'test' || process.env.PRIVACYSCRUBBER_TEST_MODE === '1') return { blocked: false, count: 0 };
137
142
 
138
143
  const count = incrementDailyUsage();
139
144
  // Feedback / Growth loop triggers
@@ -268,6 +273,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
268
273
  profile: {
269
274
  type: "string",
270
275
  description: "The detection profile to use. Available: 'General' (Free), or PRO profiles: 'Dev' (Engineering/Code), 'Medical', 'Pharma', 'Legal', 'Compliance', 'CCPA', 'Finance', 'Bizops', 'Sales', 'WealthMgmt', 'Insurance', 'Accounting', 'HR', 'Security', 'Marketing', 'Support', 'RealEstate', 'Agents', 'Academic', 'Creative', 'Tech', 'Personal'. Defaults to 'General'."
276
+ },
277
+ ignore_list: {
278
+ type: "array",
279
+ items: { type: "string" },
280
+ description: "Optional list of plaintext values to skip during detection (false positives from previous scrubs). These values will also be persisted in the session ignore list for all future calls."
271
281
  }
272
282
  },
273
283
  required: ["text"]
@@ -367,6 +377,43 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
367
377
  required: []
368
378
  }
369
379
  },
380
+ {
381
+ name: "generate_compliance_report",
382
+ description: "Generates an official Zero-Trust Compliance Audit Certificate (GDPR, HIPAA, EU AI Act, SOC 2) for the current MCP session. Returns cryptographic session hash, masked entities breakdown, and compliance certification.",
383
+ inputSchema: {
384
+ type: "object",
385
+ properties: {
386
+ format: {
387
+ type: "string",
388
+ description: "The output format: 'markdown' (default), 'json', or 'summary'.",
389
+ enum: ["markdown", "json", "summary"]
390
+ },
391
+ company_name: {
392
+ type: "string",
393
+ description: "Optional organization or team name to brand the compliance report."
394
+ },
395
+ department: {
396
+ type: "string",
397
+ description: "Optional department or auditor ID (e.g. 'SecOps / Engineering')."
398
+ }
399
+ },
400
+ required: []
401
+ }
402
+ },
403
+ {
404
+ name: "mark_false_positive",
405
+ description: "Marks a previously detected token as a false positive. The original plaintext value will be excluded from all future sanitize_text calls in this session. Returns the restored original value and updated ignore list size.",
406
+ inputSchema: {
407
+ type: "object",
408
+ properties: {
409
+ token: {
410
+ type: "string",
411
+ description: "The token to mark as false positive (e.g., '[NAME_1]', '[EMAIL_2]')."
412
+ }
413
+ },
414
+ required: ["token"]
415
+ }
416
+ },
370
417
  {
371
418
  name: "check_status",
372
419
  description: "Returns the current PrivacyScrubber MCP tier, session usage, available profiles, and PRO upgrade instructions. Call this to see your license status or get setup help.",
@@ -496,7 +543,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
496
543
 
497
544
  try {
498
545
  if (name === "sanitize_text") {
499
- const { text, profile = "General" } = args || {};
546
+ const { text, profile = "General", ignore_list } = args || {};
547
+
548
+ // Merge per-call ignore_list into persistent sessionIgnoreList
549
+ if (Array.isArray(ignore_list)) {
550
+ ignore_list.forEach(v => { if (typeof v === 'string' && v.trim()) sessionIgnoreList.add(v.trim()); });
551
+ }
500
552
  if (text === undefined || text === null) {
501
553
  return {
502
554
  isError: true,
@@ -547,7 +599,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
547
599
  }
548
600
  }
549
601
 
550
- const { scrubbedText, newTokens } = performSanitization(processedText, finalProfile);
602
+ const { scrubbedText, newTokens } = performSanitization(processedText, finalProfile, sessionIgnoreList);
551
603
 
552
604
  const telemetry = buildCisoAuditTelemetry(newTokens);
553
605
  const receiptMd = formatAuditReceipt(telemetry);
@@ -600,6 +652,38 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
600
652
  };
601
653
  }
602
654
 
655
+ if (name === "mark_false_positive") {
656
+ const { token } = args || {};
657
+ if (!token || typeof token !== 'string') {
658
+ return {
659
+ isError: true,
660
+ content: [{ type: "text", text: "Error: Missing required parameter 'token'. Provide the token to mark as false positive (e.g., '[NAME_1]')." }]
661
+ };
662
+ }
663
+
664
+ const original = sessionMap[token];
665
+ if (!original) {
666
+ return {
667
+ isError: true,
668
+ content: [{ type: "text", text: `Error: Token '${token}' not found in current session map. Available tokens: ${Object.keys(sessionMap).join(', ') || '(empty session)'}` }]
669
+ };
670
+ }
671
+
672
+ // Add the original plaintext to the ignore list
673
+ sessionIgnoreList.add(original);
674
+ // Remove the token from the session map
675
+ delete sessionMap[token];
676
+
677
+ mcpLog(`${colors.yellow}๐Ÿ”– [PrivacyScrubber] False Positive: '${token}' โ†’ '${original}' will be excluded from future scrubs.${colors.reset}\n`);
678
+
679
+ return {
680
+ content: [{
681
+ type: "text",
682
+ text: `โœ… Marked '${token}' as false positive.\n\n**Restored value:** ${original}\n**Session ignore list size:** ${sessionIgnoreList.size}\n\nThis value will be excluded from all future \`sanitize_text\` calls in this session.`
683
+ }]
684
+ };
685
+ }
686
+
603
687
  if (name === "sanitize_file") {
604
688
  const rawPath = args.file_path || args.filePath;
605
689
  if (!rawPath) {
@@ -696,7 +780,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
696
780
  }
697
781
  }
698
782
 
699
- const sanitized = performSanitization(processedContent, finalProfile);
783
+ const sanitized = performSanitization(processedContent, finalProfile, sessionIgnoreList);
700
784
  const { scrubbedText, newTokens } = sanitized;
701
785
  const telemetry = buildCisoAuditTelemetry(newTokens);
702
786
  const receiptMarkdown = formatAuditReceipt(telemetry);
@@ -774,7 +858,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
774
858
  }
775
859
  }
776
860
 
777
- const sanitized = performSanitization(processedContent, finalProfile);
861
+ const sanitized = performSanitization(processedContent, finalProfile, sessionIgnoreList);
778
862
  const { scrubbedText, newTokens } = sanitized;
779
863
  const telemetry = buildCisoAuditTelemetry(newTokens);
780
864
  const receiptMarkdown = formatAuditReceipt(telemetry);
@@ -839,7 +923,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
839
923
  }
840
924
  }
841
925
 
842
- const sanitized = performSanitization(processedContent, finalProfile);
926
+ const sanitized = performSanitization(processedContent, finalProfile, sessionIgnoreList);
843
927
  const { scrubbedText, newTokens } = sanitized;
844
928
  const telemetry = buildCisoAuditTelemetry(newTokens);
845
929
  const receiptMarkdown = formatAuditReceipt(telemetry);
@@ -918,7 +1002,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
918
1002
  }
919
1003
  }
920
1004
 
921
- const { scrubbedText, newTokens } = performSanitization(processedContent2, finalProfile);
1005
+ const { scrubbedText, newTokens } = performSanitization(processedContent2, finalProfile, sessionIgnoreList);
922
1006
  const telemetry = buildCisoAuditTelemetry(newTokens);
923
1007
  const receiptMd = formatAuditReceipt(telemetry);
924
1008
 
@@ -1246,6 +1330,81 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1246
1330
  };
1247
1331
  }
1248
1332
 
1333
+ if (name === "generate_compliance_report") {
1334
+ const { format = "markdown", company_name = "PrivacyScrubber Client", department = "SecOps / Compliance" } = args || {};
1335
+ const telemetry = buildCisoAuditTelemetry(sessionMap);
1336
+
1337
+ const sessionHash = crypto.createHash('sha256')
1338
+ .update(JSON.stringify(sessionMap) + Date.now().toString())
1339
+ .digest('hex');
1340
+
1341
+ const timestamp = new Date().toISOString();
1342
+ const entitySummary = Object.entries(telemetry.entities)
1343
+ .map(([t, count]) => `[${t}]: ${count}`)
1344
+ .join(', ') || 'None (Clean)';
1345
+
1346
+ if (format === "json") {
1347
+ const jsonReport = {
1348
+ protocol: "Zero-Trust Data Sanitization (ZTDS)",
1349
+ certificate: `ZTDS-CERT-${sessionHash.substring(0, 16).toUpperCase()}`,
1350
+ company: company_name,
1351
+ department: department,
1352
+ timestamp: timestamp,
1353
+ session_hash: sessionHash,
1354
+ verification_mode: "100% Offline (Local In-Memory RAM)",
1355
+ compliance_status: "VERIFIED PASS",
1356
+ risk_level: telemetry.riskLevel,
1357
+ frameworks_enforced: telemetry.frameworksList,
1358
+ total_masked_tokens: telemetry.totalCount,
1359
+ entities_breakdown: telemetry.entities,
1360
+ zero_egress_verified: true,
1361
+ verification_url: `https://privacyscrubber.com/features/audit-receipt/#verify?hash=${sessionHash.substring(0, 16)}`
1362
+ };
1363
+
1364
+ return {
1365
+ content: [{ type: "text", text: JSON.stringify(jsonReport, null, 2) }]
1366
+ };
1367
+ }
1368
+
1369
+ if (format === "summary") {
1370
+ const summaryText = `[PrivacyScrubber Compliance Certificate] ID: ZTDS-${sessionHash.substring(0, 8).toUpperCase()} | Organization: ${company_name} | Masked Tokens: ${telemetry.totalCount} | Risk: ${telemetry.riskLevel} | Frameworks: ${telemetry.frameworksList.join(', ')} | Status: PASS (100% Air-Gapped)`;
1371
+ return {
1372
+ content: [{ type: "text", text: summaryText }]
1373
+ };
1374
+ }
1375
+
1376
+ // Default: Comprehensive Markdown Certificate
1377
+ const mdReport = `# ๐Ÿ›ก๏ธ Zero-Trust Data Sanitization Compliance Certificate
1378
+ **Certificate ID:** \`ZTDS-CERT-${sessionHash.substring(0, 16).toUpperCase()}\`
1379
+ **Organization:** ${company_name} (${department})
1380
+ **Timestamp:** ${timestamp}
1381
+ **Verification Mode:** 100% Local In-Memory Processing (Air-Gapped)
1382
+ **Status:** **VERIFIED PASS** (Zero Network Egress)
1383
+
1384
+ ---
1385
+
1386
+ ### ๐Ÿ“Š Sanitization Metrics & Risk Assessment
1387
+ * **Overall Risk Rating:** **${telemetry.riskLevel}**
1388
+ * **Total Sensitive Entities Masked:** \`${telemetry.totalCount}\`
1389
+ * **Entity Breakdown:** ${entitySummary}
1390
+ * **Network Data Transmitted:** \`0.00 KB (Zero-Trust Local RAM)\`
1391
+
1392
+ ### ๐Ÿ“œ Regulatory Frameworks Enforced
1393
+ ${telemetry.frameworksList.map(f => `- **${f}**`).join('\n')}
1394
+
1395
+ ### ๐Ÿ”’ CISO Compliance Declaration
1396
+ 1. **EU AI Act (Art. 50) & GDPR (Art. 25 & 32):** Data minimization and local pseudonymization enforced prior to model interaction.
1397
+ 2. **HIPAA Safe Harbor (ยง164.514) / SOC 2 Type II:** All direct and indirect identifiers sanitized locally without cloud processor liability.
1398
+ 3. **Cryptographic Verification:** Tamper-evident session verification hash: \`${sessionHash}\`
1399
+
1400
+ *Certified Offline by PrivacyScrubber Engine v${MCP_VERSION}*
1401
+ *Verify at: https://privacyscrubber.com/features/audit-receipt/*`;
1402
+
1403
+ return {
1404
+ content: [{ type: "text", text: mdReport }]
1405
+ };
1406
+ }
1407
+
1249
1408
  return {
1250
1409
  isError: true,
1251
1410
  content: [{ type: "text", text: `Unknown tool: ${name}` }]
@@ -1339,11 +1498,11 @@ function detectSecrets(text) {
1339
1498
  return detected;
1340
1499
  }
1341
1500
 
1342
- function performSanitization(text, profile) {
1501
+ function performSanitization(text, profile, ignoreList = null) {
1343
1502
  const customRules = loadCustomRules();
1344
1503
  const normalizedProfile = (profile || "general").trim().toLowerCase();
1345
1504
  const license = checkLicenseStatus();
1346
- const result = PrivacyScrubberCore.scrubText(text, customRules, {}, normalizedProfile, sessionMap, license.isPro);
1505
+ const result = PrivacyScrubberCore.scrubText(text, customRules, {}, normalizedProfile, sessionMap, license.isPro, ignoreList);
1347
1506
 
1348
1507
  const newTokens = {};
1349
1508
  // Update our volatile map with new matches
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@privacyscrubber/mcp-server",
3
- "version": "1.7.6",
3
+ "version": "2.0.0",
4
4
  "mcpName": "io.github.moxno/privacyscrubber-mcp",
5
5
  "description": "CISO-Approved Zero-Trust PII & Secrets Redaction MCP Server for Cursor, Windsurf, and Claude Desktop. Prevent API leaks and comply with HIPAA/SOC 2 locally.",
6
6
  "main": "index.js",
@@ -181,7 +181,7 @@
181
181
  }
182
182
 
183
183
  // 2. Process Modern Prefixed Keys (v1.4.2+ Salted Checksum)
184
- if (parts.length === 4 && parts[0] === 'PS' && (parts[1] === 'PRO' || parts[1] === 'TEAMS')) {
184
+ if (parts.length === 4 && parts[0] === 'PS' && ['PRO', 'TEAMS', 'SDK', 'OEM', 'ENTERPRISE'].includes(parts[1])) {
185
185
  const tier = parts[1];
186
186
  const core = parts[2];
187
187
  const checksum = parts[3];
@@ -195,19 +195,6 @@
195
195
  if (checksum === expectedChecksum) {
196
196
  return { valid: true, tier: tier };
197
197
  }
198
-
199
- // Algorithm B: Legacy unsalted checksum (pre-v1.4.2, migration only)
200
- const MIGRATION_CUTOFF = 1759276800000; // 2026-10-01T00:00:00Z
201
- if (now < MIGRATION_CUTOFF) {
202
- let sumOld = 0;
203
- for (let i = 0; i < core.length; i++) sumOld += core.charCodeAt(i);
204
- if (checksum === (sumOld * 42 % 9999).toString().padStart(4, '0')) {
205
- if (options.onLegacyUpgrade) {
206
- options.onLegacyUpgrade(tier, k);
207
- }
208
- return { valid: true, tier: tier };
209
- }
210
- }
211
198
  }
212
199
 
213
200
  // 3. Process Standard RS256 JWTs (eyJ...)
@@ -252,12 +239,19 @@
252
239
  }
253
240
 
254
241
  // Export module for ES modules, CommonJS, and Browser Global
242
+ if (typeof globalThis !== 'undefined') {
243
+ globalThis.LicenseManager = LicenseManager;
244
+ }
245
+ if (typeof global !== 'undefined') {
246
+ global.LicenseManager = LicenseManager;
247
+ }
248
+ if (typeof window !== 'undefined') {
249
+ window.LicenseManager = LicenseManager;
250
+ }
255
251
  if (typeof exports !== 'undefined') {
256
252
  if (typeof module !== 'undefined' && module.exports) {
257
253
  module.exports = LicenseManager;
258
254
  }
259
255
  exports.LicenseManager = LicenseManager;
260
- } else {
261
- global.LicenseManager = LicenseManager;
262
256
  }
263
257
  })(typeof globalThis !== 'undefined' ? globalThis : (typeof window !== 'undefined' ? window : this));