Skip to main content
Glama

npi-providers-mcp-server

Npi Search Providers

npi_search_providers
Read-onlyIdempotent

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.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
cityNoPractice-location city, case-insensitive. A trailing "*" after at least 2 characters matches every city starting with them (e.g. "SAN F*").
skipNoResults to skip for pagination (0–1000). A full page names the next in nextPage.
limitNoMaximum providers to return (1–200; the registry caps at 200).
stateNo2-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_nameNoIndividual last name. Trailing wildcard "*" allowed with at least 2 leading characters.
specialtyNoPlain-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_nameNoIndividual first name. Trailing wildcard "*" allowed with at least 2 leading characters.
name_searchNoOne 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_codeNoPractice-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_typeNoRestrict 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_nameNoOrganization 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_descriptionNoExact NUCC taxonomy description for direct passthrough — use when the taxonomy description is already known. Mutually exclusive with specialty.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
capNoThe limit that was applied.
errorNoPresent when the call failed. Absent on success.
shownNoNumber of providers returned.
noticeNoGuidance — 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.
nextPageNoThe 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.
providersNoMatching provider rows (up to limit).
truncatedNoTrue when the NPPES page contained at least cap providers before location constraints were applied; more may match even when shown is below cap.
resolvedTaxonomiesNoTaxonomy candidates ranked for the specialty term. The first candidate supplies appliedTaxonomyDescription; a different candidate can be selected through taxonomy_description.
continuationPostalCodesNoPresent 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).
appliedTaxonomyDescriptionNoThe exact NUCC specialization or classification used as the specialty filter.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed13 schema fields changed
    • changedInput schema / properties / city / description
      Previous value: -"Practice-location city."New value: +"Practice-location city, case-insensitive. A trailing \"*\" after at least 2 characters matches every city starting with them (e.g. \"SAN F*\")."
    • addedInput schema / properties / city / pattern
      Added value: +"^[^*]*$|^[^*]{2,}\\*$"
    • changedInput schema / properties / organization_name / description
      Previous value: -"Organization name (implies provider_type organization). Trailing wildcard \"*\" allowed with at least 2 leading characters."New value: +"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."
    • changedInput schema / properties / postal_code / description
      Previous value: -"Practice-location postal/ZIP code (5 or 9 digits)."New value: +"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."
    • addedInput schema / properties / postal_code / pattern
      Added value: +"^[^*]*$|^\\d{2,9}\\*$"
    • changedInput schema / properties / provider_type / description
      Previous value: -"Restrict to individuals (NPI-1) or organizations (NPI-2). Omit to search both."New value: +"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)."
    • changedInput schema / properties / skip / description
      Previous value: -"Results to skip for pagination (0–1000). Only the first 1200 matches are reachable; skip beyond 1000 silently returns the same window — narrow the query instead of paging further."New value: +"Results to skip for pagination (0–1000). A full page names the next in nextPage."
    • addedOutput schema / properties / continuationPostalCodes
      Added value: +{
      +  "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).",
      +  "items": {
      +    "description": "A trailing-\"*\" postal_code prefix.",
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"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. `unresolved_specialty`: The specialty term matched no active NUCC taxonomy (the message names any inactive codes it matched). `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."New value: +"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."
    • changedOutput schema / properties / error / properties / data / properties / reason / examples
      Previous value: -[
      -  "no_search_criteria",
      -  "conflicting_specialty",
      -  "unresolved_specialty",
      -  "invalid_search_field"
      -]New value: +[
      +  "no_search_criteria",
      +  "conflicting_specialty",
      +  "mixed_provider_criteria",
      +  "unresolved_specialty",
      +  "invalid_search_field"
      +]
    • addedOutput schema / properties / nextPage
      Added value: +{
      +  "additionalProperties": false,
      +  "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.",
      +  "properties": {
      +    "limit": {
      +      "description": "The limit to send for the next page.",
      +      "type": "number"
      +    },
      +    "skip": {
      +      "description": "The skip to send for the next page.",
      +      "type": "number"
      +    }
      +  },
      +  "required": [
      +    "skip",
      +    "limit"
      +  ],
      +  "type": "object"
      +}
    • changedOutput schema / properties / notice / description
      Previous value: -"Guidance — pagination ceiling, page-size-not-total caveat, or how to broaden an empty result."New value: +"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."
    • addedOutput schema / properties / providers / items / properties / matchedOtherName
      Added value: +{
      +  "additionalProperties": false,
      +  "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).",
      +  "properties": {
      +    "name": {
      +      "description": "The other name as \"First Middle Last\", or its organization name.",
      +      "type": "string"
      +    },
      +    "type": {
      +      "description": "Registry name type, e.g. \"Former Name\", \"Professional Name\".",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "name"
      +  ],
      +  "type": "object"
      +}
  2. Changed2 schema fields changed
    • changedInput schema / properties / specialty / description
      Previous value: -"Plain-language specialty (e.g. \"pediatric cardiologist\"), resolved through the bundled NUCC taxonomy to exact descriptions before searching. The matched taxonomy is echoed in the result. Mutually exclusive with taxonomy_description."New value: +"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."
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"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. `unresolved_specialty`: The specialty term matched no NUCC taxonomy. `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."New value: +"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. `unresolved_specialty`: The specialty term matched no active NUCC taxonomy (the message names any inactive codes it matched). `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."
  3. Changed4 schema fields changed
    • changedOutput schema / properties / providers / items / properties / city / description
      Previous value: -"Practice-location city when present."New value: +"Primary practice-location city when present."
    • addedOutput schema / properties / providers / items / properties / matchedLocation
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "The additional practice location that satisfied the requested city/state/postal_code. Present only when the primary practice location is elsewhere.",
      +  "properties": {
      +    "city": {
      +      "description": "City of the matching practice location.",
      +      "type": "string"
      +    },
      +    "postalCode": {
      +      "description": "Postal/ZIP code of the matching practice location.",
      +      "type": "string"
      +    },
      +    "state": {
      +      "description": "State of the matching practice location.",
      +      "type": "string"
      +    }
      +  },
      +  "type": "object"
      +}
    • changedOutput schema / properties / providers / items / properties / postalCode / description
      Previous value: -"Practice-location postal/ZIP code when present."New value: +"Primary practice-location postal/ZIP code when present."
    • changedOutput schema / properties / providers / items / properties / state / description
      Previous value: -"Practice-location state when present."New value: +"Primary practice-location state when present."
  4. Changed12 schema fields changed
    • changedInput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedInput schema / additionalProperties
      Added value: +false
    • changedInput schema / properties / name_search / description
      Previous value: -"Convenience shortcut: a single person's name, split into first/last heuristically. For precise control use first_name/last_name."New value: +"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."
    • changedInput schema / properties / state / description
      Previous value: -"2-letter state code (e.g. \"WA\"). The registry rejects state-only searches — pair it with another criterion. Blank values from form-based clients are treated as omitted."New value: +"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."
    • changedOutput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedOutput schema / anyOf
      Added value: +[
      +  {
      +    "not": {
      +      "required": [
      +        "error"
      +      ]
      +    },
      +    "required": [
      +      "providers"
      +    ]
      +  },
      +  {
      +    "required": [
      +      "error"
      +    ]
      +  }
      +]
    • changedOutput schema / properties / appliedTaxonomyDescription / description
      Previous value: -"The single taxonomy_description sent to the registry (from specialty resolution or the raw escape hatch)."New value: +"The exact NUCC specialization or classification used as the specialty filter."
    • addedOutput schema / properties / error
      Added value: +{
      +  "additionalProperties": {},
      +  "description": "Present when the call failed. Absent on success.",
      +  "properties": {
      +    "code": {
      +      "description": "JSON-RPC error code for this failure.",
      +      "maximum": 9007199254740991,
      +      "minimum": -9007199254740991,
      +      "type": "integer"
      +    },
      +    "data": {
      +      "additionalProperties": {},
      +      "properties": {
      +        "reason": {
      +          "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. `unresolved_specialty`: The specialty term matched no NUCC taxonomy. `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.",
      +          "examples": [
      +            "no_search_criteria",
      +            "conflicting_specialty",
      +            "unresolved_specialty",
      +            "invalid_search_field"
      +          ],
      +          "type": "string"
      +        },
      +        "recovery": {
      +          "additionalProperties": {},
      +          "description": "Actionable next step for the caller.",
      +          "properties": {
      +            "hint": {
      +              "type": "string"
      +            }
      +          },
      +          "required": [
      +            "hint"
      +          ],
      +          "type": "object"
      +        },
      +        "retryable": {
      +          "description": "Whether retrying may succeed.",
      +          "type": "boolean"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "message": {
      +      "description": "Human-readable description of what went wrong.",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "code",
      +    "message"
      +  ],
      +  "type": "object"
      +}
    • changedOutput schema / properties / resolvedTaxonomies / description
      Previous value: -"The taxonomy candidates the specialty term resolved to; the first was sent to the registry. Re-run with taxonomy_description to pick a different one."New value: +"Taxonomy candidates ranked for the specialty term. The first candidate supplies appliedTaxonomyDescription; a different candidate can be selected through taxonomy_description."
    • changedOutput schema / properties / resolvedTaxonomies / items / properties / description / description
      Previous value: -"The taxonomy description (specialization or classification) the registry matched on — the value sent as taxonomy_description."New value: +"Search-compatible NUCC specialization or classification for this candidate."
    • changedOutput schema / properties / truncated / description
      Previous value: -"True when the returned page hit the limit — more may match."New value: +"True when the NPPES page contained at least cap providers before location constraints were applied; more may match even when shown is below cap."
    • removedOutput schema / required
      Removed value: -[
      -  "providers"
      -]
  5. Changed5 schema fields changed
    • addedInput schema / properties / state / anyOf
      Added value: +[
      +  {
      +    "const": "",
      +    "type": "string"
      +  },
      +  {
      +    "description": "2-letter state code (e.g. \"WA\").",
      +    "pattern": "^[A-Z]{2}$",
      +    "type": "string"
      +  }
      +]
    • changedInput schema / properties / state / description
      Previous value: -"2-letter state code (e.g. \"WA\"). The registry rejects state-only searches — pair it with another criterion."New value: +"2-letter state code (e.g. \"WA\"). The registry rejects state-only searches — pair it with another criterion. Blank values from form-based clients are treated as omitted."
    • removedInput schema / properties / state / pattern
      Removed value: -"^[A-Z]{2}$"
    • removedInput schema / properties / state / type
      Removed value: -"string"
    • addedOutput schema / properties / providers / items / properties / postalCode
      Added value: +{
      +  "description": "Practice-location postal/ZIP code when present.",
      +  "type": "string"
      +}
  6. First observed

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark this as read-only, open-world, and idempotent; the description adds substantial behavioral context beyond that: the registry never reports true match totals, one search reaches only 1200 matches, continuationPostalCodes handles the terminal window, mailing addresses are never searched, and former/other names are matched with matchedOtherName. This is exactly the kind of non-obvious behavior an agent needs to present accurate results.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Although long, the description is dense and every sentence carries operational weight. It is front-loaded with the core purpose, then progresses through matching behavior, address semantics, name behavior, and pagination. For a tool with this many quirks, the size is appropriate and there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers matching rules, address filtering, name-search behavior, taxonomy resolution, pagination limits, continuation tokens, and the presence of matchedLocation/matchedOtherName. Given the output schema exists and annotations are present, nothing critical is missing for correct invocation and result interpretation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but the description still adds real semantic value: name_search token splitting, the mutual exclusivity of specialty and taxonomy_description, organization_name implying provider_type, ZIP+4 matching nuance, and the rule that provider_type must agree with the name fields used. This goes well beyond the baseline expected from schema descriptions alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Search the NPPES NPI registry' and enumerates the exact search criteria (name, organization name, location, provider type, specialty). It also differentiates from the sibling tool by noting that the NPI is the input for npi_get_provider when the full record is needed, so the agent can disambiguate.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance: at least one search criterion is required, state-only searches are rejected, location must go in dedicated fields rather than specialty, and provider_type must match the chosen name fields. It also names the alternative for full records (npi_get_provider), giving clear routing between siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.