mcpField
O
openfda-mcp-server

openfda-mcp-server

远程服务
github.com/cyanheads健康医疗42 天前更新
代码仓库

关于 openfda-mcp-server

openfda-mcp-server 将 openFDA 公共 API 的药品、食品、器械及召回数据提供给 MCP 客户端,面向需要查询 FDA 记录的场景。它还支持字段统计和对已暂存结果执行只读 SQL 查询,并提供 STDIO 与 Streamable HTTP。

主要功能

  1. 01搜索不良事件、召回及短缺
  2. 02查询药品标签、批准和 NDC
  3. 03检索器械许可与烟草报告
  4. 04统计字段值并查看字段说明
  5. 05暂存结果并执行只读 SQL

适用场景

  1. 01查看某药品的标签、不良事件与召回
  2. 02查询药品短缺或 FDA 批准记录
  3. 03分析食品、器械或药品不良事件
  4. 04对暂存的查询结果运行 SQL

MCP 相关

通过 15 个 MCP 工具连接 openFDA 数据,涵盖查询、查找、统计和暂存结果分析。支持 STDIO 和 Streamable HTTP。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://openfda.caseyjhand.com/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

安装包
npm@cyanheads/openfda-mcp-server0.9.1

工具

14
参数类型必填说明
skipnumber否分页时要跳过的记录数(默认 0)。openFDA 的分页上限为 25000 条记录;更高的值会返回 pagination_limit_reached 错误。
sortstring否排序表达式——字段路径后可选添加 :asc 或 :desc(大小写不限;也接受 :ascending 和 :descending,所有方向均会以 asc 或 desc 发送);多个字段用逗号分隔。字段路径只能包含字母、数字、下划线和句点;任何其他字符或方向都会在请求前被拒绝。可排序的日期字段因类别而异:drug → receivedate:desc(或 receiptdate),food → date_created:desc(或 date_started),device → date_received:desc(或 date_of_event)。使用其他类别的字段(例如在 food 或 device 中使用 receivedate)会导致查询错误——请使用当前类别对应的字段。
limitnumber否要返回的记录最大数量(1–1000,默认值为 10)。在不同 openFDA 端点中,序列化记录的大小可能相差三个数量级,因此页面还受 24000 字节的序列化预算限制:如果页面超出预算,则返回的记录数会少于请求数量,并在 page_omitted 中报告截断情况。只要匹配到记录,就至少返回一条,无论其大小如何;page_bytes 会报告其大小,page_largest_fields 会列出最大的字段,这些字段可以通过投影移除。药品报告远大于其他报告——单条药品/事件报告平均有数万字节,而食品/事件报告只有几百字节。
stageboolean否将匹配结果集暂存到 DataCanvas,以便进行 SQL 分析——openfda_dataframe_describe 用于列出暂存列,openfda_dataframe_query 用于执行 SQL。默认为 false——调用仅针对一个上游请求返回一页。设为 true 时,也会将记录持续写入画布表,直到达到大小预算(staged_rows 报告写入的行数)。暂存适用于对有界切片进行记录级 SQL;若要统计所有匹配结果的分布,请使用 openfda_count_values 在服务器端通过一次请求聚合。需要 CANVAS_PROVIDER_TYPE=duckdb。
fieldsarray否要在每条返回记录中保留的点分隔记录路径,例如 ["receivedate", "patient.drug.medicinalproduct"]——返回记录中的任何键路径均可使用,openfda_describe_fields 会列出可搜索的字段。在测量内联字节预算之前,每条记录都会投影为这些路径及其标识键(safetyreportid、report_number、mdr_report_key),两个响应界面的处理方式相同;经过数组的路径会应用于每个元素。记录较大时使用此参数:如果 page_bytes 超出预算,响应会附带超大记录中最大的字段。通知中会列出任何返回记录均不包含的路径。省略则返回完整记录。路径只能包含字母、数字、下划线和点;其他字符会在请求前被拒绝。stage=true 时,仅投影内联页面——暂存表保留其列。
searchstring否openFDA 搜索查询。示例:patient.drug.medicinalproduct:"aspirin"、patient.reaction.reactionmeddrapt:"nausea" AND serious:"1"。省略则浏览最新记录。双引号、括号和范围方括号必须成对,查询末尾不得为反斜杠;否则会在请求前被拒绝。
categoryenum是产品类别——每种类别在响应中使用不同的字段架构drug | food | device
canvas_idstring否由先前对此工具或其他 openFDA 搜索工具(openfda_search_* 或 openfda_lookup_ndc)调用 stage=true 返回的 Canvas ID。传入此 ID 会将本次搜索暂存到该画布(效果等同于 stage=true),以便累积结果集并进行跨表联接。省略则暂存到新画布。

