Skip to main content
ClaudeWave
Abidit avatar
Abidit

phi-guard-mcp

Ver en GitHub

Local-first MCP server that detects potential PHI flows into LLM, logging, and analytics calls in source code.

MCP ServersRegistry oficial0 estrellas0 forksTypeScriptMITActualizado today
ClaudeWave Trust Score
95/100
Verified
Passed
  • Open-source license (MIT)
  • Actively maintained (<30d)
  • Clear description
  • Topics declared
  • Documented (README)
Last scanned: 9/18/2026
Install in Claude Code / Claude Desktop
Method: NPX · phi-guard-mcp
Claude Code CLI
claude mcp add phi-guard-mcp -- npx -y phi-guard-mcp
claude_desktop_config.json (Claude Desktop)
{
  "mcpServers": {
    "phi-guard-mcp": {
      "command": "npx",
      "args": ["-y", "phi-guard-mcp"]
    }
  }
}
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
Casos de uso

Resumen de MCP Servers

# phi-guard-mcp

[![npm version](https://img.shields.io/npm/v/phi-guard-mcp.svg)](https://www.npmjs.com/package/phi-guard-mcp)
[![npm downloads](https://img.shields.io/npm/dt/phi-guard-mcp.svg)](https://www.npmjs.com/package/phi-guard-mcp)
[![License: MIT](https://img.shields.io/npm/l/phi-guard-mcp.svg)](./LICENSE)

A local-first [MCP](https://modelcontextprotocol.io) server that catches PHI
(protected health information) flowing into LLM prompts, log statements, and
analytics calls — in your source code, before it ships.

The server itself makes no network calls: it runs as a local stdio process and
never uploads your code. What it returns is a different matter. Findings go
back to whatever MCP client launched it, so if that client is a hosted
assistant, the findings enter that model's context. Matched PHI values are
masked out of results by default for exactly this reason — see
[Security boundary](#security-boundary).

## Why

The risky moment in a healthcare codebase is rarely the database. It's the line
where a patient record gets interpolated into a prompt, a `console.log`, or an
analytics event. Those lines look harmless in review and never show up in
infrastructure scanning, because nothing is misconfigured — the code is just
doing what it says.

## Demo

![scan_code flagging a patient name and diagnosis passed into an openai.responses.create call, then redact_suggest returning a masked result](docs/assets/phi-guard-demo-preview.gif)

Eleven seconds of the walkthrough: `scan_code` flags line 15 — a patient name
and diagnosis interpolated into an `openai.responses.create` call — and
`redact_suggest` masks the same values out of a raw prompt. Every value shown is
synthetic.

> A linter for one class of mistake. Not a HIPAA certification, not a compliance
> attestation, and not a dataflow analyzer — see
> [What this is NOT](#what-this-is-not).

## Install

Requires **Node.js 22 or newer**. The entrypoint uses JSON import attributes
(`with { type: "json" }`), so older runtimes will not start it. Verified on
Node 22.18.0, 24.2.0, and 26.8.2; Node 20 and below are unsupported and
untested.

### From npm (recommended)

Nothing to clone or build. Your MCP client runs it on demand:

```bash
npx -y phi-guard-mcp --version
```

### From source

```bash
git clone https://github.com/Abidit/phi-guard-mcp.git
cd phi-guard-mcp
npm ci
```

`npm ci` runs the `prepare` script, which builds `dist/`. There is no separate
build step to forget. `npm install` works too; `npm ci` is the reproducible one
because it installs exactly what `package-lock.json` pins.

## MCP configuration

Copy-paste one of the following. The npm form needs no paths and is the one to
hand to someone else.

### Claude Code

One command, project scope:

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

Or commit a `.mcp.json` at your project root:

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

### Claude Desktop

`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS,
`%APPDATA%\Claude\claude_desktop_config.json` on Windows:

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

### Cursor

`.cursor/mcp.json` in the project, or `~/.cursor/mcp.json` globally:

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

### Running a local clone instead of the npm release

Point the client at the build output. Use an **absolute path** unless you are
certain your client launches the server with the project root as its working
directory:

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

The `.mcp.json` committed in this repo uses the relative form (`dist/index.js`)
so the repo can dogfood its own server after `npm ci`.

Whichever form you use: restart the client, or run `/mcp` in Claude Code and
reconnect `phi-guard`. A rebuild alone will not reach an already-running stdio
process.

## Tools

### `redact_suggest`

Takes a raw text snippet — a log line, a prompt, an error message — detects
PHI-shaped values, and returns a redacted version alongside what it found.

**Input**

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

**Output**

```json
{
  "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 }
  ]
}
```

The matched values are **not** echoed back by default, and neither is the
unredacted `original`. A tool result flows straight into the context of
whatever model called it, so repeating the raw PHI there would undo the point
of the tool. `start`/`end` are offsets into the original text, which is enough
to locate a match without restating it.

`detected` is ordered by pattern, not by position.

Pass `includeMatchedValues: true` when you genuinely need the raw values (a
local CLI, a test harness) and `detected[].value` plus `original` come back:

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

Patterns and their confidence scores:

| Type    | Confidence | Matches |
| ------- | ---------- | ------- |
| `ssn`   | 0.95 | `123-45-6789` |
| `mrn`   | 0.90 | `MRN-12345`, `MRN: 12345` |
| `dob`   | 0.85 | `DOB: 01/01/1980`, `born 3/14/75` |
| `name`  | 0.80 | `Patient John Doe` (captures `John Doe`) |
| `phone` | 0.75 | `555-867-5309`, `(555) 867 5309` |
| `email` | 0.70 | `jane.roe@example.com` |

That table is the complete list. The patterns start deliberately narrow — a
false positive that trains someone to ignore the tool is worse than a missed
match.

### `scan_code`

Walks a directory and flags lines where a sensitive-looking identifier appears
on the same line as a risky sink.

**Sensitive identifiers** — the complete list:

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

Matching is case-insensitive and bounded by non-letters, so `patient_name`
matches while `outpatient` and `inpatient` do not.

**Sink categories** — the complete list:

| Category | Matches |
| -------- | ------- |
| LLM providers | `openai`, `anthropic`, `bedrock` |
| Console | `console.log`, `console.error`, `console.warn` |
| Loggers | `logger.`, `winston`, `pino` |
| Analytics | `.track(` |
| Error reporting | `capture(`, `captureException(`, `captureMessage(` |

**Languages scanned** — the complete list:

| Extension | Language |
| --------- | -------- |
| `.ts`, `.tsx` | TypeScript |
| `.js`, `.jsx` | JavaScript |
| `.py` | Python |
| `.go` | Go |

Detection is purely lexical, so language support means "these file extensions
are read". There is no parser and no type information for any of them.

Skips `node_modules`, `dist`, `build`, `coverage`, `out`, `.next`, `.turbo`,
and any dotfile or dot-directory. Whole-line `//` and `#` comments are skipped,
so a file that discusses PHI handling in prose doesn't trip the scanner on its
own documentation.

Given the operative lines of
[`test/fixtures/leaky-example.ts`](test/fixtures/leaky-example.ts):

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

**Input**

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

**Output** — excerpt. That directory returns **9** findings in total: 2 from
this file, and 7 from the positive fixtures described under
[Evaluation](#evaluation).

```json
[
  {
    "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` is built by joining `path` with the entry name, so it comes back in
whatever form you passed in: absolute in, absolute out. `severity` is always
`"high"` — there is one rule, so there is one severity.

`snippet` is the offending line with any literal PHI masked, for the same
reason `redact_suggest` withholds matched values: the finding is going into a
model's context. Identifier names like `patient.diagnosis` are not literal
values, match no PHI pattern, and stay visible — they are the actionable part.

An empty array means every eligible source file discovered under `path` was
read successfully and no line matched both conditions. "Eligible" and
"discovered" are load-bearing: files with an unsupported extension, and
anything under a skipped or dot-prefixed directory, are never opened.

A scan that cannot read a directory or a file **fails** with a named error
rather than returning a shorter list, because a partial result reads as a
clean result:

```
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')
```

### The same-line rule

Both conditions must hold **on the same physical line**. This is the single
most important thing to understand about the scanner, in both directions.

It is what keeps it quiet. On this repo's own `src/` — which is dense with the
words `patient`, `diagnosis`, `mrn`, and `ssn` inside its pattern definitions —
it reports zero findings.

It is also the main reason it misses things. This leaks and is **not** flagged:
compliancehealthcarehipaallm-securitymcpmcp-serverphisecuritysource-code-analysistypescript

Lo que la gente pregunta sobre phi-guard-mcp

¿Qué es Abidit/phi-guard-mcp?

+

Abidit/phi-guard-mcp es mcp servers para el ecosistema de Claude AI. Local-first MCP server that detects potential PHI flows into LLM, logging, and analytics calls in source code. Tiene 0 estrellas en GitHub y su última actualización registrada es del 2026-09-18.

¿Cómo se instala phi-guard-mcp?

+

Puedes instalar phi-guard-mcp clonando el repositorio (https://github.com/Abidit/phi-guard-mcp) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.

¿Es seguro usar Abidit/phi-guard-mcp?

+

Nuestro agente de seguridad ha analizado Abidit/phi-guard-mcp y le ha asignado un Trust Score de 95/100 (tier: Verified). Revisa el desglose completo de comprobaciones superadas y flags en esta página.

¿Quién mantiene Abidit/phi-guard-mcp?

+

Abidit/phi-guard-mcp es mantenido por Abidit. La última actividad registrada en GitHub es del 2026-09-18, con 0 issues abiertos.

¿Hay alternativas a phi-guard-mcp?

+

Sí. En ClaudeWave puedes explorar mcp servers similares en /categories/mcp, ordenados por popularidad o actividad reciente.

Despliega phi-guard-mcp en tu cloud

Lleva este repo a producción en minutos. Cada plataforma genera su propio entorno con variables de entorno editables.

¿Mantienes este repo? Añade un badge a tu README

Pega el badge en tu README de GitHub para mostrar que está auditado por ClaudeWave. Cada badge enlaza de vuelta a esta página y muestra el Trust Score actual.

Featured on ClaudeWave: Abidit/phi-guard-mcp
[![Featured on ClaudeWave](https://claudewave.com/api/badge/abidit-phi-guard-mcp)](https://claudewave.com/repo/abidit-phi-guard-mcp)
<a href="https://claudewave.com/repo/abidit-phi-guard-mcp"><img src="https://claudewave.com/api/badge/abidit-phi-guard-mcp" alt="Featured on ClaudeWave: Abidit/phi-guard-mcp" width="320" height="64" /></a>

Más MCP Servers

Alternativas a phi-guard-mcp