npi-providers-mcp-server

v0.5.0 pre-1.0

Search NPPES providers and resolve NUCC specialty codes via MCP over STDIO or Streamable HTTP.

npi-providers.caseyjhand.com/mcp
claude mcp add --transport http npi-providers-mcp-server https://npi-providers.caseyjhand.com/mcp
codex mcp add npi-providers-mcp-server --url https://npi-providers.caseyjhand.com/mcp
{
  "mcpServers": {
    "npi-providers-mcp-server": {
      "url": "https://npi-providers.caseyjhand.com/mcp"
    }
  }
}
gemini mcp add --transport http npi-providers-mcp-server https://npi-providers.caseyjhand.com/mcp
{
  "mcpServers": {
    "npi-providers-mcp-server": {
      "command": "bunx",
      "args": [
        "mcp-remote",
        "https://npi-providers.caseyjhand.com/mcp"
      ]
    }
  }
}
{
  "mcpServers": {
    "npi-providers-mcp-server": {
      "type": "http",
      "url": "https://npi-providers.caseyjhand.com/mcp"
    }
  }
}
curl -X POST https://npi-providers.caseyjhand.com/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}'

Tools

3

npi_search_providers

open-world

Search the NPPES NPI registry for individual practitioners and healthcare organizations by name, organization name, location, provider type, and specialty. Plain-language specialty terms (e.g. "cardiologist", "pediatric cardiologist") resolve through the bundled NUCC taxonomy; the top match's specialization or classification becomes taxonomy_description, and all resolved candidates are returned in metadata. Location belongs in the dedicated city/state/postal_code inputs, not inside specialty. Each provider row includes the NPI, name, primary specialty, city/state/ZIP, type, and active/deactivated status; the NPI is the input for npi_get_provider when the full record is needed. At least one search criterion is required, and the registry rejects state-only searches. When city/state/postal_code are given, only practice addresses are searched, never mailing addresses: a provider is returned only when its primary practice location or one of its other practice locations matches all of them. A provider kept on another practice location names it in matchedLocation. Name searches also match former and other names, sorted by current name; such a row names the matching name in matchedOtherName. The registry never reports a true match total, and one search reaches only its first 1200 matches: a full page names the next in nextPage, and the terminal window (skip 1000, limit 200) returns continuationPostalCodes, postal_code prefixes that continue the search.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "npi_search_providers",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "name_search": {
      "description": "One person's name. The first token becomes first_name and the last token becomes last_name; use first_name/last_name when middle names or multi-part surnames matter.",
      "type": "string"
    },
    "first_name": {
      "description": "Individual first name. Trailing wildcard \"*\" allowed with at least 2 leading characters.",
      "type": "string"
    },
    "last_name": {
      "description": "Individual last name. Trailing wildcard \"*\" allowed with at least 2 leading characters.",
      "type": "string"
    },
    "use_first_name_alias": {
      "description": "Include first-name variants (default true upstream). False requests exact first-name matching. Applies to the resolved first_name, including name_search, only without a wildcard; other-name matching remains enabled.",
      "type": "boolean"
    },
    "organization_name": {
      "description": "Organization name (implies provider_type organization; cannot be combined with first_name, last_name, or name_search). Trailing wildcard \"*\" allowed with at least 2 leading characters.",
      "type": "string"
    },
    "provider_type": {
      "description": "Restrict to individuals (NPI-1) or organizations (NPI-2). Omit to search both; when set, it must match the name fields (\"individual\" for first_name/last_name/name_search, \"organization\" for organization_name).",
      "type": "string",
      "enum": [
        "individual",
        "organization"
      ]
    },
    "specialty": {
      "description": "Plain-language specialty (e.g. \"pediatric cardiologist\"), resolved through the bundled NUCC taxonomy to exact descriptions before searching. Codes NUCC marks inactive are never resolved. The matched taxonomy is echoed in the result. Mutually exclusive with taxonomy_description.",
      "type": "string"
    },
    "taxonomy_description": {
      "description": "Exact NUCC taxonomy description for direct passthrough — use when the taxonomy description is already known. Mutually exclusive with specialty.",
      "type": "string"
    },
    "city": {
      "description": "Practice-location city, case-insensitive. A trailing \"*\" after at least 2 characters matches every city starting with them (e.g. \"SAN F*\").",
      "type": "string",
      "pattern": "^[^*]*$|^[^*]{2,}\\*$"
    },
    "state": {
      "description": "2-letter state code (e.g. \"WA\"). The registry rejects state-only searches, so another criterion is required. A blank value is treated as omitted.",
      "anyOf": [
        {
          "type": "string",
          "const": ""
        },
        {
          "type": "string",
          "pattern": "^[A-Z]{2}$",
          "description": "2-letter state code (e.g. \"WA\")."
        }
      ]
    },
    "postal_code": {
      "description": "Practice-location ZIP code: 5 digits (also matching the ZIP+4 codes that extend it), 9 digits, or a 2–9 digit prefix with one trailing \"*\" (e.g. \"98*\", \"981*\"). A ZIP+4 prefix (6+ digits) never matches a practice address recorded with only a 5-digit ZIP.",
      "type": "string",
      "pattern": "^[^*]*$|^\\d{2,9}\\*$"
    },
    "limit": {
      "default": 10,
      "description": "Maximum providers to return (default 10). Values above 200 are clamped to the registry cap of 200 with a notice.",
      "type": "integer",
      "minimum": 1,
      "maximum": 9007199254740991
    },
    "skip": {
      "default": 0,
      "description": "Results to skip for pagination (0–1000). A full page names the next in nextPage.",
      "type": "integer",
      "minimum": 0,
      "maximum": 1000
    }
  },
  "required": [
    "limit",
    "skip"
  ],
  "additionalProperties": false
}
view source ↗

