pseudonym-mcp 0.7.2 → 0.7.4
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/README.md +119 -104
- package/dist/cli.js +4 -3
- package/dist/cli.js.map +1 -1
- package/dist/core/ollama-client.d.ts.map +1 -1
- package/dist/core/ollama-client.js.map +1 -1
- package/dist/mcp/prompts.d.ts.map +1 -1
- package/dist/mcp/prompts.js +6 -2
- package/dist/mcp/prompts.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +4 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
# pseudonym-mcp
|
|
2
2
|
|
|
3
|
-
Local
|
|
3
|
+
Local pseudonymisation tools for LLM workflows — replace detected PII with opaque tokens before you hand text to a cloud LLM, then restore those tokens afterward.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/pseudonym-mcp)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](#)
|
|
8
|
-
[](#gdpr--ai-compliance)
|
|
9
|
+
[](#)
|
|
10
10
|
[](#)
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Expose MCP tools (`mask_text` and `unmask_text`) that your client or agent can call as an explicit privacy step. The server detects PII locally, replaces it with opaque tokens, and keeps the token mapping in memory for later restoration.
|
|
13
|
+
|
|
14
|
+
It is a **defense-in-depth measure**, not a compliance silver bullet. Read the [Limitations](#limitations) and [GDPR & AI Compliance](#gdpr--ai-compliance) sections before assuming this stack does more than it does.
|
|
13
15
|
|
|
14
16
|
## What you get
|
|
15
17
|
|
|
16
18
|
- **Multi-language PII detection**: Built-in support for English (SSN, credit cards, US phone) and Polish (PESEL, IBAN, Polish phone). New **heuristic language detection** (`detectLanguage()`) infers the language from text content — `--lang` remains the authoritative override but is no longer the only input.
|
|
17
|
-
- **Hybrid NER engine**: Regex for structured PII (SSN, credit cards, IBAN, email, phone) + local Ollama LLM for unstructured entities (names,
|
|
18
|
-
- **
|
|
19
|
+
- **Hybrid NER engine**: Regex for structured PII (SSN, credit cards, IBAN, email, phone) + local Ollama LLM for unstructured entities (names, organisations).
|
|
20
|
+
- **Local-detection architecture**: Detection and substitution happen on your machine when the MCP tool is called. The cloud LLM call still happens (that's the point) — but it can see tokens instead of detected PII when your workflow uses the masked output.
|
|
19
21
|
- **Session-keyed mapping store**: Tokens like `[PERSON:1]` map back to originals in an isolated, per-request session. Multiple round-trips preserve token coherence.
|
|
20
|
-
- **
|
|
22
|
+
- **Unmask workflow support**: `mask_text` returns `auto_unmask` for clients that want to honor that preference, but this server does not intercept arbitrary LLM responses automatically.
|
|
21
23
|
- **Flexible engines**: Run `regex` only (no Ollama required), `llm` only, or `hybrid` (default).
|
|
22
24
|
- **Strict validation**: SSN area-number validation, credit card Luhn checksum, PESEL checksum — all configurable.
|
|
23
25
|
- **Graceful degradation**: If Ollama is unavailable, the regex phase still runs and no exception is thrown.
|
|
@@ -27,53 +29,57 @@ Sits between your application and any cloud LLM (Claude, GPT-4, Gemini…). Repl
|
|
|
27
29
|
|
|
28
30
|
❌ **Without pseudonym-mcp:**
|
|
29
31
|
|
|
30
|
-
- Prompt: `"John Smith, SSN 123-45-6789, card 4111 1111 1111 1111"` → sent verbatim to
|
|
31
|
-
- Every name, ID number, and credit card in your prompt is processed and potentially logged by the
|
|
32
|
-
- A
|
|
33
|
-
- Sending personal data to a
|
|
32
|
+
- Prompt: `"John Smith, SSN 123-45-6789, card 4111 1111 1111 1111"` → sent verbatim to the LLM provider
|
|
33
|
+
- Every name, ID number, and credit card in your prompt is processed and potentially logged by the provider
|
|
34
|
+
- A breach at the provider's end exposes those values in cleartext
|
|
35
|
+
- Sending personal data to a non-EU LLM provider without further safeguards raises GDPR Article 44 questions you'll need to answer
|
|
36
|
+
|
|
37
|
+
✅ **With pseudonym-mcp used before the cloud call:**
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
- The same prompt can become `"[PERSON:1], SSN [SSN:1], card [CREDIT_CARD:1]"` when you call `mask_text` first
|
|
40
|
+
- The LLM reasons about structure and content without seeing those detected values in cleartext
|
|
41
|
+
- The response can be locally de-tokenised with `unmask_text` before reaching the user
|
|
42
|
+
- Detected direct identifiers are no longer shipped upstream — though structure, dates, indirect references, and any missed PII still are
|
|
36
43
|
|
|
37
|
-
|
|
38
|
-
- The LLM reasons about the structure and content without ever seeing the real values
|
|
39
|
-
- The response is automatically de-tokenized locally before reaching the user
|
|
40
|
-
- Your GDPR DPA can truthfully state: _personal data never left the local environment_
|
|
44
|
+
This is a meaningful reduction in cleartext PII exposure. It is **not** "no personal data leaves your machine" — see [Limitations](#limitations).
|
|
41
45
|
|
|
42
46
|
## GDPR & AI Compliance
|
|
43
47
|
|
|
44
|
-
pseudonym-mcp
|
|
48
|
+
pseudonym-mcp is relevant to compliance work, but it is a **technical control**, not a compliance product. Whether you are compliant with any specific regulation depends on your full stack, your role (controller/processor), your contracts, your DPIA, and your jurisdiction.
|
|
45
49
|
|
|
46
50
|
### Why this matters
|
|
47
51
|
|
|
48
|
-
The EU **General Data Protection Regulation (GDPR)** classifies names, national ID numbers (like SSN or PESEL), bank account numbers (IBAN), email addresses, credit card numbers, and phone numbers as **personal data** under Article 4(1). Sending this data to a cloud LLM provider constitutes **processing** under Article 4(2)
|
|
52
|
+
The EU **General Data Protection Regulation (GDPR)** classifies names, national ID numbers (like SSN or PESEL), bank account numbers (IBAN), email addresses, credit card numbers, and phone numbers as **personal data** under Article 4(1). Sending this data to a cloud LLM provider constitutes **processing** under Article 4(2). Pseudonymisation is explicitly recognised under Art. 4(5) as a risk-reduction measure — but, critically, **pseudonymised data is still personal data** (Recital 26).
|
|
49
53
|
|
|
50
|
-
| GDPR Article | Obligation
|
|
51
|
-
| ------------ |
|
|
52
|
-
| Art. 5(1)(c) | **Data minimisation**
|
|
53
|
-
| Art. 25 | **Privacy by design and by default**
|
|
54
|
-
| Art. 32 | **Security of processing**
|
|
55
|
-
| Art. 44 | **Transfers to third countries**
|
|
56
|
-
| Art. 4(5) | **Pseudonymisation**
|
|
54
|
+
| GDPR Article | Obligation | Where pseudonym-mcp helps | Where it doesn't |
|
|
55
|
+
| ------------ | ------------------------------------ | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------- |
|
|
56
|
+
| Art. 5(1)(c) | **Data minimisation** | Strips detected direct identifiers before transmission | Doesn't minimise context, structure, or undetected PII |
|
|
57
|
+
| Art. 25 | **Privacy by design and by default** | Provides a technical layer that fits into a privacy-by-design architecture | Architecture and policy decisions are still your responsibility |
|
|
58
|
+
| Art. 32 | **Security of processing** | Recognised technical measure under Recital 83 (pseudonymisation) | One control among many; doesn't replace access control, logging, encryption |
|
|
59
|
+
| Art. 44 | **Transfers to third countries** | Reduces the cleartext PII you transfer | Pseudonymised personal data is still personal data — transfer rules still apply |
|
|
60
|
+
| Art. 4(5) | **Pseudonymisation** definition | The mapping store is opaque to the cloud LLM; re-identification requires the local session | Re-identification is possible from context for anyone with side knowledge |
|
|
57
61
|
|
|
58
|
-
> **
|
|
62
|
+
> **The honest bottom line:** pseudonymisation under GDPR Art. 4(5) is **not** anonymisation. The data remains personal data in your system, and Art. 44 transfer obligations are not switched off just because you tokenised the name field.
|
|
59
63
|
|
|
60
64
|
### AI Act alignment
|
|
61
65
|
|
|
62
|
-
The EU **AI Act**
|
|
66
|
+
The EU **AI Act** places additional requirements on high-risk AI systems that process personal data. Using pseudonym-mcp as an intermediary layer can:
|
|
67
|
+
|
|
68
|
+
- Support data minimisation in your AI system's data flows.
|
|
69
|
+
- Help document a technical control for transparency and human-oversight requirements.
|
|
70
|
+
- Align with the principle of **technical robustness and safety** (Art. 15) by limiting cleartext PII exposure.
|
|
63
71
|
|
|
64
|
-
|
|
65
|
-
- Supports documentation requirements for AI system transparency and human oversight.
|
|
66
|
-
- Aligns with the principle of **technical robustness and safety** (Art. 15) by limiting PII exposure surface.
|
|
72
|
+
It does not change your AI Act risk classification on its own — classification is a function of use-case and deployment context, not of the masking step in front of the model.
|
|
67
73
|
|
|
68
74
|
### US & international applicability
|
|
69
75
|
|
|
70
|
-
|
|
76
|
+
The tool is also relevant outside the EU, with the same caveats:
|
|
71
77
|
|
|
72
|
-
- **CCPA / CPRA** (California) —
|
|
73
|
-
- **HIPAA** (US healthcare) — PHI
|
|
74
|
-
- **PCI DSS** (payment industry) —
|
|
75
|
-
- **SOC 2** —
|
|
76
|
-
- **PIPEDA** (Canada), **LGPD** (Brazil), **POPIA** (South Africa) — all require appropriate safeguards for cross-border personal data transfers.
|
|
78
|
+
- **CCPA / CPRA** (California) — reduces personal information sent to third-party processors; doesn't change controller/business obligations or consumer rights.
|
|
79
|
+
- **HIPAA** (US healthcare) — pseudonymised PHI is still PHI under HIPAA. Using this tool does **not** eliminate the need for a BAA with your cloud LLM provider if you're a covered entity or business associate. It can be part of a defensible safeguard posture; it cannot substitute for one.
|
|
80
|
+
- **PCI DSS** (payment industry) — Luhn-validated detection reduces the chance card numbers ride in cleartext to an LLM. It is one control; PCI scope, segmentation, and storage rules are separate concerns.
|
|
81
|
+
- **SOC 2** — useful evidence of a technical control limiting PII exposure. Auditors will look at the full picture, not just this layer.
|
|
82
|
+
- **PIPEDA** (Canada), **LGPD** (Brazil), **POPIA** (South Africa) — all require appropriate safeguards for cross-border personal data transfers. This tool is a relevant safeguard, not a substitute for the legal basis of the transfer.
|
|
77
83
|
|
|
78
84
|
### Sector-specific applicability
|
|
79
85
|
|
|
@@ -82,27 +88,31 @@ While GDPR originates in the EU, pseudonym-mcp is equally relevant for:
|
|
|
82
88
|
| Healthcare | GDPR + HIPAA + national health data laws | Patient names, SSN, diagnoses |
|
|
83
89
|
| Banking & Finance | GDPR + PCI DSS + PSD2 + DORA | Credit cards, IBAN, SSN, PESEL |
|
|
84
90
|
| HR & Recruitment | GDPR Art. 9 (special categories) | Names, national IDs, contact details |
|
|
85
|
-
| Legal | GDPR + attorney
|
|
91
|
+
| Legal | GDPR + attorney–client privilege | Names, case numbers, personal details |
|
|
86
92
|
| Insurance | GDPR + Solvency II | Personal identifiers, health data |
|
|
87
93
|
| Public Sector (US) | CCPA + state privacy laws | SSN, driver's license numbers |
|
|
88
94
|
| Public Sector (PL) | GDPR + UODO + KRI | PESEL, NIP, REGON |
|
|
89
95
|
|
|
96
|
+
In every row of this table, pseudonym-mcp is a useful **building block**. None of those regimes can be satisfied by a masking tool alone.
|
|
97
|
+
|
|
90
98
|
## How it works
|
|
91
99
|
|
|
92
100
|
```
|
|
93
101
|
Your App / Claude Desktop
|
|
94
102
|
│
|
|
95
|
-
│
|
|
103
|
+
│ explicit mask_text tool call with PII
|
|
96
104
|
▼
|
|
97
105
|
┌─────────────────────────┐
|
|
98
106
|
│ pseudonym-mcp │
|
|
99
107
|
│ │
|
|
100
108
|
│ Phase 1: Regex NER │ ← SSN, CREDIT_CARD, EMAIL, PHONE (en)
|
|
101
|
-
│ │ ← PESEL, IBAN, EMAIL, PHONE (pl)
|
|
109
|
+
│ │ ← PESEL, IBAN, EMAIL, PHONE, NIP (pl)
|
|
102
110
|
│ Phase 2: Ollama NER │ ← PERSON, ORG (local LLM)
|
|
103
111
|
│ MappingStore (session) │ ← [TAG:N] ↔ original value
|
|
104
112
|
└────────────┬────────────┘
|
|
105
|
-
│
|
|
113
|
+
│ masked text returned to the client/agent
|
|
114
|
+
▼
|
|
115
|
+
Your workflow sends the masked text
|
|
106
116
|
▼
|
|
107
117
|
Cloud LLM API
|
|
108
118
|
(Claude / GPT-4 / Gemini)
|
|
@@ -154,17 +164,17 @@ We discussed a contract for 45 000 zł. Contact: jan.kowalski@acme.pl
|
|
|
154
164
|
In Claude Code you type:
|
|
155
165
|
|
|
156
166
|
```
|
|
157
|
-
Use mask_text on this note, then
|
|
167
|
+
Use mask_text on this note, then summarise the key points of the meeting.
|
|
158
168
|
```
|
|
159
169
|
|
|
160
|
-
**pseudonym-mcp replaces PII locally
|
|
170
|
+
**First, call `mask_text`; pseudonym-mcp replaces detected PII locally:**
|
|
161
171
|
|
|
162
172
|
```
|
|
163
173
|
Meeting with [PERSON:1] ([PESEL:1]) from [ORG:1].
|
|
164
174
|
We discussed a contract for 45 000 zł. Contact: [EMAIL:1]
|
|
165
175
|
```
|
|
166
176
|
|
|
167
|
-
**Claude responds
|
|
177
|
+
**Then ask Claude to work from the masked text. Claude responds with tokens:**
|
|
168
178
|
|
|
169
179
|
```
|
|
170
180
|
Meeting with [PERSON:1] from [ORG:1] covered a contract
|
|
@@ -178,7 +188,7 @@ Meeting with Jan Kowalski from Acme sp. z o.o. covered
|
|
|
178
188
|
a contract for 45 000 zł. Follow up via jan.kowalski@acme.pl
|
|
179
189
|
```
|
|
180
190
|
|
|
181
|
-
|
|
191
|
+
If the masked text is what you send upstream, the cloud provider sees the structure of the meeting and the amount — but not the detected name, PESEL, organisation, or email in cleartext. The swap happens on your machine.
|
|
182
192
|
|
|
183
193
|
### Obsidian vault with `session_id`
|
|
184
194
|
|
|
@@ -187,17 +197,19 @@ Anthropic / OpenAI never saw any real data. The entire swap happens on your mach
|
|
|
187
197
|
Use mask_text on my notes — remember the session_id
|
|
188
198
|
|
|
189
199
|
# ask Claude anything across multiple prompts
|
|
190
|
-
|
|
200
|
+
Summarise all meetings from Q1
|
|
191
201
|
|
|
192
202
|
# Claude replies with tokens; restore originals
|
|
193
203
|
Use unmask_text with session_id abc123 on the response
|
|
194
204
|
```
|
|
195
205
|
|
|
196
|
-
The `session_id` keeps the token map alive for the
|
|
206
|
+
The `session_id` keeps the token map alive for the session — the same `[PERSON:1]` always refers to the same person across notes. That consistency is what makes cross-note reasoning possible; it is also what makes a masked corpus potentially re-identifiable to anyone with side knowledge of your work. Use long-lived sessions deliberately.
|
|
197
207
|
|
|
198
208
|
## MCP Prompt Templates
|
|
199
209
|
|
|
200
|
-
pseudonym-mcp ships two built-in prompt templates that
|
|
210
|
+
pseudonym-mcp ships two built-in prompt templates that describe a mask → task → unmask workflow.
|
|
211
|
+
|
|
212
|
+
**Important:** MCP prompt templates are convenience helpers, not a privacy boundary. Inline prompt arguments may be visible to the host client or model before tool masking happens. For strongest privacy, call `mask_text` directly first, then use the returned `masked_text` in your LLM prompt.
|
|
201
213
|
|
|
202
214
|
### `pseudonymize_task` — inline text
|
|
203
215
|
|
|
@@ -205,30 +217,30 @@ pseudonym-mcp ships two built-in prompt templates that chain masking, an LLM tas
|
|
|
205
217
|
/pseudonymize_task text="Meeting with Jan Kowalski (PESEL: 90010112318). Contract: 45 000 zł." task="Extract action items"
|
|
206
218
|
```
|
|
207
219
|
|
|
208
|
-
|
|
220
|
+
Intended workflow:
|
|
209
221
|
|
|
210
|
-
1. pseudonym-mcp masks PII locally → `[PERSON:1]`, `[PESEL:1]`
|
|
211
|
-
2. Claude processes the
|
|
222
|
+
1. pseudonym-mcp masks detected PII locally → `[PERSON:1]`, `[PESEL:1]`
|
|
223
|
+
2. Claude processes the masked text
|
|
212
224
|
3. pseudonym-mcp restores originals in the response
|
|
213
225
|
|
|
214
226
|
Optional `lang` argument: `en` (default) or `pl`.
|
|
215
227
|
|
|
216
228
|
### `privacy_scan_file` — file / PDF (macOS only)
|
|
217
229
|
|
|
218
|
-
> **Requires [macos-vision-mcp](https://github.com/woladi/macos-vision-mcp)** — a separate MCP server that uses Apple's Vision framework to extract text from PDFs and images. macOS only.
|
|
230
|
+
> **Requires [macos-vision-mcp](https://github.com/woladi/macos-vision-mcp)** — a separate MCP server that uses Apple's Vision framework to extract text from PDFs and images on-device. macOS only.
|
|
219
231
|
|
|
220
232
|
```
|
|
221
|
-
/privacy_scan_file filePath="/Users/me/contracts/nda.pdf" task="
|
|
233
|
+
/privacy_scan_file filePath="/Users/me/contracts/nda.pdf" task="Summarise obligations and deadlines"
|
|
222
234
|
```
|
|
223
235
|
|
|
224
|
-
|
|
236
|
+
Intended workflow:
|
|
225
237
|
|
|
226
|
-
1. macos-vision-mcp extracts text from the file
|
|
227
|
-
2. pseudonym-mcp masks
|
|
228
|
-
3. Claude processes the
|
|
238
|
+
1. macos-vision-mcp extracts text from the file on-device
|
|
239
|
+
2. pseudonym-mcp masks detected PII locally
|
|
240
|
+
3. Claude processes the masked content
|
|
229
241
|
4. pseudonym-mcp restores originals before the response is shown
|
|
230
242
|
|
|
231
|
-
Optional arguments: `task` (default:
|
|
243
|
+
Optional arguments: `task` (default: _summarise the key points_), `lang` (`en` or `pl`).
|
|
232
244
|
|
|
233
245
|
## Quick Start
|
|
234
246
|
|
|
@@ -244,7 +256,7 @@ claude mcp add pseudonym-mcp -- npx -y pseudonym-mcp --engines hybrid
|
|
|
244
256
|
ollama pull llama3
|
|
245
257
|
```
|
|
246
258
|
|
|
247
|
-
Skip this step if you only need regex-based masking (`--engines regex`).
|
|
259
|
+
Skip this step if you only need regex-based masking (`--engines regex`). Without Ollama, you'll catch structured identifiers (SSN, IBAN, cards, email, phone, PESEL) but not free-form names and organisations.
|
|
248
260
|
|
|
249
261
|
> **Global install** — if you prefer `npm install -g pseudonym-mcp`, replace `npx -y pseudonym-mcp` with `pseudonym-mcp` in all snippets below.
|
|
250
262
|
|
|
@@ -254,7 +266,7 @@ Restart your client. The `mask_text` and `unmask_text` tools appear automaticall
|
|
|
254
266
|
|
|
255
267
|
| Tool | What it does | Example prompt |
|
|
256
268
|
| ------------- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
257
|
-
| `mask_text` |
|
|
269
|
+
| `mask_text` | Pseudonymise detected PII in text. Returns `masked_text` + `session_id`. | _"Use mask_text on this customer letter before summarising it"_ |
|
|
258
270
|
| `unmask_text` | Restore original values from a session. Pass the `session_id` returned by `mask_text`. | _"Use unmask_text with session_id X to restore the response"_ |
|
|
259
271
|
|
|
260
272
|
### `mask_text` input
|
|
@@ -273,7 +285,8 @@ Restart your client. The `mask_text` and `unmask_text` tools appear automaticall
|
|
|
273
285
|
{
|
|
274
286
|
"session_id": "3f2a1b...",
|
|
275
287
|
"masked_text": "[PERSON:1] (SSN: [SSN:1]) works at [ORG:1].",
|
|
276
|
-
"auto_unmask": false
|
|
288
|
+
"auto_unmask": false,
|
|
289
|
+
"ner_status": "ready"
|
|
277
290
|
}
|
|
278
291
|
```
|
|
279
292
|
|
|
@@ -302,15 +315,15 @@ Restart your client. The `mask_text` and `unmask_text` tools appear automaticall
|
|
|
302
315
|
}
|
|
303
316
|
```
|
|
304
317
|
|
|
305
|
-
| Key | Values | Default | Description
|
|
306
|
-
| ------------------ | ---------------------------- | ------------------------ |
|
|
307
|
-
| `lang` | `en`, `pl` | `en` | Language pack for regex rules
|
|
308
|
-
| `engines` | `regex` \| `llm` \| `hybrid` | `hybrid` | Which NER engines to run
|
|
309
|
-
| `ollamaModel` | any Ollama model name | `llama3` | Local LLM for entity detection
|
|
310
|
-
| `ollamaBaseUrl` | URL | `http://localhost:11434` | Ollama API endpoint
|
|
311
|
-
| `autoUnmask` | `true` \| `false` | `false` |
|
|
312
|
-
| `strictValidation` | `true` \| `false` | `true` | Enable checksum / format validation (SSN area check, Luhn for cards, PESEL checksum)
|
|
313
|
-
| `customLiterals` | `string[]` | `[]` | Specific strings always redacted regardless of engine (names, IDs, phone numbers)
|
|
318
|
+
| Key | Values | Default | Description |
|
|
319
|
+
| ------------------ | ---------------------------- | ------------------------ | ----------------------------------------------------------------------------------------- |
|
|
320
|
+
| `lang` | `en`, `pl` | `en` | Language pack for regex rules |
|
|
321
|
+
| `engines` | `regex` \| `llm` \| `hybrid` | `hybrid` | Which NER engines to run |
|
|
322
|
+
| `ollamaModel` | any Ollama model name | `llama3` | Local LLM for entity detection |
|
|
323
|
+
| `ollamaBaseUrl` | URL | `http://localhost:11434` | Ollama API endpoint |
|
|
324
|
+
| `autoUnmask` | `true` \| `false` | `false` | Report the preferred unmask behavior to clients; this server does not intercept responses |
|
|
325
|
+
| `strictValidation` | `true` \| `false` | `true` | Enable checksum / format validation (SSN area check, Luhn for cards, PESEL checksum) |
|
|
326
|
+
| `customLiterals` | `string[]` | `[]` | Specific strings always redacted regardless of engine (names, IDs, phone numbers) |
|
|
314
327
|
|
|
315
328
|
### CLI flags
|
|
316
329
|
|
|
@@ -327,7 +340,7 @@ pseudonym-mcp --lang en --engines regex --ollama-model llama3 --auto-unmask
|
|
|
327
340
|
| `--ollama-model` | Ollama model to use for NER |
|
|
328
341
|
| `--ollama-base-url` | Ollama base URL |
|
|
329
342
|
| `--config` | Path to a custom JSON config file |
|
|
330
|
-
| `--auto-unmask` |
|
|
343
|
+
| `--auto-unmask` | Set `auto_unmask: true` in `mask_text` output for clients that honor it |
|
|
331
344
|
| `--custom-literals` | Comma-separated strings to always redact, e.g. `"Jan Kowalski,78091512345"` |
|
|
332
345
|
|
|
333
346
|
### Claude Code
|
|
@@ -368,6 +381,8 @@ Add to `~/.cursor/mcp.json`:
|
|
|
368
381
|
|
|
369
382
|
## Supported PII types
|
|
370
383
|
|
|
384
|
+
Detection is best-effort. The patterns below are what the tool **looks for** — not a guarantee of what it will always catch. See [Limitations](#limitations) for known gaps.
|
|
385
|
+
|
|
371
386
|
### Custom literals
|
|
372
387
|
|
|
373
388
|
| Tag | Detection | Match |
|
|
@@ -376,15 +391,7 @@ Add to `~/.cursor/mcp.json`:
|
|
|
376
391
|
|
|
377
392
|
Custom literals are applied after the regex phase and before LLM NER, regardless of engine mode. Longest literals are matched first to prevent partial substitution.
|
|
378
393
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
| Tag | Pattern | Validation |
|
|
382
|
-
| ------- | ------------------------------------ | ------------ |
|
|
383
|
-
| `EMAIL` | RFC 5321-compatible | Format match |
|
|
384
|
-
| `IBAN` | Generic IBAN (`CC` + 2 check + BBAN) | Format match |
|
|
385
|
-
| `IP` | IPv4 (all octets 0–255) | Format match |
|
|
386
|
-
| `URL` | `http://` / `https://` URLs | Format match |
|
|
387
|
-
| `PHONE` | International `+CC` prefix format | Format match |
|
|
394
|
+
The tables below list patterns active in the current `Engine` pipeline. Some additional pattern modules exist in the repository for experimentation, but they are not advertised here unless the language rules actually use them.
|
|
388
395
|
|
|
389
396
|
### English (`--lang en`, default)
|
|
390
397
|
|
|
@@ -394,22 +401,20 @@ Custom literals are applied after the regex phase and before LLM NER, regardless
|
|
|
394
401
|
| `CREDIT_CARD` | 13–19 digits (Visa, Mastercard, Amex, Discover) | Luhn checksum |
|
|
395
402
|
| `EMAIL` | RFC 5321-compatible | Format match |
|
|
396
403
|
| `PHONE` | `+1 (XXX) XXX-XXXX`, `XXX-XXX-XXXX`, `XXX.XXX.XXXX` | Format match |
|
|
397
|
-
| `ZIP_CODE` | `XXXXX` or `XXXXX-XXXX` (paranoid mode only) | Format match |
|
|
398
404
|
| `PERSON` | Full names | Ollama NER (hybrid / llm engines) |
|
|
399
|
-
| `ORG` | Company /
|
|
405
|
+
| `ORG` | Company / organisation names | Ollama NER (hybrid / llm engines) |
|
|
400
406
|
|
|
401
407
|
### Polish (`--lang pl`)
|
|
402
408
|
|
|
403
|
-
| Tag
|
|
404
|
-
|
|
|
405
|
-
| `PESEL`
|
|
406
|
-
| `IBAN`
|
|
407
|
-
| `EMAIL`
|
|
408
|
-
| `PHONE`
|
|
409
|
-
| `NIP`
|
|
410
|
-
| `
|
|
411
|
-
| `
|
|
412
|
-
| `ORG` | Company / organization names | Ollama NER (hybrid / llm engines) |
|
|
409
|
+
| Tag | Pattern | Validation |
|
|
410
|
+
| -------- | ---------------------------------------------------------------- | ----------------------------------------------- |
|
|
411
|
+
| `PESEL` | 11-digit national ID | Full checksum (weights `[1,3,7,9,1,3,7,9,1,3]`) |
|
|
412
|
+
| `IBAN` | `PL` + 26 digits, compact or spaced | Format match |
|
|
413
|
+
| `EMAIL` | RFC 5321-compatible | Format match |
|
|
414
|
+
| `PHONE` | `+48` / `0048` prefix, 9-digit mobile, landline `(XX) XXX-XX-XX` | Format match |
|
|
415
|
+
| `NIP` | 10-digit tax ID (strict / paranoid modes) | Checksum (weights `[6,5,7,2,3,4,5,6,7]`) |
|
|
416
|
+
| `PERSON` | Full names | Ollama NER (hybrid / llm engines) |
|
|
417
|
+
| `ORG` | Company / organisation names | Ollama NER (hybrid / llm engines) |
|
|
413
418
|
|
|
414
419
|
## Language Detection
|
|
415
420
|
|
|
@@ -432,7 +437,7 @@ detectLanguage('Hello')
|
|
|
432
437
|
| `confidence` | Score 0–1 from franc, or `null` when franc was not called |
|
|
433
438
|
|
|
434
439
|
Texts shorter than 20 characters or with low confidence return `detected: 'unknown'`.
|
|
435
|
-
The detector does not affect the current
|
|
440
|
+
The detector does not affect the current pseudonymisation pipeline — `--lang` config remains authoritative.
|
|
436
441
|
It is a building block for future multi-language and auto-select modes.
|
|
437
442
|
|
|
438
443
|
## Engine modes
|
|
@@ -443,27 +448,37 @@ It is a building block for future multi-language and auto-select modes.
|
|
|
443
448
|
| `llm` | Yes | No | Yes |
|
|
444
449
|
| `hybrid` (default) | Yes (graceful fallback) | Yes | Yes |
|
|
445
450
|
|
|
446
|
-
In `hybrid` mode, Ollama runs after the regex pass so the
|
|
451
|
+
In `hybrid` mode, Ollama runs after the regex pass, so the local NER model receives already-tokenised structured identifiers. If Ollama is unreachable, the server logs a warning to stderr and returns the regex-only masked text — no crash, no hang.
|
|
447
452
|
|
|
448
453
|
## Privacy & Security notes
|
|
449
454
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
- **
|
|
453
|
-
- **
|
|
455
|
+
Calibrated claims:
|
|
456
|
+
|
|
457
|
+
- **No telemetry from the tool itself.** pseudonym-mcp makes no network requests except to your local Ollama instance and (optionally) the MCP stdio transport.
|
|
458
|
+
- **In-memory mapping by default.** The mapping store is not written to disk. Sessions are scoped to the server process lifetime.
|
|
459
|
+
- **Idempotent tokens within a session.** The same original value always maps to the same token (`[PERSON:1]` will not become `[PERSON:2]` for the same name on a second occurrence), preserving semantic coherence in LLM reasoning.
|
|
460
|
+
- **No model training.** The local Ollama model operates offline. Your data is not used to train any model by this tool.
|
|
454
461
|
- **Strict validation by default.** Invalid SSNs (area 000/666/900+), failed-Luhn credit card numbers, and invalid-checksum PESELs are not masked, preventing false positives from OCR errors or random digit sequences.
|
|
455
462
|
|
|
463
|
+
What this does **not** guarantee:
|
|
464
|
+
|
|
465
|
+
- That all PII in your input is detected.
|
|
466
|
+
- That tokenised text is unlinkable to real people — re-identification from context is possible.
|
|
467
|
+
- That the cloud provider can't learn sensitive things from structure, timing, or content.
|
|
468
|
+
- Compliance with any specific regulation — that's a system-level property, not a tool-level one.
|
|
469
|
+
|
|
456
470
|
## Limitations
|
|
457
471
|
|
|
458
472
|
pseudonym-mcp is a technical privacy control, not a legal guarantee of compliance.
|
|
459
473
|
|
|
460
|
-
- Detection is best-effort
|
|
461
|
-
-
|
|
462
|
-
-
|
|
463
|
-
-
|
|
464
|
-
- Re-identification is possible for anyone with access to the local mapping store
|
|
474
|
+
- **Detection is best-effort.** False negatives and false positives are both possible. Indirect references (e.g. _"the tall guy from accounting"_, _"my landlord"_, _"the place near the bridge"_) are not detected. Nicknames, initials, and partial names are typically missed.
|
|
475
|
+
- **Structure still travels.** Dates, amounts, relationships between tokens, narrative content, and any PII the detector missed all reach the cloud LLM. Tokenisation hides _who_, not _what kind of situation_.
|
|
476
|
+
- **Pre-mask logging is your problem.** If your application logs plaintext before passing it to `mask_text`, this tool cannot help you.
|
|
477
|
+
- **Process-local mapping.** Restarting the server ends the session and discards mappings. This is intentional.
|
|
478
|
+
- **Re-identification is possible** for anyone with access to the local mapping store, and may be possible from context alone for anyone with side knowledge. This is pseudonymisation under GDPR Art. 4(5), not anonymisation.
|
|
479
|
+
- **No legal advice.** Nothing in this README constitutes legal advice. Compliance is a system-level property — talk to your DPO, your compliance team, and your lawyers about your specific deployment.
|
|
465
480
|
|
|
466
|
-
> Under GDPR Art. 4(5),
|
|
481
|
+
> Under GDPR Art. 4(5) and Recital 26, pseudonymised data is still personal data. pseudonym-mcp substantially reduces cleartext PII exposure but does not eliminate your legal obligations.
|
|
467
482
|
|
|
468
483
|
## Development
|
|
469
484
|
|
|
@@ -472,7 +487,7 @@ git clone https://github.com/woladi/pseudonym-mcp
|
|
|
472
487
|
cd pseudonym-mcp
|
|
473
488
|
npm install
|
|
474
489
|
npm run build # tsc compile
|
|
475
|
-
npm test # vitest (
|
|
490
|
+
npm test # vitest (no Ollama required)
|
|
476
491
|
```
|
|
477
492
|
|
|
478
493
|
The test suite runs fully offline — Ollama calls are injected via constructor and mocked in all tests. No live LLM required.
|
package/dist/cli.js
CHANGED
|
@@ -3,18 +3,19 @@ import { Command } from 'commander';
|
|
|
3
3
|
import { ConfigManager } from './config/manager.js';
|
|
4
4
|
import { printOllamaStatus } from './setup/check-ollama.js';
|
|
5
5
|
import { startServer } from './mcp/server.js';
|
|
6
|
+
import { APP_VERSION } from './version.js';
|
|
6
7
|
const VALID_ENGINES = ['regex', 'llm', 'hybrid'];
|
|
7
8
|
const program = new Command();
|
|
8
9
|
program
|
|
9
10
|
.name('pseudonym-mcp')
|
|
10
|
-
.description('MCP server that pseudonymizes sensitive data locally before
|
|
11
|
-
.version(
|
|
11
|
+
.description('MCP server that pseudonymizes sensitive data locally before cloud LLM work')
|
|
12
|
+
.version(APP_VERSION)
|
|
12
13
|
.option('--lang <lang>', 'Language for regex rules: en | pl', 'en')
|
|
13
14
|
.option('--engines <mode>', 'Processing engines: regex | llm | hybrid', 'hybrid')
|
|
14
15
|
.option('--ollama-model <model>', 'Ollama model for LLM NER', 'llama3')
|
|
15
16
|
.option('--ollama-base-url <url>', 'Ollama base URL', 'http://localhost:11434')
|
|
16
17
|
.option('--config <path>', 'Path to a JSON config file (default: ./mcp-config.json)')
|
|
17
|
-
.option('--auto-unmask', '
|
|
18
|
+
.option('--auto-unmask', 'Report auto_unmask=true in tool output for clients that honor it', false)
|
|
18
19
|
.option('--custom-literals <items>', 'Comma-separated strings to always redact')
|
|
19
20
|
.action(async (opts) => {
|
|
20
21
|
const engines = VALID_ENGINES.includes(opts.engines)
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,aAAa,EAAmB,MAAM,qBAAqB,CAAA;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,aAAa,EAAmB,MAAM,qBAAqB,CAAA;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE1C,MAAM,aAAa,GAAiB,CAAC,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAA;AAE9D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;AAE7B,OAAO;KACJ,IAAI,CAAC,eAAe,CAAC;KACrB,WAAW,CAAC,4EAA4E,CAAC;KACzF,OAAO,CAAC,WAAW,CAAC;KACpB,MAAM,CAAC,eAAe,EAAE,mCAAmC,EAAE,IAAI,CAAC;KAClE,MAAM,CAAC,kBAAkB,EAAE,0CAA0C,EAAE,QAAQ,CAAC;KAChF,MAAM,CAAC,wBAAwB,EAAE,0BAA0B,EAAE,QAAQ,CAAC;KACtE,MAAM,CAAC,yBAAyB,EAAE,iBAAiB,EAAE,wBAAwB,CAAC;KAC9E,MAAM,CAAC,iBAAiB,EAAE,yDAAyD,CAAC;KACpF,MAAM,CACL,eAAe,EACf,kEAAkE,EAClE,KAAK,CACN;KACA,MAAM,CAAC,2BAA2B,EAAE,0CAA0C,CAAC;KAC/E,MAAM,CACL,KAAK,EAAE,IAQN,EAAE,EAAE;IACH,MAAM,OAAO,GAAe,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAqB,CAAC;QAC5E,CAAC,CAAE,IAAI,CAAC,OAAsB;QAC9B,CAAC,CAAC,QAAQ,CAAA;IAEZ,aAAa,CAAC,IAAI,CAAC;QACjB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,OAAO;QACP,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,cAAc,EAAE,IAAI,CAAC,cAAc;YACjC,CAAC,CAAC,IAAI,CAAC,cAAc;iBAChB,KAAK,CAAC,GAAG,CAAC;iBACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBACpB,MAAM,CAAC,OAAO,CAAC;YACpB,CAAC,CAAC,SAAS;KACd,CAAC,CAAA;IAEF,MAAM,GAAG,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,CAAA;IAE7C,IAAI,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,GAAG,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QACtD,MAAM,iBAAiB,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,WAAW,CAAC,CAAA;IAC7D,CAAC;IAED,MAAM,WAAW,EAAE,CAAA;AACrB,CAAC,CACF,CAAA;AAEH,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ollama-client.d.ts","sourceRoot":"","sources":["../../src/core/ollama-client.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAA;IACtB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAQD;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;gBAEtB,IAAI,EAAE,mBAAmB;IAMrC;;;OAGG;IACG,YAAY,CAAC,SAAS,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAyBxD;;;OAGG;IACH,MAAM,IAAI,IAAI;IAIR,eAAe,
|
|
1
|
+
{"version":3,"file":"ollama-client.d.ts","sourceRoot":"","sources":["../../src/core/ollama-client.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAA;IACtB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAQD;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;gBAEtB,IAAI,EAAE,mBAAmB;IAMrC;;;OAGG;IACG,YAAY,CAAC,SAAS,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAyBxD;;;OAGG;IACH,MAAM,IAAI,IAAI;IAIR,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;CA2D7F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ollama-client.js","sourceRoot":"","sources":["../../src/core/ollama-client.ts"],"names":[],"mappings":"AAWA,MAAM,aAAa,GAAG;;;;oFAI8D,CAAA;AAEpF;;;GAGG;AACH,MAAM,OAAO,YAAY;IACN,OAAO,CAAQ;IACf,KAAK,CAAQ;IACb,SAAS,CAAQ;IAElC,YAAY,IAAyB;QACnC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;QAC3B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;QACvB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,MAAM,CAAA;IAC3C,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,YAAY,CAAC,SAAS,GAAG,MAAM;QACnC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAA;QAC7D,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,WAAW,EAAE;gBAClD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,MAAM,EAAE,KAAK;oBACb,QAAQ,EAAE;wBACR,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE;wBAC5C,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE;qBACnC;iBACF,CAAC;aACH,CAAC,CAAA;YACF,OAAO,GAAG,CAAC,EAAE,CAAA;QACf,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAA;QACd,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,KAAK,CAAC,CAAA;QACrB,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,MAAM;QACJ,KAAK,IAAI,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;IACjD,CAAC;IAED,KAAK,CAAC,eAAe,
|
|
1
|
+
{"version":3,"file":"ollama-client.js","sourceRoot":"","sources":["../../src/core/ollama-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/mcp/prompts.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,oBAAoB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/mcp/prompts.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,oBAAoB,GAAG,MAAM,CAU1E;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAWxE"}
|
package/dist/mcp/prompts.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { ConfigManager } from '../config/manager.js';
|
|
2
2
|
export function pseudonymizeTaskMessage(args) {
|
|
3
3
|
const lang = args.lang ?? ConfigManager.getInstance().get().lang;
|
|
4
|
-
return (`
|
|
4
|
+
return (`Privacy note: this MCP prompt template includes the raw text below in the prompt message. ` +
|
|
5
|
+
`For strongest privacy, call the mask_text tool directly before giving content to a cloud LLM.\n\n` +
|
|
6
|
+
`Use pseudonym-mcp mask_text on the following text (lang: ${lang}) and save the session_id:\n\n` +
|
|
5
7
|
`<text>\n${args.text}\n</text>\n\n` +
|
|
6
8
|
`Then: ${args.task}\n\n` +
|
|
7
9
|
`Finally, call pseudonym-mcp unmask_text with the saved session_id to restore original values before showing the response.`);
|
|
@@ -9,7 +11,9 @@ export function pseudonymizeTaskMessage(args) {
|
|
|
9
11
|
export function privacyScanFileMessage(args) {
|
|
10
12
|
const lang = args.lang ?? ConfigManager.getInstance().get().lang;
|
|
11
13
|
const task = args.task ?? 'summarize the key points';
|
|
12
|
-
return (`
|
|
14
|
+
return (`Privacy note: this MCP prompt template asks another tool to extract raw text, then includes workflow instructions in the prompt. ` +
|
|
15
|
+
`For strongest privacy, extract and mask content explicitly before giving it to a cloud LLM.\n\n` +
|
|
16
|
+
`Use macos-vision-mcp to extract text from ${args.filePath}.\n` +
|
|
13
17
|
`Then use pseudonym-mcp mask_text on the result (lang: ${lang}), save session_id.\n` +
|
|
14
18
|
`Then: ${task}.\n` +
|
|
15
19
|
`Finally call pseudonym-mcp unmask_text with the session_id to restore original values in the response.`);
|
package/dist/mcp/prompts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/mcp/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAcpD,MAAM,UAAU,uBAAuB,CAAC,IAA0B;IAChE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,aAAa,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAA;IAChE,OAAO,CACL,4DAA4D,IAAI,gCAAgC;QAChG,WAAW,IAAI,CAAC,IAAI,eAAe;QACnC,SAAS,IAAI,CAAC,IAAI,MAAM;QACxB,2HAA2H,CAC5H,CAAA;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAyB;IAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,aAAa,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAA;IAChE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,0BAA0B,CAAA;IACpD,OAAO,CACL,6CAA6C,IAAI,CAAC,QAAQ,KAAK;QAC/D,yDAAyD,IAAI,uBAAuB;QACpF,SAAS,IAAI,KAAK;QAClB,wGAAwG,CACzG,CAAA;AACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/mcp/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAcpD,MAAM,UAAU,uBAAuB,CAAC,IAA0B;IAChE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,aAAa,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAA;IAChE,OAAO,CACL,4FAA4F;QAC5F,mGAAmG;QACnG,4DAA4D,IAAI,gCAAgC;QAChG,WAAW,IAAI,CAAC,IAAI,eAAe;QACnC,SAAS,IAAI,CAAC,IAAI,MAAM;QACxB,2HAA2H,CAC5H,CAAA;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAyB;IAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,aAAa,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAA;IAChE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,0BAA0B,CAAA;IACpD,OAAO,CACL,mIAAmI;QACnI,iGAAiG;QACjG,6CAA6C,IAAI,CAAC,QAAQ,KAAK;QAC/D,yDAAyD,IAAI,uBAAuB;QACpF,SAAS,IAAI,KAAK;QAClB,wGAAwG,CACzG,CAAA;AACH,CAAC"}
|
package/dist/mcp/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AA6BnE,wBAAgB,eAAe,IAAI,SAAS,CAyK3C;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAajD"}
|
package/dist/mcp/server.js
CHANGED
|
@@ -6,6 +6,7 @@ import { OllamaClient } from '../core/ollama-client.js';
|
|
|
6
6
|
import { MappingStore } from '../core/mapping-store.js';
|
|
7
7
|
import { ConfigManager } from '../config/manager.js';
|
|
8
8
|
import { pseudonymizeTaskMessage, privacyScanFileMessage } from './prompts.js';
|
|
9
|
+
import { APP_VERSION } from '../version.js';
|
|
9
10
|
const NER_WARNING = {
|
|
10
11
|
ready: null,
|
|
11
12
|
warming_up: 'NER unavailable — Ollama is still loading the model. Retry in a few seconds for PERSON/ORG masking.',
|
|
@@ -24,7 +25,7 @@ function getOrCreateEngine(sessionId) {
|
|
|
24
25
|
export function createMcpServer() {
|
|
25
26
|
const server = new McpServer({
|
|
26
27
|
name: 'pseudonym-mcp',
|
|
27
|
-
version:
|
|
28
|
+
version: APP_VERSION,
|
|
28
29
|
});
|
|
29
30
|
server.tool('mask_text', `Pseudonymize sensitive entities in text before sending to a cloud LLM.
|
|
30
31
|
|
|
@@ -122,7 +123,7 @@ in the session identified by session_id.`, {
|
|
|
122
123
|
};
|
|
123
124
|
});
|
|
124
125
|
server.registerPrompt('pseudonymize_task', {
|
|
125
|
-
description: '
|
|
126
|
+
description: 'Convenience workflow for masking text, running a task, and restoring originals. Not a privacy boundary for prompt arguments.',
|
|
126
127
|
argsSchema: {
|
|
127
128
|
text: z.string().describe('Text containing sensitive data'),
|
|
128
129
|
task: z.string().describe('What to do with the anonymized text'),
|
|
@@ -140,7 +141,7 @@ in the session identified by session_id.`, {
|
|
|
140
141
|
],
|
|
141
142
|
}));
|
|
142
143
|
server.registerPrompt('privacy_scan_file', {
|
|
143
|
-
description: '
|
|
144
|
+
description: 'Convenience workflow for OCR, masking, task execution, and restore. Not a privacy boundary for extracted prompt content.',
|
|
144
145
|
argsSchema: {
|
|
145
146
|
filePath: z.string().describe('Path to the file to scan (PDF, image, etc.)'),
|
|
146
147
|
task: z
|
package/dist/mcp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,MAAM,EAAkB,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,MAAM,EAAkB,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAE3C,MAAM,WAAW,GAAqC;IACpD,KAAK,EAAE,IAAI;IACX,UAAU,EACR,qGAAqG;IACvG,QAAQ,EAAE,IAAI;CACf,CAAA;AAED,iFAAiF;AACjF,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAA;AAE1C,SAAS,iBAAiB,CAAC,SAAiB;IAC1C,IAAI,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACpC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,YAAY,CAAC,SAAS,CAAC,CAAC,CAAA;QAChD,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;IACjC,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,WAAW;KACrB,CAAC,CAAA;IAEF,MAAM,CAAC,IAAI,CACT,WAAW,EACX;;;;;;;6CAOyC,EACzC;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;QACrD,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,uFAAuF,CACxF;QACH,eAAe,EAAE,CAAC;aACf,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;aACjB,QAAQ,EAAE;aACV,QAAQ,CAAC,+DAA+D,CAAC;QAC5E,YAAY,EAAE,CAAC;aACZ,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CACP,oGAAoG,CACrG;KACJ,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,EAAE,EAAE;QAC5D,MAAM,GAAG,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,CAAA;QAC7C,MAAM,GAAG,GAAG,UAAU,IAAI,MAAM,CAAC,UAAU,EAAE,CAAA;QAC7C,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAA;QAErC,iEAAiE;QACjE,IAAI,YAAY,IAAI,CAAC,GAAG,CAAC,OAAO,KAAK,KAAK,IAAI,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,EAAE,CAAC;YACxE,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAA;YACvF,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAA;YACpC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;gBAC7B,IAAI,MAAM,MAAM,CAAC,YAAY,EAAE;oBAAE,MAAK;gBACtC,MAAM,SAAS,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;gBACvC,IAAI,SAAS,GAAG,KAAK,EAAE,CAAC;oBACtB,MAAM,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAA;gBACtD,CAAC;qBAAM,CAAC;oBACN,MAAK;gBACP,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,UAAkB,CAAA;QACtB,IAAI,SAAoB,CAAA;QACxB,IAAI,CAAC;YACH,CAAC;YAAA,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAA;QACtF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,yBAAyB,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBAClF,OAAO,EAAE,IAAI;aACd,CAAA;QACH,CAAC;QAED,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAA;QACtC,MAAM,YAAY,GAA4B;YAC5C,UAAU,EAAE,GAAG;YACf,WAAW,EAAE,UAAU;YACvB,WAAW,EAAE,GAAG,CAAC,UAAU;YAC3B,UAAU,EAAE,SAAS;SACtB,CAAA;QACD,IAAI,OAAO;YAAE,YAAY,CAAC,aAAa,CAAC,GAAG,OAAO,CAAA;QAElD,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;iBAC5C;aACF;SACF,CAAA;IACH,CAAC,CACF,CAAA;IAED,MAAM,CAAC,IAAI,CACT,aAAa,EACb;;;yCAGqC,EACrC;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;QAC1E,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;KACxE,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;QACvC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,mBAAmB,UAAU,oDAAoD;qBACxF;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAA;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QACpC,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;SACrD,CAAA;IACH,CAAC,CACF,CAAA;IAED,MAAM,CAAC,cAAc,CACnB,mBAAmB,EACnB;QACE,WAAW,EACT,8HAA8H;QAChI,UAAU,EAAE;YACV,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;YAC3D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;YAChE,IAAI,EAAE,CAAC;iBACJ,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;iBAClB,QAAQ,EAAE;iBACV,QAAQ,CAAC,mDAAmD,CAAC;SACjE;KACF,EACD,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACzB,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE;aAC/E;SACF;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,cAAc,CACnB,mBAAmB,EACnB;QACE,WAAW,EACT,0HAA0H;QAC5H,UAAU,EAAE;YACV,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;YAC5E,IAAI,EAAE,CAAC;iBACJ,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,iEAAiE,CAAC;YAC9E,IAAI,EAAE,CAAC;iBACJ,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;iBAClB,QAAQ,EAAE;iBACV,QAAQ,CAAC,mDAAmD,CAAC;SACjE;KACF,EACD,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QAC7B,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,sBAAsB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE;aAClF;SACF;KACF,CAAC,CACH,CAAA;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,MAAM,GAAG,eAAe,EAAE,CAAA;IAChC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAA;IAE5C,6EAA6E;IAC7E,kEAAkE;IAClE,MAAM,GAAG,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,CAAA;IAC7C,IAAI,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,GAAG,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QACtD,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAA;QAC7F,YAAY,CAAC,MAAM,EAAE,CAAA;IACvB,CAAC;IAED,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;AACjC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,UAAU,CAAA"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAA"}
|
package/package.json
CHANGED