phi-redact-mcp
umbryn-mcp
一个 MCP 服务器,在文本到达 LLM 之前对 PII/PHI 进行脱敏——自托管、故障关闭、且符合 HIPAA 要求。
在受监管领域构建 LLM 和 Agent 管道的团队,在数据进入模型提供商基础设施之前,没有一种干净、即插即用的方式来剥离 PHI/PII。umbryn-mcp 就是那道边界:三个 MCP 工具——redact、restore、detect——将敏感值擦除为可逆的占位符,完全在你控制的基础设施内运行,并且在检测不确定时阻止请求,而不是泄露数据。
redact("Patient MRN: 1234567, provider NPI 1234567893, ssn 078-05-1120, john.doe@example.com")
redacted_text (safe to send to the model):
"Patient MRN: [MEDICAL_RECORD_NUMBER_1], provider NPI [NPI_1], ssn [US_SSN_1], [EMAIL_ADDRESS_1]"
token_map (kept local, never sent to the model):
[MEDICAL_RECORD_NUMBER_1] → 1234567
[NPI_1] → 1234567893
[US_SSN_1] → 078-05-1120
[EMAIL_ADDRESS_1] → john.doe@example.com将脱敏后的文本发送给模型;将 token_map 保存在本地;之后调用 restore 来恢复结果。往返是逐字节精确的,并通过基于属性的测试得到验证。
为什么存在
PHI/PII 脱敏的 MCP 细分领域是真实存在但服务不足的——现有的选项是薄薄的 Presidio 包装器,没有针对 HIPAA 的检测,而且关键是,无法保证检测失败会阻止请求,而不是静默地传递原始数据。因此,团队要么自己构建边界,要么将敏感数据发送给提供商并依赖 BAA 来覆盖——这是导致实际合规事件的設計错误。
简单的 Presidio 包装器 | 应用内正则 | Cloud DLP API | umbryn-mCP | |
即插即用的 MCP 工具 | 有时 | ❌ | ❌ | ✅ |
在检测不确定时故障关闭 | ❌ | ❌ | ❌ | ✅ |
HIPAA 标识符(NPI、DEA、MBI、MRN、CLIA) | ❌ | 部分 | 部分 | ✅ |
可逆(恢复原始内容) | 很少 | 自行实现 | 部分 | ✅ |
自托管,零出站流量 | ✅ | ✅ | ❌(发送数据出去) | ✅ |
零重量级依赖即可运行 | ❌(需要 spaCy) | ✅ | 不适用 | ✅(正则引擎) |
可选的 ML NER(姓名、地址) | ✅ | ❌ | ✅ | ✅( |
为什么构建它: MCP 迅速成为主流——它现在是 Claude、Cursor 和 ChatGPT 中的一等公民,遍布数千台服务器——但 PHI/PII 脱敏这一角落却留给了少数无人维护的包装器。这个项目用一个诚实、可审计、故障关闭的边界填补了这一空白,并保持开源,让你所依赖的脱敏逻辑完全可检查,而不是一个黑盒。
Related MCP server: pii-anonymizer
功能特性
三个工具,一个边界——
redact(→ 擦除后的文本 + 可逆的 token 映射)、restore(→ 原始文本)、detect(→ 发现的实体,不修改文本)。构造上故障关闭——如果检测出错或任何检测结果低于置信度阈值,调用将返回类型化错误。不确定性会阻止;它永远不会“能脱敏多少就脱敏多少,然后放行其余部分”。
符合 HIPAA 的检测——校验和验证的 NPI 和 DEA、位置类型化的 Medicare MBI、上下文锚定的 MRN、CLIA 实验室 ID,以及标准的 PII(电子邮件、电话、SSN、信用卡、IBAN、IP、URL)。
零出站流量,自托管——默认引擎是纯正则 + 校验和,没有网络调用,也没有重量级依赖。它可以安装在任何运行 Python 的地方。
可选的 ML 升级——
pip install "umbryn-mcp[presidio]"可透明地添加 Microsoft Presidio + spaCy 以进行PERSON/LOCATIONNER。可逆且确定性——防碰撞的类型化占位符使
restore(redact(x)) == x对任意输入成立;相同的输入和配置总是产生相同的输出。
何时使用(以及何时不使用)
在以下情况下使用 umbryn-mcp:
你将医疗、临床、金融或用户生成的文本发送到第三方 LLM API,并且需要防止 PHI/PII 进入该提供商的基础设施和日志。
你在受监管领域构建 Agent 或 MCP 管道,并希望有一个即插即用的擦除边界,只需一次工具调用即可接入。
你需要可逆脱敏,以便下游步骤仍然有效:
redact→ 发送给模型 →restore。你想要一个可以逐行审计的自托管、无出站流量的检测器。
你需要特定于 HIPAA 的标识符(NPI、DEA、Medicare MBI、MRN、CLIA),而不仅仅是姓名和电子邮件。
在以下情况下请使用其他方案:
你需要不可逆的去标识化/匿名化(如令牌化、k-匿名)——这里的脱敏设计上是可逆的。
你需要脱敏非文本数据(图像、音频、PDF、数据库行)——范围仅限于文本。
你想要一个经过认证的合规产品——这只是一个技术控制措施,而不是合规计划(请参阅范围与诚实的局限性)。
你想要一个透明代理,自动擦除请求路径中的所有内容——v1 是显式工具调用;代理模式在路线图上。
你要求保证 100% 召回率——包括本工具在内的任何检测器都无法保证这一点。
快速开始(< 60 秒)
pip install umbryn-mcp # zero heavy deps; runs immediately然后将其注册到你的 MCP 客户端。
Claude Desktop / Claude Code(claude_desktop_config.json,或 claude mcp add umbryn-mcp -- umbryn-mcp):
{
"mcpServers": {
"umbryn-mcp": {
"command": "umbryn-mcp"
}
}
}Cursor(.cursor/mcp.json)和 VS Code 使用相同的结构——请参阅 examples/ 获取可直接粘贴的配置。
想要姓名/地址检测?
pip install "umbryn-mcp[presidio]"
python -m spacy download en_core_web_lg服务器会自动检测 Presidio 并升级——无需更改配置。(设置 UMBRYN_ENGINE=regex 以强制使用无依赖引擎,或设置 =presidio 以要求使用 ML 引擎。)
工作原理
工具调用通过 stdio 进入;Redactor 核心运行配置的检测引擎,确定性地解决重叠问题,应用故障关闭阈值检查,并将检测到的跨度替换为可逆的类型化占位符。只有擦除后的文本才应离开你运行的边界。
flowchart LR
A[MCP client<br/>Claude · Cursor · agent] -- redact / restore / detect --> B[umbryn-mcp<br/>stdio server]
B --> C[Redactor core<br/>fail-closed · reversible]
C --> D{Detection engine}
D -->|default, zero deps| E[Regex + checksums]
D -->|optional| F[Presidio + spaCy NER]
C -. scrubbed text .-> A
A -- scrubbed text only --> G[(LLM / downstream)]Redactor 核心仅依赖于一个小型 DetectionEngine 接口——从不直接依赖 Presidio 或 MCP。原始数据和检测引擎保留在你运行的边界内;只有擦除后的文本才会离开。请参阅 docs/ARCHITECTURE.md 和 docs/THREAT_MODEL.md。
工具
redact(text) → { redacted_text, token_map, entities }
将检测到的 PHI/PII 替换为类型化占位符,如 [NPI_1]。token_map 将每个占位符映射回其原始值——请将其保存在本地;切勿发送给模型。 entities 列出已脱敏的内容(类型/跨度/分数),用于审计。
restore(redacted_text, token_map) → { text }
反转脱敏操作,精确恢复原始文本。对仍包含占位符的模型输出调用是安全的。
detect(text) → { entities, count }
报告发现的实体——类型、跨度、置信度——不修改文本。与 redact 不同,它会显示低置信度的命中,而不是阻止,因此你可以在管道中信任该边界之前检查覆盖率。
如何使用(真实管道)
模式是 redact → model → restore,token 映射永远不会离开你这边:
在模型之前擦除。 调用
redact(user_text)。仅将redacted_text发送给 LLM。将token_map保存在你的进程中——像对待原始输入一样敏感地对待它,切勿将其传递给模型。让模型处理占位符。 它会看到
[NPI_1]、[US_SSN_1]等——这些语义中性的令牌,它可以推理并回显。之后重新水合。 调用
restore(model_output, token_map)将真实值交换回模型的响应中,然后再到达你的用户或数据库。处理阻止。 如果
redact返回[LOW_CONFIDENCE]或[DETECTION_ERROR]工具错误,则边界拒绝泄露——报告它,收紧输入,或降低风险,但不要将原始文本继续传递。
在管道中信任它之前,请对具有代表性的(合成)数据调用 detect(sample_text),以准确了解捕获了什么和未捕获什么,并根据你的风险承受能力调整阈值(如下)。
精确的故障关闭
两个阈值控制每次 redact 调用:
detection_floor(默认0.35)——灵敏度边界。低于它的信号被视为噪声。min_confidence(默认0.5)——信任阈值。
任何通过下限但得分低于 min_confidence 的候选者都会使调用进入故障关闭模式:它返回 [LOW_CONFIDENCE] 错误,而不是脱敏置信度高的跨度并放行不确定的跨度。引擎错误返回 [DETECTION_ERROR]。发生任何错误时,都不会返回脱敏文本。 两个阈值都可配置(见下文)。
配置
所有配置都是可选的;合理的默认值意味着它可以在零配置下运行。通过客户端的 env 块设置。
变量 | 默认值 | 含义 |
|
|
|
|
| 信任阈值;低于此值的检测将故障关闭 |
|
| 低于此值,信号被视为噪声 |
|
| 使用类型化错误拒绝更大的输入 |
|
| 用于 Presidio 引擎的 spaCy 模型 |
|
| 为每次 |
| (未设置) | JSON 配置文件的路径(见下文) |
配置文件
对于不适合扁平环境变量的设置,将 UMBRYN_CONFIG 指向一个 JSON 文件。对于上述标量值,环境变量仍然优先于文件,因此你可以提供一个文件并根据启动调整。格式错误的文件(错误的 JSON、未知阈值、无法编译的正则表达式)将在启动时关闭,而不是静默降级。
{
// Per-entity trust thresholds override min_confidence for that type.
"entity_thresholds": { "PHONE_NUMBER": 0.7, "IP_ADDRESS": 0.9 },
// Entity types to drop entirely — never detected, never redacted.
// (A privacy trade-off you're opting into: a disabled type can leak.)
"disabled_entities": ["URL"],
// Your own recognizers, no fork required. `validator` names a built-in
// check-digit function (luhn, npi, dea, iban, nhs) — config supplies data,
// never code.
"recognizers": [
{
"entity_type": "EMPLOYEE_ID",
"regex": "\\bEMP-\\d{6}\\b",
"base_score": 0.85,
"context": ["employee", "badge"],
"context_required": false
}
],
"audit_log": true
}一个可复制的示例位于 examples/umbryn_config.json。
实体覆盖范围
实体 | 正则引擎(默认) | Presidio 引擎( |
电子邮件、电话、SSN、信用卡、IP、URL | ✅ | ✅ |
NPI(Luhn + 80840 校验位) | ✅ | ✅ |
DEA(校验位) | ✅ | ✅ |
Medicare MBI(位置类型化) | ✅ | ✅ |
MRN(上下文锚定) | ✅ | ✅ |
Medicare HICN(SSN + 受益人代码) | ✅ | ✅ |
CLIA 实验室编号 | ✅ | ✅ |
US ITIN(9XX 范围结构) | ✅ | ✅ |
UK NHS 号码(mod-11 校验) | ✅ | ✅ |
加拿大 SIN(Luhn 校验) | ✅ | ✅ |
US 驾驶执照(上下文锚定) | ✅ | ✅ |
IBAN(mod-97 / ISO 7064 校验) | ✅ | ✅ |
人名 | ❌ | ✅(spaCy NER) |
地址 / 位置 | ❌ | ✅(spaCy NER) |
自定义识别器(你的正则 + 校验位,通过配置) | ✅ | ✅ |
基准测试
检测质量是经过测量的,而非被声称的。以下数字是默认(零依赖)引擎在合成评估语料上的得分——200 份生成的文档,约 1,800 个标记片段,其中混入了校验和失败的相似项作为干扰项,以保持精确率的真实性。可通过 python eval/run_eval.py --markdown 复现。
实体 | 精确率 | 召回率 | F1 | TP | FP | FN |
| 1.00 | 1.00 | 1.00 | 87 | 0 | 0 |
| 1.00 | 1.00 | 1.00 | 105 | 0 | 0 |
| 1.00 | 1.00 | 1.00 | 72 | 0 | 0 |
| 1.00 | 1.00 | 1.00 | 119 | 0 | 0 |
| 1.00 | 1.00 | 1.00 | 144 | 0 | 0 |
| 1.00 | 1.00 | 1.00 | 87 | 0 | 0 |
| 1.00 | 1.00 | 1.00 | 62 | 0 | 0 |
| 1.00 | 1.00 | 1.00 | 200 | 0 | 0 |
| 1.00 | 1.00 | 1.00 | 126 | 0 | 0 |
| 1.00 | 1.00 | 1.00 | 78 | 0 | 0 |
| 0.94 | 1.00 | 0.97 | 200 | 12 | 0 |
| 1.00 | 1.00 | 1.00 | 144 | 0 | 0 |
| 1.00 | 1.00 | 1.00 | 95 | 0 | 0 |
| 1.00 | 1.00 | 1.00 | 81 | 0 | 0 |
| 1.00 | 1.00 | 1.00 | 97 | 0 | 0 |
| 1.00 | 1.00 | 1.00 | 136 | 0 | 0 |
\* = 与 HIPAA 相关的标识符,受 CI 质量门控约束。**门控集合上的汇总:精确率 0.99,召回率 1.00。**如果召回率低于 0.90 或精确率低于 0.80,门控将使构建失败。(NPI 的 12 个误报是恰好通过 Luhn/80840 校验位的相似 10 位数字——这是一种刻意、故障安全的过度编辑偏向。)
这些是合成的最佳条件,格式整洁、邻近上下文词;现实世界的文本要杂乱得多。请将其视为回归护栏和合理性检查,而非保证——务必在您自己的代表性数据上评估。
范围与诚实的局限
**此工具在某一边界上减少 PHI/PII 暴露。它并不能使系统“符合 HIPAA”。**合规性是整个系统和组织的属性——其政策、合同、访问控制、审计态势和人员——而非任何单一库的属性。运行 umbryn-mcp 可以是合规设计的一部分,但它不是认证、保证,或业务伙伴协议、风险评估或法律顾问的替代品。
具体而言,本项目不:保证 100% 检测(没有检测器能做到)、在可逆编辑之外进行去标识化、覆盖非文本数据,或在 v1 中充当透明代理(编辑通过显式工具调用完成)。没有检测器是完美的——在依赖它之前,请先在代表性数据上评估。有关完整边界、假设和残余风险,参见 docs/THREAT_MODEL.md;报告问题请参见 SECURITY.md。
如何贡献
贡献者非常欢迎——这是一个刻意友好的地方,可以提交你的第一个开源 PR,维护者会尽量快速响应。
**最容易的高价值贡献:**为新的标识符添加检测识别器(一个正则 + 可选的校验位验证器 + 一个测试)。这个 add-a-recognizer 问题表单 兼作规范,CONTRIBUTING.md 逐步介绍了六个步骤。
其他好的帮助方式:改进文档、添加测试用例或示例客户端配置,或从 路线图 中挑选一些事项。浏览 good first issues 或打开一个问题来提出建议。
git clone https://github.com/Rinava/umbryn-mcp && cd umbryn-mcp
pip install -e ".[dev]"
pytest # fast invariant suite (Presidio faked, sub-second)
ruff check . && mypy src/umbryn_mcp
python eval/run_eval.py完整指南——开发设置、约定,以及固定数据的无真实 PHI 规则——位于 CONTRIBUTING.md 中。通过贡献,你同意你的工作以 MIT 许可发布。
许可证
MIT — 与 Presidio 一致并最大化复用。使用 Microsoft Presidio(可选)和 MCP Python SDK 构建。
umbryn-mcp 由 Kenda 背后的团队构建。
Available Tools
3 toolsdetectDetect PHI/PIIA
Report the PHI/PII entities found in text without modifying it.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | Text to inspect |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | Number of entities found |
| entities | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description bears full responsibility. It explicitly states 'without modifying it', which signals non-destructive behavior. However, it lacks details about output format, error handling, or what entities are considered PHI/PII, leaving some behavioral ambiguity.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, concise sentence of 10 words that front-loads the key purpose. Every word earns its place, with no redundancy or unnecessary detail.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple tool with one parameter and an output schema (context signal), the description covers the core functionality and non-modifying behavior. It could mention expected output shape or limitations, but the presence of an output schema mitigates the need for extensive return value details.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with a clear parameter description 'Text to inspect'. The description adds context about PHI/PII entities, but this aligns with the tool's purpose rather than enhancing parameter understanding. The schema already sufficiently explains the parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool reports PHI/PII entities without modifying text. It distinguishes itself from sibling tools 'redact' and 'restore' by explicitly noting the non-modifying nature, making its purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description does not provide explicit guidance on when to use this tool versus the sibling tools 'redact' and 'restore'. While the context implies detection is a prerequisite for redaction, no direct usage instructions or alternatives are mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
redactRedact PHI/PIIA
Replace PHI/PII in text with reversible typed placeholders.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | Text to scrub |
Output Schema
| Name | Required | Description |
|---|---|---|
| entities | Yes | What was redacted, for auditing |
| token_map | Yes | placeholder -> original value; keep local, do NOT send to the model |
| redacted_text | Yes | Text with PHI/PII replaced by typed placeholders |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description bears full burden. It discloses that redaction is reversible and uses typed placeholders, but does not elaborate on side effects, permission requirements, or output format details.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, concise sentence that communicates the core functionality. It is front-loaded and free of superfluous content, though it could benefit from additional context.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simple tool (one required parameter, output schema exists), the description provides sufficient context about the redaction operation and its reversible nature. It complements the siblings without needing extra details.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema covers 100% of parameters with a clear 'text' parameter description. The tool description adds minimal extra meaning beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly specifies the action ('Replace'), the resource ('PHI/PII in text'), and the nature of the output ('reversible typed placeholders'). It effectively distinguishes from sibling tools 'detect' and 'restore' by implying the redaction step.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is provided on when to use this tool versus its siblings ('detect' for identification, 'restore' for reversal). It omits prerequisites, exclusions, or typical workflow context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
restoreRestore redacted textB
Reverse a redaction using its token map, recovering the original text.
| Name | Required | Description | Default |
|---|---|---|---|
| token_map | Yes | placeholder -> original value | |
| redacted_text | Yes | Text containing placeholders |
Output Schema
| Name | Required | Description |
|---|---|---|
| text | Yes | The rehydrated original text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description must disclose behavioral traits. It only states the core function without mentioning side effects, required permissions, error cases, or behavior when token map is incomplete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence that is clear and efficient, but it could be more structured with separate sections for purpose and usage.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given full schema coverage and an output schema, the description is adequate for a simple tool, but it lacks usage guidelines and behavioral transparency, which are gaps for completeness.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description reuses the schema descriptions for both parameters, adding no additional meaning beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's action ('Reverse'), the resource ('a redaction'), and the method ('using its token map, recovering the original text'). This distinguishes it from sibling tools 'detect' and 'redact'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage when you have a redacted text and token map to restore, but it does not explicitly state when to use this tool versus alternatives, nor does it provide prerequisites or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.1.0- First observed
detect - First observed
redact - First observed
restore
TDQS
Scored across 3 tools
Each tool has a distinct and non-overlapping purpose: detect finds entities, redact replaces them, and restore reverses the redaction. No ambiguity.
All tool names are single verbs (detect, redact, restore) following a consistent pattern, making them easily predictable.
Three tools exactly cover the full PHI redaction workflow (detect, redact, restore) without unnecessary extras or missing steps.
The tool set provides a complete pipeline: detection, redaction with reversible placeholders, and restoration. No obvious gaps for the stated purpose.
Maintenance
Related MCP Connectors
MCP server for detecting and redacting PII (Personally Identifiable Information) in PDF documents.
HealthGuard - 12-tool health/medical AI safety MCP: PII redaction, HIPAA, GDPR Art.9.
Stateless PII redaction over MCP/REST. Free ≤1000 words or $0.01/call; file upload supported.
Hosted MCP server exposing US hospital procedure cost data to AI assistants
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceAn MCP proxy that pseudo-anonymizes PII before data reaches external AI providers like Claude, ChatGPT, or Gemini.18MIT
- FlicenseNot gradedqualityDmaintenanceMCP server for automatic detection and redaction of PII in text, with anonymization and deanonymization capabilities, all local processing.1-
- AlicenseAqualityCmaintenanceMCP server and CLI for detecting, redacting, and auditing PHI in medical text before it is sent to AI agents, with tools for scan, redact, audit, and validate operations.4MIT
- AlicenseAqualityCmaintenanceMCP server and CLI for detecting, redacting, and auditing PHI in medical text before it reaches AI agents.4MIT