DEV Community

Cover image for How to give Claude an FDA adverse-event (FAERS) tool with the Apify MCP server
Michael
Michael

Posted on • Originally published at scrapers.lat

How to give Claude an FDA adverse-event (FAERS) tool with the Apify MCP server

Ask Claude what the known safety signals are for a given drug and it will answer from its training data: a plausible summary, frozen at some point in the past, with no report IDs behind it. For a casual question that is fine. For pharmacovigilance work, where the job is to spot a real signal in real reports, "a plausible summary" is the opposite of what you need. You need the underlying cases: who was affected, what reaction was recorded, how serious it was, and which drug the reporter actually flagged.

In this guide we connect Claude to the official Apify MCP server and expose a single Actor that reads the FDA Adverse Event Reporting System (FAERS). By the end you will have a working tool that Claude, Cursor, or any MCP client can call mid-conversation to pull real adverse-event reports for a drug, complete with patient details, reactions, seriousness, and the suspect-versus-concomitant breakdown that a safety review actually turns on.

Everything below is a real setup with real output. No mocked responses.

What is the Apify MCP server?

Model Context Protocol (MCP) is an open standard that lets AI clients call external tools. The Apify MCP server (https://mcp.apify.com) implements that standard on top of the Apify platform, which means every one of the thousands of Actors in the Apify Store becomes a tool an agent can invoke.

Why route an Actor through MCP instead of hard-coding an API call?

  • The agent decides when to fetch. Claude reads the conversation, notices it needs current report data it does not have, and calls the tool on its own. You do not write glue code for every question.
  • Structured input and output. The MCP server hands Claude the Actor's input schema, so the model fills in the parameters correctly, and returns a clean dataset it can reason over.
  • One connection, many tools. The same MCP endpoint exposes search-actors, fetch-actor-details, and call-actor, so an agent can discover and run any Actor without new configuration.
  • No infrastructure. The server is hosted. You add a few lines to a config file and you are done.

The Actor we will use

We will expose the openFDA Drug Adverse Events & Recalls Scraper. Given a drug name, it returns FAERS safety reports as structured records: the safety report ID, patient sex and age, the reported reactions, the seriousness flag and its reasons (hospitalization, life-threatening, death), the report type and dates, the reporting country, and the full list of drugs on the report, each marked as suspect or concomitant with its indication and route. The same Actor can also pull drug recall actions when you switch its dataset input.

That field set is what pharmacovigilance and drug-safety review needs: not a single number, but the whole report, so an analyst can see the patient context and judge which drug was implicated. FAERS is public and authoritative, which makes it a clean first source to wire into an agent.

The openFDA Drug Adverse Events Actor on the Apify Store

Step 1: Get your Apify API token

Sign in to the Apify Console, open Settings → Integrations, and copy your personal API token. The MCP server uses it to authenticate and to bill Actor runs to your account.

📌 Note: the token is a secret. Keep it in the client config only, never in a prompt or a committed file.

Step 2: Point Claude Desktop at the Apify MCP server

Open Claude Desktop's config file (Settings → Developer → Edit Config, or ~/Library/Application Support/Claude/claude_desktop_config.json on macOS) and add the Apify server. The tools query parameter is the important part: it tells the server which Actor to expose, so Claude gets one focused tool instead of the entire Store.

{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=scrapers_lat/openfda-drug-events-scraper",
      "headers": {
        "Authorization": "Bearer YOUR_APIFY_TOKEN"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Cursor uses the same JSON in .cursor/mcp.json. If you prefer to run it locally over stdio instead of the hosted endpoint:

{
  "mcpServers": {
    "apify": {
      "command": "npx",
      "args": ["-y", "@apify/actors-mcp-server", "--tools", "scrapers_lat/openfda-drug-events-scraper"],
      "env": { "APIFY_TOKEN": "YOUR_APIFY_TOKEN" }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Restart Claude Desktop so it picks up the new server.

Step 3: Confirm the tool is loaded

After the restart, the Actor shows up as a callable tool. If you list the tools the Apify server exposes, you will see the storage helpers plus the Actor itself, named after its Store handle:

get-actor-run, get-dataset-items, get-key-value-store-record,
abort-actor-run, scrapers_lat--openfda-drug-events-scraper
Enter fullscreen mode Exit fullscreen mode

That last entry, scrapers_lat--openfda-drug-events-scraper, is our pharmacovigilance tool. Claude now knows it exists, what it does (from the Actor's README), and what inputs it takes (from the input schema the server passes along): a searchQuery drug name, a dataset selector for events or recalls, an optional date range, and a maxRecords cap.

Step 4: Ask Claude to pull adverse-event reports

Now the payoff. In a normal chat, ask a question that requires the actual reports:

"Pull recent FDA adverse-event reports (FAERS) that mention aspirin. Show me one serious case in full: patient, reactions, and which drug was flagged as the suspect."

Claude recognizes it cannot answer this from memory, selects the FAERS tool, and fills in the input from your question. Under the hood the client sends a tools/call with the Actor's parameters:

{
  "name": "scrapers_lat--openfda-drug-events-scraper",
  "arguments": {
    "searchQuery": "aspirin",
    "dataset": "events",
    "maxRecords": 25
  }
}
Enter fullscreen mode Exit fullscreen mode

The Apify MCP server starts the Actor, waits for it to finish, and returns the dataset. Here is the real run metadata it produced:

{
  "runId": "DzlAwbvYGb0ojGgBt",
  "actorName": "scrapers_lat/openfda-drug-events-scraper",
  "status": "SUCCEEDED",
  "startedAt": "2026-07-30T17:43:55.891Z",
  "finishedAt": "2026-07-30T17:44:00.884Z",
  "stats": { "runTimeSecs": 4.8 }
}
Enter fullscreen mode Exit fullscreen mode

Under five seconds, twenty-five live FAERS reports.

Step 5: Read the real output

The dataset the tool returns is structured safety-report data. This is an actual record from the run (trimmed to the fields that matter for a safety review):

{
  "safetyReportId": "10003432",
  "reportType": "Spontaneous",
  "serious": true,
  "seriousnessReasons": ["Hospitalization"],
  "receiveDate": "2014-03-12",
  "primarySourceCountry": "US",
  "reporterQualification": "Consumer or non-health professional",
  "patientSex": "Female",
  "patientAge": "84 year",
  "reactions": ["Oedema peripheral", "Fluid retention"],
  "drugs": [
    { "product": "LETAIRIS", "genericName": "AMBRISENTAN",
      "characterization": "Suspect", "indication": "PULMONARY HYPERTENSION",
      "route": "ORAL" },
    { "product": "ASPIRIN", "genericName": "ASPIRIN",
      "characterization": "Concomitant", "route": "ORAL" }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Claude reads that and answers in plain language: this is a serious report, safety report 10003432, for an 84-year-old woman who was hospitalized with peripheral oedema and fluid retention. Aspirin is in her medication list, but the reporter marked it concomitant; the flagged suspect drug is Letairis (ambrisentan), taken for pulmonary hypertension, where fluid retention is a known class signal. Every one of those facts is traceable to an official FAERS record, not the model's memory.

Claude calling the FAERS tool and answering with a real adverse-event report

The suspect-versus-concomitant distinction is the whole point. A naive keyword search for "aspirin" surfaces this report, but the report author did not blame aspirin. An analyst needs to see that difference, and the model needs the structured characterization field to convey it honestly rather than implying aspirin caused the oedema. The tool surfaces it; a summary from memory would flatten it.

A real use case: a signal-triage assistant

Put this in context. A drug-safety analyst monitoring a product needs to work through incoming FAERS reports and separate noise from signal. For each drug of interest they need to know, quickly: how many recent reports are serious, what reactions recur, and in how many of them the drug was the actual suspect versus merely on the patient's medication list.

Without a tool, the analyst queries the FAERS front end, opens reports one at a time, and copies fields into a spreadsheet. With the tool wired into Claude, the analyst names the drug and asks the agent to pull the recent reports, count how many are flagged serious, tally the top reactions, and list the cases where the drug is marked suspect with its recorded seriousness reason. Claude calls the Actor, reasons over the returned dataset, and produces a short triage note with the report IDs as evidence. The analyst spends their time on the judgment call, not the copy-paste.

A concrete version of that ask reads like a brief: "Pull the last batch of reports for this drug, group them by reaction, tell me which reactions appear in serious reports, and flag any case where the drug is the suspect and the seriousness reason is death or life-threatening." Claude fills the input, runs the Actor once, and answers in a table it can defend line by line, because every row points back to a safetyReportId you can open in the FAERS record. The same prompt works for the next drug with one word changed, which is exactly why an agent tool beats a saved dashboard: the question can move, and the tool moves with it.

This is the shape of every good agent tool: it removes the mechanical fetch, not the decision. And because each record carries its safetyReportId, every claim in the agent's summary is auditable back to the source report.

Going further: chain a second tool

Adverse-event triage rarely stops at the report itself. Once you have a suspect drug, the next question is what its approved label says: the indications, the warnings, the boxed warnings, the adverse reactions the manufacturer already lists. The same MCP connection can expose more Actors by extending the tools parameter:

https://mcp.apify.com?tools=scrapers_lat/openfda-drug-events-scraper,scrapers_lat/openfda-drug-labels-scraper
Enter fullscreen mode Exit fullscreen mode

Now the agent can pull the FAERS reports for a drug and fetch its official FDA label in the same conversation, then tell you whether a recurring reaction in the reports is already a documented warning on the label or looks like something new. Because each Actor is a separate tool, the agent picks the right one for each step on its own: events for the field signal, labels for the approved reference.

🏹 Troubleshooting: if the tool does not appear in Claude, the two usual causes are a missing or misspelled Actor handle in the tools parameter (it must be the exact username/actor-name from the Store URL) and a config that was edited while Claude was running. Fix the handle, save, and fully restart the client.

📌 Note: each tool call is a real Actor run billed to your Apify account (this Actor is pay-per-result). For interactive triage the cost is a fraction of a cent per query; if you plan to sweep thousands of drugs on a schedule, run the Actor directly through the Apify API or a scheduled task instead of one call per chat message.

A word on interpretation

FAERS is a spontaneous-reporting system. A report means someone submitted it, not that the drug caused the event, and many reports come from consumers rather than clinicians. The reaction in a report can have any outcome, the same case can list a dozen drugs, and duplicate reports exist. The value of wiring FAERS into an agent is not automated causation; it is fast, auditable access to the raw reports so a trained reviewer can do the interpreting. Keep that framing and the tool earns its place in a serious workflow.

Wrapping up

You now have an AI agent that can pull real FDA adverse-event reports on demand, mid-conversation, with the patient context, seriousness, and suspect-drug detail a safety review actually needs. The pattern is reusable: pick an Actor that returns authoritative structured data, expose it through the Apify MCP server with the tools parameter, and let the agent decide when to call it.

To take it further:

  • Switch the Actor's dataset input to pull drug recall actions instead of events, or set a date range to focus on a reporting window.
  • Add the drug-labels Actor, or a clinical-trials or NDC-directory Actor, to build a multi-step drug-intelligence agent.
  • Read the Apify MCP server docs for OAuth setup, resource reads, and the search-actors / call-actor tools that let an agent discover Actors it was not preconfigured with.

The Actor used in this guide: openFDA Drug Adverse Events & Recalls Scraper.

Top comments (0)