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
"""
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