mcpField
P
pseudonym-mcp

pseudonym-mcp

本地服务
github.com/woladi安全28 周前更新

关于 pseudonym-mcp

pseudonym-mcp 在文本发送给云端 LLM 前于本地检测并替换敏感信息,之后可还原原文。它适用于需要显式隐私处理步骤的 MCP 客户端,是降低风险的措施,而非合规产品。

主要功能

  1. 01本地检测并屏蔽个人信息
  2. 02正则与本地 Ollama NER 引擎
  3. 03按会话隔离的令牌映射
  4. 04使用 unmask_text 还原原文
  5. 05多语言与地区规则
  6. 06仅正则、仅 LLM 或混合模式

适用场景

  1. 01云端 LLM 处理前屏蔽标识信息
  2. 02还原模型回复中的姓名与值
  3. 03处理需要重复引用令牌的笔记
  4. 04在 MCP 工作流中加入个人信息保护步骤

MCP 相关

向 MCP 客户端提供 mask_text、unmask_text 工具及提示词模板。检测和令牌映射在本地进行;客户端需显式调用屏蔽工具,再将文本发送给云端 LLM。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"woladi-pseudonym": {
"command": "npx",
"args": [
"-y",
"pseudonym-mcp"
]
}
}
}
启动命令npx -y pseudonym-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmpseudonym-mcp0.9.0

工具

2

收录的工具列表 · 更新于 2 周前

参数类型必填说明
textstring是要进行假名化处理的文本
session_idstring否可选:重用现有会话,以便在多次调用间保持令牌编号连续
wait_for_nerboolean否如果为 true,则在处理前最多等待 30 秒,让 Ollama 完成模型加载(默认值:false)
custom_literalsarray否始终要遮盖的特定字符串(姓名、ID、电话号码)

详细介绍

pseudonym-mcp

pseudonym-mcp — 在本地屏蔽个人身份信息,安全地发送到云端大模型,并立即还原

适用于大模型工作流的本地假名化工具——将检测到的个人身份信息替换为不透明令牌,再将文本交给云端大模型,之后即可还原这些令牌。

npm version License: MIT Node 18+ GDPR-aligned Local detection Offline NER

提供 MCP 工具(mask_text 和 unmask_text),供客户端或 Agent 调用,将其作为明确的隐私保护步骤。服务会在本地检测个人身份信息,将其替换为不透明令牌,并将令牌映射保存在内存中,以便之后还原。

这是一种纵深防御措施,并非一劳永逸的合规方案。在假设此技术栈能做到其实际能力之外的事之前,请先阅读限制和 GDPR 与 AI 合规部分。

你将获得

  • 涵盖 12 种语言环境的 46 个识别器,默认全部启用:波兰(PESEL、NIP、REGON、身份证、护照、不动产登记簿)、欧盟(采用 mod-97 校验的 IBAN、覆盖全部 27 个成员国的 VAT,以及德国、意大利、西班牙、法国、荷兰、捷克/斯洛伐克、瑞典、芬兰和英国的国家身份识别码)和美国(SSN、ITIN、EIN、ABA 路由号码、银行卡)。其中 24 个会验证实际校验位。想减少误报时,可使用 --lang 缩小范围——参见语言环境覆盖范围采用失败即关闭策略。启发式语言检测(detectLanguage())会根据文本内容推断语言——--lang 仍是权威的覆盖选项。
  • 混合式 NER 引擎:使用正则表达式识别结构化个人身份信息(SSN、信用卡、IBAN、电子邮件、电话号码),并使用本地 Ollama 大模型识别非结构化实体(姓名、组织)。
  • 本地检测架构:调用 MCP 工具时,检测和替换都在你的设备上进行。云端大模型调用仍会发生(这正是设计目的)——但如果你的工作流使用脱敏后的输出,大模型看到的将是令牌,而非检测到的个人身份信息。
  • 按会话隔离的映射存储:[PERSON:1] 之类的令牌会在独立的单次请求会话中映射回原始内容。多次往返处理也能保持令牌一致。
  • 支持还原工作流:对于希望遵循该偏好的客户端,mask_text 会返回 auto_unmask,但此服务不会自动拦截任意大模型响应。
  • 灵活的引擎:可仅运行 regex(无需 Ollama)、仅运行 llm,或运行 hybrid(默认)。
  • 严格验证:可验证 SSN 地区号码、信用卡 Luhn 校验和及 PESEL 校验和——且均可配置。
  • 平稳降级:如果 Ollama 不可用,仍会执行正则阶段,且不会抛出异常。
  • 原生支持 MCP:兼容 Claude Code、Claude Desktop、Cursor 及任何兼容 MCP 的客户端。

