openfda-mcp-server

v0.3.1 pre-1.0

Query FDA data on drugs, food, devices, and recalls via openFDA. STDIO or Streamable HTTP.

openfda.caseyjhand.com/mcp
claude mcp add --transport http openfda-mcp-server https://openfda.caseyjhand.com/mcp
codex mcp add openfda-mcp-server --url https://openfda.caseyjhand.com/mcp
{
  "mcpServers": {
    "openfda-mcp-server": {
      "url": "https://openfda.caseyjhand.com/mcp"
    }
  }
}
gemini mcp add --transport http openfda-mcp-server https://openfda.caseyjhand.com/mcp
{
  "mcpServers": {
    "openfda-mcp-server": {
      "command": "bunx",
      "args": [
        "mcp-remote",
        "https://openfda.caseyjhand.com/mcp"
      ]
    }
  }
}
{
  "mcpServers": {
    "openfda-mcp-server": {
      "type": "http",
      "url": "https://openfda.caseyjhand.com/mcp"
    }
  }
}
curl -X POST https://openfda.caseyjhand.com/mcp \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}'

Tools

14

openfda_search_adverse_events

Search adverse event reports across drugs, food, and devices. Use to investigate safety signals, find reports for a specific product, or explore reactions by demographics.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openfda_search_adverse_events",
    "arguments": {
      "category": "<category>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "category": {
      "type": "string",
      "enum": [
        "drug",
        "food",
        "device"
      ],
      "description": "Product category — each has different field schemas in the response"
    },
    "search": {
      "description": "openFDA search query. Examples: patient.drug.medicinalproduct:\"aspirin\", patient.reaction.reactionmeddrapt:\"nausea\" AND serious:\"1\". Omit to browse recent.",
      "type": "string"
    },
    "sort": {
      "description": "Sort expression (field:asc or field:desc). Example: receivedate:desc. Invalid or non-sortable fields cause a query error — use a documented field name.",
      "type": "string"
    },
    "limit": {
      "default": 10,
      "description": "Maximum number of records to return (1-1000, default 10)",
      "type": "number",
      "minimum": 1,
      "maximum": 1000
    },
    "skip": {
      "default": 0,
      "description": "Number of records to skip for pagination (0-25000, default 0)",
      "type": "number",
      "minimum": 0,
      "maximum": 25000
    },
    "canvas_id": {
      "description": "DataCanvas session id from a prior call. Omit to start a fresh canvas; the response returns a new one when canvas is enabled. When canvas (CANVAS_PROVIDER_TYPE=duckdb) is enabled the full matched set is staged for SQL and limit/skip apply only to the inline path.",
      "type": "string"
    }
  },
  "required": [
    "category",
    "limit",
    "skip"
  ],
  "additionalProperties": false
}
view source ↗

openfda_search_animal_events

Search adverse event reports for veterinary drugs and devices submitted to the FDA Center for Veterinary Medicine. Records include animal species, breed, age, weight, drug name and route, adverse reactions (using VeDDRA terminology), and outcome. Use to investigate safety signals for veterinary products, find reports by animal species or drug, or explore reaction patterns.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openfda_search_animal_events",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "search": {
      "description": "openFDA search query using field:value syntax. Examples: animal.species:\"Dog\", drug.brand_name:\"Bravecto\", reaction.veddra_term_name:\"Vomiting\", serious_ae:\"true\". Omit to browse recent reports.",
      "type": "string"
    },
    "sort": {
      "description": "Sort expression (field:asc or field:desc). Example: original_receive_date:desc. Invalid or non-sortable fields cause a query error — use a documented field name.",
      "type": "string"
    },
    "limit": {
      "default": 10,
      "description": "Maximum number of records to return (1-1000, default 10)",
      "type": "number",
      "minimum": 1,
      "maximum": 1000
    },
    "skip": {
      "default": 0,
      "description": "Number of records to skip for pagination (0-25000, default 0)",
      "type": "number",
      "minimum": 0,
      "maximum": 25000
    },
    "canvas_id": {
      "description": "DataCanvas session id from a prior call. Omit to start a fresh canvas; the response returns a new one when canvas is enabled. When canvas (CANVAS_PROVIDER_TYPE=duckdb) is enabled the full matched set is staged for SQL and limit/skip apply only to the inline path.",
      "type": "string"
    }
  },
  "required": [
    "limit",
    "skip"
  ],
  "additionalProperties": false
}
view source ↗

