GDPR / PII Redactor - MCP server that detects and redacts Personally Identifiable Information from raw text — deterministic regex, zero external APIs. Built with Vurb.ts
🛡️ GDPR / PII Redactor
MCP server that detects and redacts Personally Identifiable Information from raw text — deterministic regex, zero external APIs, V8-safe. Built with Vurb.ts.
Why This Exists
Every AI agent that processes user text risks leaking PII — names, emails, tax IDs, credit cards. GDPR mandates data minimisation (Art. 5(1)(c)) and purpose limitation (Art. 5(1)(b)).
This MCP server gives any LLM client a deterministic PII firewall — call pii.redact before saving any user-provided text. Zero hallucination, zero external API calls, zero network dependencies.
Architecture
Agent receives user text
↓
MCP scans with 30 validated patterns (27 EU states + 5 universal)
↓
Replaces PII with [REDACTED_TYPE] placeholders
↓
Returns safe text + audit report (with DLP-protected values)
↓
Agent stores only the redacted text
Double DLP protection:
- Engine redacts PII in the text itself
- Presenter
.redactPII()masks detection values in the audit report — the LLM never sees original PII
Tools
| Tool | Verb | Description |
|---|---|---|
| pii.redact | mutation | Redact PII from text — returns clean text + detection report |
| pii.scan | query | Scan-only — detect and classify PII without modifying text |
| pii.batch | mutation | Batch-redact multiple fields in a single call |
| pii.supported_entities | query | List all 30 detectable entity types |
EU Coverage — All 27 Member States
| Country | Entity Type | Pattern | |---|---|---| | 🇵🇹 Portugal | NIF | 9 digits, check digit | | 🇪🇸 Spain | DNI / NIE | 8 digits + letter / X·Y·Z + 7 digits + letter | | 🇫🇷 France | NIR | 15 digits (Sécurité Sociale) | | 🇮🇹 Italy | Codice Fiscale | 16-char alphanumeric (very distinctive) | | 🇩🇪 Germany | Steuer-ID | 11 digits with structural validation | | 🇳🇱 Netherlands | BSN | 9 digits, mod 11 check | | 🇧🇪 Belgium | NRN | YY.MM.DD-XXX.XX | | 🇵🇱 Poland | PESEL | 11 digits with weighted checksum | | 🇸🇪 Sweden | Personnummer | YYYYMMDD-XXXX | | 🇩🇰 Denmark | CPR | DDMMYY-XXXX | | 🇫🇮 Finland | HETU | DDMMYY[-+A]XXXC | | 🇮🇪 Ireland | PPS | 7 digits + 1–2 letters | | 🇦🇹 Austria | SVN | 4 digits + DDMMYY | | 🇷🇴 Romania | CNP | 13 digits (sex + birthdate + region) | | 🇨🇿 Czech Republic | Rodné číslo | YYMMDD/XXXX | | 🇸🇰 Slovakia | Rodné číslo | YYMMDD/XXXX | | 🇭🇷 Croatia | OIB | 11 digits, ISO 7064 check | | 🇬🇷 Greece | ΑΦΜ | 9 digits with checksum | | 🇭🇺 Hungary | Adóazonosító jel | 10 digits, starts with 8 | | 🇧🇬 Bulgaria | ЕГН | 10 digits, weighted checksum | | 🇱🇹 Lithuania | Asmens kodas | 11 digits (sex + birthdate) | | 🇱🇻 Latvia | Personas kods | DDMMYY-XXXXX | | 🇪🇪 Estonia | Isikukood | 11 digits (sex + birthdate) | | 🇸🇮 Slovenia | EMŠO | 13 digits | | 🇺🇸 US | SSN | AAA-BB-CCCC (included for completeness) |
Plus universal patterns: Email, Phone, Credit Card (Luhn), IBAN, IP Address — all structurally validated, no context required.
Usage Examples
🔒 Example 1 — Redacting User Input Before Storage
User: "Save this customer note: João Silva, NIF 123456789, called about invoice #4521. His email is joao.silva@empresa.pt and card ending 4111 1111 1111 1111."
The LLM calls pii.redact:
Result:
redacted_text: "[REDACTED_NIF_PT] called about invoice #4521. His email is
[REDACTED_EMAIL] and card ending [REDACTED_CREDIT_CARD]."
entities_found: 3
entity_summary: { nif_pt: 1, email: 1, credit_card: 1 }
risk_level: critical (financial + government ID)
The Presenter renders a Mermaid pie chart of entity distribution and suggests pii.scan to verify.
🔍 Example 2 — Scanning Before Deciding
User: "Check if this text has any sensitive data: My Belgian ID is 85.05.15-001.28 and I live in Brussels."
The LLM calls pii.scan:
Result:
has_pii: true
risk_level: 🟠 high (government ID detected)
detections: [{ type: "nrn_be", start: 43, end: 57 }]
The Presenter suggests pii.redact as the next action.
📦 Example 3 — Batch Processing a Form
User: "Redact all PII from this customer form with fields: name, email, notes."
The LLM calls pii.batch:
{
"fields": [
{ "field": "name", "text": "Maria García, DNI 12345678A" },
{ "field": "email", "text": "maria@empresa.es" },
{ "field": "notes", "text": "Called from +34 612 345 678 about IBAN ES91 2100 0418 4502 0005 1332" }
]
}
Result:
total_fields: 3
fields_with_pii: 3
total_entities: 4
Deploy
Vinkius Cloud — One Command ⚡
The fastest path to production. vurb deploy publishes your server to Vinkius Cloud's global edge — zero infrastructure, built-in DLP, kill switch, audit logging, and a managed MCP token:
npm install
vurb deploy
No Dockerfile, no CI/CD pipeline, no servers to manage. You get a connection token that works with any MCP client — Cursor, Claude Desktop, Claude Code, Windsurf, Cline, VS Code + Copilot.
# Deploy with a custom name
vurb deploy --name gdpr-pii-redactor
💡 Tip: Install the Vinkius extension to manage your deployed server directly from VS Code, Cursor, or Windsurf — live connections, requests, P95 latency, DLP intercepts, token management, tool toggling, logs, and deployment history.
Connect Your MCP Client
After deploying, share the managed token with any MCP-compatible client:
Claude Desktop / Cursor / Windsurf
{
"mcpServers": {
"gdpr-pii-redactor": {
"url": "https://edge.vinkius.com/your-token/mcp"
}
}
}
Self-Hosted Alternatives
The same ToolRegistry runs anywhere — no code changes required:
| Platform | Adapter |
|---|---|
| Vercel Edge Functions | @vurb/vercel |
| Cloudflare Workers | @vurb/cloudflare |
| Any Node.js server | Stdio / HTTP+SSE transport |
Full deployment guides: Production Server · Vercel Adapter · Cloudflare Adapter
Running Locally via stdio
If you prefer to run the server locally and connect via stdio — the native MCP transport used by Claude Desktop, Cursor, and Windsurf:
# 1. Install dependencies
npm install
# 2. Build
npm run build
# 3. Test it directly (optional)
node dist/server.js
Then add it to your MCP client config (e.g. claude_desktop_config.json):
{
"mcpServers": {
"gdpr-pii-redactor": {
"command": "node",
"args": ["/absolute/path/to/gdpr-pii-redactor/dist/server.js"]
}
}
}
Or run without cloning via npx (after the package is published):
{
"mcpServers": {
"gdpr-pii-redactor": {
"command": "npx",
"args": ["-y", "@vinkius/gdpr-pii-redactor"]
}
}
}
Note: The stdio transport is the default. No environment variables are required — all 30 PII patterns are embedded, zero external APIs or network dependencies.
Development
# Install dependencies
npm install
# Development server with HMR
vurb dev
# Type-check
npm run typecheck
# Run tests
npm test
Project Structure
src/
├── data/ ← PII types and interfaces
│ └── types.ts
├── engine/ ← Detection and redaction logic
│ ├── patterns.ts 30 validated patterns + checksums (Luhn, mod 11, ISO 7064)
│ └── pii-engine.ts scan / redact / batch / risk assessment
├── models/ M — defineModel()
│ └── index.ts
├── views/ V — definePresenter()
│ └── index.ts
├── agents/ A — Tool definitions
│ └── pii/
│ ├── redact.tool.ts
│ ├── scan.tool.ts
│ ├── batch.tool.ts
│ └── supported-entities.tool.ts
├── vurb.ts Shared Vurb instance
└── server.ts Bootstrap
Built with Vurb.ts
| Feature | Usage |
|---|---|
| defineModel() | 5 domain models with guidance labels |
| definePresenter() | Mermaid charts, collectionUi, agentLimit, suggestActions |
| .redactPII() | DLP engine masks detections[*].value — LLM never sees raw PII |
| f.mutation() / f.query() | Correct semantic verbs for data transformation vs read-only |
| .concurrency() | Load shedding: 10 active / 50 queued for redact, 15/100 for scan |
| .egress() | 1MB payload guard on redact, 2MB on batch |
| .stale() | Real-time tool — every call has unique input |
| .cached() | Static reference data for supported_entities |
| f.error() | Self-healing errors with suggestions |
| .instructions() | AI-first guidance: "call BEFORE saving to database" |
| agentLimit | Batch results truncated at 20 with pagination guidance |
| Explicit tool imports | V8-safe bootstrap — no filesystem access at runtime |
Get started with Vurb.ts → · Documentation →
License
Apache 2.0 — See LICENSE for details.