详细介绍

@cyanheads/openfda-mcp-server

通过 openFDA 查询药品、食品、器械和召回数据。支持 STDIO 或 Streamable HTTP。

15 个工具

版本 许可证 Docker MCP SDK npm TypeScript Bun

安装到 Claude Desktop 安装到 Cursor 安装到 VS Code

框架

公共托管服务: https://openfda.caseyjhand.com/mcp


概述

通过 openFDA 公共 API 获取药品、食品、器械和召回数据。搜索不良事件、召回、药品批准和器械许可;查询 NDC 代码和药品标签;聚合任意端点的字段计数。

工具
工具描述
openfda_drug_profile输入一个药品名称 → 汇总的 FDA 资料:身份信息、标签、不良事件、召回、批准和短缺
openfda_search_adverse_events搜索药品、食品和器械的不良事件报告
openfda_search_animal_events搜索兽用药品和器械的不良事件报告
openfda_search_drug_shortages按状态、可获得性、治疗类别和制造商搜索 FDA 药品短缺记录
openfda_search_tobacco_reports搜索烟草制品、电子烟和雾化设备的问题报告
openfda_search_recalls搜索药品、食品和器械的执法报告及召回行动
openfda_count_values汇总并统计任意 openFDA 端点中任意字段的唯一值
openfda_describe_fields返回 openFDA 端点的可搜索字段路径,并按类别分组
openfda_get_drug_label查询 FDA 药品标签(包装说明书 / SPL 文档)
openfda_search_drug_approvals搜索 Drugs@FDA 数据库中的 NDA/ANDA 申请批准信息
openfda_search_device_clearances搜索 FDA 器械上市前通知:510(k) 许可和 PMA 批准
openfda_lookup_ndc在 NDC(国家药品代码)目录中查询药品
openfda_dataframe_describe列出已暂存到 DataCanvas 的表和列架构
openfda_dataframe_query对暂存到 DataCanvas 的结果集运行只读 SQL
openfda_dataframe_drop删除一个暂存到 DataCanvas 的表(需主动启用,默认关闭)

功能参考

openfda_drug_profile 工具
  • 输入一个 drug 名称(品牌名或通用名),解析一次以确定其身份信息(通用名、NDC、RxCUI、SPL 集 ID);召回、批准和短缺信息以 meta.fanOutKey 为键——当输入名称是已解析通用名的某种成分时使用该名称,否则使用通用名;meta.resolvedVia(label、ndc、none)表示信息来源,并优先选择单一成分产品而非复方产品
  • 召回和批准查询也会搜索 openFDA 从未统一过的记录(product_description、products.active_ingredients.name);recalls_total 会在最新 5 条召回记录旁给出匹配数
  • label、adverse_events、recalls、approval 和 shortage 部分尽力返回结果,未找到时返回 null(或空的 recalls);degraded[] 会列出上游子查询失败的部分,因此列出的部分表示未知,而不是不存在
  • 身份验证、配置和取消错误会导致整个调用失败,而不会仅使某个部分降级

openfda_search_adverse_events 工具
  • category(drug、food、device)用于选择端点及其记录架构;每页最多 1000 条记录
  • 可排序的日期字段因类别而异:receivedate(药品)、date_created(食品)、date_received(器械);使用其他类别的字段会导致 query_error
  • 文本输出会在原始值旁解码药品给药途径、反应结局和患者年龄组代码(via oral (048)、fatal (5)、elderly (6));结构化输出保留这些代码