openfda_search_drug_shortages

Search FDA drug shortage records. Returns per-product shortage status, availability, therapeutic category, dosage form, manufacturer, and dates. Use to check whether a drug is currently in shortage, find all oncology drugs with supply issues, or retrieve the openfda block (brand_name, product_ndc, rxcui) to chain into openfda_get_drug_label or openfda_lookup_ndc.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openfda_search_drug_shortages",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "search": {
      "description": "openFDA search query using field:value syntax. Examples: status:\"Current\", therapeutic_category:\"Oncology\", generic_name:\"carboplatin\", company_name:\"pfizer\". Omit to browse all records. Call openfda_describe_fields({ endpoint: \"drug/shortages\" }) for the complete field list.",
      "type": "string"
    },
    "sort": {
      "description": "Sort expression (field:asc or field:desc). Example: update_date:desc. Invalid or non-sortable fields cause a query error — use a documented field name.",
      "type": "string"
    },
    "limit": {
      "default": 10,
      "description": "Maximum number of records to return (1-1000, default 10)",
      "type": "number",
      "minimum": 1,
      "maximum": 1000
    },
    "skip": {
      "default": 0,
      "description": "Number of records to skip for pagination (0-25000, default 0)",
      "type": "number",
      "minimum": 0,
      "maximum": 25000
    },
    "canvas_id": {
      "description": "DataCanvas session id from a prior call. Omit to start a fresh canvas; the response returns a new one when canvas is enabled. When canvas (CANVAS_PROVIDER_TYPE=duckdb) is enabled the full matched set is staged for SQL and limit/skip apply only to the inline path.",
      "type": "string"
    }
  },
  "required": [
    "limit",
    "skip"
  ],
  "additionalProperties": false
}
view source ↗

openfda_search_recalls

Search enforcement reports and recall actions across drugs, food, and devices.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openfda_search_recalls",
    "arguments": {
      "category": "<category>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "category": {
      "type": "string",
      "enum": [
        "drug",
        "food",
        "device"
      ],
      "description": "Product category"
    },
    "endpoint": {
      "default": "enforcement",
      "description": "Report type. Default enforcement. The recall endpoint is only available for devices.",
      "type": "string",
      "enum": [
        "enforcement",
        "recall"
      ]
    },
    "search": {
      "description": "openFDA search query. Examples: classification:\"Class I\" (also \"Class II\" or \"Class III\"), recalling_firm:\"pfizer\", reason_for_recall:\"undeclared allergen\".",
      "type": "string"
    },
    "sort": {
      "description": "Sort expression (field:asc or field:desc). Example: report_date:desc. Invalid or non-sortable fields cause a query error — use a documented field name.",
      "type": "string"
    },
    "limit": {
      "default": 10,
      "description": "Maximum number of records to return (1-1000).",
      "type": "number",
      "minimum": 1,
      "maximum": 1000
    },
    "skip": {
      "default": 0,
      "description": "Pagination offset (0-25000).",
      "type": "number",
      "minimum": 0,
      "maximum": 25000
    },
    "canvas_id": {
      "description": "DataCanvas session id from a prior call. Omit to start a fresh canvas; the response returns a new one when canvas is enabled. When canvas (CANVAS_PROVIDER_TYPE=duckdb) is enabled the full matched set is staged for SQL and limit/skip apply only to the inline path.",
      "type": "string"
    }
  },
  "required": [
    "category",
    "endpoint",
    "limit",
    "skip"
  ],
  "additionalProperties": false
}
view source ↗

openfda_search_tobacco_reports