❌ 不使用 / ✅ 使用

❌ 不使用 pseudonym-mcp:

  • 提示词:"John Smith, SSN 123-45-6789, card 4111 1111 1111 1111" → 原样发送给大模型提供商
  • 提示词中的每个姓名、身份证号码和信用卡号都会由提供商处理,并可能被记录
  • 提供商一旦发生数据泄露,这些值就会以明文形式暴露
  • 未采取进一步保障措施,就将个人数据发送给非欧盟大模型提供商,会引发 GDPR 第 44 条相关问题,需要你作出说明

✅ 在云端调用前使用 pseudonym-mcp:

  • 先调用 mask_text,同一条提示词就可以变成 "[PERSON:1], SSN [SSN:1], card [CREDIT_CARD:1]"
  • 大模型可以推理结构和内容,而无需看到这些已检测到的值的明文
  • 响应可通过 unmask_text 在本地进行去标记化,然后再发送给用户
  • 检测到的直接标识符不再会被发送到上游;但结构、日期、间接引用以及任何漏检的 PII 仍会发送

这能有效减少以明文形式暴露的 PII。但这并不意味着“个人数据不会离开你的设备”——请参阅限制。

GDPR 与 AI 合规

pseudonym-mcp 与合规工作相关,但它是一个技术控制措施,而非合规产品。你是否符合任何特定法规,取决于你的完整技术栈、你的角色(控制者/处理者)、合同、DPIA 以及所在司法管辖区。

为什么这很重要

欧盟《通用数据保护条例(GDPR)》根据第 4(1) 条,将姓名、国家身份证号码(如 SSN 或 PESEL)、银行账户号码(IBAN)、电子邮件地址、信用卡号码和电话号码归类为个人数据。将此类数据发送给云端大模型提供商,构成第 4(2) 条所称的处理。第 4(5) 条明确认可假名化是降低风险的措施,但关键在于,假名化数据仍属于个人数据(序言第 26 条)。

GDPR 条款义务pseudonym-mcp 能提供的帮助无法解决的问题
第 5(1)(c) 条数据最小化在传输前剔除检测到的直接标识符无法最小化上下文、结构或未检测到的 PII
第 25 条通过设计实现隐私保护和默认隐私保护提供可融入隐私保护设计架构的技术层架构和策略决策仍由你负责
第 32 条处理安全属于序言第 83 条认可的技术措施(假名化)只是众多控制措施之一,不能替代访问控制、日志记录和加密
第 44 条向第三国传输减少你传输的明文 PII假名化个人数据仍是个人数据——传输规则仍然适用
第 4(5) 条假名化定义云端大模型无法读取映射存储;重新识别需要本地会话了解相关背景信息的人员仍可通过上下文重新识别

坦诚地说:GDPR 第 4(5) 条所指的假名化并非匿名化。数据在你的系统中仍然属于个人数据;仅仅因为你将姓名字段替换为标记,并不会让第 44 条的传输义务失效。

AI 法案合规

欧盟《AI 法案》对处理个人数据的高风险 AI 系统提出了额外要求。使用 pseudonym-mcp 作为中间层可以:

  • 支持精简 AI 系统数据流中的数据。
  • 帮助记录一项技术控制措施,以满足透明度和人工监督要求。
  • 通过限制明文个人身份信息(PII)的暴露,与技术稳健性和安全性原则(第 15 条)保持一致。

它本身不会改变你的 AI 法案风险分类——分类取决于使用场景和部署环境,而不是模型前的掩码步骤。

美国及国际适用性

该工具在欧盟以外也同样适用,但需注意相同的限制:

  • CCPA / CPRA(加利福尼亚州)——减少发送给第三方处理者的个人信息;不会改变控制者/企业的义务或消费者权利。
  • HIPAA(美国医疗保健)——根据 HIPAA,假名化的受保护健康信息(PHI)仍然属于 PHI。如果你是受监管实体或业务伙伴,使用此工具不会免除你与云端大模型提供商签订业务伙伴协议(BAA)的必要性。它可以成为可辩护的安全保障措施的一部分,但不能取而代之。
  • PCI DSS(支付行业)——通过 Luhn 校验的检测可降低卡号以明文形式发送给大模型的可能性。这只是一项控制措施;PCI 范围、分段和存储规则是另外需要考虑的问题。
  • SOC 2——可作为限制 PII 暴露的技术控制措施的有用证据。审计人员会考察整体情况,而不只是这一层。
  • PIPEDA(加拿大)、LGPD(巴西)、POPIA(南非)——这些法规都要求为跨境个人数据传输采取适当的安全保障措施。该工具是一种相关的保障措施,但不能替代数据传输的法律依据。
