Koskamo

npi-providers-mcp-server

An MCP server that allows agents to search the US NPPES NPI registry for healthcare providers and organizations by name, location, and specialty. It resolves plain-language specialty terms using the bundled NUCC taxonomy and fetches detailed provider records including credentials and practice addresses.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

npi-providers-mcp-server logo, by cyanheadsCommunity listingStreamable HTTPNo sign-inEndpoint checked 2026-11-07Published by cyanheads
MCP endpoint (Streamable HTTP)
https://npi-providers.caseyjhand.com/mcp
Vendor documentation

What its tools do

3 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.

3 of 3 have a description · 3 of 3 declare behavior hints · 3 of 3 with parameters document them all

Checks and signals

Each line is separate evidence, not a trust score.

  • Passed Endpoint answered the live check ·
  • Availability 1 of 1 checks passed in 30 days

What you can do with it

  • Search for individual practitioners or healthcare organizations by name and location
  • Resolve plain-language specialty terms to exact NUCC taxonomy codes
  • Fetch detailed professional practice records for specific NPIs
  • Browse the NUCC Healthcare Provider Taxonomy offline

Source and maintenance

Community listingRegistry 0.5.0
Maintenance checked

Protocol and capabilities

Server
npi-providers-mcp-server 0.5.0
MCP protocol negotiated in check
2025-11-25
Tools
3 advertised
Resources
1 advertised
Resource templates
3 advertised
Prompts
0 advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": true
  },
  "logging": {},
  "prompts": {
    "listChanged": true
  },
  "resources": {
    "subscribe": true,
    "listChanged": true
  },
  "extensions": {
    "io.modelcontextprotocol/skills": {
      "directoryRead": true
    }
  }
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

US healthcare provider directory over the live, keyless NPPES NPI Registry, plus a bundled NUCC taxonomy code set for offline specialty resolution. Public professional practice data only (name, practice address, specialty, credential, NPI) — no personal or home data, so only practice-location (LOCATION) addresses are kept for individual providers and their mailing address is withheld. Typical flow: npi_search_providers (resolve a name/specialty/place to candidate NPIs) → npi_get_provider (decode one or more NPIs to their provider records). Ground plain-language specialties with npi_lookup_taxonomy before searching. The registry never reports a true match total and one search reaches only its first 1200 matches by skip; npi_search_providers names the next page, and at that terminal window returns postal_code prefixes that continue the search.

Tools

3 advertised

npi_search_providers — Npi Search Providers
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-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.

