phi-redact-mcp
umbryn-mcp
Un servidor MCP que redacta PII/PHI del texto antes de que llegue a un LLM: autohospedado, con bloqueo ante incertidumbre y compatible con HIPAA.
Los equipos que construyen canalizaciones de LLM y agentes en sectores regulados no tienen una forma limpia e integrable de eliminar PHI/PII de una carga útil antes de que cruce a la infraestructura del proveedor del modelo. umbryn-mcp es ese límite: tres herramientas MCP — redact, restore, detect — que convierten valores sensibles en marcadores de posición reversibles, se ejecutan íntegramente dentro de la infraestructura que controlas y bloquean la solicitud si la detección es incierta, en lugar de filtrar datos.
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.comEnvía el texto redactado al modelo; mantén el token_map local; llama a restore después para rehidratar el resultado. Los viajes de ida y vuelta son exactos a nivel de byte y están demostrados con pruebas basadas en propiedades.
Por qué existe
El nicho de MCP para redacción de PHI/PII es real pero está poco atendido: las opciones existentes son envoltorios básicos de Presidio sin detección específica de HIPAA y, lo que es crítico, sin garantía de que un fallo de detección bloquee la solicitud en lugar de pasar silenciosamente los datos sin procesar. Así que los equipos o construyen su propio límite o envían datos sensibles a un proveedor y se apoyan en un BAA para cubrirlo: el error de diseño que provoca incidentes de cumplimiento reales.
Envoltorio básico de Presidio | Regex en tu app | Cloud DLP API | umbryn-mcp | |
Herramientas MCP de integración directa | a veces | ❌ | ❌ | ✅ |
Bloqueo ante detección incierta | ❌ | ❌ | ❌ | ✅ |
Identificadores HIPAA (NPI, DEA, MBI, MRN, CLIA) | ❌ | parcial | parcial | ✅ |
Reversible (restaurar original) | raramente | por cuenta propia | algunos | ✅ |
Autohospedado, cero tráfico de salida | ✅ | ✅ | ❌ (envía datos al exterior) | ✅ |
Funciona con cero dependencias pesadas | ❌ (requiere spaCy) | ✅ | n/a | ✅ (motor de regex) |
NER de ML opcional (nombres, direcciones) | ✅ | ❌ | ✅ | ✅ (extra |
Por qué se creó: MCP se generalizó rápidamente: ahora es de primera clase en Claude, Cursor y ChatGPT, en miles de servidores; pero el ámbito de la redacción de PHI/PII quedó en manos de unos pocos envoltorios sin mantenimiento. Esto llena ese vacío con un único límite honesto, auditable y con bloqueo ante incertidumbre, mantenido como código abierto para que la lógica de redacción de la que dependes sea totalmente inspeccionable en lugar de una caja negra.
Related MCP server: MCP Presidio
Features
Tres herramientas, un solo límite —
redact(→ texto depurado + mapa de tokens reversible),restore(→ original),detect(→ entidades encontradas, sin mutación).Bloqueo ante incertidumbre por construcción — si la detección da error o cualquier detección cae por debajo del umbral de confianza, la llamada devuelve un error tipado. La incertidumbre bloquea; nunca redacta lo que puede y deja pasar el resto.
Detección preparada para HIPAA — NPI y DEA validados por suma de verificación, MBI de Medicare con tipo posicional, MRN anclado al contexto, IDs de laboratorio CLIA, además de PII estándar (correo electrónico, teléfono, SSN, tarjeta de crédito, IBAN, IP, URL).
Cero tráfico de salida, autohospedado — el motor por defecto es regex puro + sumas de verificación, sin llamadas de red ni dependencias pesadas. Se instala en cualquier lugar donde se instale Python.
Mejora de ML opcional —
pip install "umbryn-mcp[presidio]"añade Microsoft Presidio + spaCy para NER dePERSON/LOCATION, de forma transparente.Reversible y determinista — los marcadores de posición tipados a prueba de colisiones hacen que
restore(redact(x)) == xpara cualquier entrada; la misma entrada + configuración siempre produce la misma salida.
Cuándo usarlo (y cuándo no)
Recurre a umbryn-mcp cuando:
Envías texto sanitario, clínico, financiero o generado por el usuario a una API de LLM de terceros y necesitas que la PHI/PII no llegue a la infraestructura ni a los registros de ese proveedor.
Estás construyendo una canalización de agente o MCP en un sector regulado y quieres un límite de depuración integrable que se conecte con una sola llamada a una herramienta.
Necesitas redacción reversible para que los pasos posteriores sigan funcionando:
redact→ enviar al modelo →restore.Quieres un detector autohospedado y sin tráfico de salida que puedas auditar línea por línea.
Necesitas identificadores específicos de HIPAA (NPI, DEA, MBI de Medicare, MRN, CLIA), no solo nombres y correos electrónicos.
Recurre a otra opción cuando:
Necesitas desidentificación/anonimización irreversible (tokenización, k-anonimato) — aquí la redacción es reversible por diseño.
Necesitas redactar datos no textuales (imágenes, audio, PDF, filas de bases de datos) — el alcance es el texto.
Quieres un producto con cumplimiento certificado — esto es un control técnico, no un programa de cumplimiento (consulta Alcance y limitaciones honestas).
Quieres un proxy transparente que depure automáticamente todo en la ruta de solicitudes — la v1 es llamadas explícitas a herramientas; el modo proxy está en la hoja de ruta.
Exiges una recuperación del 100 % garantizada — ningún detector, incluido este, puede prometerlo.
Inicio rápido (< 60 segundos)
pip install umbryn-mcp # zero heavy deps; runs immediatelyLuego regístralo en tu cliente MCP.
Claude Desktop / Claude Code (claude_desktop_config.json, o claude mcp add umbryn-mcp -- umbryn-mcp):
{
"mcpServers": {
"umbryn-mcp": {
"command": "umbryn-mcp"
}
}
}Cursor (.cursor/mcp.json) y VS Code usan la misma estructura: consulta examples/ para ver configuraciones listas para copiar y pegar.
¿También quieres detección de nombres y direcciones?
pip install "umbryn-mcp[presidio]"
python -m spacy download en_core_web_lgEl servidor detecta automáticamente Presidio y se actualiza: no hace falta cambiar la configuración. (Establece UMBRYN_ENGINE=regex para forzar el motor sin dependencias, o =presidio para exigir el de ML).
Cómo funciona
Una llamada a herramienta entra por stdio; el núcleo Redactor ejecuta el motor de detección configurado, resuelve las superposiciones de forma determinista, aplica la comprobación del umbral de bloqueo y sustituye los segmentos detectados por marcadores de posición tipados reversibles. Solo el texto depurado debe salir del límite que ejecutas.
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)]El núcleo Redactor depende solo de una pequeña interfaz DetectionEngine: nunca de Presidio o MCP directamente. Los datos sin procesar y el motor de detección permanecen dentro del límite que ejecutas; solo el texto depurado sale de él. Consulta docs/ARCHITECTURE.md y docs/THREAT_MODEL.md.
Las herramientas
redact(text) → { redacted_text, token_map, entities }
Reemplaza la PHI/PII detectada por marcadores de posición tipados como [NPI_1]. token_map asocia cada marcador de posición con su valor original — mantenlo local; nunca lo envíes al modelo. entities enumera lo redactado (tipo/segmento/puntuación) para auditoría.
restore(redacted_text, token_map) → { text }
Revierte una redacción y recupera el texto original exactamente. Es seguro llamarla sobre la salida del modelo que aún contenga los marcadores.
detect(text) → { entities, count }
Informa de las entidades encontradas — tipo, segmento, confianza — sin modificar el texto. A diferencia de redact, muestra los aciertos de baja confianza en lugar de bloquear, para que puedas inspeccionar la cobertura antes de confiar en el límite en una canalización.
Cómo usarlo (una canalización real)
El patrón es redact → modelo → restore, con el mapa de tokens sin salir nunca de tu lado:
Depura antes del modelo. Llama a
redact(user_text). Envía soloredacted_textal LLM. Manténtoken_mapen tu proceso: trátalo con la misma sensibilidad que la entrada sin procesar y nunca se lo pases al modelo.Deja que el modelo trabaje con los marcadores. Ve
[NPI_1],[US_SSN_1], etc.: tokens semánticamente neutros sobre los que puede razonar y que puede repetir.Rehidrata después. Llama a
restore(model_output, token_map)para devolver los valores reales a la respuesta del modelo antes de que llegue a tu usuario o a tu base de datos.Gestiona el bloqueo. Si
redactdevuelve un error de herramienta[LOW_CONFIDENCE]o[DETECTION_ERROR], el límite se ha negado a filtrar: hazlo visible, refuerza la entrada o reduce el riesgo, pero no envíes el texto sin procesar.
Antes de confiar en él en una canalización, llama a detect(sample_text) sobre datos representativos (sintéticos) para ver exactamente qué se detecta y qué no, y ajusta los umbrales (abajo) a tu tolerancia al riesgo.
Bloqueo ante incertidumbre, con precisión
Dos umbrales gobiernan cada llamada a redact:
detection_floor(por defecto0.35) — el límite de sensibilidad. Las señales por debajo se tratan como ruido.min_confidence(por defecto0.5) — el umbral de confianza.
Cualquier candidato que supere el límite pero puntúe por debajo de min_confidence pone la llamada en modo de bloqueo: devuelve un error [LOW_CONFIDENCE] en lugar de redactar los segmentos con confianza y dejar pasar el incierto. Los errores del motor devuelven [DETECTION_ERROR]. Ante cualquier error, no se devuelve texto redactado. Ambos umbrales son configurables (ver más abajo).
Configuración
Todo es opcional; los valores predeterminados razonables hacen que se ejecute sin configuración. Se configura mediante el bloque env del cliente.
Variable | Default | Significado |
|
|
|
|
| Umbral de confianza; las detecciones por debajo bloquean la llamada |
|
| Por debajo de este valor, una señal se trata como ruido |
|
| Rechaza una entrada mayor con un error tipado |
|
| Modelo de spaCy para el motor de Presidio |
|
| Emite un registro de auditoría estructurado por cada llamada a |
| (sin definir) | Ruta a un archivo de configuración JSON (abajo) |
Archivo de configuración
Para ajustes que no encajan en una variable de entorno plana, apunta UMBRYN_CONFIG a un archivo JSON. Las variables de entorno siguen teniendo prioridad sobre el archivo para los valores escalares anteriores, así que puedes distribuir un solo archivo y ajustarlo en cada lanzamiento. Un archivo mal formado (JSON inválido, umbral desconocido, regex no compilable) falla en modo bloqueado al inicio en lugar de degradarse silenciosamente.
{
// 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
}Hay un ejemplo listo para copiar en examples/umbryn_config.json.
Cobertura de entidades
Entidad | Motor de regex (predeterminado) | Motor de Presidio ( |
Correo electrónico, Teléfono, SSN, Tarjeta de crédito, IP, URL | ✅ | ✅ |
NPI (dígito de control Luhn + 80840) | ✅ | ✅ |
DEA (dígito de control) | ✅ | ✅ |
Medicare MBI (tipado por posición) | ✅ | ✅ |
MRN (con anclaje contextual) | ✅ | ✅ |
Medicare HICN (SSN + código de beneficiario) | ✅ | ✅ |
CLIA número de laboratorio | ✅ | ✅ |
ITIN de EE. UU. (estructura de rango 9XX) | ✅ | ✅ |
Número NHS del Reino Unido (verificación mod-11) | ✅ | ✅ |
SIN canadiense (verificación Luhn) | ✅ | ✅ |
Licencia de conducir de EE. UU. (con anclaje contextual) | ✅ | ✅ |
IBAN (verificación mod-97 / ISO 7064) | ✅ | ✅ |
Nombres de personas | ❌ | ✅ (spaCy NER) |
Direcciones / ubicaciones | ❌ | ✅ (spaCy NER) |
Reconocedores personalizados (tu regex + dígito de control, mediante configuración) | ✅ | ✅ |
Evaluación comparativa
La calidad de detección se mide, no se asume. Los números siguientes corresponden al motor predeterminado (sin dependencias) evaluado sobre el corpus de evaluación sintético — 200 documentos generados, ~1.800 spans etiquetados, con imitaciones que fallan el checksum entretejidas como distractores para mantener la precisión honesta. Reprodúcelos con python eval/run_eval.py --markdown.
Entity | Precisión | Exhaustividad | 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 |
\* = identificador relevante para HIPAA, sujeto al control de calidad del CI. Agregado sobre el conjunto evaluado: precisión 0.99, exhaustividad 1.00. El control hace fallar la compilación si la exhaustividad cae por debajo de 0.90 o la precisión por debajo de 0.80. (Los 12 falsos positivos de NPI son números de 10 dígitos parecidos a los reales que pasan el dígito de control Luhn/80840: un sesgo deliberado y a prueba de fallos hacia el enmascaramiento excesivo).
Son condiciones sintéticas de mejor caso, con formato limpio y palabras de contexto cercanas; el texto del mundo real es más desordenado. Trata esto como una barrera de regresión y una comprobación de cordura, no como una garantía: evalúa siempre con tus propios datos representativos.
Alcance y limitaciones honestas
**Esta herramienta reduce la exposición de PHI/PII en un único punto de un sistema. No hace que un sistema «cumpla la HIPAA». Volver a cumplimiento normativo a todo un sistema y organización: sus políticas, contratos, controles de acceso, postura de auditoría y personas. No es propiedad de una única librería. Ejecutar umbryn-mcp pueden ser parte de un diseño conforme, pero la herramienta no es una certificación ni una garantía, ni un sustituto de un Acuerdo de Asociado Comercial, ni de una evaluación de riesgos, ni de legal counsel.
Concretamente, este proyecto no:
garantiza el 100 % de la detección (ningún detector es perfecto);
an describe beyond a reversible redaction;
ocupa datos no textuales;
actúa como proxy transparente en v1 (redar must call via explicit methods you integrate).
Ningún detector es perfecto: evalúa con tus propios datos representativos. Evalúa before confide in itición: more on a case by case. Consult docs/THREAT_MODEL.md para understanding the full scope and assumptions, and SECURITY.md to report incidents.
Cómo contribuir
Las contribuciones son muy bienvenidas: this place is intentionally friendly for a first open source PR, and maintainers try to respond quickly.
The easiest and high-value contribution: add a detection risible for a new identifier (a regex + an optional validator of check digit + a test). The add-a-recognizer issue form doubles as a spec, and CONTRIBUTING.md walks you through the six steps in detail.
Other good ways to help: improve documentation, add test cases or example client configurations, or tackle something from the posible roadmap. Explore good first issues or open an issue to propose something.
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.pyThe full guide — development setup, conventions, and the rule of no real PHI on fixtures — is in CONTRIBUTING.md. By contributing you agree that your work is MIT-licensed.
License
License MIT-licensed — matches Presidio and maximizes reuse. Built with Microsoft Presidio (optional) and the MCP Python SDK.
umbryn-mcp is built by the team behind Kenda.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceAn MCP proxy that pseudo-anonymizes PII before data reaches external AI providers like Claude, ChatGPT, or Gemini.18MIT
- AlicenseAqualityDmaintenanceAn MCP server that enables LLMs to detect and anonymize over 25 types of Personally Identifiable Information (PII) using Microsoft Presidio. It supports various redaction strategies and can process both plain text and structured data to help ensure data privacy.10MIT
- FlicenseNot gradedqualityDmaintenanceMCP server for automatic detection and redaction of PII in text, with anonymization and deanonymization capabilities, all local processing.1
- AlicenseAqualityBmaintenanceMCP 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
Related MCP Connectors
Hosted MCP server exposing US hospital procedure cost data to AI assistants
Self-hosted MCP gateway: turn any API, database or MCP server into AI connectors — no code.
An MCP server for Arcjet - the runtime security platform that ships with your AI code.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Rinava/umbryn-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server