openfda_search_animal_events 工具
  • 可选地使用 search 搜索兽医报告,例如 animal.species、drug.active_ingredients.name、reaction.veddra_term_name、serious_ae;每页最多 1000 条记录
  • 每条记录中的品牌名和制造商名称都会被屏蔽为 MSK,因此请按活性成分搜索;drug.manufacturer.registration_number 可将结果缩小到某个批准
  • 记录包含动物种类、品种、年龄和体重、药品及给药途径、VeDDRA 反应术语和结局

openfda_search_drug_shortages 工具
  • 可选地按 status(Current / To Be Discontinued / Resolved)、therapeutic_category、generic_name 或 company_name 进行 search;每页最多 1000 条记录
  • 每条记录的 openfda 块包含 brand_name、product_ndc 和 rxcui,可用于接续调用 openfda_get_drug_label 或 openfda_lookup_ndc

openfda_search_tobacco_reports 工具
  • 可选地按 tobacco_products、reported_health_problems、reported_product_problems 或 nonuser_affected 进行 search;每页最多 1000 条记录
  • 报告包含问题数组以及 number_tobacco_products、number_health_problems 和 number_product_problems 计数

openfda_search_recalls 工具
  • category(drug、food、device)以及 endpoint:enforcement(默认,适用于所有类别)或 recall(仅适用于设备;其他类别会以 recall_endpoint_non_device 失败);每页最多 1000 条记录
  • Enforcement 记录包含 recall_number、classification(Class I/II/III)和 status;设备召回记录则包含 product_res_number 和 recall_status,不含危害分类

openfda_count_values 工具
  • endpoint(20 个 openFDA endpoint 中的任意一个)、count 字段表达式以及可选的 search;返回最多 1000 个热门词项(默认 100 个),按计数排序;日期字段会为每个不同的 YYYYMMDD 日期返回一个词项,排序方式相同
  • 如果存在超出 limit 的不同词项,truncated 会标记这一情况;但达到 1000 个词项的上限时,会显示无法确定数据是否完整的提示(日期计数在任何 limit 下都是精确的,因为 openFDA 会发送每个日期);如果 openFDA 无法聚合某个表达式,则会以 not_aggregatable 失败(请从 openfda_describe_fields 获取 countAs 格式)
  • 即使启用了 bulk 镜像,也始终通过实时 API 执行

openfda_describe_fields 工具
  • endpoint:与 openfda_count_values 接受的 20 个 endpoint 相同
  • 按类别分组的字段路径;每个字段都包含 type、描述和 countAs(已验证的计数表达式;字段无法聚合时为 null),以及关于引号、AND/OR、.exact 和日期范围的 queryTips

openfda_get_drug_label 工具
  • 必须在标签字段(openfda.brand_name、openfda.generic_name、openfda.manufacturer_name、set_id)上执行 search;limit 默认值为 5,最大值为 1000
  • 如果某页超过 24,000 字节的内联预算,则会返回 kind: "outline"(按大小从大到小排列的章节名称和大小),而不是标签文本;再次调用并传入 sections: [...],即可获取这些章节以及身份元数据(openfda、set_id、id、effective_time、version),即使超出预算也会完整返回
  • *_table 章节在文本输出中会渲染为 Markdown 表格;结构化结果则保留原始 SPL 标记

openfda_search_drug_approvals 工具
  • 可选地按 openfda.brand_name、sponsor_name(以大写形式存储,因此带引号的小写值不会匹配任何内容)、submissions.submission_type 或 submissions.review_priority 进行 search;每页最多 1000 条记录
  • 记录包含 application_number、sponsor_name、products[] 以及该申请的完整 submissions[] 历史记录

openfda_search_device_clearances 工具
  • pathway(510k 或 pma,每次调用只能指定一个)以及可选的 search,可按 applicant、product_code、advisory_committee_description 或 openfda.device_name 搜索;每页最多 1000 条记录
  • 510(k) 记录包含 k_number、device_name 和 decision_date;PMA 记录包含 pma_number、trade_name 和 supplement_number