npi_search_providers input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "city": {
      "type": "string",
      "pattern": "^[^*]*$|^[^*]{2,}\\*$",
      "description": "Practice-location city, case-insensitive. A trailing \"*\" after at least 2 characters matches every city starting with them (e.g. \"SAN F*\")."
    },
    "skip": {
      "type": "integer",
      "default": 0,
      "maximum": 1000,
      "minimum": 0,
      "description": "Results to skip for pagination (0–1000). A full page names the next in nextPage."
    },
    "limit": {
      "type": "integer",
      "default": 10,
      "maximum": 9007199254740991,
      "minimum": 1,
      "description": "Maximum providers to return (default 10). Values above 200 are clamped to the registry cap of 200 with a notice."
    },
    "state": {
      "anyOf": [
        {
          "type": "string",
          "const": ""
        },
        {
          "type": "string",
          "pattern": "^[A-Z]{2}$",
          "description": "2-letter state code (e.g. \"WA\")."
        }
      ],
      "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."
    },
    "last_name": {
      "type": "string",
      "description": "Individual last name. Trailing wildcard \"*\" allowed with at least 2 leading characters."
    },
    "specialty": {
      "type": "string",
      "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."
    },
    "first_name": {
      "type": "string",
      "description": "Individual first name. Trailing wildcard \"*\" allowed with at least 2 leading characters."
    },
    "name_search": {
      "type": "string",
      "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."
    },
    "postal_code": {
      "type": "string",
      "pattern": "^[^*]*$|^\\d{2,9}\\*$",
      "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."
    },
    "provider_type": {
      "enum": [
        "individual",
        "organization"
      ],
      "type": "string",
      "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)."
    },
    "organization_name": {
      "type": "string",
      "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."
    },
    "taxonomy_description": {
      "type": "string",
      "description": "Exact NUCC taxonomy description for direct passthrough — use when the taxonomy description is already known. Mutually exclusive with specialty."
    },
    "use_first_name_alias": {
      "type": "boolean",
      "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."
    }
  },
  "additionalProperties": false
}
npi_search_providers output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "providers"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "cap": {
      "type": "number",
      "description": "The limit that was applied."
    },
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "no_search_criteria",
                "conflicting_specialty",
                "mixed_provider_criteria",
                "unresolved_specialty",
                "invalid_search_field"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `no_search_criteria`: No effective search criterion was provided. `conflicting_specialty`: Both specialty and taxonomy_description were supplied. `mixed_provider_criteria`: Individual criteria (first_name, last_name, name_search) were combined with organization criteria (organization_name), directly or through provider_type. `unresolved_specialty`: The specialty term matched no active NUCC taxonomy (the message names any inactive codes it matched), or was made only of generic words (\"doctor\", \"M.D.\", \"specialist\") that name no specialty. `invalid_search_field`: The registry returned a field error (e.g. wildcard under 2 characters, bad provider type). Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "shown": {
      "type": "number",
      "description": "Number of providers returned."
    },
    "notice": {
      "type": "string",
      "description": "Guidance — the page-size-not-total caveat, the next page or terminal-window continuation procedure, other-name and location-filter counts, or how to broaden an empty result."
    },
    "nextPage": {
      "type": "object",
      "required": [
        "skip",
        "limit"
      ],
      "properties": {
        "skip": {
          "type": "number",
          "description": "The skip to send for the next page."
        },
        "limit": {
          "type": "number",
          "description": "The limit to send for the next page."
        }
      },
      "description": "The next page: re-run the same arguments with this skip and limit. Present after a full page while rows remain reachable. When skip + limit passes 1000 it is skip 1000, limit 200, whose leading rows repeat rows already returned (the notice says how many) — dedupe by NPI.",
      "additionalProperties": false
    },
    "providers": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "npi",
          "type",
          "name",
          "status"
        ],
        "properties": {
          "npi": {
            "type": "string",
            "description": "10-digit National Provider Identifier — the chaining key for npi_get_provider."
          },
          "city": {
            "type": "string",
            "description": "Primary practice-location city when present."
          },
          "name": {
            "type": "string",
            "description": "Assembled \"First Last\" (individual) or organization name."
          },
          "type": {
            "enum": [
              "individual",
              "organization"
            ],
            "type": "string",
            "description": "Provider enumeration type (NPI-1 vs NPI-2)."
          },
          "state": {
            "type": "string",
            "description": "Primary practice-location state when present."
          },
          "status": {
            "enum": [
              "active",
              "deactivated"
            ],
            "type": "string",
            "description": "Registry status — never treat a deactivated NPI as current."
          },
          "credential": {
            "type": "string",
            "description": "Credential (e.g. \"MD\", \"DO\", \"RN\") when present."
          },
          "postalCode": {
            "type": "string",
            "description": "Primary practice-location postal/ZIP code when present."
          },
          "matchedLocation": {
            "type": "object",
            "properties": {
              "city": {
                "type": "string",
                "description": "City of the matching practice location."
              },
              "state": {
                "type": "string",
                "description": "State of the matching practice location."
              },
              "postalCode": {
                "type": "string",
                "description": "Postal/ZIP code of the matching practice location."
              }
            },
            "description": "The additional practice location that satisfied the requested city/state/postal_code. Present only when the primary practice location is elsewhere.",
            "additionalProperties": false
          },
          "primaryTaxonomy": {
            "type": "object",
            "required": [
              "code"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Primary taxonomy code."
              },
              "description": {
                "type": "string",
                "description": "Primary taxonomy description."
              }
            },
            "description": "The provider's primary taxonomy (the entry flagged primary, else the first listed).",
            "additionalProperties": false
          },
          "matchedOtherName": {
            "type": "object",
            "required": [
              "name"
            ],
            "properties": {
              "name": {
                "type": "string",
                "description": "The other name as \"First Middle Last\", or its organization name."
              },
              "type": {
                "type": "string",
                "description": "Registry name type, e.g. \"Former Name\", \"Professional Name\"."
              }
            },
            "description": "The other (former, professional, DBA, or alternate) name this row matched the name search through. Present only when the current name fails a requested last_name, organization_name, or wildcard first_name and this other name satisfies it (case-insensitive, ignoring punctuation and spaces, trailing \"*\" as a prefix). An exact first_name alone never marks a row: the registry also matches first-name variants (Bob for Robert).",
            "additionalProperties": false
          }
        },
        "description": "A compact provider row for disambiguation.",
        "additionalProperties": false
      },
      "description": "Matching provider rows (up to limit)."
    },
    "truncated": {
      "type": "boolean",
      "description": "True when the NPPES page contained at least cap providers before location constraints were applied; more may match even when shown is below cap."
    },
    "resolvedTaxonomies": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "code",
          "description"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Resolved NUCC taxonomy code."
          },
          "description": {
            "type": "string",
            "description": "Search-compatible NUCC specialization or classification for this candidate."
          }
        },
        "additionalProperties": false
      },
      "description": "Taxonomy candidates ranked for the specialty term. The first candidate supplies appliedTaxonomyDescription; a different candidate can be selected through taxonomy_description."
    },
    "appliedFirstNameAlias": {
      "type": "boolean",
      "description": "Effective first-name alias expansion for a resolved non-wildcard first name, including the upstream default true. Absent when no first name exists or it contains a wildcard."
    },
    "continuationPostalCodes": {
      "type": "array",
      "items": {
        "type": "string",
        "description": "A trailing-\"*\" postal_code prefix."
      },
      "description": "Present only at the terminal window (a full page at skip 1000, limit 200): postal_code prefixes that continue the same search, each re-run from skip 0 with the same arguments — the notice gives the full procedure. Empty when no postal split remains (postal_code is already a 5-digit ZIP, a full ZIP+4, or not a numeric ZIP prefix)."
    },
    "appliedTaxonomyDescription": {
      "type": "string",
      "description": "The exact NUCC specialization or classification used as the specialty filter."
    }
  },
  "additionalProperties": false
}
npi_search_providers annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true
}
npi_get_provider — Npi Get Provider
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-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.