特定行业的适用性
行业相关法规常见处理的 PII 类型
医疗保健GDPR + HIPAA + 国家健康数据法律患者姓名、SSN、诊断信息
银行与金融GDPR + PCI DSS + PSD2 + DORA信用卡、IBAN、SSN、PESEL
人力资源与招聘GDPR 第 9 条(特殊类别)姓名、国家身份证件号码、联系方式
法律GDPR + 律师—客户保密特权姓名、案件编号、个人详细信息
保险GDPR + Solvency II个人身份标识、健康数据
公共部门(美国)CCPA + 州隐私法SSN、驾驶证号码
公共部门(波兰)GDPR + UODO + KRIPESEL、NIP、REGON

对于此表中的每一行,pseudonym-mcp 都是一项有用的基础构件。仅靠掩码工具无法满足上述任何一项法规要求。

工作原理

Your App / Claude Desktop
        │
        │  explicit mask_text tool call with PII
        ▼
┌─────────────────────────┐
│      pseudonym-mcp      │
│                         │
│  Phase 1: Pattern NER   │  ← 46 rules: national IDs, tax numbers,
│                         │    IBAN, VAT, cards, wallets, devices
│                         │    scored, checksum-verified, context-aware
│  Phase 2: Ollama NER    │  ← PERSON, ORG  (local LLM)
│  MappingStore (session) │  ← [TAG:N] ↔ original value
└────────────┬────────────┘
             │  masked text returned to the client/agent
             ▼
      Your workflow sends the masked text
             ▼
      Cloud LLM API
      (Claude / GPT-4 / Gemini)
             │
             │  response with [TAG:N] tokens
             ▼
┌─────────────────────────┐
│      pseudonym-mcp      │
│   unmask_text / revert  │  ← tokens → originals
└────────────┬────────────┘
             │  restored response
             ▼
        Your App / User
令牌格式
US / English identifiers (en pack):
[PERSON:1]       John Smith
[SSN:1]          123-45-6789
[CREDIT_CARD:1]  4111 1111 1111 1111
[ORG:1]          Acme Corp
[EMAIL:1]        [email protected]
[PHONE:1]        (555) 123-4567

Polish identifiers (pl pack):
[PERSON:1]       Jan Kowalski
[PESEL:1]        90010112318
[ORG:1]          Auto-Lux
[NIP:1]          526-000-00-05
[REGON:1]        123456785
[IBAN:1]         PL27114020040000300201355387
[EMAIL:1]        [email protected]
[PHONE:1]        +48 123 456 789

映射存储在会话范围内的内存存储中。每次调用 mask_text 都会返回一个 session_id;将其传回 unmask_text 即可还原原文。

真实示例

Claude Code / Obsidian 中的会议记录

你有一条记录:

Meeting with Jan Kowalski (PESEL: 90010112318) from Acme sp. z o.o.
We discussed a contract for 45 000 zł. Contact: [email protected]

在 Claude Code 中输入:

Use mask_text on this note, then summarise the key points of the meeting.

首先,调用 mask_text;pseudonym-mcp 会在本地替换检测到的 PII:

Meeting with [PERSON:1] ([PESEL:1]) from [ORG:1].
We discussed a contract for 45 000 zł. Contact: [EMAIL:1]

然后让 Claude 根据掩码后的文本进行处理。Claude 会以令牌作答:

Meeting with [PERSON:1] from [ORG:1] covered a contract
for 45 000 zł. Follow up via [EMAIL:1].

pseudonym-mcp 会在本地还原原文:

Meeting with Jan Kowalski from Acme sp. z o.o. covered
a contract for 45 000 zł. Follow up via [email protected]

如果你发送到上游的是掩码后的文本,云服务提供商能看到会议结构和金额,但看不到检测到的姓名、PESEL、组织或电子邮件的明文。替换过程在你的设备上完成。

带有 session_id 的 Obsidian 库
# mask the entire vault once — save the session_id
Use mask_text on my notes — remember the session_id

