MCP De-identification Server

 

Overview

Available since Healthcare NLP 6.3.0

The Model Context Protocol (MCP) De-identification Servers enable AI coding assistants (such as Cursor and VS Code Copilot) to access state-of-the-art clinical de-identification pipelines directly as tools. This integration allows you to sanitize clinical text instantly within your IDE while maintaining strict HIPAA compliance through local, secure execution.

Key Features

  • Direct integration with Cursor and VS Code
  • Local execution for HIPAA compliance
  • Support for both masking and obfuscation modes
  • Detection of 30+ PHI entity types
  • Two deployment architectures for different use cases

Architecture Options

Two architectures are available to accommodate different deployment requirements:

A thin, instant-startup Python server that connects your IDE to a robust backend de-identification service.

Specifications:

  • Startup Time: < 1 second
  • Memory: ~100MB (MCP server)
  • Ports: 8001 (MCP) + 9000 (backend)
  • Best For: Teams sharing a backend GPU server; frequent IDE restarts

Architecture Diagram:

IDE (Cursor/VSCode) → MCP Server v2 → Deid Service Container → Spark NLP Healthcare

Monolithic Architecture (v1)

Battery-included approach with the Spark NLP pipeline embedded directly inside the MCP server container.

Specifications:

  • Startup Time: 2-5 minutes (pipeline loading)
  • Memory: 8GB+ reserved
  • Port: 8000
  • Best For: Air-gapped environments; single-container deployments

Architecture Diagram:

IDE (Cursor/VSCode) → MCP Server v1 (containing embedded Spark NLP Pipeline)

Architecture Comparison

Aspect v1 Monolithic v2 Lightweight
Port 8000 8001 (MCP) + 9000 (backend)
Memory 8GB+ reserved ~100MB (MCP server only)
Startup Time 2-5 minutes Instant (<1 second)
Docker Required Yes MCP: No, Backend: Yes
Use Case Standalone deployment Shared backend, multiple clients

Prerequisites

  • Docker and Docker Compose installed
  • Valid John Snow Labs Healthcare NLP license
  • 8GB+ available memory for pipeline container
  • Cursor or VS Code with GitHub Copilot

License Configuration

Both architectures require a valid John Snow Labs Healthcare NLP license provided via a spark_jsl.json file.

Required License Keys

{
  "SPARK_NLP_LICENSE": "eyJ...",
  "SECRET": "x.x.x-xxxxxxxxx"
}
Key Description
SPARK_NLP_LICENSE JWT license token for Spark NLP Healthcare
SECRET PyPI token for private package installation

Optional License Keys

{
  "SPARK_OCR_LICENSE": "eyJ...",
  "AWS_ACCESS_KEY_ID": "AKIA...",
  "AWS_SECRET_ACCESS_KEY": "...",
  "AWS_SESSION_TOKEN": "..."
}

These keys are required for OCR capabilities or S3 model downloads.

Security: Docker Secrets

The license file is mounted as a Docker secret at /run/secrets/spark_jsl.json to keep credentials secure and prevent them from being baked into Docker images.

# docker-compose.yml
secrets:
  spark_jsl:
    file: ./spark_jsl.json

services:
  deid-service:
    secrets:
      - source: spark_jsl
        target: spark_jsl.json

Note: If you do not have a JSL Healthcare NLP license, visit johnsnowlabs.com to request a trial.

Installation Steps

Step 1: Clone the Repository

git clone https://github.com/JohnSnowLabs/spark-nlp-workshop.git
cd spark-nlp-workshop/agents/mcp_servers/deidentification

Step 2: Configure License File

Option A: Copy example and edit

cp spark_jsl.json.example spark_jsl.json
# Edit spark_jsl.json with your actual JSL license credentials

Option B: Copy existing license

cp /path/to/your/spark_jsl.json ./deid-service/spark_jsl.json

Step 3: Start Backend Service

cd deid-service

# Set JSL secret for Docker build
export JSL_SECRET=$(jq -r '.SECRET' spark_jsl.json)

# Build and start
docker compose up --build

Wait for the service to report “Application startup complete”. First startup takes 2-5 minutes for model download; subsequent starts are faster due to caching.

Test the backend:

curl -X POST http://localhost:9000/deidentify \
  -H "Content-Type: application/json" \
  -d '{"text":"Dr. John Lee treated patient Emma Wilson","mode":"both"}'

Step 4: Start MCP Server

Option A: Lightweight v2 (Recommended)

cd jsl-deid-mcp-server-v2
pip install -e .
python -m src.server

Server starts on http://localhost:8001/mcp

Option B: Monolithic v1

cd jsl-deid-mcp-server-v1
export JSL_SECRET=$(jq -r '.SECRET' spark_jsl.json)
docker compose up --build

Server starts on http://localhost:8000/mcp

Step 5: Configure IDE Client

Cursor Configuration

Add to ~/.cursor/mcp.json (macOS/Linux):

{
  "mcpServers": {
    "jsl-deid": {
      "url": "http://localhost:8001/mcp",
      "transport": "streamable-http"
    }
  }
}