npi_get_provider input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "npis"
  ],
  "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)."
        },
        {
          "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)."
          },
          "maxItems": 100,
          "minItems": 1,
          "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."
    }
  },
  "additionalProperties": false
}
npi_get_provider output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "found",
        "notFound",
        "errored",
        "invalid",
        "totalCount"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "none_found",
                "invalid_npi_format"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `none_found`: Every attempted NPI lookup returned a confirmed no-record response — none failed with an upstream error (those surface as the underlying service/timeout error instead). Unprocessed NPIs remain unresolved. `invalid_npi_format`: Every requested NPI failed the NPI check digit, so none was looked up. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "found": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "npi",
          "type",
          "status",
          "name",
          "taxonomies",
          "addresses",
          "practiceLocations",
          "identifiers",
          "otherNames",
          "endpoints"
        ],
        "properties": {
          "npi": {
            "type": "string",
            "description": "10-digit National Provider Identifier."
          },
          "sex": {
            "type": "string",
            "description": "Sex code, for individuals, when present."
          },
          "name": {
            "type": "string",
            "description": "Assembled \"First Last\" or organization name."
          },
          "type": {
            "enum": [
              "individual",
              "organization"
            ],
            "type": "string",
            "description": "Enumeration type (NPI-1 vs NPI-2)."
          },
          "status": {
            "enum": [
              "active",
              "deactivated"
            ],
            "type": "string",
            "description": "Registry status — never treat a deactivated NPI as current."
          },
          "lastName": {
            "type": "string",
            "description": "Last name, for individuals."
          },
          "addresses": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "city": {
                  "type": "string",
                  "description": "City."
                },
                "line1": {
                  "type": "string",
                  "description": "Address line 1."
                },
                "line2": {
                  "type": "string",
                  "description": "Address line 2."
                },
                "state": {
                  "type": "string",
                  "description": "State."
                },
                "purpose": {
                  "type": "string",
                  "description": "Address purpose: LOCATION (practice) or MAILING. Only LOCATION rows are kept for individual providers; organizations also carry MAILING."
                },
                "faxNumber": {
                  "type": "string",
                  "description": "Fax number, when present."
                },
                "postalCode": {
                  "type": "string",
                  "description": "Postal/ZIP code."
                },
                "addressType": {
                  "type": "string",
                  "description": "Address type (DOM domestic or FOR foreign)."
                },
                "countryCode": {
                  "type": "string",
                  "description": "ISO country code."
                },
                "countryName": {
                  "type": "string",
                  "description": "Country name."
                },
                "telephoneNumber": {
                  "type": "string",
                  "description": "Telephone number, when present."
                }
              },
              "description": "A practice (LOCATION) address, or an organization mailing address.",
              "additionalProperties": false
            },
            "description": "Registry addresses. Only LOCATION (practice) rows are kept for individual providers — their mailing address is withheld; organizations carry both LOCATION and MAILING rows."
          },
          "endpoints": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "endpoint"
              ],
              "properties": {
                "use": {
                  "type": "string",
                  "description": "Endpoint use code (e.g. \"HIE\"), when present."
                },
                "city": {
                  "type": "string",
                  "description": "Endpoint city, when present."
                },
                "line1": {
                  "type": "string",
                  "description": "Endpoint address line 1, when present."
                },
                "line2": {
                  "type": "string",
                  "description": "Endpoint address line 2, when present."
                },
                "state": {
                  "type": "string",
                  "description": "Endpoint state, when present."
                },
                "endpoint": {
                  "type": "string",
                  "description": "The endpoint URI/address."
                },
                "postalCode": {
                  "type": "string",
                  "description": "Endpoint postal/ZIP code, when present."
                },
                "addressType": {
                  "type": "string",
                  "description": "Endpoint address type (DOM/FOR), when present."
                },
                "affiliation": {
                  "type": "string",
                  "description": "Whether the endpoint is affiliated with an organization (Y/N), when present."
                },
                "contentType": {
                  "type": "string",
                  "description": "Endpoint content type code, when present."
                },
                "countryCode": {
                  "type": "string",
                  "description": "Endpoint ISO country code, when present."
                },
                "countryName": {
                  "type": "string",
                  "description": "Endpoint country name, when present."
                },
                "endpointType": {
                  "type": "string",
                  "description": "Endpoint type code (e.g. \"DIRECT\", \"FHIR\")."
                },
                "useDescription": {
                  "type": "string",
                  "description": "Endpoint use description, when present."
                },
                "affiliationName": {
                  "type": "string",
                  "description": "Name of the affiliated organization, when present."
                },
                "endpointDescription": {
                  "type": "string",
                  "description": "Free-text description of the endpoint (e.g. \"Carequality\"), when present."
                },
                "useOtherDescription": {
                  "type": "string",
                  "description": "What the endpoint is used for when the use code is OTHER, when present."
                },
                "contentTypeDescription": {
                  "type": "string",
                  "description": "Endpoint content type description, when present."
                },
                "contentOtherDescription": {
                  "type": "string",
                  "description": "The content the endpoint carries when the content type is OTHER (e.g. \"C-CDA\"), when present."
                },
                "endpointTypeDescription": {
                  "type": "string",
                  "description": "Endpoint type description."
                }
              },
              "description": "A FHIR or Direct messaging endpoint with its routing address and context.",
              "additionalProperties": false
            },
            "description": "FHIR / Direct endpoints, when present."
          },
          "firstName": {
            "type": "string",
            "description": "First name, for individuals."
          },
          "credential": {
            "type": "string",
            "description": "Credential (e.g. \"MD\"), when present."
          },
          "middleName": {
            "type": "string",
            "description": "Middle name, when present."
          },
          "namePrefix": {
            "type": "string",
            "description": "Name prefix (e.g. \"Dr.\"), when present."
          },
          "nameSuffix": {
            "type": "string",
            "description": "Name suffix (e.g. \"Jr.\"), when present."
          },
          "otherNames": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "description": "Other-name type (former name, DBA, etc.)."
                },
                "prefix": {
                  "type": "string",
                  "description": "Name prefix, when present."
                },
                "suffix": {
                  "type": "string",
                  "description": "Name suffix, when present."
                },
                "lastName": {
                  "type": "string",
                  "description": "Last name, for individuals."
                },
                "firstName": {
                  "type": "string",
                  "description": "First name, for individuals."
                },
                "credential": {
                  "type": "string",
                  "description": "Credential, when present."
                },
                "middleName": {
                  "type": "string",
                  "description": "Middle name, for individuals, when present."
                },
                "organizationName": {
                  "type": "string",
                  "description": "Organization name, for organizations."
                }
              },
              "description": "A former or alternate name.",
              "additionalProperties": false
            },
            "description": "Former / alternate names, when present."
          },
          "taxonomies": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "code",
                "primary"
              ],
              "properties": {
                "code": {
                  "type": "string",
                  "description": "Taxonomy code."
                },
                "state": {
                  "type": "string",
                  "description": "License state for this taxonomy, when present."
                },
                "license": {
                  "type": "string",
                  "description": "License number for this taxonomy, when present."
                },
                "primary": {
                  "type": "boolean",
                  "description": "Whether this is the provider's primary taxonomy."
                },
                "description": {
                  "type": "string",
                  "description": "Taxonomy description."
                },
                "taxonomyGroup": {
                  "type": "string",
                  "description": "Taxonomy group, when present."
                }
              },
              "description": "A taxonomy (specialty) on the record.",
              "additionalProperties": false
            },
            "description": "All taxonomies (specialties) on the record."
          },
          "identifiers": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "identifier"
              ],
              "properties": {
                "code": {
                  "type": "string",
                  "description": "Identifier type code."
                },
                "state": {
                  "type": "string",
                  "description": "Associated state, when present."
                },
                "issuer": {
                  "type": "string",
                  "description": "Issuing organization, when present."
                },
                "identifier": {
                  "type": "string",
                  "description": "The secondary identifier value."
                },
                "description": {
                  "type": "string",
                  "description": "Identifier type description (e.g. \"MEDICAID\")."
                }
              },
              "description": "A secondary identifier (Medicaid, etc.).",
              "additionalProperties": false
            },
            "description": "Secondary identifiers (Medicaid, etc.), when present."
          },
          "lastUpdated": {
            "type": "string",
            "description": "Date the record was last updated."
          },
          "createdEpoch": {
            "type": "number",
            "description": "Record creation timestamp, epoch milliseconds, when present."
          },
          "soleProprietor": {
            "type": "string",
            "description": "Sole-proprietor flag (YES/NO), when present."
          },
          "enumerationDate": {
            "type": "string",
            "description": "Date the NPI was enumerated."
          },
          "lastUpdatedEpoch": {
            "type": "number",
            "description": "Record last-update timestamp, epoch milliseconds, when present."
          },
          "organizationName": {
            "type": "string",
            "description": "Organization legal name, for organizations."
          },
          "certificationDate": {
            "type": "string",
            "description": "Certification date, when present."
          },
          "practiceLocations": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "city": {
                  "type": "string",
                  "description": "City."
                },
                "line1": {
                  "type": "string",
                  "description": "Address line 1."
                },
                "line2": {
                  "type": "string",
                  "description": "Address line 2."
                },
                "state": {
                  "type": "string",
                  "description": "State."
                },
                "purpose": {
                  "type": "string",
                  "description": "Address purpose: LOCATION (practice) or MAILING. Only LOCATION rows are kept for individual providers; organizations also carry MAILING."
                },
                "faxNumber": {
                  "type": "string",
                  "description": "Fax number, when present."
                },
                "postalCode": {
                  "type": "string",
                  "description": "Postal/ZIP code."
                },
                "addressType": {
                  "type": "string",
                  "description": "Address type (DOM domestic or FOR foreign)."
                },
                "countryCode": {
                  "type": "string",
                  "description": "ISO country code."
                },
                "countryName": {
                  "type": "string",
                  "description": "Country name."
                },
                "telephoneNumber": {
                  "type": "string",
                  "description": "Telephone number, when present."
                }
              },
              "description": "A practice (LOCATION) address, or an organization mailing address.",
              "additionalProperties": false
            },
            "description": "Additional practice locations, when present."
          },
          "authorizedOfficial": {
            "type": "object",
            "properties": {
              "title": {
                "type": "string",
                "description": "Authorized official title or position."
              },
              "lastName": {
                "type": "string",
                "description": "Authorized official last name."
              },
              "firstName": {
                "type": "string",
                "description": "Authorized official first name."
              },
              "credential": {
                "type": "string",
                "description": "Authorized official credential."
              },
              "middleName": {
                "type": "string",
                "description": "Authorized official middle name."
              },
              "namePrefix": {
                "type": "string",
                "description": "Authorized official name prefix, when present."
              },
              "nameSuffix": {
                "type": "string",
                "description": "Authorized official name suffix, when present."
              },
              "telephoneNumber": {
                "type": "string",
                "description": "Authorized official telephone number."
              }
            },
            "description": "Authorized official block, for organizations.",
            "additionalProperties": false
          },
          "organizationalSubpart": {
            "type": "string",
            "description": "Organizational subpart flag, for organizations."
          }
        },
        "description": "A decoded NPPES provider record — the registry's professional-practice data. Only LOCATION address rows are kept for individual providers.",
        "additionalProperties": false
      },
      "description": "Decoded records for NPIs that resolved."
    },
    "notice": {
      "type": "string",
      "description": "Guidance when some NPIs failed the check digit, returned no record, or hit an upstream error."
    },
    "errored": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "npi",
          "reason"
        ],
        "properties": {
          "npi": {
            "type": "string",
            "description": "The requested NPI whose lookup failed operationally."
          },
          "reason": {
            "type": "string",
            "description": "The upstream failure reason (service unavailable, timeout, etc.)."
          }
        },
        "description": "A requested NPI whose lookup failed with an upstream error.",
        "additionalProperties": false
      },
      "description": "NPIs whose lookups failed with an upstream/transport error (service unavailable, timeout) — distinct from a confirmed miss in notFound. These are unresolved, not absent; retry them."
    },
    "invalid": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "npi",
          "reason"
        ],
        "properties": {
          "npi": {
            "type": "string",
            "description": "The requested NPI that failed the check digit."
          },
          "reason": {
            "type": "string",
            "description": "Why the NPI was rejected."
          }
        },
        "description": "A requested NPI that failed the NPI check digit.",
        "additionalProperties": false
      },
      "description": "NPIs that failed the NPI check digit — not valid NPIs, usually a typo. They were never looked up, so they are neither confirmed misses nor upstream failures."
    },
    "notFound": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "npi",
          "reason"
        ],
        "properties": {
          "npi": {
            "type": "string",
            "description": "The requested NPI with no record."
          },
          "reason": {
            "type": "string",
            "description": "Why it returned nothing (e.g. no registry record)."
          }
        },
        "description": "A requested NPI that returned no record.",
        "additionalProperties": false
      },
      "description": "NPIs with a valid check digit that returned no record (deactivated or never enumerated). A confirmed absence, not a failure."
    },
    "totalCount": {
      "type": "number",
      "description": "Number of provider records that resolved from the requested NPIs."
    },
    "unprocessed": {
      "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": "Distinct valid NPIs beyond the first 10, in input order; not looked up. Present only when the lookup limit is exceeded."
    }
  },
  "additionalProperties": false
}
npi_get_provider annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true
}
npi_lookup_taxonomy — Npi Lookup Taxonomy
Advertised by the server during the last successful anonymous check.
Advertised read-only

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.