# ask Claude anything across multiple prompts
Summarise all meetings from Q1

# Claude replies with tokens; restore originals
Use unmask_text with session_id abc123 on the response

session_id 会在整个会话期间保留令牌映射,因此在不同笔记中,相同的 [PERSON:1] 始终指向同一个人。这种一致性使跨笔记推理成为可能;同时,也意味着任何了解你工作情况的人都可能利用旁证重新识别出经过脱敏的语料。请谨慎使用长期会话。

MCP 提示词模板

pseudonym-mcp 内置了两个提示词模板,用于描述“脱敏 → 执行任务 → 还原”的工作流。

重要提示: MCP 提示词模板只是便捷辅助工具,并非隐私边界。在工具进行脱敏之前,内联提示词参数可能已对宿主客户端或模型可见。要获得最强隐私保护,请先直接调用 mask_text,然后在大模型提示词中使用返回的 masked_text。

pseudonymize_task — 内联文本
/pseudonymize_task text="Meeting with Jan Kowalski (PESEL: 90010112318). Contract: 45 000 zł." task="Extract action items"

预期工作流:

  1. pseudonym-mcp 在本地脱敏检测到的 PII → [PERSON:1]、[PESEL:1]
  2. Claude 处理脱敏后的文本
  3. pseudonym-mcp 还原响应中的原始内容

可选的 lang 参数:en 或 pl。它只会标注生成的提示词文本;服务实际运行的语言包由自身的 --lang 决定。

privacy_scan_file — 文件 / PDF(仅限 macOS)

需要 macos-vision-mcp——这是一个独立的 MCP 服务,使用 Apple 的 Vision 框架在设备上从 PDF 和图像中提取文本。仅限 macOS。

/privacy_scan_file filePath="/Users/me/contracts/nda.pdf" task="Summarise obligations and deadlines"

预期工作流:

  1. macos-vision-mcp 在设备上从文件中提取文本
  2. pseudonym-mcp 在本地脱敏检测到的 PII
  3. Claude 处理脱敏后的内容
  4. pseudonym-mcp 在显示响应前还原原始内容

可选参数:task(默认:总结要点)、lang(en 或 pl——仅用于标注提示词文本)。

快速开始

步骤 1 — 添加到你的 MCP 客户端(以 Claude Code 为例——无需安装):

claude mcp add pseudonym-mcp -- npx -y pseudonym-mcp --engines hybrid

步骤 2 —(可选)拉取一个 Ollama 模型,以启用完整的混合式 NER:

ollama pull llama3

如果你只需要基于正则表达式的脱敏(--engines regex),可以跳过此步骤。没有 Ollama 时,你仍可检测结构化标识符(SSN、IBAN、银行卡号、电子邮件、电话、PESEL),但无法检测非结构化的人名和组织名称。

全局安装——如果你更倾向于使用 npm install -g pseudonym-mcp,请在下方所有代码片段中将 npx -y pseudonym-mcp 替换为 pseudonym-mcp。

重启客户端。mask_text 和 unmask_text 工具会自动显示。

可用工具

工具功能提示词示例
mask_text对文本中检测到的 PII 进行假名化处理。返回 masked_text + session_id。“在总结这封客户来信之前,先对其使用 mask_text”
unmask_text从会话中还原原始值。传入 mask_text 返回的 session_id。“使用 session_id X 调用 unmask_text,还原响应”
mask_text 输入
{
  "text": "John Smith (SSN: 123-45-6789) works at Acme Corp.",
  "session_id": "optional — omit to create a new session",
  "custom_literals": ["John Smith", "Acme Corp"]
}
mask_text 输出
{
  "session_id": "3f2a1b...",
  "masked_text": "[PERSON:1] (SSN: [SSN:1]) works at [ORG:1].",
  "auto_unmask": false,
  "ner_status": "ready",
  "active_locales": ["pl", "en", "de", "it", "es", "fr", "nl", "cz", "sk", "se", "fi", "uk"]
}

active_locales 列出已运行的语言包。如果服务通过 --lang 缩小了语言范围,响应还会包含 disabled_locales 和 locale_warning,其中会列出服务无法识别的标识符:

{
  "active_locales": ["en"],
  "disabled_locales": ["pl", "de", "it", "es", "fr", "nl", "cz", "sk", "se", "fi", "uk"],
  "locale_warning": "Locale packs disabled: pl (PESEL, NIP, REGON, …); de (Steuer-IdNr, PLZ); … Identifiers from those countries are NOT detected and will pass through unmasked. Start the server without --lang, or with --lang all, to load every pack."
}
unmask_text 输入
{
  "text": "The case concerns [PERSON:1] at [ORG:1].",
  "session_id": "3f2a1b..."
}

