Inspiration

FDA drug safety data is public, but it's buried behind complex API endpoints, raw JSON payloads, and regulatory jargon that most people will never navigate on their own. A patient who just got prescribed Lisinopril shouldn't need to know how to query api.fda.gov/drug/label.json to find out if their medication has a black box warning. A parent checking whether their child's antibiotic has been recalled shouldn't have to parse enforcement report classifications to understand if it's serious.

What it does

DrugBot is a conversational AI assistant that queries four live FDA databases — adverse events, product labeling, recall enforcement, and drug shortages — and presents the results in plain language through a chat interface.

Ask "Tell me about Lisinopril" and it pulls the official FDA label with dosage, warnings, and contraindications. Then it proactively asks if you'd like to check for recalls or shortages of that same drug. Ask "Are there any critical recalls?" without naming a specific drug and it immediately calls get_critical_recalls to surface Class I alerts — reason, lot numbers, distribution states, and all — instead of asking you to be more specific. Follow up with "What about shortages?" and it carries the conversation context forward without making you repeat yourself.

12 MCP tools span the four FDA data categories:

Category Tools Example Query
Adverse Events search_adverse_events, get_serious_adverse_events "Does Aspirin cause bleeding?"
Product Labeling get_drug_label, search_drug_labels "What's the dosage for Metformin?"
Recall Enforcement search_recalls, get_recent_drug_recalls, get_recalls_by_classification, get_critical_recalls "Any Class I recalls?"
Drug Shortages search_drug_shortages, get_current_drug_shortages, search_shortages_by_manufacturer "Is Adderall still in shortage?"

How we built it

The system is a three-tier architecture with clean separation of concerns:

MCP Server (server.py)

Built with FastMCP and Python, this is the data gatekeeper. It exposes 12+ tools via the @mcp.tool() decorator, each wrapping a specific OpenFDA API endpoint. An internal filtering layer (openfda_api.py) strips unnecessary fields from raw FDA responses before they reach the LLM. For product labeling, the filter extracts only safety-critical fields:

entry = {
    "brand_name": openfda.get("brand_name", ["Unknown"])[0],
    "generic_name": openfda.get("generic_name", ["Unknown"])[0],
    "manufacturer": openfda.get("manufacturer_name", ["Unknown"])[0],
    "indication": indications,
    "warnings_summary": warnings,
    "contraindications": contraindications,
    "adverse_reactions_summary": adverse_reactions,
    "dosage": get_first(item.get("dosage_and_administration", []))
}

MCP Client (client.py)

Built with FastAPI and the native Gemini SDK, this is the agentic brain. On startup, a lifespan handler performs four initialization steps:

# 1. Establish SSE Connection
app.state.sse_streams = sse_client(REMOTE_SERVER_URL)
streams = await app.state.sse_streams.__aenter__()

# 2. Initialize MCP Client Session
app.state.client_session = ClientSession(streams[0], streams[1])
mcp_session = await app.state.client_session.__aenter__()
await mcp_session.initialize()

# 3. Fetch Tools
mcp_tools = await mcp_session.list_tools()
app.state.gemini_tools = convert_mcp_to_gemini_tools(mcp_tools)

# 4. Initialize Gemini Client
gemini_client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))
## Challenges we ran into
The OpenFDA API returns massive JSON payloads. Feeding that directly to Gemini would be slow, expensive, and noisy. We built a custom filtering layer that extracts only the fields Gemini needs while preserving every safety-critical detail. Getting the balance right — aggressive enough to cut 60–80% of tokens, conservative enough to never drop a recall reason or lot number — took significant iteration across all four endpoints.
## Accomplishments that we're proud of
**The proactive safety workflow works end-to-end.** It's one thing to describe "the AI should offer follow-up safety checks" in a requirements doc. It's another to watch Gemini answer a dosage question about Metformin, then unprompted say *"Would you like me to check if Metformin has any active recalls or shortages?"* — and actually execute the right tool when the user says yes. That full loop, from system prompt design to MCP tool execution to rendered response, working reliably is the accomplishment we're most proud of.

## What we learned
**MCP is a powerful abstraction for tool-use architectures.** Separating "what data exists" (server) from "how to reason about it" (client) from "how to present it" (UI) made the system dramatically easier to debug. When a recall query returned bad data, we could immediately isolate whether the problem was in the FDA API response, the server's filtering logic, or the client's prompt.

**System prompt engineering is underrated.** The difference between a good and great agentic experience came down to ~80 lines of carefully written instructions. Details like *"Call `get_critical_recalls(limit=25)` immediately on broad recall queries"* and *"Never run extra checks automatically — always ask permission"* transformed the assistant from a generic chatbot into something that felt genuinely designed for pharmaceutical safety.

## What's next for AI-powered DrugBot
**Persistent session storage.** Replacing in-memory `user_sessions` with Redis to support conversation continuity across container restarts and horizontal scaling.

**Streaming responses.** The current architecture returns complete responses. Adding server-sent event streaming from the MCP Client to the UI would let users see Gemini's answer as it generates, dramatically improving perceived latency.

**Drug interaction checking.** A new MCP tool that cross-references multiple drug labels to flag potential interactions — *"You're asking about Lisinopril and Ibuprofen — here's what the FDA says about combining them."*

**User medication profiles.** Letting users save a personal medication list so DrugBot can proactively alert them when a recall or shortage affects one of their drugs, without them needing to ask.

**Expanding beyond drugs.** The openFDA API also covers medical devices and food safety. The MCP architecture makes it straightforward to add new tool groups for device recalls, food contamination alerts, and cosmetic safety data — same pattern, new endpoints.

Built With

Share this project:

Updates