Skip to main content
Glama
drug_recalls.py10.5 kB
""" OpenFDA drug recalls (Enforcement) integration. """ import logging from typing import Any from .constants import ( OPENFDA_DEFAULT_LIMIT, OPENFDA_DISCLAIMER, OPENFDA_DRUG_ENFORCEMENT_URL, ) from .drug_recalls_helpers import ( build_recall_search_params, ) from .utils import ( clean_text, format_count, make_openfda_request, truncate_text, ) logger = logging.getLogger(__name__) async def search_drug_recalls( drug: str | None = None, recall_class: str | None = None, status: str | None = None, reason: str | None = None, since_date: str | None = None, limit: int = OPENFDA_DEFAULT_LIMIT, skip: int = 0, api_key: str | None = None, ) -> str: """ Search FDA drug recall records from Enforcement database. Args: drug: Drug name (brand or generic) to search for recall_class: Classification (1, 2, or 3) status: Recall status (ongoing, completed, terminated) reason: Search text in recall reason since_date: Only show recalls after this date (YYYYMMDD format) limit: Maximum number of results to return skip: Number of results to skip (for pagination) api_key: Optional OpenFDA API key (overrides OPENFDA_API_KEY env var) Returns: Formatted string with drug recall information """ # Build search parameters search_params = build_recall_search_params( drug, recall_class, status, reason, since_date, limit, skip ) # Make the request response, error = await make_openfda_request( OPENFDA_DRUG_ENFORCEMENT_URL, search_params, "openfda_recalls", api_key ) if error: return f"⚠️ Error searching drug recalls: {error}" if not response or not response.get("results"): return "No drug recall records found matching your criteria." # Format the results results = response["results"] total = ( response.get("meta", {}).get("results", {}).get("total", len(results)) ) output = ["## FDA Drug Recall Records\n"] if drug: output.append(f"**Drug**: {drug}") if recall_class: output.append(f"**Classification**: Class {recall_class}") if status: output.append(f"**Status**: {status}") if since_date: output.append(f"**Since**: {since_date}") output.append( f"**Total Recalls Found**: {format_count(total, 'recall')}\n" ) # Summary of recall classes if multiple results if len(results) > 1: output.extend(_format_recall_class_summary(results)) # Show results output.append(f"### Recalls (showing {len(results)} of {total}):\n") for i, recall in enumerate(results, 1): output.extend(_format_recall_summary(recall, i)) output.append(f"\n{OPENFDA_DISCLAIMER}") return "\n".join(output) async def get_drug_recall( recall_number: str, api_key: str | None = None, ) -> str: """ Get detailed drug recall information for a specific recall. Args: recall_number: FDA recall number api_key: Optional OpenFDA API key (overrides OPENFDA_API_KEY env var) Returns: Formatted string with detailed recall information """ # Search for the specific recall search_params = {"search": f'recall_number:"{recall_number}"', "limit": 1} response, error = await make_openfda_request( OPENFDA_DRUG_ENFORCEMENT_URL, search_params, "openfda_recalls", api_key ) if error: return f"⚠️ Error retrieving drug recall: {error}" if not response or not response.get("results"): return f"No recall record found for {recall_number}" recall = response["results"][0] # Format detailed recall information output = [f"## Drug Recall Details: {recall_number}\n"] # Basic information output.extend(_format_recall_header(recall)) # Reason and details output.extend(_format_recall_details(recall)) # Distribution information output.extend(_format_distribution_info(recall)) # OpenFDA metadata if openfda := recall.get("openfda"): output.extend(_format_recall_openfda(openfda)) output.append(f"\n{OPENFDA_DISCLAIMER}") return "\n".join(output) def _format_recall_class_summary(results: list[dict[str, Any]]) -> list[str]: """Format summary of recall classifications.""" output = [] # Count by classification class_counts = {"Class I": 0, "Class II": 0, "Class III": 0} for recall in results: classification = recall.get("classification", "") if classification in class_counts: class_counts[classification] += 1 if any(class_counts.values()): output.append("### Classification Summary:") if class_counts["Class I"]: output.append( f"- **Class I** (most serious): {class_counts['Class I']} recalls" ) if class_counts["Class II"]: output.append( f"- **Class II** (moderate): {class_counts['Class II']} recalls" ) if class_counts["Class III"]: output.append( f"- **Class III** (least serious): {class_counts['Class III']} recalls" ) output.append("") return output def _format_recall_summary(recall: dict[str, Any], num: int) -> list[str]: """Format a single recall summary.""" output = [f"#### {num}. Recall {recall.get('recall_number', 'Unknown')}"] # Classification and status classification = recall.get("classification", "Unknown") status = recall.get("status", "Unknown") # Add severity indicator severity_emoji = { "Class I": "🔴", # Most serious "Class II": "🟡", # Moderate "Class III": "🟢", # Least serious }.get(classification, "⚪") output.append(f"{severity_emoji} **{classification}** - {status}") # Date if init_date := recall.get("recall_initiation_date"): formatted_date = f"{init_date[:4]}-{init_date[4:6]}-{init_date[6:]}" output.append(f"**Initiated**: {formatted_date}") # Product description if product_desc := recall.get("product_description"): cleaned = truncate_text(clean_text(product_desc), 200) output.append(f"**Product**: {cleaned}") # OpenFDA names openfda = recall.get("openfda", {}) if brand_names := openfda.get("brand_name"): output.append(f"**Brand**: {', '.join(brand_names[:3])}") # Reason for recall if reason := recall.get("reason_for_recall"): cleaned_reason = truncate_text(clean_text(reason), 300) output.append(f"\n**Reason**: {cleaned_reason}") # Firm name if firm := recall.get("recalling_firm"): output.append(f"\n**Recalling Firm**: {firm}") output.append("") return output def _format_recall_header(recall: dict[str, Any]) -> list[str]: """Format the header section of detailed recall.""" output = ["### Recall Information"] output.append( f"**Recall Number**: {recall.get('recall_number', 'Unknown')}" ) output.append( f"**Classification**: {recall.get('classification', 'Unknown')}" ) output.append(f"**Status**: {recall.get('status', 'Unknown')}") if event_id := recall.get("event_id"): output.append(f"**Event ID**: {event_id}") # Dates if init_date := recall.get("recall_initiation_date"): formatted = f"{init_date[:4]}-{init_date[4:6]}-{init_date[6:]}" output.append(f"**Initiation Date**: {formatted}") if report_date := recall.get("report_date"): formatted = f"{report_date[:4]}-{report_date[4:6]}-{report_date[6:]}" output.append(f"**Report Date**: {formatted}") if term_date := recall.get("termination_date"): formatted = f"{term_date[:4]}-{term_date[4:6]}-{term_date[6:]}" output.append(f"**Termination Date**: {formatted}") output.append("") return output def _format_recall_details(recall: dict[str, Any]) -> list[str]: """Format recall details and reason.""" output = ["### Product and Reason"] if product_desc := recall.get("product_description"): output.append(f"**Product Description**:\n{clean_text(product_desc)}") if reason := recall.get("reason_for_recall"): output.append(f"\n**Reason for Recall**:\n{clean_text(reason)}") if quantity := recall.get("product_quantity"): output.append(f"\n**Product Quantity**: {quantity}") if code_info := recall.get("code_info"): output.append(f"\n**Code Information**:\n{clean_text(code_info)}") output.append("") return output def _format_distribution_info(recall: dict[str, Any]) -> list[str]: """Format distribution information.""" output = ["### Distribution Information"] if firm := recall.get("recalling_firm"): output.append(f"**Recalling Firm**: {firm}") if city := recall.get("city"): state = recall.get("state", "") country = recall.get("country", "") location = city if state: location += f", {state}" if country: location += f", {country}" output.append(f"**Location**: {location}") if dist_pattern := recall.get("distribution_pattern"): output.append( f"\n**Distribution Pattern**:\n{clean_text(dist_pattern)}" ) if action := recall.get("voluntary_mandated"): output.append(f"\n**Action Type**: {action}") output.append("") return output def _format_recall_openfda(openfda: dict[str, Any]) -> list[str]: """Format OpenFDA metadata for recall.""" output = ["### Drug Information"] if brand_names := openfda.get("brand_name"): output.append(f"**Brand Names**: {', '.join(brand_names)}") if generic_names := openfda.get("generic_name"): output.append(f"**Generic Names**: {', '.join(generic_names)}") if manufacturers := openfda.get("manufacturer_name"): output.append(f"**Manufacturers**: {', '.join(manufacturers[:3])}") if ndas := openfda.get("application_number"): output.append(f"**Application Numbers**: {', '.join(ndas[:5])}") if routes := openfda.get("route"): output.append(f"**Routes**: {', '.join(routes)}") if pharm_class := openfda.get("pharm_class_epc"): output.append(f"**Pharmacologic Class**: {', '.join(pharm_class[:3])}") output.append("") return output

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/genomoncology/biomcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server