配置

mcp-config.json(项目根目录)
{
  "lang": "all",
  "engines": "hybrid",
  "ollamaModel": "llama3",
  "ollamaBaseUrl": "http://localhost:11434",
  "autoUnmask": false,
  "strictValidation": true,
  "sensitivity": "balanced",
  "extraLocales": [],
  "customLiterals": ["Jan Kowalski", "78091512345", "+48 123 456 789"]
}
键值默认值描述
langall、en、pl、de、it、es、fr、nl、cz、sk、se、fi、ukall正则规则的语言包。all 会运行所有语言包——见下文
enginesregex | llm | hybridhybrid要运行的 NER 引擎
ollamaModel任意 Ollama 模型名称llama3用于实体检测的本地 LLM
ollamaBaseUrlURLhttp://localhost:11434Ollama API 端点
autoUnmasktrue | falsefalse向客户端报告首选的取消屏蔽行为;此服务不会拦截响应
strictValidationtrue | falsetrue启用校验和/格式验证(SSN 区域检查、银行卡的 Luhn 校验、PESEL 校验和)
sensitivitybalanced | strict | paranoidbalanced屏蔽匹配项所需的置信度
extraLocalesstring[][]除 lang 外还要运行的其他语言包,例如 ["de", "it"]。当 lang 为 all 时无需设置
customLiteralsstring[][]无论使用哪种引擎,始终会脱敏的特定字符串(姓名、ID、电话号码)
区域覆盖采用默认开启策略

除非指定区域,否则会运行所有区域包。 lang 默认值为 all,因此全新启动的服务会同时识别波兰、美国、德国、意大利、西班牙、法国、荷兰、捷克/斯洛伐克、瑞典、芬兰和英国标识符。

这是有意为之。在调用端看来,限制为单一区域包的服务与完整服务无法区分:它会返回看似正常的文本并报告成功,但其他所有国家的标识符都会原样通过。某个区域包误将订单号识别为敏感信息,会浪费不必要的令牌;未能识别 PESEL,则可能引发事故。

任何未指向真实区域包的值——拼写错误、空字符串、all——都会启用所有区域包。只有在你主动要求时才会缩小范围;缩小范围后,服务会在启动时通过 stderr 以及每个 mask_text 响应(disabled_locales、locale_warning)明确告知。

代价。 同时运行十二个区域包,意味着要针对每个数字测试十二种国家级假设,因此在某个国家并不起眼的格式,可能会在另一个国家被屏蔽:

输入被屏蔽为原因
123456789PHONE符合波兰 9 位号码规则
045678/2024CZ_SK_BIRTH_NUMBER符合 rodné číslo 格式
AB123456CUK_NINO符合 National Insurance 格式
123456789012345FR_NIR以 1 或 2 开头的 15 位数字

如果你的文档仅涉及单一司法管辖区,且这些标记只是噪声,请主动缩小服务的区域范围——--lang en、--lang pl --extra-locales de,it——并接受无法检测已移除区域包中的标识符这一结果。

配置文件的读取位置

mcp-config.json 会在服务的工作目录中查找。对于由 MCP 启动的进程,该目录是客户端的工作目录,而不是已安装的软件包目录。npm 包中附带的副本仅为示例,永远不会被加载。需要指定文件时,请传入 --config /path/to/mcp-config.json。

设置的优先级从高到低为:CLI 标志 → mcp-config.json → 内置默认值。只有实际输入的标志才算 CLI 输入,因此配置文件仍会决定命令行中未指定的所有设置。

CLI 标志

所有配置键都可以在启动时覆盖(优先级最高):

pseudonym-mcp --lang pl --extra-locales de,it --sensitivity strict --engines regex
标志描述
--lang正则规则的语言包:all、en、pl、de、it、es、fr、nl、cz、sk、se、fi、uk(默认值:all)
--enginesregex、llm 或 hybrid(默认值:hybrid)
--ollama-model用于 NER 的 Ollama 模型
--ollama-base-urlOllama 基础 URL
--sensitivitybalanced、strict 或 paranoid(默认值:balanced)
--extra-locales以逗号分隔的语言区域,与 --lang 一起识别,例如 de,it
--config自定义 JSON 配置文件的路径
--auto-unmask在 mask_text 输出中设置 auto_unmask: true,供支持此选项的客户端使用
--custom-literals始终进行脱敏的字符串,以逗号分隔,例如 "Jan Kowalski,78091512345"
Claude Code
claude mcp add pseudonym-mcp -- npx -y pseudonym-mcp --engines hybrid
Claude Desktop