npi_lookup_taxonomy input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "mode"
  ],
  "properties": {
    "code": {
      "type": "string",
      "description": "For get only: exact NUCC taxonomy code, e.g. \"207RC0000X\"."
    },
    "mode": {
      "enum": [
        "resolve",
        "get",
        "browse"
      ],
      "type": "string",
      "description": "resolve: plain-language specialty to codes; get: exact code; browse: hierarchy."
    },
    "skip": {
      "type": "integer",
      "maximum": 1000,
      "minimum": 0,
      "description": "Entries to skip before the page (0–1000). Keep the same query and limit, then raise skip by limit each call."
    },
    "limit": {
      "type": "integer",
      "maximum": 9007199254740991,
      "minimum": 1,
      "description": "Maximum entries for resolve/browse; defaults to 20. Positive integers above 50 are clamped to 50 unless NPI_CLAMP_LIMITS is disabled."
    },
    "query": {
      "type": "string",
      "description": "The plain-language specialty term to resolve, e.g. \"pediatric cardiologist\"."
    },
    "section": {
      "enum": [
        "Individual",
        "Non-Individual"
      ],
      "type": "string",
      "description": "For browse only: NUCC section, independent of NPI entity type. Individual includes Group codes."
    },
    "grouping": {
      "type": "string",
      "description": "Filter to a top-level grouping by case-insensitive substring, e.g. \"physicians\"."
    }
  },
  "additionalProperties": false
}
npi_lookup_taxonomy output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "matches"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "cap": {
      "type": "number",
      "description": "The limit that was applied."
    },
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "no_match",
                "missing_argument",
                "wrong_mode_argument"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `no_match`: A get code matched no taxonomy entry, a resolve query matched no active one (the message names any inactive codes it matched), or a resolve query was made only of generic words (\"doctor\", \"M.D.\", \"specialist\") that name no specialty. `missing_argument`: The required query or code was missing or blank after trimming. `wrong_mode_argument`: An explicitly supplied field belongs to a different mode. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "shown": {
      "type": "number",
      "description": "Number of entries returned."
    },
    "notice": {
      "type": "string",
      "description": "Guidance — how to page a truncated result with skip, or how to broaden when nothing matched."
    },
    "matches": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "code",
          "grouping",
          "classification",
          "displayName",
          "section",
          "status"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "NUCC taxonomy code, e.g. \"207RC0000X\"."
          },
          "notes": {
            "type": "string",
            "description": "NUCC Notes: sources, revision history, and status remarks. Returned by mode \"get\" only, when NUCC records a note."
          },
          "status": {
            "enum": [
              "active",
              "inactive"
            ],
            "type": "string",
            "description": "NUCC status. Inactive codes are no longer maintained: mode \"resolve\" excludes them, while \"get\" and \"browse\" return them."
          },
          "section": {
            "enum": [
              "Individual",
              "Non-Individual"
            ],
            "type": "string",
            "description": "NUCC section. Individual includes Group codes; Non-Individual covers facilities, suppliers and agencies. Provider entity type comes from NPPES enumeration_type."
          },
          "grouping": {
            "type": "string",
            "description": "Top-level grouping, e.g. \"Allopathic & Osteopathic Physicians\"."
          },
          "definition": {
            "type": "string",
            "description": "Scope note / definition. Absent for a handful of codes."
          },
          "replacedBy": {
            "type": "string",
            "description": "For an inactive code, the active replacement code NUCC names, when it names one."
          },
          "displayName": {
            "type": "string",
            "description": "Human-readable display name, e.g. \"Cardiovascular Disease Physician\"."
          },
          "classification": {
            "type": "string",
            "description": "Classification within the grouping, e.g. \"Internal Medicine\"."
          },
          "specialization": {
            "type": "string",
            "description": "Specialization within the classification, e.g. \"Cardiovascular Disease\". Absent for top-level classification codes."
          }
        },
        "description": "A single NUCC taxonomy entry.",
        "additionalProperties": false
      },
      "description": "Matching taxonomy entries. For mode \"get\" this is the single requested entry; for \"resolve\"/\"browse\" it is the ranked/sorted matches up to limit."
    },
    "truncated": {
      "type": "boolean",
      "description": "True when the list was capped at `limit` (more entries may match)."
    }
  },
  "additionalProperties": false
}
npi_lookup_taxonomy annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}