openfda_lookup_ndc 工具
  • 必须按 product_ndc、brand_name、generic_name、openfda.manufacturer_name 或 active_ingredients.name 进行 search;每页最多 1000 条记录
  • 记录包含 product_ndc、labeler_name、dosage_form、route、marketing_category、active_ingredients[] 和 packaging[]

openfda_dataframe_describe 工具
  • 使用暂存搜索中的 canvas_id;列出每个表的 name、kind、完整暂存 row_count,以及包含 DuckDB 类型和是否可为 null 的列
  • 当 CANVAS_PROVIDER_TYPE=none 时失败并返回 canvas_disabled;当 canvas_id 已过期或从未存在时失败并返回 canvas_not_found

openfda_dataframe_query 工具
  • 使用 canvas_id 和一条只读 SELECT;不允许 DDL、DML、COPY 和文件读取函数。标量以文本形式存储(数学运算需使用 CAST),嵌套的 openFDA 数据块以 JSON 列存储
  • 行数上限为 canvas 行数限制;truncated: true 表示需要使用 ORDER BY 和 LIMIT/OFFSET 继续分页;失败时返回 canvas_disabled、canvas_not_found、missing_table 或 invalid_query

openfda_dataframe_drop 工具
  • 默认关闭:设置 OPENFDA_DATAFRAME_DROP_ENABLED=true 后即可调用;否则该工具会在着陆页上标记为已禁用,且不会出现在 tools/list 中
  • 使用 canvas_id 和 openfda_dataframe_describe 返回的 table 名称;删除该表或视图,并返回 remaining_tables,canvas 和其中其他表会保留
  • 失败时返回 canvas_disabled、canvas_not_found 或 missing_table(已删除、已过期或名称拼写错误)

功能

基于 @cyanheads/mcp-ts-core 构建:支持 stdio 和 Streamable HTTP 传输、可插拔身份验证(none / jwt / oauth)、可切换存储(in-memory、filesystem、Supabase、Cloudflare KV/R2/D1),并提供结构化日志记录和可选的 OpenTelemetry 跟踪。

openFDA 专属功能:

  • 一个客户端支持全部 20 个 openFDA 端点,遇到 429 和 5xx 时会重试。无需 API 密钥(每天 1K 次请求);免费的 OPENFDA_API_KEY 可将限额提升至每天 120K 次
  • 查询使用点分路径,并以 AND/OR 连接 field:value 条件(子句之间 URL 风格的 + 会被视为空格);openfda_describe_fields 会列出路径,格式错误的查询会在发起请求前以 malformed_search 失败
  • 分页:limit 最高为 1000,skip 最高可达 openFDA 的 25,000 条记录上限(超过后返回 pagination_limit_reached);每页大小限制为 24,000 字节
  • 在任何 openfda_search_* 工具或 openfda_lookup_ndc 中使用 fields,可按指定的点分路径裁剪每条记录,使大型记录也能以内联形式返回
  • DataCanvas 暂存(默认开启;设置 CANVAS_PROVIDER_TYPE=none 可关闭),可使用 stage: true 或 canvas_id;还可选配本地批量镜像(OPENFDA_MIRROR_ENABLED=true),对精确键查找进行响应而不消耗 API 配额

便于 Agent 使用的输出:

  • 明确披露边界:page_omitted、page_bytes、page_largest_fields、projected_fields、标签 outline 和 staged_rows 会报告所有截断情况
  • 带类型的失败:调用方可根据 error.data.reason(rate_limited、query_error、not_aggregatable 等)进行分支处理,而无需解析消息
  • 区分未知与不存在:对于没有 FDA 记录的部分,openfda_drug_profile 会返回 null,并在 degraded[] 中列出失败的部分
  • 空结果指引:搜索无匹配结果时,会提示查看 openfda_describe_fields 并尝试更宽泛的搜索词

开始使用

连接到托管实例,无需安装:

claude mcp add --transport http openfda-mcp-server https://openfda.caseyjhand.com/mcp

或在本地运行:

claude mcp add openfda-mcp-server -- npx -y @cyanheads/openfda-mcp-server

对于其他客户端,请将以下内容添加到 MCP 配置文件:

{
  "mcpServers": {
    "openfda-mcp-server": {
      "command": "npx",
      "args": ["-y", "@cyanheads/openfda-mcp-server"]
    }
  }
}

无需 API 密钥。将免费的 openFDA API 密钥 设置为 OPENFDA_API_KEY,可将限额从每天 1K 次请求提升至 120K 次。Docker 或源码构建方式请参阅运行服务。

配置

变量说明默认值
OPENFDA_API_KEY从 open.fda.gov 获取的免费 API 密钥;每日限额从 1K 次请求提高至 120K 次。none
OPENFDA_BASE_URLAPI 基础 URL 覆盖值,用于代理或模拟服务。https://api.fda.gov
OPENFDA_MIRROR_ENABLED从本地批量镜像响应精确键查找。false
OPENFDA_MIRROR_PATH存放每个镜像数据集对应 SQLite 文件的目录。./data/openfda-mirror
OPENFDA_MIRROR_REFRESH_CRON进程内镜像刷新的 Cron 表达式(仅限 HTTP 传输)。none
OPENFDA_MIRROR_FALLBACK_LIVE镜像尚未就绪、缺少记录或发生故障时,回退到实时 API。true
OPENFDA_MIRROR_REFRESH_TIMEOUT_MS单次刷新被中止前的墙钟时间预算,单位为 ms。21600000 (6h)
OPENFDA_MIRROR_BASE_URL提供批量下载清单(download.json)的主机。https://api.fda.gov
CANVAS_PROVIDER_TYPEDataCanvas 暂存和 SQL。none 会禁用这些功能;数据框工具仍会列出,但会返回 canvas_disabled。duckdb
OPENFDA_DATAFRAME_DROP_ENABLED启用 openfda_dataframe_drop,用于删除暂存表。需要 CANVAS_PROVIDER_TYPE=duckdb。false
MCP_TRANSPORT_TYPE传输方式:stdio 或 http。stdio
MCP_HTTP_PORTHTTP 服务端口。3010
MCP_SESSION_MODEHTTP 会话模式:stateless、stateful 或 auto。stateless
MCP_AUTH_MODE身份验证:none、jwt 或 oauth。none
MCP_LOG_LEVEL日志级别(debug、info、warning、error 等)。info
LOGS_DIR日志文件目录(仅 Node.js)。<app-root>/logs
STORAGE_PROVIDER_TYPE存储后端:in-memory、filesystem、supabase、cloudflare-kv/r2/d1。in-memory
OTEL_ENABLED启用 OpenTelemetry。false

完整的可选覆盖项列表请参见 .env.example。

Claude Desktop MCPB 包会禁用 DataCanvas,因为其中不包含特定于平台的 DuckDB 绑定。要使用暂存和 SQL,请使用 npm 或 Docker。

本地批量镜像

设置 OPENFDA_MIRROR_ENABLED=true 后,服务会在本地保留四个 openFDA 批量数据转储(drug/label、drug/ndc、drug/enforcement、drug/drugsfda)的 SQLite 副本。只有精确查找会在本地响应:单个带引号的 field:"value" 条件,字段为 id、set_id、product_id、product_ndc、recall_number、event_id 或 application_number;不带 count 或 sort,skip 为 0,且只有一条匹配记录。其他所有请求都会转发到 API。

初始数据抓取会单独运行,不会在启动时执行:

bun run mirror:init                  # all four datasets
bun run mirror:init drug/enforcement # one dataset
bun run mirror:status                # sync state per dataset
bun run mirror:verify                # integrity check + row counts
bun run mirror:refresh               # re-harvest datasets whose dump has advanced

刷新会重新读取整个数据转储。设置 OPENFDA_MIRROR_REFRESH_CRON,即可通过 HTTP 传输在进程内运行刷新;使用 stdio 时,请在宿主机上运行 bun run mirror:refresh。镜像响应中的 meta.lastUpdated 是所提供数据转储的时间戳,可能与实时 API 中的时间戳不同。