编辑 ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "pseudonym-mcp": {
      "command": "npx",
      "args": ["-y", "pseudonym-mcp", "--engines", "hybrid"]
    }
  }
}
Cursor

添加到 ~/.cursor/mcp.json:

{
  "mcpServers": {
    "pseudonym-mcp": {
      "command": "npx",
      "args": ["-y", "pseudonym-mcp", "--engines", "regex"]
    }
  }
}

支持的 PII 类型

覆盖波兰、欧洲和美国的 46 个识别器,其中 24 个经过校验和验证

检测采用尽力而为的方式。以下模式是工具查找的内容,并不保证始终能检测到。已知的不足之处请参阅限制。

以下所有表格中的检测项在默认配置下均处于启用状态。--lang 会关闭相应语言包;请参阅语言区域覆盖采用失败关闭机制。

自定义字面量
标签检测方式匹配结果
CUSTOM与 customLiterals 配置或 custom_literals 工具参数进行精确匹配(不区分大小写)完整字符串

自定义字面量会在正则阶段之后、LLM NER 之前应用,与引擎模式无关。匹配时优先处理较长的字面量,以避免部分替换。

如何判定匹配

置信度指示器:纯数字得分为 0.15,附近的上下文词将其提升至 0.50,通过校验和则提升至 0.85;对照偏执、严格和平衡阈值

每种模式都有一个置信度分数。通过校验会提高分数,匹配项附近的上下文词——“PESEL:”“NIP”“Steuer-ID”“出生日期”——也会提高分数,单凭上下文词就足以达到默认阈值。凡是达到敏感度阈值的内容都会被遮蔽:

--sensitivity阈值效果
balanced0.50默认值。具有辨识度的格式、已验证的校验和,以及任何带有标签的内容。
strict0.35增加较弱的格式:裸 IBAN 类字符串、日期、通用标识符。
paranoid0.10规则能识别的所有内容,包括误报。

如果校验失败意味着“根本不是此类实体”(例如银行卡号未通过 Luhn 校验),就会丢弃候选项。如果校验失败意味着输入错误(例如 PESEL),候选项会以较低置信度保留——让输错的标识符进入云端,比白白遮蔽一个数字更糟。

下方标有 ✓ 的规则会验证实际的校验位。

全局 — 对所有语言均启用
标签检测内容校验方式
EMAIL兼容 RFC 5321 的地址
PHONE国际格式
IBAN76 个国家/地区,符合 ISO 13616 长度✓ mod-97
VAT_ID全部 27 个欧盟成员国,以及 XI✓ PL、IT、NL、SI、LU
CRYPTO_WALLETBitcoin(Base58Check、bech32)、Ethereum✓ BTC
IMEI移动设备标识符✓ Luhn
VIN车辆识别号码✓ ISO 3779
MAC硬件地址
UUIDUUID / GUID
IPIPv4 和 IPv6
URL网址
DATE日历日期——当内容可识别为出生日期时会被遮蔽
波兰语(pl 包)
标签检测内容校验方式
PESEL国家身份证号,11 位数字✓ Mod-10
NIP税号——发票上可带连字符、空格,也可不带分隔符✓ Mod-11
REGON企业登记号,9 位或 14 位数字✓ Mod-11
ID_CARD身份证,ABC123456✓
PASSPORT两个字母加七位数字✓
KW土地登记簿(不动产登记簿)✓
KRS法院登记号——需要标签
IBANPL 前缀或不带前缀的 26 位 NRB✓ mod-97
PHONE+48 / 0048、手机、固定电话
POSTAL_CODEXX-XXX
美国(en pack)
Tag检测方式校验和
SSN带连字符的形式;点分隔、空格分隔和裸格式需要标签区域/组范围
CREDIT_CARD13–19 位数字✓ Luhn
ITIN纳税人识别号
EIN雇主识别号
ABA_ROUTING银行路由号码✓ 3-7-1
PASSPORT九位数字——需要标签
DRIVER_LICENSE各州格式——需要标签
ZIP_CODEXXXXX / XXXXX-XXXX
其他欧洲地区语言环境

