mcpField
P
phi-guard-mcp

phi-guard-mcp

ローカル
github.comセキュリティ06 週間前に更新

phi-guard-mcp について

phi-guard-mcpは、コードの公開前にLLMのプロンプト、ログ、分析呼び出しへのPHI流出を検出するローカルMCPサーバーです。テキストのマスキング提案と同一行を対象にしたコードスキャンを行い、一致値は既定で隠します。

主な機能

  1. 01テキスト内のPHI検出とマスキング
  2. 02機密識別子と危険な呼び出しのコードスキャン
  3. 03結果での一致値の既定非表示
  4. 04TypeScript、JavaScript、Python、Goのスキャン

活用シーン

  1. 01プロンプトやログ断片のPHI確認
  2. 02公開前のコードに潜む漏えいのスキャン
  3. 03一致値を露出させずに検出結果を確認

MCP 対応

ローカルのstdio MCPサーバーとして動作し、redact_suggestとscan_codeのツールをクライアントに提供します。tools機能のみを宣言し、リソースとプロンプトは提供しません。

設定

ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。

mcp.json · 共通設定
{
"mcpServers": {
"abidit-phi-guard": {
"command": "npx",
"args": [
"-y",
"phi-guard-mcp"
]
}
}
}
起動コマンドnpx -y phi-guard-mcp

ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。

パッケージ
npmphi-guard-mcp0.2.0

ツール

2

掲載時のツール一覧 · 2 週間前に更新

パラメーター型必須説明
textstringはいPHI を含む可能性がある生のテキスト
includeMatchedValuesbooleanいいえ一致した生の PHI 値と元のテキストを結果に含めます。デフォルトではオフです。結果は呼び出し元のモデルのコンテキストに渡されます。

詳細

phi-guard-mcp

npm version npm downloads License: MIT

ソースコード内で、PHI(保護対象医療情報)がLLMのプロンプト、ログ出力、分析用の呼び出しに流れ込み、リリースされる前に検出する、ローカルファーストのMCPサーバーです。

サーバー自体はネットワーク通信を行いません。ローカルのstdioプロセスとして実行され、コードをアップロードすることはありません。ただし、検出結果がどう扱われるかは別の問題です。検出結果は、サーバーを起動したMCPクライアントに返されるため、そのクライアントがホスト型アシスタントの場合、検出結果はそのモデルのコンテキストに入ります。このため、検出されたPHIの値はデフォルトで結果からマスキングされます。詳しくはセキュリティ境界をご覧ください。

概要

医療関連のコードベースでリスクが高いのは、データベースではないことがほとんどです。患者の記録がプロンプト、console.log、分析イベントに埋め込まれる箇所です。こうした行はレビューでは問題がないように見え、インフラストラクチャのスキャンにも検出されません。設定ミスがあるわけではなく、コードが記述どおりに動いているだけだからです。

デモ

患者名と診断情報が渡された openai.responses.create 呼び出しを scan_code が検出し、その後 redact_suggest がマスキングされた結果を返す様子

ウォークスルーの11秒間では、scan_code が15行目にある openai.responses.create 呼び出しに埋め込まれた患者名と診断情報を検出し、redact_suggest が未加工のプロンプトから同じ値をマスキングします。表示される値はすべて合成データです。

ある種のミスを検出するリンターです。HIPAA認証でも、コンプライアンスの証明でも、データフローアナライザーでもありません。詳しくは これは何ではないかをご覧ください。

インストール

Node.js 22以降が必要です。エントリーポイントではJSONのインポート属性(with { type: "json" })を使用するため、古いランタイムでは起動しません。Node 22.18.0、24.2.0、26.8.2で動作確認済みです。Node 20以前はサポート対象外で、テストも行っていません。

npmから(推奨)

クローンもビルドも不要です。MCPクライアントが必要に応じて実行します。

npx -y phi-guard-mcp --version
ソースから
git clone https://github.com/Abidit/phi-guard-mcp.git
cd phi-guard-mcp
npm ci

npm ci は prepare スクリプトを実行して dist/ をビルドします。別途ビルドする手順を忘れる心配はありません。npm install も使えますが、package-lock.json で固定された内容を正確にインストールするため、再現性を確保するには npm ci を使用します。

