Humanlearning's picture
feat: Add NPI API client functions for searching and retrieving provider details.
ca50165
import httpx
import logging
from typing import List, Optional
from npi_mcp_server.config import NPI_API_BASE_URL
from npi_mcp_server.schemas import (
ProviderSummary,
ProviderDetail,
SearchProvidersResponse
)
logger = logging.getLogger(__name__)
async def search_providers(
query: str,
state: Optional[str] = None,
taxonomy: Optional[str] = None
) -> List[ProviderSummary]:
"""
Search for healthcare providers via the NPI API.
Args:
query: Name (first/last) or organization name.
state: Two-letter state code.
taxonomy: Taxonomy code or description.
Returns:
List of ProviderSummary objects.
"""
url = f"{NPI_API_BASE_URL.rstrip('/')}/search_providers"
payload = {
"query": query,
"state": state,
"taxonomy": taxonomy
}
# Remove None values
payload = {k: v for k, v in payload.items() if v is not None}
logger.info(f"Searching providers with payload: {payload}")
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
async with httpx.AsyncClient() as client:
try:
response = await client.post(url, json=payload, headers=headers, timeout=30.0)
response.raise_for_status()
data = response.json()
logger.info(f"Received response from NPI API: {data}")
# Expecting: { "results": [ ... ] }
return SearchProvidersResponse(**data).results
except httpx.HTTPStatusError as e:
logger.error(f"HTTP error calling NPI API: {e.response.status_code} - {e.response.text}")
raise RuntimeError(f"NPI API returned error: {e.response.status_code}") from e
except Exception as e:
logger.error(f"Error calling NPI API: {e}")
raise RuntimeError(f"Failed to search providers: {str(e)}") from e
async def get_provider_by_npi(npi: str) -> Optional[ProviderDetail]:
"""
Retrieve details for a specific provider by NPI.
Args:
npi: 10-digit NPI string.
Returns:
ProviderDetail object or None if not found.
"""
url = f"{NPI_API_BASE_URL.rstrip('/')}/provider/{npi}"
async with httpx.AsyncClient() as client:
try:
response = await client.get(url, timeout=30.0)
if response.status_code == 404:
return None
response.raise_for_status()
data = response.json()
return ProviderDetail(**data)
except httpx.HTTPStatusError as e:
logger.error(f"HTTP error calling NPI API: {e.response.status_code} - {e.response.text}")
raise RuntimeError(f"NPI API returned error: {e.response.status_code}") from e
except Exception as e:
logger.error(f"Error calling NPI API: {e}")
raise RuntimeError(f"Failed to get provider: {str(e)}") from e