与其他所有数据包一样,这些语言环境默认启用。使用 --lang 可缩小范围, 也可以使用 --extra-locales de,it 将指定语言与其相邻语言搭配使用—— 一张波兰发票也可能包含德国和意大利标识符。

LocaleTag检测方式校验和
deDE_TAX_IDSteueridentifikationsnummer✓ ISO 7064
dePOSTAL_CODEPLZ
itIT_FISCAL_CODECodice fiscale✓
esES_NIF / ES_NIEDNI/NIF 和外国人身份证✓ mod-23
frFR_NIRNuméro de sécurité sociale✓ mod-97
nlNL_BSNBurgerservicenummer✓ elfproef
cz skCZ_SK_BIRTH_NUMBERRodné číslo✓ mod-11
seSE_PERSONNUMMERPersonnummer✓ Luhn
fiFI_HETUHenkilötunnus✓ mod-31
ukUK_NHSNHS number✓ mod-11
ukUK_NINONational Insurance number
由大模型检测,而非通过模式检测
Tag检测方式要求
PERSON全名Ollama NER(hybrid / llm 引擎)
ORG公司/组织名称Ollama NER(hybrid / llm 引擎)

语言检测

pseudonym-mcp 包含一个基于 franc 的轻量级启发式语言检测器。 它会根据文本内容推断语言,并返回结构化结果:

detectLanguage('Umowa zostaje zawarta na czas nieokreślony')
// → { detected: 'pl', source: 'text', raw: 'pol', confidence: 0.94 }

detectLanguage('Hello')
// → { detected: 'unknown', source: 'fallback', raw: null, confidence: null }
字段描述
detected'pl'、'en' 或 'unknown'
source'text'——franc 已运行且映射成功;'fallback'——文本过短或无法确定
rawfranc 返回的原始 ISO 639-3 代码(例如 'pol'),或 null
confidencefranc 返回的 0–1 分数;未调用 franc 时为 null

短于 20 个字符或置信度较低的文本会返回 detected: 'unknown'。 该检测器不会影响当前的假名化流程——--lang 配置仍具有决定性。 它是构建未来多语言和自动选择模式的基础组件。

引擎模式

模式需要 Ollama检测结构化 PII检测姓名 / 组织
regex否是否
llm是否是
hybrid(默认)是(优雅降级)是是

在 hybrid 模式下,Ollama 会在正则扫描之后运行,因此本地 NER 模型接收到的结构化标识符已经过令牌化。如果 Ollama 无法访问,服务会向 stderr 输出警告,并返回仅经过正则处理的文本,不会崩溃或卡住。

隐私与安全说明

经过审慎校准的声明:

  • 工具本身不会进行遥测。 pseudonym-mcp 不会发起网络请求,除非连接到你的本地 Ollama 实例,以及(可选)MCP stdio 传输。
  • 默认在内存中保存映射。 映射存储不会写入磁盘。会话的生命周期与服务进程相同。
  • 同一会话中的令牌具有幂等性。 相同的原始值始终映射到同一令牌(同一个姓名再次出现时,[PERSON:1] 不会变成 [PERSON:2]),从而保留大模型推理中的语义连贯性。
  • 不训练模型。 本地 Ollama 模型离线运行。此工具不会使用你的数据训练任何模型。
  • 默认严格验证。 无效的 SSN(区域码为 000/666/900+)、未通过 Luhn 校验的信用卡号,以及校验和无效的 PESEL 均不会被屏蔽,以避免将 OCR 错误或随机数字序列误判为敏感信息。

以下情况无法保证:

  • 能检测出输入中的所有 PII。
  • 令牌化后的文本无法关联到真实人物——仍可能根据上下文重新识别。
  • 云服务提供商无法从结构、时间或内容中获知敏感信息。
  • 符合任何特定法规——合规性取决于系统层面,而非工具层面。

局限性