MCPの設定

以下のいずれかをコピーして貼り付けてください。npm形式はパスが不要で、ほかの人に案内する場合にも適しています。

Claude Code

プロジェクトのスコープで、コマンドを1つ実行します。

claude mcp add phi-guard -- npx -y phi-guard-mcp

または、プロジェクトのルートに .mcp.json をコミットします。

{
  "mcpServers": {
    "phi-guard": {
      "command": "npx",
      "args": ["-y", "phi-guard-mcp"]
    }
  }
}
Claude Desktop

macOSでは ~/Library/Application Support/Claude/claude_desktop_config.json、Windowsでは %APPDATA%\Claude\claude_desktop_config.json を使用します。

{
  "mcpServers": {
    "phi-guard": {
      "command": "npx",
      "args": ["-y", "phi-guard-mcp"]
    }
  }
}
Cursor

プロジェクト内の .cursor/mcp.json、または全体設定の ~/.cursor/mcp.json を使用します。

{
  "mcpServers": {
    "phi-guard": {
      "command": "npx",
      "args": ["-y", "phi-guard-mcp"]
    }
  }
}
npmリリースではなくローカルのクローンを実行する場合

クライアントからビルド出力を指定します。クライアントがプロジェクトルートを作業ディレクトリとしてサーバーを起動すると確信できる場合を除き、絶対パスを使用してください。

{
  "mcpServers": {
    "phi-guard": {
      "command": "node",
      "args": ["/absolute/path/to/phi-guard-mcp/dist/index.js"]
    }
  }
}

このリポジトリにコミットされている .mcp.json では相対パス(dist/index.js)を使用しているため、npm ci の後にリポジトリ自身のサーバーをdogfoodできます。

いずれの方法でも、クライアントを再起動するか、Claude Codeで /mcp を実行して phi-guard に再接続してください。ビルドし直すだけでは、すでに実行中のstdioプロセスには反映されません。

ツール

redact_suggest

生のテキスト断片(ログ行、プロンプト、エラーメッセージなど)を受け取り、 PHIらしい値を検出し、検出内容とともにマスキングしたテキストを返します。

入力

{ "text": "Patient John Doe (MRN-12345), DOB: 01/01/1980" }

出力

{
  "redacted": "Patient [NAME] ([MRN]), [DOB]",
  "detected": [
    { "type": "mrn",  "confidence": 0.9,  "start": 18, "end": 27 },
    { "type": "dob",  "confidence": 0.85, "start": 30, "end": 45 },
    { "type": "name", "confidence": 0.8,  "start": 8,  "end": 16 }
  ]
}

一致した値は、デフォルトでは返されず、マスキング前のoriginalも返されません。ツールの結果は、それを呼び出したモデルのコンテキストにそのまま渡されるため、生のPHIをそこに繰り返すと、ツールの目的が損なわれます。start/endは元のテキスト内のオフセットなので、一致した値を再掲しなくても位置を特定できます。

detectedは位置順ではなく、パターン順に並びます。

生の値が本当に必要な場合(ローカルCLIやテストハーネスなど)は、includeMatchedValues: trueを渡すと、detected[].valueとoriginalが返されます。

{ "text": "Patient John Doe (MRN-12345)", "includeMatchedValues": true }

パターンと信頼度スコア:

TypeConfidenceMatches
ssn0.95123-45-6789
mrn0.90MRN-12345, MRN: 12345
dob0.85DOB: 01/01/1980, born 3/14/75
name0.80Patient John Doe(John Doeを取得)
phone0.75555-867-5309, (555) 867 5309
email0.70[email protected]

この表がすべてのパターンです。パターンは意図的に狭く設定されています。ツールを無視するようになる誤検出は、検出漏れよりも深刻です。

scan_code

ディレクトリを走査し、機微な識別子らしきものが、リスクのある出力先と同じ行に現れる行にフラグを付けます。

機微な識別子 — すべての識別子:

patient, diagnosis, dob, ssn, mrn, birthdate, medicalrecord

大文字と小文字を区別せず、英字以外で区切られている場合に一致するため、patient_nameは一致しますが、outpatientとinpatientは一致しません。

出力先のカテゴリ — すべてのカテゴリ:

