mcpField
D
Drug Prices

Drug Prices

远程服务
pipeworx.io健康医疗03 天前更新

关于 Drug Prices

Drug Prices 是面向医疗研究人员和分析人员的 MCP 服务,用于查询美国药房采购价格、Medicare Part B 支付上限及 340B 数据。它区分 NADAC 与 ASP 两类基准,并说明缺失数据的原因。

主要功能

  1. 01查询 NADAC 采购价格
  2. 02查看每周 NADAC 价格历史
  3. 03查询 Medicare Part B ASP 上限
  4. 04并列比较可用药价基准
  5. 05搜索 340B 实体与药房

适用场景

  1. 01核对药品的药房采购成本
  2. 02查看药品的 Part B 支付上限
  3. 03结合日期和单位比较价格基准
  4. 04查找参与计划的 340B 站点及药房关联

MCP 相关

通过 Pipeworx 端点向 MCP 客户端提供药价与 340B 查询工具。README 也介绍了服务端点及其可用工具。

配置

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

服务地址https://gateway.pipeworx.io/drug-prices/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 配置后重启。需要授权的服务会在首次连接时提示登录。

工具

详细介绍

drug-prices

美国药品价格基准:药房购买药品的成本,以及 Medicare Part B 为服务提供者施用的药品支付的金额。无需密钥。

属于 Pipeworx — 一个将 AI Agent 连接到 1878+ 个实时数据源的 MCP 网关。这是一项独立、非官方的集成,与上游提供方无关联、未获其认可,也不是由其发布。

这两个数字经常被混为一谈,而本工具包的大部分工作就是将它们区分开来。

NADACASP 支付限额
回答的问题零售药房向批发商支付的金额Medicare 向诊所支付的金额
更新频率每周每季度
索引依据NDCHCPCS(J-code)
典型药品仿制药片剂、零售产品肿瘤药物、生物制剂、输注药物、疫苗
来源CMS,经由 data.medicaid.govCMS ASP 定价文件(ZIP)

仿制药片剂有 NADAC,但没有 ASP。输注用肿瘤药物有 ASP,通常没有零售 NADAC。drug_price_compare 会报告存在的基准,并说明为何另一项缺失,而不是返回空结果。

工具

  • nadac_price(drug | ndc, as_of?, limit?) — 当前单位采购成本
  • nadac_history(ndc, weeks?) — 每周价格序列和变化百分比
  • asp_payment_limit(hcpcs | drug, quarter?, limit?) — Part B 每剂量单位限额
  • drug_price_compare(drug, ndc?) — 并列展示两项基准及其版本日期

数据处理

NADAC 从实时数据读取 — data.medicaid.gov 提供了真正的查询 API(筛选、排序、分页),数据集包含约 20 个月的数据,因此无需镜像。ASP 完全没有 API:CMS 每季度发布一个 ZIP 文件,因此通过 scripts/ingest-asp-payment-limits.mjs 将其导入 asp_payment_limits,再从 Supabase 读取。

node scripts/ingest-asp-payment-limits.mjs            # current quarter
node scripts/ingest-asp-payment-limits.mjs --back=5   # backfill

易错点

构建此工具包时,我们遇到了以下每一个问题,而且每次都导致了看似确定的错误答案,而不是报错。

最新的 NADAC 周数据通常是更正文件,而不是完整的一周数据。 NADAC 会发布完整的每周文件,也会发布一些周期外的小型更正文件,它们共用同一个 effective_date 列。经测量,2026-08-28:2026-08-26 → 77 行,2026-08-19 → 58,163 行,2026-08-12 → 6 行。显而易见的设计——取 max(effective_date),然后筛选——会命中只有 77 行的文件,导致几乎所有药品都返回“找不到价格”,而这与 NADAC 未涵盖该药品的情况无法区分。应当先按药品筛选,然后取匹配结果中最新的日期。

数据存储 API 会静默忽略未知参数。 ?sort=-effective_date 返回 HTTP 200,但行数据并未排序——与 ?zzznonsense=x 返回的内容逐字节相同。只有 sorts[0][property] + sorts[0][order] 这种写法才能排序。这里拼写错误不会失败;它会悄无声息地返回某个任意周的价格。

