NPI MCP Server
An offline-capable MCP (Model Context Protocol) server for the CMS NPPES NPI Registry, written in Python, deployable on Azure App Service as a Docker container.
Features
- ✅ Works offline — uses a local SQLite database
- 🔄 Auto-updates every 7 days from CMS NPPES (background scheduler)
- 🐳 Docker-ready with multi-stage build
- ☁️ Azure App Service deployment with persistent storage
- 🔍 Full-text search with wildcard support
- ✔️ Luhn validation for NPI check digits
- 📊 ~8M+ provider records from the full NPPES dataset
MCP Tools
| Tool | Description |
|---|---|
npi_search | Search by name, specialty, city, state, ZIP |
npi_lookup | Look up a specific NPI number |
npi_validate | Validate NPI format + Luhn check digit (offline) |
db_status | Check DB record count, last/next update time |
db_update | Manually trigger a data refresh |
Quick Start (Local)
1. Build and run with Docker Compose
git clone <this-repo>
cd npi-mcp-server
# Build and start
docker compose up -d
# Trigger initial data load (one-time, ~30-60 min)
curl -X POST "http://localhost:8000/update?force=true"
# Monitor progress
docker compose logs -f
2. Check health
curl http://localhost:8000/health
3. Connect MCP client
Point your MCP client to: http://localhost:8000/sse
Azure Deployment
Prerequisites
- Azure CLI installed:
brew install azure-clior see docs - Docker installed
- Azure subscription
Deploy
# Log in to Azure
az login
# Edit variables at top of script
nano deploy-azure.sh
# Run deployment (takes ~5 minutes)
chmod +x deploy-azure.sh
./deploy-azure.sh
After deployment
Trigger the initial NPI data load (one-time, requires internet):
curl -X POST "https://your-app.azurewebsites.net/update?force=true"
The full NPPES file is ~900MB compressed / ~8GB uncompressed. Loading takes 30-60 minutes. After that, weekly incremental updates run automatically.
Architecture
┌─────────────────────────────────────────────────────┐
│ Azure App Service │
│ │
│ ┌──────────────┐ ┌──────────────────────────┐ │
│ │ FastAPI/SSE │───▶│ MCP Server (mcp SDK) │ │
│ │ HTTP layer │ │ - npi_search │ │
│ └──────────────┘ │ - npi_lookup │ │
│ │ - npi_validate │ │
│ ┌──────────────┐ │ - db_status/update │ │
│ │ Background │ └──────────────────────────┘ │
│ │ Scheduler │ │ │
│ │ (every 7d) │ ▼ │
│ └──────────────┘ ┌──────────────────────────┐ │
│ │ SQLite Database │ │
│ │ /data/npi.db │ │
│ │ (~5-10 GB) │ │
│ └──────────────────────────┘ │
│ │ │
│ ┌──────────────────────────┐ │
│ │ Azure File Share │ │
│ │ (persistent volume) │ │
│ └──────────────────────────┘ │
└─────────────────────────────────────────────────────┘
│
│ (weekly, when internet available)
▼
┌─────────────────────┐
│ CMS NPPES │
│ download.cms.gov │
└─────────────────────┘
Environment Variables
| Variable | Default | Description |
|---|---|---|
NPI_DB_PATH | /data/npi.db | SQLite database path |
NPI_UPDATE_DAYS | 7 | Days between auto-updates |
DOWNLOAD_TIMEOUT | 3600 | Download timeout in seconds |
PORT | 8000 | HTTP server port |
API Endpoints
| Endpoint | Method | Description |
|---|---|---|
/ | GET | Server info |
/health | GET | Health check (used by Azure) |
/status | GET | DB status (record count, last update) |
/update | POST | Trigger manual update (?force=true) |
/sse | GET | MCP SSE connection endpoint |
/messages | POST | MCP messages endpoint |
Storage Requirements
| Component | Size |
|---|---|
| NPPES ZIP download | ~900 MB |
| SQLite database | ~5-10 GB |
| Recommended Azure File Share | 50 GB |
Use Azure App Service B2 or higher (2 vCPU, 3.5 GB RAM minimum).
Connecting MCP Clients
Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"npi-registry": {
"url": "https://your-app.azurewebsites.net/sse",
"transport": "sse"
}
}
}
Local stdio mode (for dev/testing)
python main.py
Data Source
Data comes from CMS NPPES, the official National Plan and Provider Enumeration System. Updated monthly (full) and weekly (incremental) by CMS.