How to Search the NPI Registry Programmatically
Every healthcare provider in the United States -- physicians, nurse practitioners, hospitals, pharmacies, labs -- has a National Provider Identifier (NPI). It is a unique 10-digit number assigned by CMS through the National Plan and Provider Enumeration System (NPPES). If you are building anything that touches healthcare data, from insurance verification to referral management to claims processing, you need to look up NPIs.
The official NPPES API exists, but anyone who has used it in production knows its limitations. This article covers what NPI numbers are, why the official API is frustrating, and how to search the registry reliably from your application.
What NPI numbers contain
An NPI record includes far more than just a number and a name:
- NPI number: The 10-digit identifier
- Provider type: Individual (Type 1) or Organization (Type 2)
- Name: First, last, and credential suffix for individuals; organization name for Type 2
- Taxonomy codes: Specialties and sub-specialties (mapped to standardized taxonomy descriptions)
- Practice addresses: Mailing and practice location with phone/fax
- Other identifiers: State license numbers, DEA numbers, Medicare/Medicaid IDs
- Enumeration date: When the NPI was first assigned
The NPPES API problem
CMS provides a free API at https://npiregistry.cms.hhs.gov/api/. It works, but it has well-documented issues:
- Slow response times. Queries frequently take 2-5 seconds. Complex searches can time out entirely.
- No caching headers. Every request hits their backend fresh, which contributes to the latency.
- Rate limiting without documentation. After a burst of requests, you start getting 429 errors with no clear guidance on limits.
- Inconsistent availability. The API occasionally returns 500 errors during peak hours or maintenance windows.
- Limited search flexibility. You cannot search by partial name easily, and combining filters is unintuitive.
For a prototype, these issues are tolerable. For production healthcare software serving clinicians who need sub-second results, they are not.
Searching for providers
Here is a search for cardiologists in California:
curl "https://npi-lookup.up.railway.app/search?taxonomy_description=cardiology&state=CA&limit=3"
{
"result_count": 3,
"results": [
{
"number": 1234567890,
"basic": {
"first_name": "JAMES",
"last_name": "CHEN",
"credential": "MD",
"gender": "M",
"enumeration_date": "2005-06-15"
},
"taxonomies": [
{
"code": "207RC0000X",
"desc": "Cardiovascular Disease",
"primary": true,
"state": "CA",
"license": "A123456"
}
],
"addresses": [
{
"address_purpose": "LOCATION",
"city": "LOS ANGELES",
"state": "CA",
"postal_code": "900XX"
}
]
}
]
}
Looking up a specific NPI
When you have a provider's NPI number and need their details:
curl "https://npi-lookup.up.railway.app/lookup/1234567890"
This returns the full NPI record: name, credentials, all taxonomy codes, addresses, and identifiers.
Integrating into a Node.js application
Here is a practical example: a provider search component for a referral management system.
const NPI_BASE = 'https://npi-lookup.up.railway.app';
const searchProviders = async ({ name, specialty, state, city, limit = 10 }) => {
const params = new URLSearchParams();
if (name) { params.set('name', name); }
if (specialty) { params.set('taxonomy_description', specialty); }
if (state) { params.set('state', state); }
if (city) { params.set('city', city); }
params.set('limit', String(limit));
const res = await fetch(`${NPI_BASE}/search?${params}`);
const data = await res.json();
return data.results.map((p) => ({
npi: p.number,
name: `${p.basic.first_name} ${p.basic.last_name}, ${p.basic.credential || ''}`.trim(),
specialty: p.taxonomies.find((t) => t.primary)?.desc || 'Unknown',
city: p.addresses.find((a) => a.address_purpose === 'LOCATION')?.city || '',
state: p.addresses.find((a) => a.address_purpose === 'LOCATION')?.state || '',
}));
};
const lookupNpi = async (npi) => {
const res = await fetch(`${NPI_BASE}/lookup/${npi}`);
return res.json();
};
// Find orthopedic surgeons in Texas
const surgeons = await searchProviders({
specialty: 'orthopedic',
state: 'TX',
limit: 5,
});
console.log(surgeons);
// [
// { npi: 1234567890, name: "SARAH WILLIAMS, MD", specialty: "Orthopaedic Surgery", ... },
// ...
// ]
Using the MCP server in Claude Desktop
For quick lookups during development or clinical workflow design, the MCP Healthcare server lets you search the NPI registry conversationally through Claude.
npx @easysolutions906/mcp-healthcare
Add this to your Claude Desktop configuration (claude_desktop_config.json):
{
"mcpServers": {
"healthcare": {
"command": "npx",
"args": ["-y", "@easysolutions906/mcp-healthcare"]
}
}
}
With the server connected, you can ask Claude "Find me cardiologists in San Francisco" or "Look up NPI 1234567890" and it calls the npi_search or npi_lookup tool directly. The response includes the full provider record: name, credentials, specialties, practice addresses, and license information.
This is useful when you are building a healthcare application and need to verify test NPI numbers, explore the data model, or check whether a provider's taxonomy code matches what you expect. Instead of switching to a browser and navigating the NPPES website, you get the answer in your editor.
What makes this different from hitting NPPES directly
This API proxies to the same NPPES data source but adds several practical improvements:
- Faster response formatting. The raw NPPES response is verbose and nested. This API flattens it into a more usable structure.
- Combined search parameters. Search by name, specialty description, city, and state in a single clean query string.
- Consistent availability. Railway deployment means the API layer stays up even if NPPES is slow, and responses are formatted consistently regardless of upstream quirks.
The MCP server version goes a step further: it makes NPI data available as a tool that AI assistants can call, which means you can integrate provider lookups into AI-powered clinical workflows.
Get started
- REST API: Deployed on Railway. No signup required. Search and lookup endpoints are open.
-
MCP server:
npx @easysolutions906/mcp-healthcareadds NPI tools (plus ICD-10, NDC, and DEA) to Claude Desktop or Cursor. -
npm package:
npm install @easysolutions906/mcp-healthcare
The NPI registry contains over 8 million active providers. Search it in milliseconds, not seconds.
Top comments (0)