NADAC 数据集 ID 每年 1 月都会轮换,标题中的年份也不代表其涵盖的日期范围。 名为“...NADAC ... 2026”的数据集涵盖的生效日期为 2025-01-01 至 2026-08-26。调用时会按标题解析 ID,并以最后一个已知 ID 作为备用,因此 1 月不会导致工具包出错。

NADAC 包含两个日期。 effective_date 是价格适用的周;as_of_date 是 CMS 发布价格的日期。价格以第一个日期为准;两个日期都会返回。

ASP 支付限额的版本日期并非其对应的季度。 CMS 文件中明确写道:生效日期为 2026-07-01 的文件“based on 1Q26 ASP data”。当前有效的限额是根据大约早两个季度的 ASP 数据得出的,因此将其与本周的 NADAC 进行比较,时间跨度约为 6 个月。始终会返回两个季度。

ASP CSV 使用的是 windows-1252 编码,而非 UTF-8,且实际数据值中包含一个 0xA0("1 million\xa0PFU")。按 UTF-8 读取会抛出错误;更糟的是,grep 遇到非法字节会静默中止,这就是为什么 J9271 最初看起来像是缺失于实际包含它的文件中。

ASP CSV 的表头不在第 1 行(前面有 9 行说明,行数也会因季度而异),而且内部文件名中包含各季度的生成日期(…File 061626.csv)。这两者都通过模式匹配,而非固定偏移量或固定名称来处理。CMS 对 ZIP 文件是否带有 -final-file 后缀也不统一,因此会尝试两种写法。

NADAC 用品牌名而非成分名来命名品牌药品。 APIXABAN 匹配到 0 行;ELIQUIS 匹配到 204 行。因此,对仍在使用品牌名的药品进行通用名搜索,会返回一个看似确定的空结果;那个很容易想到的解释——“一定是由诊所给药”——在这种情况下显然是错的。空结果说明会按可能性从高到低列出这两种可能,而不是武断地断定其中一种。

NDC 有三种格式——带连字符的 5-4-2 位格式、11 位格式,以及缺少前导零的 10 位格式——它们作为字符串并不能互换。所有格式都会规范化为标准的 11 位格式。

payment_limit 的单位取决于其 dosage 单位。 J9271 的价格为每 1 MG $60.645,因此 200 MG 的给药量是其 200 倍。如果返回限额时不同时注明单位,就可能造成 200 倍的误差,因此二者始终一起返回。

drug_price_compare 有意不对两个基准值进行计算。 NADAC 按定价单位(EA/ML/GM)计价,ASP 按 HCPCS 剂量计价——两者的分母不同,测量时间也相隔数月。将其中一个除以另一个,会得到一个看似确定、实则毫无意义的“利润率”。

340B 涵盖实体

b340_covered_entities 和 b340_contract_pharmacies 读取 HRSA OPAIS 的镜像数据:截至 2026-09-07 的导出数据中,包含 94,363 条涵盖实体注册记录(其中 64,413 条目前正在参与)和 398,441 条合同药房关联记录。

一个 340B ID 对应一个站点,而非一个机构——一个医疗系统会持有多个 ID,parent_id340b 用于将子站点关联到其注册的母医院。名录中约三分之一是已终止的注册记录,因此除非你特别要求,否则这两个工具都会将其排除;如果没有匹配项,工具会明确说明,而不会暗示该实体从未存在过。

type 可使用普通词语(如 "hospital"、"health center"、"Ryan White"、"critical access"),也可使用 HRSA 的 23 个代码;state 既可使用 "Texas",也可使用 "TX"。如果值无法识别,工具会拒绝请求(REFUSED)并列出有效值,而不会悄悄忽略该值,因为忽略筛选条件会返回完整的未筛选结果集,并显示正常的 200 状态码,看起来就像是有效答案。

不提供联系人。 导出数据包含 authorizingOfficial 和 primaryContact,涉及 94,363 名具名人士及其直拨电话号码。这些信息既未被导入,也没有对应的列,因此任何查询都无法返回这些信息。请参阅迁移标头。