CategoryMatches
LLM プロバイダーopenai, anthropic, bedrock
コンソールconsole.log, console.error, console.warn
ロガーlogger., winston, pino
分析.track(
エラー報告capture(, captureException(, captureMessage(

走査対象の言語 — すべての言語:

ExtensionLanguage
.ts, .tsxTypeScript
.js, .jsxJavaScript
.pyPython
.goGo

検出は純粋に字句ベースです。そのため、言語への対応とは「これらの拡張子のファイルを読み取る」という意味です。いずれの言語についても、パーサーや型情報は使用しません。

node_modules、dist、build、coverage、out、.next、.turbo、およびすべてのドットファイルとドットディレクトリをスキップします。行全体が//または#で始まるコメントはスキップされるため、PHIの取り扱いについて説明するファイルの文章が、それ自体のドキュメントによってスキャナーに検出されることはありません。

test/fixtures/leaky-example.tsの実際に処理対象となる行を例にします。

const prompt = await openai.responses.create({ input: `Patient: ${patient.name}, diagnosis: ${patient.diagnosis}` });
console.log("Sending patient prompt to LLM:", prompt);

入力

{ "path": "/abs/path/to/repo/test/fixtures" }

出力 — 抜粋。このディレクトリからは合計9件の検出結果が返されます。このファイルから2件、評価で説明する陽性フィクスチャから7件です。

[
  {
    "file": "/abs/path/to/repo/test/fixtures/leaky-example.ts",
    "line": 7,
    "severity": "high",
    "issue": "Sensitive-looking identifier passed to a risky sink (LLM call, logger, or analytics)",
    "snippet": "const prompt = await openai.responses.create({ input: `Patient: ${patient.name}, diagnosis: ${patient.diagnosis}` });"
  },
  {
    "file": "/abs/path/to/repo/test/fixtures/leaky-example.ts",
    "line": 8,
    "severity": "high",
    "issue": "Sensitive-looking identifier passed to a risky sink (LLM call, logger, or analytics)",
    "snippet": "console.log(\"Sending patient prompt to LLM:\", prompt);"
  }
]

fileはpathとエントリー名を結合して作成されるため、渡した形式のまま返されます。絶対パスを渡せば、絶対パスが返されます。severityは常に"high"です。ルールは1つなので、重要度も1種類です。

snippetは問題のある行を示し、リテラルのPHIがあればマスキングします。これは、redact_suggestが一致した値を返さないのと同じ理由です。検出結果はモデルのコンテキストに入るためです。patient.diagnosisのような識別子名はリテラル値ではなく、どのPHIパターンにも一致しないため、そのまま表示されます。これらは対処に必要な情報です。

空の配列は、pathの下で見つかった対象ソースファイルがすべて正常に読み取られ、両方の条件に一致する行がなかったことを意味します。「対象」と「見つかった」は重要です。サポート対象外の拡張子を持つファイルや、スキップ対象またはドットで始まるディレクトリ内のファイルは、開かれることがありません。

ディレクトリまたはファイルを読み取れないスキャンは、結果が一部だけだと問題のない結果に見えてしまうため、短いリストを返すのではなく、名前付きエラーで失敗します。

No such path: "/nope". Pass an absolute path to a directory that exists on the
machine running this server. (ENOENT: no such file or directory, stat '/nope')
同一行ルール

両方の条件が同じ物理行上で成立する必要があります。これは、スキャナーを理解するうえで、どちらの方向から見ても最も重要な点です。

このルールのおかげで誤検知を抑えられます。このリポジトリ自身の src/ は、パターン定義内に patient、diagnosis、mrn、ssn という単語が多く含まれていますが、検出結果はゼロです。

一方、見逃しが発生する主な理由でもあります。次の情報漏えいは検出されません。

const value = patient.diagnosis;   // sensitive identifier, no sink
console.log("audit", value);       // sink, no sensitive identifier

データフロー解析も、変数追跡も、行をまたいだ相関分析もありません。動作例は test/fixtures/known-limitations/split-across-lines.ts にあり、テストスイートは実行のたびにこれをスキャンするため、この制限が忘れられず、明示されたままになります。

評価

npm run verify

コマンドは1つです。型チェック(src/ と test/ を厳格モードで実行)、ビルド、続いて stdio 経由で実サーバーに対してフィクスチャスイートを実行します。

現在の結果は次のとおりです。

代表的な情報漏えいフィクスチャを7件すべて検出し、クリーンなフィクスチャ5件はどれも誤検出しませんでした。

これらのフィクスチャはすべて test/fixtures/ にあるため、鵜呑みにせず自分で確認できます。

7件の情報漏えいフィクスチャは、5つのシンクカテゴリ(OpenAI、Anthropic、Sentry、Winston、分析)と2つの言語(TypeScript、Python)を対象としています。単純な単語境界の正規表現では見逃される snake_case 識別子(patient_name、patient_diagnosis)も含まれています。これらは Python と Go で一般的な命名規則です。また、ハードコードされたリテラルを含むフィクスチャでは、scan_code が返す snippet からリテラルの PHI がマスクされることを確認します。

5件のクリーンなフィクスチャには、PHI を漏えいさせずにコメントや文章で PHI ポリシーについて説明するコードと、患者の記録を正当に扱いながら、リスクのある送信先には送らないコードが含まれています。

テストスイートでは、次の点も検証します。

  • README の動作例で、7行目と8行目に正確に2件の検出結果が引き続き出ること
  • scan_code の結果にリテラルの PHI が一切含まれないこと
  • redact_suggest がデフォルトで一致した値と元の値をすべて省略すること
  • includeMatchedValues: true を指定すると、実際にそれらの値が返されること
  • パスが存在しない場合と、ディレクトリの代わりにファイルを指定した場合に、それぞれ名前付きエラーが返されること

この数値が示していないこと。 このプロジェクトが独自のルールをテストするために作成した、手書きのファイル12件からなるフィクスチャスイートの結果です。検出率でも、ベンチマークでも、誤検知率でも、外部検証でもありません。実際の医療関連コードベースでスキャナーがどの程度機能するかについては何も示していません。偽陰性率は不明であり、上記の同一行ルールを考慮すれば、確実にゼロではありません。それを測定するには、このプロジェクトが持っていないラベル付きコーパスが必要です。

その他のチェック:

npm test          # fixture suite only
npm run typecheck # src/ and test/ under strict mode
npm run test:smoke  # minimal stdio round-trip

または、ブラウザーを使わずに公式 Inspector から実行します。

npx @modelcontextprotocol/inspector --cli node dist/index.js --method tools/list
npx @modelcontextprotocol/inspector --cli node dist/index.js \
  --method tools/call --tool-name redact_suggest \
  --tool-arg text="Patient John Doe (MRN-12345)"

サーバーが宣言するのは tools 機能のみであるため、プロトコルレベルでは resources/list と prompts/list は -32601 Method not found を返します。Inspector CLI はこれらを {"resources": []} と {"prompts": []} に正規化するため、Inspector UI では赤く表示される場合があります。どちらも想定どおりの動作であり、不具合ではありません。

トラブルシューティング

実行するとサーバーがハングしたように見えます。 これは正常な動作です。stdio サーバーのため、stdin で JSON-RPC を待ち受け、自身では何も出力しません。インストールを確認するだけであれば、npx -y phi-guard-mcp --help または node dist/index.js --version を実行してください。

クライアントに phi-guard が失敗または切断と表示されます。 設定に記載したコマンドを手動で実行し、stderr を確認してください。npx -y phi-guard-mcp --version、または node /absolute/path/to/dist/index.js --version を実行します。バージョンが表示される場合、問題はサーバーではなく設定のパスにあります。

Cannot find module '.../dist/index.js'。 クローンから実行していて、dist/ がまだビルドされていません。dist/ は意図的に gitignore されています。npm ci を実行してください。

起動時に SyntaxError: Unexpected identifier 'assert' またはインポート属性のエラーが発生します。 Node のバージョンが 22 より古いです。node --version で確認してください。MCP クライアントがシェルとは別の Node を起動する場合があることに注意してください。

コードを変更しても反映されません。 すでに実行中の stdio プロセスは古いビルドを使い続けます。再ビルドしてから、クライアントを再起動するか、サーバーに再接続してください(Claude Code では /mcp)。

漏えいがあると分かっているリポジトリで scan_code が [] を返します。 考えられる原因は、可能性の高い順に 3 つあります。識別子とシンクが別の行にある(同一行ルールを参照)、ファイル拡張子がサポート対象に含まれていない、またはディレクトリがスキップされている(dist、build、ドットで始まるもの)。このリポジトリの test/fixtures ディレクトリを指定してスキャナーが動作していることを確認してください。9 件の検出結果が返される必要があります。

scan_code が No such path でエラーになります。 パスはサーバーを実行しているマシン上で解決されます。また、相対パスは、MCP クライアントがプロセスに指定した作業ディレクトリを基準に解決されます。絶対パスを指定してください。

これは何ではないか

  • ホステッドサービスではありません。 ローカルの stdio プロセスです。バックエンドもアカウントもテレメトリーもなく、サーバー自身がネットワーク呼び出しを行うこともありません。ただし、これは「マシンから何も外部に送信されない」という意味ではありません。検出結果は MCP クライアントに返され、そのクライアントがホステッドアシスタントである場合もあります。セキュリティ境界を参照してください。
  • HIPAA 認証、監査、コンプライアンス証明ではありません。 scan_code を実行しても、規制当局に示せる証明にはなりません。特定の種類のミスを検出するリンターであり、コンプライアンスの証拠ではありません。クリーンな結果は「この特定のパターンは検出されなかった」と捉え、「このコードベースは HIPAA に準拠している」と決して捉えないでください。
  • 作成者以外による検証はありません。 フィクスチャは、このプロジェクトがこのプロジェクトのテスト用に作成したものです。外部レビューも、第三者監査も、実際の医療関連コードベースを用いた評価も行われていません。
  • Prowler、AWS Config、クラウド構成管理ツールの競合製品ではありません。 これらはインフラストラクチャと設定をスキャンします。このツールはソースコードを読み取り、異なる種類の問題を検出します。これらは相互に補完するものであり、このツールが置き換えるものではありません。
  • 網羅的ではありません。 正規表現ベースの検出には、実際の誤検出見逃し率がありますが、その率は測定されていません。名前を照合できない変数内の PHI や、外部呼び出しから渡される値は検出できません。
  • 行をまたいで値を追跡することはできません。 同一行ルールを参照してください。実際のデータフロー解析は対象外であり、これは意図的な制約です。
  • コメントを完全には考慮しません。 行全体が // または # で始まるコメントのみスキップされます。ブロックコメント(/* ... */)と行末のコメントはスキャンされるため、その中にシンクのキーワードがあると、何も実行されない場合でも検出されることがあります。
  • シークレットスキャナーでも、コードレビューの代替でもありません。 あるパターン、つまり機密情報らしい名前とリスクのある呼び出しが近接している箇所を探します。
セキュリティ境界

サーバーは、実行されているマシン上で、渡された任意のディレクトリを、起動したユーザーの権限で読み取ります。サンドボックスも許可リストもありません。読み取り権限のあるコードを指定してください。

サーバーはソケットを開かず、外部へのリクエストも行いません。しかし、だからといってデータがローカルにとどまるとは限りません。ツールの結果はサーバーを起動した MCP クライアントに返されます。そのクライアントがホスト型アシスタントの場合、結果はこのプロジェクトの利用規約ではなく、そのプロバイダーの規約に基づいて送信され、処理されます。すべての scan_code と redact_suggest の結果は、モデルプロバイダーに送信するコンテンツとして扱ってください。

snippet と redact_suggest の結果は、PHI の値ではなく識別子名と位置が送信されるように、デフォルトでマスキングされています。マスキングには前述と同じ正規表現セットを使用しているため、誤検出漏れ率も同じです。パターンで認識されない値は、マスキングされずにそのまま渡されます。「マスキングされた」ことを保証とみなさないでください。また、そのクライアントのデータ取り扱いについて十分に確認する前に、ホスト型クライアント経由で本番環境の PHI を対象に実行しないでください。

貢献

npm run verify が成功する必要があります。CI では Node 22 と 24 で実行されます。

ライセンス

MIT — LICENSE を参照してください。

MCP サーバー承認済み

mcpservers.org に掲載

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。