内容
# fhir-mcp
> **可信赖的 AI 代理 FHIR 桥梁。**
> 将任何与 MCP 兼容的助手插入真实的 FHIR R4 服务器 - 具有可复制的临床评估,可逆的关键去识别,CDS Hooks 决策支持和每次调用的审计跟踪。
**🚀 实时演示:** [**`https://dhairya-fhir-mcp.fly.dev/`**](https://dhairya-fhir-mcp.fly.dev/) → JSON 信息 · [**`/sse`**](https://dhairya-fhir-mcp.fly.dev/sse) → MCP 端点
Synthea 风格的合成患者(5 个黄金包,无真实 PHI)。将任何 MCP 客户端指向 `/sse` 并调用 `search_patients`、`get_patient_summary`、`run_cds_hook` 或其他 8 种工具。部署您自己的副本:请参阅 [`DEPLOY.md`](DEPLOY.md)。
<p>
<a href="https://github.com/DhairyaShah981/fhir-mcp/actions"><img src="https://img.shields.io/github/actions/workflow/status/DhairyaShah981/fhir-mcp/ci.yml?branch=main&label=CI" alt="CI"></a>
<a href="https://github.com/DhairyaShah981/fhir-mcp/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-blue" alt="License"></a>
<a href="https://pypi.org/project/fhir-mcp/"><img src="https://img.shields.io/pypi/v/fhir-mcp?label=pypi" alt="PyPI"></a>
<img src="https://img.shields.io/badge/FHIR-R4-orange" alt="FHIR R4">
<img src="https://img.shields.io/badge/MCP-1.x-purple" alt="MCP">
</p>
---
## 为什么存在
LLM 编码代理已与数据库、IDE、GitHub、Slack 和桌面端集成。**医疗保健领域除外。** 当临床医生、创始人或后台团队尝试为与 MCP 兼容的助手提供真实的 EHR 环境时,他们会遇到同样的障碍:FHIR 是一份 2000 页的规范,数据中充满 PHI,没有人信任一个自由形式的 LLM 来接触它。
已经存在六个开源 FHIR MCP 服务器。**但它们都没有解决信任问题。** 它们将 FHIR 资源暴露为 MCP 工具,希望 LLM 不会产生幻觉代码,并使用正则表达式掩盖一些 PHI。没有可复制的临床准确性基准。没有受控的重新识别路径。没有通往 **CDS Hooks** 的桥梁 - 临床决策支持的生产标准。LLM 跟踪和审计日志之间没有链接。
`fhir-mcp` 是 **第一个为信任而设计的 FHIR MCP 服务器,而不仅仅是访问** - 因此您可以将其放入您的 MCP 客户端,并在周一早上进行演示,周五向临床安全官员进行演示,并对他们提出的每个问题都有可辩护的答案。
| 能力 | [Momentum][m] | [xSoVx][x] | [WSO2][w] | [AWS HealthLake][a] | [Flexpa][f] | [langcare][l] | **fhir-mcp** |
|---|:--:|:--:|:--:|:--:|:--:|:--:|:--:|
| FHIR 资源 MCP 工具 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 出口去识别 | ❌ | ⚠️ 不可逆转的掩码 | ❌ | ❌ | ❌ | ⚠️ 仅日志清理 | ✅ |
| **可逆转、密钥、审计重新识别** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **✅** |
| **可复制的临床评估框架** (在存储库中,CI 门控) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **✅** |
| **CDS Hooks 桥** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **✅** |
| MCP 资源 + 提示 | ❌ | ⚠️ 仅提示 | ❌ | ⚠️ 仅资源 | ❌ | ⚠️ 通过嵌入式应用 | **✅ 所有三个** |
| 审计日志链接到 LLM 跟踪 ID | ❌ | ⚠️ 通用跟踪 ID | ❌ | ❌ | ❌ | ⚠️ HIPAA 审计,非 LLM 跟踪 | **✅** |
| 零配置本地模式 | ⚠️ | ⚠️ | ❌ | ❌ | ✅ | ⚠️ | ✅ |
[m]: https://github.com/the-momentum/fhir-mcp-server
[x]: https://github.com/xSoVx/fhir-mcp
[w]: https://github.com/wso2/fhir-mcp-server
[a]: https://awslabs.github.io/mcp/servers/healthlake-mcp-server
[f]: https://github.com/flexpa/mcp-fhir
[l]: https://github.com/langcare/langcare-mcp-fhir
<sub>最后一次手动验证:2026-05-23。</sub>
---
## 评估排行榜
_每次推送时由 CI 生成。运行 `uv run python evals/report.py` 本地。_
| 评估 | 分数 | 覆盖率 |
|---|---|---|
| 临床准确性(结构) | 7/7 ✅ | 5 个黄金患者 · ~40 个资源 · 7 个场景 |
| 临床准确性(判断 LLM) | _如果没有 `ANTHROPIC_API_KEY` 则跳过_ | 可选加入 |
| 去识别泄漏 | **0 次泄漏** ✅ | 所有 5 个包 → ~40 个资源 → ≥30 个已知 PHI 代币,扫描每个工具输出 |
| 代码验证 | 31/31 ✅ | LOINC · SNOMED · RxNorm · ICD-10 (离线表) |
| CDS Hooks 正确性 | 4/4 ✅ | 药物-药物、药物-过敏、预取去识别、未知钩安全 |
| 跨模型判断器传播 | _可选加入_ | 运行 `python -m evals.cross_model` 并使用 API 密钥 |
**工程健康状况(v0.2.1):** **206 个测试通过** · **96% 行覆盖率** (运行 `uv run pytest tests evals --cov=src/fhir_mcp` 本地)· ruff + pyright clean · MCP stdio 端到端验证 · SMART OAuth2(PKCE + 后端服务)实现 · 5 个黄金 Synthea 包 · [STRIDE 威胁模型](docs/THREAT_MODEL.md)。
> 上面的排行榜是可复制的:`uv run python evals/report.py --out scoreboard.md` 重新运行每个套件并写入表格。判断 LLM 评分是可选加入的;如果没有 API 密钥,它被报告为跳过,而不是假过。
---
## SMART on FHIR
`fhir-mcp` 是一个机密 SMART 应用。两个 OAuth2 流已连接:
| 流 | 用例 | CLI 助手 |
|---|---|---|
| **授权代码 + PKCE** | 对 SMART Health IT / Epic on FHIR 沙盒进行交互式启动。 | `fhir-mcp smart-discover <iss>` · `fhir-mcp smart-authorize-url` |
| **后端服务(非对称 JWT 承载者)** | 对支持 [SMART 后端服务](https://www.hl7.org/fhir/smart-app-launch/backend-services.html) 的 EHR 进行服务器到服务器的访问。 | `fhir-mcp smart-jwt` (创建一个客户端断言) |
自定义范围 `fhir-mcp/reid` 控制重新识别:
```bash
# 或者本地密钥 …
FHIR_MCP_ENABLE_REID=true FHIR_MCP_REID_KEY=… fhir-mcp reid PT_a1b2
# … 或者传递一个包含 `fhir-mcp/reid` 的 SMART 代币来从代码重新识别。
```
每个重新识别调用都会写入一个 `audit_events` 行,包含请求的 SMART 主体(或 `Patient/...` 上下文),Langfuse 跟踪 ID 和使用的身份验证路径。
## 30 秒快速入门
```bash
# 1. 运行服务器(无需注册,无需 .env - 使用内存 Synthea 患者)
uvx fhir-mcp serve
# 2. 将其连接到 Claude Desktop
cat >> ~/Library/Application\ Support/Claude/claude_desktop_config.json <<'JSON'
{
"mcpServers": {
"fhir-mcp": {
"command": "uvx",
"args": ["fhir-mcp", "serve"]
}
}
}
JSON
# 3. 重新启动 Claude Desktop 并询问:
# “查找具有糖尿病的 Smith 患者并总结第一个患者。”
```
想要真实的 FHIR 数据?通过一个 env 变量切换后端:
```bash
FHIR_MCP_BACKEND=hapi uvx fhir-mcp serve
```
---
## 架构
```mermaid
flowchart LR
subgraph CLI["AI 客户端"]
A[MCP 兼容客户端]
end
subgraph SRV["fhir-mcp 服务器"]
B[MCP 服务器<br/>mcp-python-sdk]
C[工具路由器]
D[FHIR 客户端<br/>httpx, R4 JSON]
E[去识别管道<br/>结构遍历 + 正则表达式 + Vault]
F[CDS Hooks 桥]
G[术语<br/>LOINC/SNOMED/RxNorm]
H[审计日志记录器]
I[Langfuse 跟踪器]
end
subgraph BE["数据后端"]
J[HAPI 公共测试服务器]
K[内存 Synthea 包]
end
subgraph OPT["云可选加入"]
L[(Supabase<br/>审计 + phi_vault + pgvector)]
M[Langfuse 云]
end
subgraph EXT["外部标准"]
N[cds-hooks.org 沙盒]
O[tx.fhir.org]
end
A <-->|MCP stdio| B
B --> C
C --> D
C --> E
C --> F
C --> G
C --> H
C --> I
D --> J
D --> K
F --> N
G --> O
H --> L
I --> M
```
---
## 工具目录(v0.0.1 中发布的 8 个)
| 工具 | 目的 |
|---|---|
| `search_patients` | 按姓名、MRN、出生日期、性别搜索。返回具有稳定伪名的去识别摘要。 |
| `get_patient_summary` | 综合临床摘要:病况、活动药物、过敏、近期观察、主要诊断。 |
| `search_observations` | LOINC + 日期范围 + 值操作查询,以及 **趋势窗口** (“过去 12 个月的 HbA1c 斜率”)。 |
| `search_conditions` | SNOMED 编码或自由文本搜索,可按临床状态筛选。 |
| `get_medications` | 活动药物列表,包含 RxNorm + 剂量 + 来自 CDS Hooks 的药物相互作用标志。 |
| `validate_code` | 解析 LOINC / SNOMED / RxNorm / ICD-10 代码。离线优先;可选 tx.fhir.org 备用。 |
| `create_clinical_note` | 结构化 SOAP / 出院 / 事先授权笔记;发出 FHIR `DocumentReference`。 |
| `run_cds_hook` | 执行 CDS Hooks 决策支持调用。默认离线模拟;可选加入实时沙盒。 |
**资源** (`fhir://patient/{pseudonym}/…`):
| 资源 | URI | 格式 |
|---|---|---|
| `patient_summary` | `fhir://patient/{pseudonym}/summary` | 文本/降价 |
| `lab_trends` | `fhir://patient/{pseudonym}/trends` | 应用程序/json |
| `medications` | `fhir://patient/{pseudonym}/medications` | 文本/降价 |
**提示:** `soap_note` · `discharge_summary` · `prior_auth_letter` - 版本化模板,协调上述工具调用并生成生产形状的文件。
---
## 安全性和合规性状况
- **默认情况下,每个出口都会进行去识别。** 结构化 FHIR 路径遍历 + 正则表达式识别器(MRN、电话、电子邮件、日期、SSN)检测 PHI。检测到的 PHI 被替换为稳定的伪名 (`PT_a1b2c3d4e5f60718` 等,HMAC-SHA256 在每个保管库上加盐,64 位尾部)。原始 ↔ 伪名映射生活在保管库中(本地 SQLite;云模式下的 Postgres / Supabase)。Presidio 可作为可选的 `deid-advanced` 额外功能。**静止状态下 Vault 的 AES-GCM 加密正在 v0.3 路线图上** - `docs/THREAT_MODEL.md` 明确指出当前保管库存储明文,操作员必须相应地处理它。
- **重新识别是一条特权、审计的路径。** 除非启用 `FHIR_MCP_ENABLE_REID=true` 加上作用域密钥(或具有正确作用域的 SMART-on-FHIR 代币)。每个重新识别调用都会写入一行审计,包含请求者、Langfuse 跟踪 ID 和显示的伪名。
- **每个工具调用都会被审计。** 调用 `audit_events` 行:`(timestamp, actor, tool, args_hash, resource_refs[], trace_id, outcome)`。打开审计行 → 直接跳转到 LLM 跟踪。
- **没有 PHI 逃逸到可观察性。** Langfuse 跨度只会看到伪名;保管库值永远不会离开审计数据库。
- **HIPAA 感知日志记录默认值。** 参数哈希(不是值)默认情况下;仅在开发中选择详细审计。
## 评估方法 - 杀手锏
大多数 FHIR MCP 项目都没有任何临床准确性基准。我们提供 **四个** 套件,它们在每次推送时都会在 CI 上运行:
1. **临床准确性。** 确定的 Synthea 包 → 调用工具 → 判定 LLM (`claude-sonnet-4-6`,固定)根据版本化的评分标准对输出进行评分。通过 ≥8/10。
2. **去识别泄漏。** 每个包的已知 PHI 代币在每个工具的输出中重新扫描。通过 = 零泄漏,超过 1,000 个装置。
3. **代码验证。** 50 个已知的 LOINC / SNOMED / RxNorm 代码 → 预期的规范显示。
4. **CDS Hooks 正确性。** 已知的药物相互作用对必须产生预期的 `cards[]`。
可复制性不可或缺:Synthea 种子、判断提示和判断模型都固定在 `evals/conftest.py` 中。完整的排行榜会在每次 CI 运行后自动渲染到此 README 的顶部。
---
## 路线图
- **v0.1** (发布于 2026-05-23):所有 8 个工具、3 个资源、3 个提示、完整的评估套件、169 个测试,覆盖率 96%,MCP stdio 验证端到端。
- **v0.2** (发布于 2026-05-23):SMART on FHIR OAuth2(PKCE + 后端服务流程);范围强制重新识别;Supabase Postgres 模式用于审计 + 保管库;跨模型判断器框架骨架;5 个黄金 Synthea 包;STRIDE 威胁模型;PyPI 发布工作流程。
- **v0.2.1** (发布于 2026-05-23):关闭“实时 CDS Hooks 泄漏 PHI 给第三方”的信任漏洞(预取现在在客户端边界处去识别);伪名宽度增加到 64 位 + 碰撞检测;保管库获得 `asyncio.Lock`;`@audited(phi_args=...)` 剥离声明的 PHI 字段,即使在 `FHIR_MCP_VERBOSE_AUDIT=true` 下;HAPI 日期范围搜索修复;`$everything` 现限制在 200 个资源。
- **v0.3** (2026 年 Q3):静止状态下 Vault 的 AES-GCM 加密 ([#1](https://github.com/DhairyaShah981/fhir-mcp/issues/1));FHIR 批量导出 (`$export`);FHIR 订阅;R5 双重支持;夜间实时 FHIR 沙盒集成测试 ([#3](https://github.com/DhairyaShah981/fhir-mcp/issues/3));跨模型基准连入 CI;MCP `2026-07-28` 无状态传输迁移 ([#2](https://github.com/DhairyaShah981/fhir-mcp/issues/2))。
---
## 贡献
欢迎 PR。参见 [`CLAUDE.md`](CLAUDE.md) 贡献者上下文(思维模型、约定、做/不做)。每个 PR 都必须保持评估排行榜绿色。
## 许可证
[Apache-2.0](LICENSE)。FHIR® 是 HL7 的注册商标,根据许可证使用。