如何保持数据新鲜——由人点击按钮

此处的 340B 数据会由人工有意地大约每月刷新一次:

  1. .github/workflows/340b-refresh-reminder.yml 每月 1 日运行,仅当距上次加载已超过 25 天,且没有已打开的相同请求时,才会提交一项 fleet 任务。
  2. 某人点击 https://340bopais.hrsa.gov/Reports 上的 Covered Entity Daily Export (JSON),然后运行 bash scripts/340b-drop.sh ~/Downloads/340B_CoveredEntityJson_Daily_*.zip。
  3. .github/workflows/340b-ingest.yml 解析并加载数据,然后关闭该任务。

as_of 取自导出文件名,而非加载日期,因此即使文件在 Downloads 文件夹中放了一周,也不会夸大数据的新鲜程度。加载器会拒绝替换为少于 50,000 个实体的名录,因此下载不完整时会明确报错,而不是悄悄缩减数据。每个响应都会附带 as_of。

为什么不自动化

在 fleet #618 中提出,并在 #633 中探测:我们运行的任何程序都无法获取该导出。 已于 2026-09-01(fleet #804)和 2026-09-07(fleet #633)重新验证:情况依然如此。

HRSA OPAIS(340bopais.hrsa.gov)采用的是 Blazor Server,并非此处最初记录的客户端渲染方式。/Reports 会加载 _framework/blazor.web.js(.NET 8+ Blazor Web App),且 SignalR circuit 端点处于活动状态。

此文件过去引用的 411 响应并不能证明任何事情——不要重复该探测。 对主机上的任何路径发送不带请求体的 POST,边缘节点都会返回 411 Length Required,即使该路径并不存在也是如此。发送空请求体并设置 Content-Length: 0 后,路径才会明确区分(2026-09-01 测得):

路径不带请求体的 POSTPOST -d ''
/_blazor/negotiate?negotiateVersion=1411200 {"negotiateVersion":1,"connectionId":"…","connectionToken":"…","availableTransports":[WebSockets, ServerSentEvents, LongPolling]}
/DXXRDV411404,0 字节
/nonexistentpath123411404,0 字节

值得特别提到 /DXXRDV,因为 /Reports 会加载 DevExpress Web Document Viewer 脚本,而该控件通常确实会在该路径下挂载一个 HTTP 控制器——这是个看起来很有希望的 REST 入口,但 OPAIS 并未开放它。

没有可复现的请求。 在浏览器中加载 /Reports、清空网络日志,然后点击 Covered Entity Daily Export (JSON),记录到的 HTTP 请求为零——无论筛选所有请求,还是专门筛选 _blazor,结果都一样。文件是通过页面加载时就已建立的 WebSocket 返回的,而 WebSocket 帧不是 HTTP 请求。HRSA 自己的常见问题解答也表达了同样的意思:没有直接下载 URL,而且“回发和按钮点击必须在当前会话和视图状态的上下文中完成”。

