pseudonym-mcp について
pseudonym-mcpは、テキストをクラウドLLMに送る前にローカルで機密情報を検出してトークン化し、後から元の値に戻せます。明示的なプライバシー処理を必要とするMCPクライアント向けで、コンプライアンス製品ではなくリスク低減策です。
主な機能
- 01ローカルでの個人情報検出とマスキング
- 02正規表現とローカルOllamaのNERエンジン
- 03セッション単位のトークン対応表
- 04unmask_textによる原文復元
- 05複数言語・地域のルール
- 06正規表現のみ、LLMのみ、ハイブリッドの各モード
活用シーン
- 01クラウドLLM処理前に識別情報をマスキング
- 02モデルの応答に含まれる名前や値を復元
- 03同じトークンを参照するメモの処理
- 04MCPワークフローに個人情報保護手順を追加
MCP 対応
mask_textとunmask_textのツール、およびプロンプトテンプレートをMCPクライアントに提供します。検出とトークン対応表の管理はローカルで行われ、クラウドLLMに送る前にクライアントが明示的にマスキングを呼び出す必要があります。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
2掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| text | string | はい | 仮名化するテキスト |
| session_id | string | いいえ | 任意:既存のセッションを再利用し、複数回の呼び出し間でトークン番号を維持します |
| wait_for_ner | boolean | いいえ | true の場合、処理前に Ollama のモデル読み込み完了を最大 30 秒待ちます(デフォルト:false) |
| custom_literals | array | いいえ | 常にマスキングする特定の文字列(氏名、ID、電話番号) |
詳細
pseudonym-mcp
LLM ワークフロー向けのローカル仮名化ツールです。テキストをクラウド LLM に渡す前に、検出した PII を不透明なトークンに置き換え、その後トークンを復元します。
クライアントやエージェントが明示的なプライバシー保護のステップとして呼び出せる MCP ツール(mask_text と unmask_text)を提供します。サーバーは PII をローカルで検出して不透明なトークンに置き換え、後で復元できるようトークンの対応関係をメモリ内に保持します。
これは多層防御の手段であり、コンプライアンスを一挙に解決するものではありません。この仕組みでできることを過信する前に、制限事項とGDPR と AI コンプライアンスのセクションをお読みください。
提供機能
- 12 のロケールに対応する 46 種類の認識器を標準ですべて有効化:ポーランド(PESEL、NIP、REGON、dowód、paszport、księga wieczysta)、EU(mod-97 検証に対応した IBAN、27 加盟国すべての VAT に加え、DE、IT、ES、FR、NL、CZ/SK、SE、FI、UK の国民 ID)、米国(SSN、ITIN、EIN、ABA ルーティング番号、カード)。そのうち 24 種類は実際のチェックディジットを検証します。誤検出を減らしたい場合は、
--langで対象を絞り込めます。詳しくはロケール対応はフェイルクローズをご覧ください。ヒューリスティックによる言語検出(detectLanguage())はテキスト内容から言語を推定します。--langは引き続き優先される上書き設定です。 - ハイブリッド NER エンジン:構造化 PII(SSN、クレジットカード、IBAN、メールアドレス、電話番号)には正規表現を、非構造化エンティティ(氏名、組織名)にはローカルの Ollama LLM を使用します。
- ローカル検出アーキテクチャ:MCP ツールの呼び出し時に、検出と置換をお使いのマシン上で行います。クラウド LLM の呼び出し自体は行われます(それが目的です)が、ワークフローでマスキング済みの出力を使用すれば、検出された PII の代わりにトークンを参照できます。
- セッション単位のマッピングストア:
[PERSON:1]のようなトークンは、リクエストごとに分離されたセッション内で元の値に対応付けられます。複数回の往復でもトークンの一貫性が保たれます。 - マスキング解除ワークフローのサポート:
mask_textは、この設定を尊重するクライアント向けにauto_unmaskを返しますが、このサーバーが任意の LLM 応答を自動で傍受することはありません。 - 柔軟なエンジン:
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"→ そのまま LLM プロバイダーに送信されます - プロンプト内のすべての氏名、ID 番号、クレジットカード番号が処理され、プロバイダーによって記録される可能性があります
- プロバイダー側で情報漏えいが発生すると、これらの値が平文で露呈します
- さらなる保護措置なしに個人データを EU 域外の LLM プロバイダーに送信すると、GDPR 第 44 条に関する説明責任が生じます
✅ クラウドへの呼び出し前に pseudonym-mcp を使用した場合:
- 先に
mask_textを呼び出すと、同じプロンプトを"[PERSON:1], SSN [SSN:1], card [CREDIT_CARD:1]"に置き換えられます - LLM は、検出された値を平文で見ることなく、構造と内容を推論します
- ユーザーに届く前に、
unmask_textを使ってレスポンスをローカルでトークン解除できます - 検出された直接識別子は送信されなくなります。ただし、構造、日付、間接的な参照、見逃された PII は引き続き送信されます
これにより、平文の PII が露呈するリスクを大幅に低減できます。ただし、「個人データが一切マシンの外に出ない」わけではありません。制限事項を参照してください。
GDPR と AI コンプライアンス
pseudonym-mcp はコンプライアンス対応に役立ちますが、コンプライアンス製品ではなく、技術的な管理策です。特定の規制に準拠しているかどうかは、スタック全体、役割(管理者/処理者)、契約、DPIA、管轄区域によって異なります。
重要な理由
EU の一般データ保護規則(GDPR)では、氏名、国民 ID 番号(SSN や PESEL など)、銀行口座番号(IBAN)、メールアドレス、クレジットカード番号、電話番号を第 4 条(1)における個人データと定めています。このデータをクラウド LLM プロバイダーに送信することは、第 4 条(2)における処理に該当します。仮名化は、第 4 条(5)でリスク低減策として明示的に認められています。ただし、重要なのは、仮名化されたデータも依然として個人データであるという点です(前文 26)。
| GDPR 条項 | 義務 | pseudonym-mcp が役立つ点 | 対応できない点 |
|---|---|---|---|
| 第 5 条(1)(c) | データの最小化 | 送信前に、検出された直接識別子を除去します | コンテキスト、構造、未検出の PII は最小化されません |
| 第 25 条 | データ保護の設計およびデフォルト化 | プライバシー・バイ・デザインのアーキテクチャに組み込める技術的なレイヤーを提供します | アーキテクチャやポリシーに関する判断は、引き続き利用者の責任です |
| 第 32 条 | 処理の安全性 | 前文 83 で認められた技術的措置(仮名化)です | 多くの管理策のうちの一つであり、アクセス制御、ログ記録、暗号化の代わりにはなりません |
| 第 44 条 | 第三国への移転 | 移転する平文の PII を減らします | 仮名化された個人データも依然として個人データであり、移転に関する規則は引き続き適用されます |
| 第 4 条(5) | 仮名化の定義 | マッピングストアはクラウド LLM からは不透明で、再識別にはローカルセッションが必要です | 周辺知識を持つ人は、コンテキストから再識別できる可能性があります |
率直に言うと: GDPR 第 4 条(5)における仮名化は、匿名化ではありません。データはシステム内で引き続き個人データとして扱われ、氏名フィールドをトークン化しただけで第 44 条の移転義務がなくなるわけではありません。
AI Act への準拠
EU の AI Act は、個人データを処理する高リスク AI システムに追加要件を課しています。中間レイヤーとして pseudonym-mcp を使用すると、次のことができます。
- AI システムのデータフローにおけるデータ最小化をサポートします。
- 透明性と人間による監督の要件に対する技術的管理策の文書化に役立ちます。
- 明文の PII への露出を抑えることで、技術的堅牢性と安全性の原則(第 15 条)に沿うことができます。
これだけで AI Act におけるリスク分類が変わるわけではありません。分類はユースケースと導入コンテキストによって決まり、モデルの前段階で行うマスキングによって決まるものではありません。
米国および国際的な適用範囲
同じ注意点はありますが、このツールは EU 以外でも役立ちます。
- CCPA / CPRA(カリフォルニア州) — サードパーティの処理業者に送信される個人情報を減らしますが、管理者や事業者の義務、または消費者の権利は変わりません。
- HIPAA(米国の医療分野) — 仮名化された PHI も HIPAA の下では PHI です。対象事業体または業務提携者である場合、このツールを使用しても、クラウド LLM プロバイダーとの BAA が不要になるわけではありません。適切な安全対策の一環にはなり得ますが、その代わりにはなりません。
- PCI DSS(決済業界) — Luhn 検証を用いた検出により、カード番号が明文のまま LLM に送られる可能性を減らします。これは管理策の一つです。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、運転免許証番号 |
| 公共部門(PL) | GDPR + UODO + KRI | PESEL、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には、マスク → タスク → マスク解除のワークフローを説明する、組み込みのプロンプトテンプレートが2つ用意されています。
重要: MCP プロンプトテンプレートは便利なヘルパーであり、プライバシーを保護する境界ではありません。インラインのプロンプト引数は、ツールによるマスキングが行われる前に、ホストクライアントやモデルから見える場合があります。プライバシーを最大限に確保するには、まずmask_textを直接呼び出し、返されたmasked_textをLLMのプロンプトで使用してください。
pseudonymize_task — インラインテキスト
/pseudonymize_task text="Meeting with Jan Kowalski (PESEL: 90010112318). Contract: 45 000 zł." task="Extract action items"
想定されるワークフロー:
- pseudonym-mcpが検出したPIIをローカルでマスクします →
[PERSON:1]、[PESEL:1] - Claudeがマスク済みのテキストを処理します
- pseudonym-mcpが応答内の元の値を復元します
省略可能なlang引数:enまたはpl。生成されるプロンプトテキストに注釈を付けるだけです。サーバーが実際に実行するパックは、サーバー自身の--langによって決まります。
privacy_scan_file — ファイル/PDF(macOSのみ)
macos-vision-mcpが必要です — AppleのVisionフレームワークを使用して、PDFや画像からデバイス上でテキストを抽出する、別のMCPサーバーです。macOSのみで利用できます。
/privacy_scan_file filePath="/Users/me/contracts/nda.pdf" task="Summarise obligations and deadlines"
想定されるワークフロー:
- macos-vision-mcpがデバイス上でファイルからテキストを抽出します
- pseudonym-mcpが検出したPIIをローカルでマスクします
- Claudeがマスク済みのコンテンツを処理します
- pseudonym-mcpが応答を表示する前に元の値を復元します
省略可能な引数:task(デフォルト:要点を要約する)、lang(enまたはpl。プロンプトテキストに注釈を付けるだけです)。
クイックスタート
ステップ1 — MCPクライアントに追加します(Claude Codeの例 — インストールは不要です):
claude mcp add pseudonym-mcp -- npx -y pseudonym-mcp --engines hybrid
ステップ2 —(任意)ハイブリッドNERを完全に利用するため、Ollamaモデルを取得します:
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"]
}
| キー | 値 | デフォルト | 説明 |
|---|---|---|---|
lang | all, en, pl, de, it, es, fr, nl, cz, sk, se, fi, uk | all | 正規表現ルールに使用するロケールパックです。all の場合はすべてのパックを実行します。以下を参照してください |
engines | regex | llm | hybrid | hybrid | 実行する NER エンジン |
ollamaModel | 任意の Ollama モデル名 | llama3 | エンティティ検出に使用するローカル LLM |
ollamaBaseUrl | URL | http://localhost:11434 | Ollama API エンドポイント |
autoUnmask | true | false | false | 推奨するマスク解除の動作をクライアントに通知します。このサーバーはレスポンスを傍受しません |
strictValidation | true | false | true | チェックサム/形式の検証を有効にします(SSN の地域コード確認、カード番号の Luhn 検証、PESEL チェックサム) |
sensitivity | balanced | strict | paranoid | balanced | マスクする前にマッチに必要な確信度の高さ |
extraLocales | string[] | [] | lang と併せて実行する追加のロケールパック。例:["de", "it"]。lang が all の場合は重複します |
customLiterals | string[] | [] | エンジンにかかわらず、常に編集する特定の文字列(名前、ID、電話番号) |
ロケールの適用範囲はフェイルクローズです
ロケールを指定しない限り、すべてのロケールパックが実行されます。 lang のデフォルト値は all です。そのため、新しいサーバーはポーランド、米国、ドイツ、イタリア、スペイン、フランス、オランダ、チェコ/スロバキア、スウェーデン、フィンランド、英国の識別子を一度に認識します。
これは意図的な仕様です。1つのパックに絞ったサーバーも、呼び出し側から見るとすべてのパックが有効なサーバーと区別できません。見た目には問題のないテキストを返し、成功を報告する一方で、ほかのすべての国の識別子はそのまま通過します。注文番号に反応するパックは不要なトークンを消費し、PESELを検出できないパックはインシデントを招きます。
実在するパックを指定していない場合(入力ミス、空文字列、all)は、すべてのパックが有効になります。適用範囲が狭まるのは、明示的に指定した場合に限られます。その場合、サーバーは起動時の stderr および 各 mask_text レスポンス(disabled_locales、locale_warning)でその旨を通知します。
コストについて。 12個のパックを同時に実行すると、すべての数値に対して12か国分の仮説を検証することになります。そのため、ある国では珍しくない形式が、別の国ではマスキングされます。
| 入力 | マスキング結果 | 理由 |
|---|---|---|
123456789 | PHONE | ポーランドの有効な9桁の電話番号体系 |
045678/2024 | CZ_SK_BIRTH_NUMBER | rodné číslo の形式 |
AB123456C | UK_NINO | National Insurance の形式 |
123456789012345 | FR_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) |
--engines | regex、llm、または hybrid(デフォルト:hybrid) |
--ollama-model | NER に使用する Ollama モデル |
--ollama-base-url | Ollama のベース URL |
--sensitivity | balanced、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 タイプ
検出はベストエフォートです。以下のパターンは、このツールが検出対象とするものであり、常に検出できることを保証するものではありません。既知の制限については、制限事項を参照してください。
以下のすべての表は、デフォルト設定で有効です。--lang を指定するとパックが無効になります。ロケールのカバー範囲はフェイルクローズを参照してください。
カスタムリテラル
| タグ | 検出方法 | 一致 |
|---|---|---|
CUSTOM | customLiterals 設定または custom_literals ツールパラメーターとの完全一致(大文字と小文字を区別しない) | 文字列全体 |
カスタムリテラルは、エンジンモードにかかわらず、正規表現フェーズの後、LLM NER の前に適用されます。部分置換を防ぐため、長いリテラルから先に照合されます。
マッチの判定方法
すべてのパターンには信頼度スコアが設定されています。チェックサムが有効だとスコアが上がり、マッチの近くに文脈語(「PESEL:」、「NIP」、「Steuer-ID」、「date of birth」など)がある場合もスコアが上がります。文脈語だけでも、デフォルトのしきい値に達するほどです。マスクされるのは、機密度の基準を満たすものです。
--sensitivity | しきい値 | 効果 |
|---|---|---|
balanced | 0.50 | デフォルトです。特徴的な形式、検証済みのチェックサム、ラベル付きのものを検出します。 |
strict | 0.35 | より判別しにくい形式を追加します。IBANに似た数字のみの文字列、日付、一般的な識別子などです。 |
paranoid | 0.10 | ルールで検出できるものすべてを対象とします。誤検出も含みます。 |
チェックサムの失敗が「このエンティティではない」ことを意味する場合(Luhn検証に失敗したカード番号など)、候補は破棄されます。一方、入力ミスを意味する場合(PESELなど)、候補は信頼度を下げて残ります。入力ミスの識別子がクラウドに送られるより、関係のない番号がマスクされるほうが安全です。
以下で✓の付いたルールは、実際のチェックディジットを検証します。
グローバル — すべての言語で有効
| タグ | 検出内容 | チェックサム |
|---|---|---|
EMAIL | RFC 5321互換のアドレス | |
PHONE | 国際形式 | |
IBAN | 76か国、ISO 13616の桁数 | ✓ mod-97 |
VAT_ID | EU加盟27か国すべて、およびXI | ✓ PL、IT、NL、SI、LU |
CRYPTO_WALLET | Bitcoin(Base58Check、bech32)、Ethereum | ✓ BTC |
IMEI | モバイルデバイス識別子 | ✓ Luhn |
VIN | 車両識別番号 | ✓ ISO 3779 |
MAC | ハードウェアアドレス | |
UUID | UUID / GUID | |
IP | IPv4およびIPv6 | |
URL | ウェブアドレス | |
DATE | 暦日 — 生年月日と解釈される場合にマスク |
ポーランド語(pl パック)
| タグ | 検出内容 | チェックサム |
|---|---|---|
PESEL | 国民識別番号、11桁 | ✓ Mod-10 |
NIP | 税務識別番号 — 請求書上のハイフン区切り、空白区切り、または数字のみの形式 | ✓ Mod-11 |
REGON | 事業者登録番号、9桁または14桁 | ✓ Mod-11 |
ID_CARD | Dowód osobisty、ABC123456 | ✓ |
PASSPORT | 2文字と7桁の数字 | ✓ |
KW | Księga wieczysta(土地登記簿) | ✓ |
KRS | 裁判所登録番号 — ラベルが必要 | |
IBAN | PL接頭辞、または数字のみの26桁のNRB | ✓ mod-97 |
PHONE | +48 / 0048、携帯電話、固定電話 | |
POSTAL_CODE | XX-XXX |
米国(en パック)
| タグ | 検出 | チェックサム |
|---|---|---|
SSN | ハイフン付き形式。ドット区切り、スペース区切り、区切りなしの形式にはラベルが必要です | 領域/グループ範囲 |
CREDIT_CARD | 13~19 桁 | ✓ Luhn |
ITIN | 納税者識別番号 | |
EIN | 雇用者識別番号 | |
ABA_ROUTING | 銀行ルーティング番号 | ✓ 3-7-1 |
PASSPORT | 9 桁 — ラベルが必要です | |
DRIVER_LICENSE | 州ごとの形式 — ラベルが必要です | |
ZIP_CODE | XXXXX / XXXXX-XXXX |
その他のヨーロッパのロケール
他のすべてのパックと同様、これらはデフォルトで実行されます。--lang で対象を絞るか、
--extra-locales de,it で選択した言語に隣接するロケールを組み合わせます —
ポーランド語の請求書には、ドイツ語とイタリア語の識別子も含まれます。
| ロケール | タグ | 検出 | チェックサム |
|---|---|---|---|
de | DE_TAX_ID | 納税者識別番号 | ✓ ISO 7064 |
de | POSTAL_CODE | 郵便番号 | |
it | IT_FISCAL_CODE | 納税者番号 | ✓ |
es | ES_NIF / ES_NIE | DNI/NIF および外国人 ID | ✓ mod-23 |
fr | FR_NIR | 社会保障番号 | ✓ mod-97 |
nl | NL_BSN | 市民サービス番号 | ✓ elfproef |
cz sk | CZ_SK_BIRTH_NUMBER | 出生番号 | ✓ mod-11 |
se | SE_PERSONNUMMER | 個人番号 | ✓ Luhn |
fi | FI_HETU | 個人識別コード | ✓ mod-31 |
uk | UK_NHS | NHS 番号 | ✓ mod-11 |
uk | UK_NINO | 国民保険番号 |
パターンではなく LLM が検出
| タグ | 検出 | 必要なもの |
|---|---|---|
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' — 短すぎる、または判定不能の場合 |
raw | franc の ISO 639-3 コード(例:'pol')、または null |
confidence | franc のスコア(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]に変わることはありません)。これにより、LLM の推論における意味の一貫性が保たれます。 - モデルのトレーニングは行いません。 ローカルの Ollama モデルはオフラインで動作します。このツールによって、データがモデルのトレーニングに使われることはありません。
- デフォルトでは厳密な検証を行います。 無効な SSN(地域コードが 000/666/900 以上)、Luhn 検査に失敗したクレジットカード番号、チェックサムが無効な PESEL はマスクされません。これにより、OCR エラーや無作為な数字列による誤検出を防ぎます。
以下については保証されません:
- 入力内のすべての PII が検出されること。
- トークン化されたテキストから実在の人物を特定できないこと。文脈から再識別できる可能性があります。
- クラウドプロバイダーが、構造、タイミング、内容から機密情報を知り得ないこと。
- 特定の規制への準拠。これはツール単体ではなく、システム全体に関わるものです。
制限事項
pseudonym-mcp は技術的なプライバシー制御であり、法令への準拠を保証するものではありません。
- 検出はベストエフォートです。 偽陰性と偽陽性のどちらも発生する可能性があります(例:「経理の背の高い人」、「大家」、「橋の近くの場所」 のような間接的な表現は検出されません)。あだ名、イニシャル、名前の一部は通常、検出されません。
- 構造は引き続き送信されます。 金額、トークン間の関係、物語の内容、および検出されなかった PII は、すべてクラウド LLM に送信されます。日付は、生年月日として解釈される場合、または
--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 は必要ありません。
認識器の追加
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',
}
src/patterns/index.tsのallPatterns配列に登録します。配線が必要なのはここだけです。ルールセットはロケールごとにレジストリーから導出されるため、ほかにルールの存在を知らせる必要はありません。- 新しい言語を追加する場合は、
src/patterns/types.tsのSupportedLocaleとSUPPORTED_LOCALESの両方にロケールを追加します。デフォルトの選択ではこのリストが読み込まれるため、リストに含まれていないパックは実行されません。また、src/language/language-map.tsに ISO 639-3 から短縮コードへのマッピングを追加します。tests/default-coverage.test.tsは両者に不整合があると失敗し、各パックに標本が 1 つあることを求めます。
スコアの選び方:まずは低めに設定し、判定は証拠に委ねます。このエンティティにしか現れない形式(ABC123456、codice fiscale など)なら、0.5 付近から始められます。何にでもなり得る数字の並びなら、0.15〜0.25 から始め、validate または context で基準を満たすようにします。
checksumMode の選び方:チェックに失敗した場合、そのエンティティではあり得ないものとして扱う場合(カードの Luhn)は filter、チェック失敗がタイプミスを意味し、見逃すとデータが漏えいする場合(PESEL、IBAN)は boost、チェックでは不可能な値を除外できるだけで何も確認できない場合(米国の SSN の範囲)は gate を選びます。
3 つすべての例については、src/patterns/locale/pl/ をご覧ください。
コントリビューション
コントリビューションを歓迎します。コミットメッセージには Conventional Commits に従ってください。
リリースは changesets で実施します。変更がユーザーに見える場合は、プルリクエストに変更セットを追加してください。
npm run changeset # pick patch / minor / major, describe the change
master へのマージ後、「version packages」プルリクエストが作成され、バージョン、server.json、src/version.ts、変更履歴が更新されます。そのプルリクエストをマージすると、npm への公開(プロベナンス付きの Trusted Publishing)、リリースのタグ付け、MCP レジストリーエントリーの更新が行われます。保留中の変更セットがない状態でマージしても、何も公開されません。
言語パックのコントリビューションを特に歓迎します。ドイツ語(Personalausweis、Steuer-ID)、フランス語(NIR、SIRET)、スペイン語(DNI/NIE)などが加われば、このツールの有用性が大きく広がります。
ライセンス
MIT — Adrian Wolczuk
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。