pseudonym-mcp 是一种技术隐私控制措施,并非合规性的法律保证。

  • 检测仅尽力而为。 可能出现漏报和误报。无法检测间接指代(例如 “会计部那个高个子”、“我的房东”、“桥附近的那个地方”)。昵称、姓名首字母和部分姓名通常也会被漏掉。
  • 结构仍会传出。 数额、令牌之间的关系、叙述内容,以及检测器漏掉的任何 PII 都会发送给云端大模型。只有被识别为出生日期的日期,或在更高的 --sensitivity 设置下,日期才会被屏蔽;其他日历信息仍会传出。令牌化隐藏的是 谁,而不是 发生了什么情况。
  • 缩小 --lang 范围会从源头静默缩小检测范围。 关闭某个区域语言包后,系统根本不会查找该语言包对应的标识符——输出看起来干净无异,但调用仍会报告成功。服务会在 stderr 和每个 mask_text 响应中说明哪些语言包已关闭;但没有任何下游机制会强制你查看这些信息。
  • 掩码前的日志由你负责。 如果你的应用在将明文传给 mask_text 之前记录了明文,此工具无能为力。
  • 映射仅在进程内有效。 重启服务会结束会话并丢弃映射,这是有意为之。
  • 可能重新识别身份。 能访问本地映射存储的人可以重新识别身份;仅凭上下文,掌握相关背景知识的人也可能做到这一点。这属于 GDPR 第 4(5) 条所述的假名化,而非匿名化。
  • 不提供法律建议。 本 README 中的任何内容均不构成法律建议。合规性取决于系统层面;请就你的具体部署咨询 DPO、合规团队和律师。

根据 GDPR 第 4(5) 条和序言第 26 条,假名化数据仍属于个人数据。pseudonym-mcp 可大幅减少明文 PII 的暴露,但无法免除你的法律义务。

开发

git clone https://github.com/woladi/pseudonym-mcp
cd pseudonym-mcp
npm install
npm run build    # tsc compile
npm test         # vitest (no Ollama required)

测试套件完全离线运行——Ollama 调用通过构造函数注入,并在所有测试中进行模拟。无需实时 LLM。

添加识别器
  1. 在 src/patterns/locale/<lang>/ 下添加文件(如果与语言无关,则添加到 src/patterns/global/ 下),导出一个 PatternRule:
export const regonRule: PatternRule = {
  id: 'pl.regon',
  entityType: 'REGON',
  patterns: [
    { name: 'REGON (14 digits)', regex: /\b\d{14}\b/g, score: 0.25 },
    { name: 'REGON (9 digits)', regex: /\b\d{9}\b/g, score: 0.15 },
  ],
  locales: ['pl'],
  context: ['regon', 'nr regon', 'gus'],
  description: 'Polish business register number',
  validate: regonChecksum,
  checksumMode: 'boost',
}
  1. 将其注册到 src/patterns/index.ts 中的 allPatterns 数组。这是唯一需要接线的地方——规则集会按语言区域从注册表派生,因此无需让其他地方知道该规则的存在。
  2. 对于全新的语言,在 src/patterns/types.ts 的 SupportedLocale 和 SUPPORTED_LOCALES 两者中添加该语言区域——默认选择会加载此列表,因此未列入其中的规则包永远不会运行——并在 src/language/language-map.ts 中添加 ISO 639-3 → 短代码映射。若两者不一致,tests/default-coverage.test.ts 会失败,并要求每个规则包都提供一个样例。

选择分数:从较低分数开始,让证据发挥作用。仅作为此类实体出现的格式(ABC123456,即税号)可以从接近 0.5 的分数开始。可能代表任何内容的一串数字可以从 0.15–0.25 开始,并依靠 validate 或 context 达到门槛。

选择 checksumMode:如果校验失败意味着它绝不可能是此类实体(银行卡上的 Luhn 校验),则选 filter;如果校验失败意味着存在笔误,而漏检会导致数据泄露(PESEL、IBAN),则选 boost;如果校验只能排除不可能的值、却无法确认任何内容(美国 SSN 范围),则选 gate。

参见 src/patterns/locale/pl/,其中提供了这三种模式的完整示例。

贡献

欢迎贡献。请遵循 Conventional Commits 编写提交消息。

发布使用 changesets。如果你的更改会影响用户,请在 PR 中添加一个 changeset:

npm run changeset   # pick patch / minor / major, describe the change

合并到 master 后,会创建一个“version packages” PR,用于更新版本、server.json、src/version.ts 和变更日志;合并该 PR 后,会发布到 npm(使用 Trusted Publishing,并提供来源证明)、为发布打标签,并刷新 MCP 注册表条目。没有待处理 changeset 的合并不会发布任何内容。

特别欢迎贡献语言规则包——德语(Personalausweis、Steuer-ID)、法语(NIR、SIRET)、西班牙语(DNI/NIE)等语言都能显著拓展该工具的实用性。

许可证

MIT — Adrian Wolczuk

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。