更正,2026-09-07 测得(fleet #633,Alaric):阻碍因素是有状态的 circuit,而不是 WebSocket。 此文件过去曾称,WebSocket 传输“让 curl、Worker 和 cron 都无事可做”。这个理由是错的,错法和它所取代的 411 理由一样——它指出的只是表象,下一个重新探测的人只需一条命令就能推翻它。negotiate 通告了三种传输方式,而非一种:WebSockets、ServerSentEvents 和 LongPolling。LongPolling 使用普通 HTTP POST/GET,因此 Worker 可以驱动这个 circuit。真正不该这么做的原因在于连接后调用方必须完成的工作:重放 Blazor 组件握手,从二进制渲染批次中读取按钮的组件 ID,针对该组件派发合成 UI 事件,并从 circuit 帧中重新组装流式文件。这是在模拟有状态 UI 会话,任何组件变更都会导致它失效——而且会静默失效,返回越来越短的实体列表,而不是报错。结论不变,但现在有了正确的证据:问题不在于传输方式受阻,而在于这需要充当一个抓取实时 UI 的爬虫。

也没有镜像站点,已于 2026-09-01 重新检查:HRSA Data Warehouse 下载目录(452 KB 的列表,125 个数据集标签)中,字符串 340b 出现零次;healthdata.gov 的 Socrata 目录通过 ?q=340B 返回 resultSetSize: 1,唯一的结果是 data.hrsa.gov (HRSA Data Warehouse) 链接条目,而非数据集;catalog.data.gov/api/3/action/package_search 在 API 本身就返回 404;data.hrsa.gov/api/views.json 和显而易见的批量下载路径也都返回 404。

因此,解决办法是由人工介入,而现在已经落实(Bruce 已同意每月点击一次,2026-09-07)。340B 注册按季度周期变动——导出每晚生成,只是因为它每晚都会重新生成,并不代表名单每天都在变化——因此每月点击一次即可获取真实表格,带有可信的 as_of,也无需依赖一个在下次组件变更时就会静默失效的有状态应用爬虫。请参阅上文“保持数据最新的方式”。

快速开始

添加到你的 MCP 客户端(Claude Desktop、Cursor、Windsurf 等):

{
  "mcpServers": {
    "drug-prices": {
      "url": "https://gateway.pipeworx.io/drug-prices/mcp"
    }
  }
}
此端点实际提供的内容

https://gateway.pipeworx.io/drug-prices/mcp 上的 tools/list 会返回上表中的工具,以及 Pipeworx 共享元工具——ask_pipeworx、 discover_tools、search_within、remember/recall,以及网关级工具集中的其他工具。因此,你看到的工具数量会多于表格所列:目前,单个工具包端点除了该工具包自身的工具外,还会列出大约 30 个共享工具。连接的 initialize 响应会说明确切范围,是当天情况的权威答案。

这是有意为之,并非意外的多路复用。元工具可以让限定范围的连接回答此工具包未涵盖的问题——通过 ask_pipeworx 跨整个目录进行路由——因此你无需再添加第二个 MCP 服务。目前无法挂载不含这些工具的工具包端点;如果额外的架构定义占用的上下文比路由带来的价值更大,请连接一次完整网关,而不是连接多个工具包端点。

或者,连接完整的 Pipeworx 网关,直接列出每个工具包的所有工具,而不只是当前工具包的工具:

{
  "mcpServers": {
    "pipeworx": {
      "url": "https://gateway.pipeworx.io/mcp"
    }
  }
}

两个 URL 都连接到同一个网关和相同的 1878+ 个数据源。唯一的区别是直接列出哪个工具包的工具;通过任一 URL,ask_pipeworx 都能访问所有工具。

没有 MCP 客户端?通过 HTTP 调用

curl -X POST https://gateway.pipeworx.io/v1/tools/nadac_price \
  -H 'Content-Type: application/json' \
  -d '{"drug":"atorvastatin 20 mg"}'

首次调用无需账号。检查任意工具:GET https://gateway.pipeworx.io/v1/tools/nadac_price。查找工具包:使用 {"query":"..."} 调用 POST https://gateway.pipeworx.io/v1/tools/search_packs。

独立运行(无需网关账号)

此软件包也可以作为本地 stdio MCP 服务运行——无需 Pipeworx 账号,也无需经过网关往返:

{
  "mcpServers": {
    "drug-prices": {
      "command": "npx",
      "args": ["-y", "@pipeworx/mcp-drug-prices"]
    }
  }
}

或者直接运行,确认它能启动:

npx -y @pipeworx/mcp-drug-prices

它通过 stdin/stdout 使用 MCP,并响应 initialize/tools/list/tools/call,但仅限此工具包的工具——不包含上方网关连接所提供的任何共享元工具。源代码相同,工具相同,但没有 ask_pipeworx 路由。

使用 ask_pipeworx

你可以用通俗英语提问,而不是直接调用工具——此方式既适用于上方的工具包端点,也适用于完整网关:

ask_pipeworx({ question: "your question about Drug Prices data" })

网关会自动选择合适的工具并填入参数。

更多信息

许可证

MIT

评论

支持 Markdown

第一次接触 MCP?

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

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