Search problem reports submitted to the FDA for tobacco products, including e-cigarettes, vaping products, cigarettes, and smokeless tobacco. Reports capture product type, reported health problems (e.g. seizure, chest pain), product problems (e.g. exploding battery), whether a non-user was affected, and submission date. Use to investigate safety signals, find reports by product type, or analyze health effects.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openfda_search_tobacco_reports",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "search": {
      "description": "openFDA search query using field:value syntax. Examples: tobacco_products:\"Electronic cigarette\", reported_health_problems:\"Seizure\", nonuser_affected:\"Yes\". Omit to browse recent reports.",
      "type": "string"
    },
    "sort": {
      "description": "Sort expression (field:asc or field:desc). Example: date_submitted:desc. Invalid or non-sortable fields cause a query error — use a documented field name.",
      "type": "string"
    },
    "limit": {
      "default": 10,
      "description": "Maximum number of records to return (1-1000, default 10)",
      "type": "number",
      "minimum": 1,
      "maximum": 1000
    },
    "skip": {
      "default": 0,
      "description": "Number of records to skip for pagination (0-25000, default 0)",
      "type": "number",
      "minimum": 0,
      "maximum": 25000
    },
    "canvas_id": {
      "description": "DataCanvas session id from a prior call. Omit to start a fresh canvas; the response returns a new one when canvas is enabled. When canvas (CANVAS_PROVIDER_TYPE=duckdb) is enabled the full matched set is staged for SQL and limit/skip apply only to the inline path.",
      "type": "string"
    }
  },
  "required": [
    "limit",
    "skip"
  ],
  "additionalProperties": false
}
view source ↗

openfda_count_values

Aggregate and tally unique values for any field across any openFDA endpoint. Returns ranked term-count pairs sorted by count descending. Pair with openfda_search_adverse_events, openfda_search_drug_approvals, openfda_search_device_clearances, openfda_search_recalls, openfda_get_drug_label, or openfda_lookup_ndc when sample records help interpret the aggregates.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openfda_count_values",
    "arguments": {
      "endpoint": "<endpoint>",
      "count": "<count>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "endpoint": {
      "type": "string",
      "enum": [
        "drug/event",
        "drug/label",
        "drug/enforcement",
        "drug/ndc",
        "drug/drugsfda",
        "drug/shortages",
        "food/event",
        "food/enforcement",
        "device/event",
        "device/510k",
        "device/pma",
        "device/recall",
        "device/enforcement",
        "device/classification",
        "device/registrationlisting",
        "device/udi",
        "device/covid19serology",
        "animalandveterinary/event",
        "tobacco/problem",
        "other/substance"
      ],
      "description": "Full openFDA endpoint path (e.g. \"drug/event\", \"device/classification\")"
    },
    "count": {
      "type": "string",
      "description": "Field to count. Append .exact for whole-phrase counting (e.g. \"patient.reaction.reactionmeddrapt.exact\", \"openfda.brand_name.exact\")"
    },
    "search": {
      "description": "Filter query to scope the count (e.g. patient.drug.medicinalproduct:\"metformin\")",
      "type": "string"
    },
    "limit": {
      "default": 100,
      "description": "Number of top terms to return (default 100, max 1000)",
      "type": "number",
      "minimum": 1,
      "maximum": 1000
    }
  },
  "required": [
    "endpoint",
    "count",
    "limit"
  ],
  "additionalProperties": false
}
view source ↗

openfda_describe_fields

Return the searchable field paths for an openFDA endpoint, grouped by category with type and description. Use before constructing a search query to find the correct dotted field path — field names differ per endpoint and are not discoverable from the tool schema alone.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openfda_describe_fields",
    "arguments": {
      "endpoint": "<endpoint>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "endpoint": {
      "type": "string",
      "enum": [
        "drug/event",
        "drug/label",
        "drug/enforcement",
        "drug/ndc",
        "drug/drugsfda",
        "drug/shortages",
        "food/event",
        "food/enforcement",
        "device/event",
        "device/510k",
        "device/pma",
        "device/recall",
        "device/enforcement",
        "animalandveterinary/event",
        "tobacco/problem"
      ],
      "description": "openFDA endpoint to describe (e.g. \"drug/event\", \"drug/shortages\", \"device/510k\"). Must be one of the cataloged endpoints."
    }
  },
  "required": [
    "endpoint"
  ],
  "additionalProperties": false
}
view source ↗

openfda_get_drug_label