Prompts

0 advertised

No prompt definitions available.

Resources

1 advertised

npi-providers-guide

Advertised by the server during the last successful anonymous check.

Select and verify specialty cohorts with npi_* tools. Use when a provider search needs an exact specialty, an ambiguous professional category, or a defensible completeness claim.

npi-providers-guide URI
skill://npi-providers-guide/SKILL.md

MIME type: text/markdown

npi-provider — NPI provider record

Advertised by the server during the last successful anonymous check.

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.

npi-provider URI template
npi://provider/{npi}

MIME type: application/json

npi-taxonomy — NUCC taxonomy entry

Advertised by the server during the last successful anonymous check.

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.

npi-taxonomy URI template
npi://taxonomy/{code}

MIME type: application/json

io.modelcontextprotocol/skills

Advertised by the server during the last successful anonymous check.

io.modelcontextprotocol/skills URI template
skill://{+path}

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
571 ms
95th percentile latency
571 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 571 ms · metadata changed · 3 tool(s), 1 resource(s), 3 resource template(s), 0 prompt(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http npi-providers-mcp-server-caseyjhand https://npi-providers.caseyjhand.com/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add npi-providers-mcp-server-caseyjhand --url https://npi-providers.caseyjhand.com/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable npi-providers-mcp-server-caseyjhand in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "npi-providers-mcp-server-caseyjhand": {
      "url": "https://npi-providers.caseyjhand.com/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "npi-providers-mcp-server-caseyjhand": {
      "type": "streamableHttp",
      "url": "https://npi-providers.caseyjhand.com/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start npi-providers-mcp-server-caseyjhand and inspect its tools.
VS Code configuration
{
  "servers": {
    "npi-providers-mcp-server-caseyjhand": {
      "type": "http",
      "url": "https://npi-providers.caseyjhand.com/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http npi-providers-mcp-server-caseyjhand https://npi-providers.caseyjhand.com/mcp

Claude Desktop

Open Claude Settings > Connectors > Add custom connector, enter this server URL and enable it for the conversation. This is a manual remote-connector handoff, not a desktop JSON configuration.
Claude Desktop configuration
https://npi-providers.caseyjhand.com/mcp

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "npi-providers-mcp-server-caseyjhand": {
      "serverUrl": "https://npi-providers.caseyjhand.com/mcp"
    }
  }
}

Let your agent find its tools

Find servers like npi-providers-mcp-server from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.