在 Node 上,请安装可选的 better-sqlite3 对等依赖(Bun 使用内置的 bun:sqlite)。OPENFDA_MIRROR_REFRESH_CRON 还需要可选的 node-cron 对等依赖;未安装时,服务会在启动时失败。

运行服务

本地开发

需要 Bun v1.4.0 或更高版本(或 Node.js v24+)。

  • 克隆并安装:

    git clone https://github.com/cyanheads/openfda-mcp-server.git
    cd openfda-mcp-server && bun install
    cp .env.example .env   # optionally set OPENFDA_API_KEY and the mirror or canvas options
    
  • 构建并运行:

    # One-time build
    bun run rebuild
    
    # Run the built server
    bun run start:stdio
    # or
    bun run start:http
    
  • 运行检查和测试:

    bun run devcheck   # Lint, format, typecheck, security
    bun run test       # Vitest test suite
    bun run lint:mcp   # Validate MCP definitions against spec
    
Docker
docker run --rm -p 3010:3010 ghcr.io/cyanheads/openfda-mcp-server:latest

该镜像默认使用 HTTP 传输、无状态会话模式,并将日志写入 /var/log/openfda-mcp-server。若要通过 MCP 客户端使用 stdio 运行,请使用 "command": "docker" 和 "args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/openfda-mcp-server:latest"]。若要在本地构建,运行 docker build -t openfda-mcp-server .;默认会安装 OpenTelemetry 对等依赖,若要省略这些依赖,请使用 --build-arg OTEL_ENABLED=false 构建。若要在容器更换后保留镜像采集的数据,请在 /usr/src/app/data/openfda-mirror 上挂载卷。

项目结构

目录用途
src/index.tscreateApp() 入口:工具注册、服务设置、镜像刷新配置。
src/config使用 Zod 解析并验证特定于服务的环境变量。
src/mcp-server/tools/definitions工具定义(*.tool.ts),共 15 个。
src/mcp-server/tools共享工具辅助模块:各端点的字段目录、输入模式和校验逻辑、格式化程序、SPL 表格渲染。
src/services/openfdaopenFDA API 客户端(重试、速率限制、错误规范化)、内联页面预算、fields 记录投影、canvas 暂存。
src/services/openfda/mirror可选的本地批量镜像:数据集注册表、转储读取器、采集器、镜像与实时查询的选择逻辑、刷新计划。
src/services/canvas用于暂存和 SQL 的 DataCanvas 访问器。
scripts/openfda-mirror.ts由 mirror:* 脚本调用的镜像生命周期 CLI。
tests/单元测试和集成测试,结构与 src/ 对应。

开发指南

开发指南和架构规则请参阅 CLAUDE.md。简要说明:

  • 处理程序抛出错误,由框架捕获;工具逻辑中不要使用 try/catch
  • 使用 ctx.log 记录请求范围内的日志
  • 在 src/mcp-server/tools/definitions/index.ts 的汇总入口中注册新工具
  • 封装外部 API 调用:校验原始数据 → 规范化为领域类型 → 返回输出模式;绝不编造 openFDA 未返回的字段

数据归属说明

数据来自 openFDA,这是美国食品药品监督管理局的一项服务。根据 openFDA 许可,这些数据依据 CC0 1.0 许可奉献给公有领域,但有一个例外:GMDN® 设备分类内容(Term Code、Term Name 和 Term Definition)由 The GMDN Agency 授权;重新分发这些内容或将其用于训练 AI,均需获得该机构的单独许可。

因此,本地镜像仅涵盖药品数据集。device/classification 和所有其他设备端点均不包含在镜像中;摄取程序也会拒绝任何带有 GMDN 相关字段的记录,不会将其写入磁盘。

FDA 不为本项目背书。请勿依赖 openFDA 来做出医疗护理相关决定。

贡献

欢迎提交问题。提交前请运行检查和测试:

bun run devcheck
bun run test

许可证

本项目采用 Apache 2.0 许可证。详情请参阅 LICENSE 文件。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。