Look up FDA drug labeling (package inserts / SPL documents). Check indications, warnings, dosage, contraindications, active ingredients, or any structured label section.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openfda_get_drug_label",
    "arguments": {
      "search": "<search>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "search": {
      "type": "string",
      "description": "Query targeting label fields. Examples: openfda.brand_name:\"aspirin\", openfda.generic_name:\"metformin\", openfda.manufacturer_name:\"pfizer\". For a specific revision, pass set_id with the SPL UUID returned in earlier results."
    },
    "sort": {
      "description": "Sort expression (field:asc or field:desc). Example: effective_time:desc. Invalid or non-sortable fields cause a query error — use a documented field name.",
      "type": "string"
    },
    "limit": {
      "default": 5,
      "description": "Maximum number of results to return (1-1000). Default 5. Labels are large.",
      "type": "number",
      "minimum": 1,
      "maximum": 1000
    },
    "skip": {
      "default": 0,
      "description": "Number of results to skip for pagination (0-25000). Default 0.",
      "type": "number",
      "minimum": 0,
      "maximum": 25000
    }
  },
  "required": [
    "search",
    "limit",
    "skip"
  ],
  "additionalProperties": false
}
view source ↗

openfda_search_drug_approvals

Search the Drugs@FDA database for drug application approvals (NDAs and ANDAs). Returns application details, sponsor info, and full submission history. Pair with openfda_get_drug_label to read the approved label, or openfda_count_values to aggregate by sponsor_name, product_type, or route.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openfda_search_drug_approvals",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "search": {
      "description": "openFDA search query. Examples: openfda.brand_name:\"humira\", sponsor_name:\"pfizer\", submissions.submission_type:\"ORIG\" AND submissions.review_priority:\"PRIORITY\". Omit to browse recent.",
      "type": "string"
    },
    "sort": {
      "description": "Sort expression (field:asc or field:desc). Example: submissions.submission_status_date:desc. Invalid or non-sortable fields cause a query error — use a documented field name.",
      "type": "string"
    },
    "limit": {
      "default": 10,
      "description": "Maximum number of records to return (1-1000, default 10)",
      "type": "number",
      "minimum": 1,
      "maximum": 1000
    },
    "skip": {
      "default": 0,
      "description": "Number of records to skip for pagination (0-25000, default 0)",
      "type": "number",
      "minimum": 0,
      "maximum": 25000
    },
    "canvas_id": {
      "description": "DataCanvas session id from a prior call. Omit to start a fresh canvas; the response returns a new one when canvas is enabled. When canvas (CANVAS_PROVIDER_TYPE=duckdb) is enabled the full matched set is staged for SQL and limit/skip apply only to the inline path.",
      "type": "string"
    }
  },
  "required": [
    "limit",
    "skip"
  ],
  "additionalProperties": false
}
view source ↗

openfda_search_device_clearances

Search FDA device premarket notifications — 510(k) clearances and PMA approvals.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openfda_search_device_clearances",
    "arguments": {
      "pathway": "<pathway>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "pathway": {
      "type": "string",
      "enum": [
        "510k",
        "pma"
      ],
      "description": "Premarket pathway. 510(k) is the most common; PMA is for higher-risk devices."
    },
    "search": {
      "description": "openFDA search query. Examples: applicant:\"medtronic\", advisory_committee_description:\"cardiovascular\", product_code:\"DXN\", openfda.device_name:\"catheter\". Omit to browse recent.",
      "type": "string"
    },
    "sort": {
      "description": "Sort expression (field:asc or field:desc). Example: decision_date:desc. Invalid or non-sortable fields cause a query error — use a documented field name.",
      "type": "string"
    },
    "limit": {
      "default": 10,
      "description": "Maximum number of records to return (1-1000).",
      "type": "number",
      "minimum": 1,
      "maximum": 1000
    },
    "skip": {
      "default": 0,
      "description": "Pagination offset (0-25000).",
      "type": "number",
      "minimum": 0,
      "maximum": 25000
    },
    "canvas_id": {
      "description": "DataCanvas session id from a prior call. Omit to start a fresh canvas; the response returns a new one when canvas is enabled. When canvas (CANVAS_PROVIDER_TYPE=duckdb) is enabled the full matched set is staged for SQL and limit/skip apply only to the inline path.",
      "type": "string"
    }
  },
  "required": [
    "pathway",
    "limit",
    "skip"
  ],
  "additionalProperties": false
}
view source ↗

openfda_lookup_ndc