npi_get_provider

open-world

Fetch NPPES records from up to 100 raw NPI entries per call. Deduplicate in input order, validate check digits, and look up the first 10 distinct valid NPIs; remaining valid NPIs are listed in unprocessed and are never looked up. Decodes an NPI from a claim, prescription, or another health data source into the provider's professional-practice profile: every taxonomy with its primary flag, license number and state; practice addresses with phone and fax (only LOCATION rows are kept for individual providers, so their mailing address is withheld; organizations also carry their mailing address); credential, sex, sole-proprietor flag; enumeration and last-updated dates; active/deactivated status; secondary identifiers (Medicaid, etc.); and FHIR/Direct endpoints. Each NPI must be 10 digits with a valid check digit (its last digit); every NPI failing the check digit lands in invalid and is never looked up. Reports partial success: valid NPIs with no registry record (deactivated or never enumerated) land in notFound, while NPIs whose lookup hit an upstream error (registry unavailable, timeout) land in errored — kept distinct from confirmed misses — rather than failing the whole call.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "npi_get_provider",
    "arguments": {
      "npis": "<npis>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "npis": {
      "anyOf": [
        {
          "type": "string",
          "pattern": "^\\d{10}$",
          "description": "A 10-digit National Provider Identifier whose last digit is its check digit (Luhn over the number prefixed with 80840)."
        },
        {
          "minItems": 1,
          "maxItems": 100,
          "type": "array",
          "items": {
            "type": "string",
            "pattern": "^\\d{10}$",
            "description": "A 10-digit National Provider Identifier whose last digit is its check digit (Luhn over the number prefixed with 80840)."
          },
          "description": "An array of up to 100 ten-digit NPIs; only the first 10 distinct valid NPIs are looked up."
        }
      ],
      "description": "A single 10-digit NPI, or an array of up to 100. Entries are deduplicated in order, then check digits are validated; the first 10 distinct valid NPIs are looked up and any remaining valid NPIs are listed in unprocessed. Every invalid NPI is reported in invalid."
    }
  },
  "required": [
    "npis"
  ],
  "additionalProperties": false
}
view source ↗

npi_lookup_taxonomy

Resolve and browse the NUCC Healthcare Provider Taxonomy — the specialty code set NPPES uses — fully offline (bundled). Mode `resolve` turns a plain-language specialty (e.g. "cardiologist", "heart doctor") into matching active taxonomy entries, excluding codes NUCC marks inactive; mode `get` returns the full entry for an exact code, including NUCC's Notes; mode `browse` walks the hierarchy (grouping → classification → specialization), optionally filtered by grouping and NUCC section. Individual includes Group codes; section does not determine NPI entity type, which comes from NPPES enumeration_type. Every entry carries its status, and an inactive code names its replacement when NUCC gives one; `get` and `browse` still return inactive codes. A resolved entry's specialization, or its classification when specialization is absent, maps directly to npi_search_providers.taxonomy_description.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "npi_lookup_taxonomy",
    "arguments": {
      "mode": "<mode>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "mode": {
      "type": "string",
      "enum": [
        "resolve",
        "get",
        "browse"
      ],
      "description": "resolve: plain-language specialty to codes; get: exact code; browse: hierarchy."
    },
    "query": {
      "description": "The plain-language specialty term to resolve, e.g. \"pediatric cardiologist\".",
      "type": "string"
    },
    "limit": {
      "description": "Maximum entries for resolve/browse; defaults to 20. Positive integers above 50 are clamped to 50 unless NPI_CLAMP_LIMITS is disabled.",
      "type": "integer",
      "minimum": 1,
      "maximum": 9007199254740991
    },
    "skip": {
      "description": "Entries to skip before the page (0–1000). Keep the same query and limit, then raise skip by limit each call.",
      "type": "integer",
      "minimum": 0,
      "maximum": 1000
    },
    "code": {
      "description": "For get only: exact NUCC taxonomy code, e.g. \"207RC0000X\".",
      "type": "string"
    },
    "grouping": {
      "description": "Filter to a top-level grouping by case-insensitive substring, e.g. \"physicians\".",
      "type": "string"
    },
    "section": {
      "description": "For browse only: NUCC section, independent of NPI entity type. Individual includes Group codes.",
      "type": "string",
      "enum": [
        "Individual",
        "Non-Individual"
      ]
    }
  },
  "required": [
    "mode"
  ],
  "additionalProperties": false
}
view source ↗

Resources

2

A single provider's decoded NPPES record by NPI number — the resource twin of npi_get_provider for one NPI: the registry's professional-practice data, keeping only LOCATION address rows for individual providers (their mailing address is withheld). Read-only, stable URI, useful as injectable context when an NPI is already known.

uri npi://provider/{npi} mime application/json

A single NUCC Healthcare Provider Taxonomy entry by code (grouping, classification, specialization, definition, NUCC Notes, display name, NUCC section, and status — active or inactive, with the replacement code NUCC names for an inactive one). NUCC section is independent of NPPES provider entity type. Inactive codes remain readable here. The resource twin of npi_lookup_taxonomy mode "get". Fully offline.

uri npi://taxonomy/{code} mime application/json

Extensions

1

io.modelcontextprotocol/skills

{
  "directoryRead": true
}