Restart Cursor after updating the configuration.

VS Code Copilot Configuration

Add to project_folder/.vscode/mcp.json:

{
  "mcp.servers": {
    "jsl-deid": {
      "url": "http://localhost:8001/mcp",
      "type": "http"
    }
  }
}

Restart VS Code after updating the configuration.

Verification (Optional)

Initialize Session

curl -s -i -X POST http://localhost:8001/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}'

Call De-identification Tool

Replace <SESSION_ID> with the mcp-session-id from the initialize response header:

curl -s -X POST http://localhost:8001/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Mcp-Session-Id: <SESSION_ID>" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "deidentify_text",
      "arguments": {
        "text": "Dr. John Lee treated patient Emma Wilson on 11/05/2024.",
        "mode": "both"
      }
    },
    "id": 2
  }'

Usage

Sample Clinical Text

Dr. John Lee, from Royal Medical Clinic in Chicago, attended to the patient on 11/05/2024.
The patient's medical record number is 56467890.
The patient, Emma Wilson, is 50 years old, her Contact number: 444-456-7890.

Output Modes

Mode: masked

PHI entities replaced with labels:

Dr. <NAME>, from <HOSPITAL> in <CITY>, attended to the patient on <DATE>.
The patient's medical record number is <ID>.
The patient, <PATIENT>, is <AGE> years old, her Contact number: <PHONE>.

Mode: obfuscated

PHI entities replaced with realistic fake values:

Dr. Vivia Ammon, from Baltimore Va Medical Center in Healdton, attended to the patient on 06/06/2024.
The patient's medical record number is 25958147.
The patient, Marla Sakai, is 40 years old, her Contact number: 999-925-8147.

Mode: both

Returns both masked and obfuscated versions in a single response:

{
  "masked": "Dr. <DOCTOR>, from <HOSPITAL> in <CITY>, attended to the patient on <DATE>.\nThe patient's medical record number is <MEDICALRECORD>.\nThe patient, <PATIENT>, is <AGE> years old, her Contact number: <PHONE>.",
  "obfuscated": "Dr. Vivia Ammon, from Baltimore Va Medical Center in Healdton, attended to the patient on 06/06/2024.\nThe patient's medical record number is 25958147.\nThe patient, Marla Sakai, is 40 years old, her Contact number: 999-925-8147.",
  "error": null
}

Using in Cursor

In the Cursor chat:

Use the Deid MCP to de-identify this clinical note with masked output.
"Dr. John Lee, from Royal Medical Clinic in Chicago, attended to the patient on 11/05/2024..."

Cursor will automatically invoke the deidentify_text tool and return the result.

Using in VS Code Copilot

In VS Code Copilot Chat:

Utilize the Deid MCP to anonymize this clinical note, employing both masked and obfuscated output modes.
"Dr. John Lee, from Royal Medical Clinic in Chicago, attended to the patient on 11/05/2024..."

Supported PHI Entity Types

The pipeline detects and processes 30+ PHI entity types including:

Personal Identifiers:

  • PATIENT, DOCTOR, USERNAME
  • AGE, DATE
  • SSN, DLN (Driver’s License), LICENSE

Contact Information:

  • PHONE, FAX, EMAIL, URL

Location Data:

  • HOSPITAL, CITY, STATE, COUNTRY, ZIP
  • STREET, LOCATION

Medical Identifiers:

  • MEDICALRECORD, HEALTHPLAN, ACCOUNT
  • IDNUM, BIOID

Organization:

  • ORGANIZATION, PROFESSION

Vehicle/Device:

  • DEVICE, PLATE, VIN

The underlying pipeline is clinical_deidentification from Spark NLP Healthcare, which combines NER models, rule-based matchers, and contextual parsers for high-accuracy PHI detection.

Technical Details

Privacy by Design

The servers log request metadata (text size, mode, latency) but never log clinical content:

# What is logged
logger.info(f"Deidentify request: {len(text)} chars, mode={mode}")
logger.info(f"Deidentify completed: {elapsed_ms:.0f}ms")

# What is never logged
# logger.info(f"Processing: {text}")  # NEVER

Streamable HTTP Transport

The implementation uses FastMCP’s streamable_http_app() with uvicorn for IDE compatibility, providing the HTTP-based transport expected by Cursor and VS Code Copilot.

Pipeline Warmup

On startup, the pipeline processes a sample text to trigger JVM JIT compilation and lazy initialization. This ensures consistent latency for actual requests:

  • Without warmup: First request can take 10-30 seconds
  • With warmup: Typical latency is 100-500ms depending on text length

Resources

Future Additions

This de-identification MCP server is the first in a planned series of healthcare NLP tools for AI assistants:

  • Data Curation MCP Server - Clinical entity extraction and structuring
  • Medical Coding MCP Server - ICD-10, CPT code assignment

Getting Started

Clone the repository, configure your license, and bring clinical de-identification to your IDE. The v2 lightweight architecture enables you to start in under 10 minutes with post-installation response times of less than a second.

Last updated