Look up drugs in the NDC (National Drug Code) Directory. Identify drug products by NDC code, find active ingredients, packaging details, or manufacturer info. Pair with openfda_get_drug_label using the returned brand_name or set_id to read the package insert.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openfda_lookup_ndc",
    "arguments": {
      "search": "<search>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "search": {
      "type": "string",
      "description": "openFDA search query. Examples: product_ndc:\"0363-0218\", brand_name:\"aspirin\", generic_name:\"metformin\", openfda.manufacturer_name:\"walgreen\", active_ingredients.name:\"ASPIRIN\""
    },
    "sort": {
      "description": "Sort expression (field:asc or field:desc). Example: listing_expiration_date:desc. Invalid or non-sortable fields cause a query error — use a documented field name.",
      "type": "string"
    },
    "limit": {
      "default": 10,
      "description": "Maximum number of records to return (1-1000, default 10)",
      "type": "number",
      "minimum": 1,
      "maximum": 1000
    },
    "skip": {
      "default": 0,
      "description": "Number of records to skip for pagination (0-25000, default 0)",
      "type": "number",
      "minimum": 0,
      "maximum": 25000
    },
    "canvas_id": {
      "description": "DataCanvas session id from a prior call. Omit to start a fresh canvas; the response returns a new one when canvas is enabled. When canvas (CANVAS_PROVIDER_TYPE=duckdb) is enabled the full matched set is staged for SQL and limit/skip apply only to the inline path.",
      "type": "string"
    }
  },
  "required": [
    "search",
    "limit",
    "skip"
  ],
  "additionalProperties": false
}
view source ↗

openfda_drug_profile

Resolve one drug name to its FDA identity, then fan out in parallel across the bounded per-drug openFDA endpoints and merge into one profile: identity, label highlights, adverse-event summary, recall history, Drugs@FDA approval, and shortage status. Replaces chaining openfda_get_drug_label, openfda_search_adverse_events, openfda_search_recalls, openfda_search_drug_approvals, and openfda_search_drug_shortages — and reconciles the identifier drift between endpoints that makes that chaining error-prone. Each section is best-effort: a miss returns null rather than failing the call. For deep dives into any one area, use the dedicated tool.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openfda_drug_profile",
    "arguments": {
      "drug": "<drug>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "drug": {
      "type": "string",
      "minLength": 1,
      "description": "Drug name to profile — brand or generic (e.g. \"metformin\", \"Humira\", \"Glucophage\"). Resolved once to canonical FDA identifiers, which then key every sub-query."
    }
  },
  "required": [
    "drug"
  ],
  "additionalProperties": false
}
view source ↗

openfda_dataframe_describe

List the tables and column schemas on a DataCanvas staged by an openFDA search tool. Call before openfda_dataframe_query to discover the exact table name, column names, and DuckDB types needed for valid SQL. row_count is the full staged result set, not the inline preview count. Columns typed JSON hold nested openFDA objects/arrays — query them with DuckDB json functions.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openfda_dataframe_describe",
    "arguments": {
      "canvas_id": "<canvas_id>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "canvas_id": {
      "type": "string",
      "description": "Canvas ID from an openFDA search tool response."
    }
  },
  "required": [
    "canvas_id"
  ],
  "additionalProperties": false
}
view source ↗

openfda_dataframe_query

Run a read-only SQL SELECT against a DataCanvas table staged by an openFDA search tool (canvas_id + canvas_table in its response when spilled=true). Enables GROUP BY, COUNT/SUM/AVG, time-series, and joins across the full result set without re-paging the API. Call openfda_dataframe_describe first to get the exact table and column names. Scalar fields are stored as text (CAST for numeric math); nested objects/arrays are JSON columns — read them with DuckDB json functions, e.g. json_extract_string(openfda, '$.brand_name[0]'). Only SELECT is allowed — DDL, DML, COPY, and file-reading functions are blocked.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openfda_dataframe_query",
    "arguments": {
      "canvas_id": "<canvas_id>",
      "query": "<query>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "canvas_id": {
      "type": "string",
      "description": "Canvas ID from an openFDA search tool response (the canvas_id field)."
    },
    "query": {
      "type": "string",
      "description": "SQL SELECT against the staged table. Use the table name from openfda_dataframe_describe. Example: \"SELECT classification, COUNT(*) AS n FROM spilled_ab12cd34 GROUP BY classification ORDER BY n DESC\"."
    }
  },
  "required": [
    "canvas_id",
    "query"
  ],
  "additionalProperties": false
}
view source ↗