内容
# fhirHydrant
一款完全可配置的开源 Node.js MCP 服务器,适用于 R4+ FHIR APIs。它通过 SMART on FHIR v2 Backend Services 使用签名 JWT 客户端凭证将 MCP 兼容的客户端连接到临床数据。
fhirHydrant 将 FHIR 资源、命名操作、术语查找和分页转换为 MCP 工具。默认资源和操作是起点:资源、操作、搜索控件、说明和消息可以通过配置文件扩展、修剪或替换,无需更改源代码。
- SMART 后端服务身份验证,带有 JWKS 托管、密钥轮换、令牌刷新和动态范围
- 可配置的资源工具,用于搜索、直接读取和可选的元数据控制的 CRUD
- 配置驱动的命名操作,用于临床数据、术语、IPS、患者匹配、验证和自定义工作流
- CapabilityStatement 感知的工具、搜索控件、操作控制和运行时范围检查
- 代币经济功能:紧凑的响应、FHIRPath 过滤、字节限制、`_count` 塑形和超大 Bundle 重试
- 可选的术语工具、无 PHI 审计事件和 stdio 或 Streamable HTTP 传输
> **注意:** 通过 MCP 工具调用返回的 FHIR 数据可能包含 PHI。请确保您的 MCP 客户端的转录存储和日志记录行为符合您的合规要求。
## 目录
- [快速入门](#快速入门)
- [工具](#工具)
- [元数据和范围控制](#元数据和范围控制)
- [代币经济和响应塑形](#代币经济和响应塑形)
- [审计事件](#审计事件)
- [SMART 后端身份验证和密钥](#SMART-后端身份验证和密钥)
- [环境变量](#环境变量)
- [FHIR 版本支持](#FHIR-版本支持)
- [自定义工具和消息](#自定义工具和消息)
- [传输](#传输)
- [开发](#开发)
## 快速入门
### 要求
- Node.js >= 24
- 支持 SMART Backend Services 的 FHIR 服务器
- SMART Backend Services 客户端注册
- RSA-2048 私钥,其公钥可通过 JWKS 获取
stdio 传输通常需要外部托管的 JWKS URL。内置的 `/jwks` 端点仅在 fhirHydrant 在 HTTP 上运行时可用。
### 安装
```sh
# 全局安装
npm install -g fhirhydrant
# 或在不安装的情况下运行
npx fhirhydrant
```
从源代码运行:
```sh
git clone https://github.com/faulkj/fhirhydrant.git
cd fhirhydrant
npm install
npm run build
```
### MCP 客户端配置
对于桌面 MCP 客户端,stdio 通常是最简单的传输:
```json
{
"mcpServers": {
"fhirhydrant": {
"command": "npx",
"args": ["-y", "fhirhydrant"],
"env": {
"MCP_TRANSPORT": "stdio",
"FHIR_BASE_URL": "https://fhir.example.org",
"FHIR_CLIENT_ID": "your-client-id",
"FHIR_ACTIVE_KEY": "LS0tLS1CRUdJTi...base64-of-your-pem...",
"FHIR_JWKS_URL": "https://example.org/.well-known/jwks.json"
}
}
}
}
```
`FHIR_ACTIVE_KEY` 是您的 RSA PKCS#8 私钥,以 base64 编码。`kid` 在启动时自动派生,通过截断的 JWK 指纹,并记录到控制台。
## 工具
fhirHydrant 从配置和运行时能力检查中注册工具。确切的列表取决于 `config/resources.json`、授予的 SMART 范围、`/metadata`、写入设置、操作设置和术语设置。
| 工具或系列 | 可用时 | 目的 |
| --- | --- | --- |
| 资源工具 | 资源已配置并允许元数据/范围 | 搜索、直接读取和可选的 CRUD FHIR 资源 |
| `capabilities` | 始终注册 | 检查 CapabilityStatement 摘要、注册工具、跳过的工具、搜索参数、操作和元数据注释 |
| `paginate` | 始终注册 | 使用服务器返回的 `next` URL 获取 FHIR Bundle 的下一页 |
| `operate` | 至少有一个命名操作通过控制 | 调用配置的 FHIR 命名操作,用于临床数据、术语、IPS、匹配、验证或自定义工作流 |
| `bundle` | `FHIR_BUNDLE_CAPABILITIES` 已设置 | 提交 FHIR batch 或 transaction Bundle;写入需要额外确认 |
| `terminology_lookup` | `FHIR_TERMINOLOGY_BASE_URL` 已设置 | 查找一个 LOINC 或 SNOMED CT 代码 |
| `code_search` | `FHIR_TERMINOLOGY_BASE_URL` 已设置 | 按文本过滤搜索 LOINC 或 SNOMED CT 代码 |
### 资源工具
资源工具从 [config/resources.json](config/resources.json) 生成。随附的配置涵盖了常见的临床、行政、药物、执业者、组织和文档资源。您可以扩展、修剪或替换资源集,而无需更改源代码。
每个资源工具支持配置的搜索参数、可选的直接读取(使用 `_id`、`fhirpath` 和 `responseMode`)。
资源工具默认情况下为搜索/读取。设置 `FHIR_WRITE_CAPABILITIES` 以启用元数据控制的 CRUD 操作:
```sh
FHIR_WRITE_CAPABILITIES=create,update,patch,delete
```
| 操作 | 必需参数 | FHIR 调用 |
| --- | --- | --- |
| `create` | `body` | `POST /ResourceType` |
| `update` | `_id`, `body` | `PUT /ResourceType/{id}` |
| `patch` | `_id`, `body` | `PATCH /ResourceType/{id}` 使用 JSON Patch |
| `delete` | `_id` | `DELETE /ResourceType/{id}` |
写入主体在 FHIR 调用前会进行验证:`body.resourceType` 必须与工具资源匹配,`body.id` 必须与 `_id` 匹配(如果存在),而补丁需要一个 JSON Patch 数组。范围根据启用的功能派生:读取/搜索使用 `system/Patient.rs`,创建/读取/搜索使用 `system/Patient.crs`,而完全写入支持使用 `system/Patient.cruds`。SMART v2 没有单独的补丁字母,因此补丁映射到 `u`。
### 核心工具
`capabilities` 返回缓存的 CapabilityStatement 摘要、注册和跳过的工具、搜索参数、操作和元数据注释。
`paginate` 使用服务器返回的 `next` URL 获取一个 Bundle 页面,并针对 FHIR 源和允许的路径前缀进行验证。当紧凑模式激活并且获取的页面有更多结果时,分页会自动将多个上游页面合并为一个紧凑的响应(与资源搜索工具的行为相同)。传递 `prefetch=false` 以禁用合并并获取单个页面。
### 命名操作
`operate` 工具从 `config/operations.json` 调用 FHIR 命名操作。随附的操作目录涵盖了临床聚合、验证、文档查找、术语操作、IPS 生成和患者匹配。您可以扩展、修剪、替换或禁用操作目录,而无需更改源代码。
### 术语工具
设置 `FHIR_TERMINOLOGY_BASE_URL` 以启用:
| 工具 | 描述 |
| --- | --- |
| `terminology_lookup` | 查找一个 LOINC 或 SNOMED CT 代码 |
| `code_search` | 按文本过滤搜索代码,支持分页 |
这些工具直接调用配置的术语服务器。它们不使用临床 FHIR 服务器凭证。使用一个与您选择的 FHIR 版本匹配的术语端点,例如 `https://tx.fhir.org/r4`。
### 包执行
设置 `FHIR_BUNDLE_CAPABILITIES=batch`(或 `batch,transaction`)以启用 `bundle`。此工具提交一个 FHIR batch 或 transaction Bundle,并通过标准响应管道返回服务器的响应。
**安全模型:**
- 只读 batch Bundles(所有 GET 条目)仅需 `FHIR_BUNDLE_CAPABILITIES=batch` 即可允许。
- 编写条目(POST、PUT、PATCH、DELETE)还需要 `FHIR_BUNDLE_WRITES_ENABLED=true` 和 `FHIR_WRITE_CAPABILITIES` 中的相应操作。
- Transaction Bundles 需要明确的 `FHIR_BUNDLE_CAPABILITIES=transaction`。
- 每个条目都针对配置的资源、SMART 范围和元数据交互进行预检。如果任何单个条目失败,则整个 Bundle 在提交之前被拒绝。
**V1 排除项:** 条件请求、`_history` 路径、绝对 URL 和 Bundle 条目内的 `$operation` URL 不受支持。
## 元数据和范围控制
除非 `FHIR_METADATA_MODE=off`,否则 fhirHydrant 在启动时获取 FHIR 服务器的 CapabilityStatement。在 `strict` 模式下:
- 仅当资源类型存在于 `/metadata` 中,资源工具才会被注册。
- 服务器端搜索控件(例如 `_count`、`_sort`、`_summary`、`_elements`、`_include` 和 `_revinclude`)仅在广告时才会公开。
- 如果服务器未宣传搜索参数,则会阻止搜索参数。
- 编写操作需要 `FHIR_WRITE_CAPABILITIES` 和匹配的 CapabilityStatement 交互。
- 命名操作需要目标资源类型存在、授予的 SMART 范围允许资源以及操作本身在资源 CapabilityStatement 条目中被宣传。
在 `warn` 模式下,未宣传的参数将允许,但会发出警告,而缺失的资源类型仍将被跳过。SMART 范围也会在运行时进行检查,因此工具可以存在于模式中,但仍会被授予的令牌范围阻止。
## 代币经济和响应塑形
FHIR 响应通常比 MCP 客户端需要的大得多。fhirHydrant 在检索后根据代币经济塑形响应,使用服务器端控件,当 FHIR 服务器宣传它们时。
| 功能 | 行为 |
| --- | --- |
| `_count` 默认/上限 | 默认情况下不注入 `_count`(服务器决定页面大小)。设置 `FHIR_DEFAULT_COUNT` 以注入一个;`FHIR_MAX_COUNT` 限制明确的调用者值(0 = 无上限) |
| 页面合并 | 当紧凑模式激活时,服务器顺序获取多个上游页面,立即压缩每个页面,并返回一个合并的紧凑 Bundle。由 `maxResults`、`prefetch` 和 `FHIR_PREFETCH_*` 环境变量控制 |
| 字节限制 | `FHIR_MAX_RESPONSE_BYTES` 限制每个工具的响应;超大 Bundle 被透明地分段 |
| 自动重试 | 超大搜索 Bundle 尝试本地分段,然后在必要时使用较小的 `_count` 作为回退 |
| FHIRPath | `fhirpath` 在本地过滤返回的 FHIR JSON,并将匹配的节点作为数组返回 |
| 紧凑模式 | `responseMode=compact` 删除常见的 FHIR 信封噪音并简化数据类型 |
| 完整模式 | `responseMode=full` 返回原始 FHIR JSON |
| 锁定紧凑模式 | `FHIR_RESPONSE_MODE=compact-locked` 从工具模式中隐藏 `responseMode` |
紧凑输出是面向 AI 的 JSON,而不是规范的 FHIR。它减少或简化了 FHIR 噪音和常见数据类型,如 `meta`、`narrative`、`CodeableConcept`、`Reference`、`Quantity` 和较新的数据类型,如 `CodeableReference`。
## 审计事件
设置 `FHIR_AUDIT_SINK` 为 `console`、`file` 或两者。
审计事件包括时间戳、工具、适用时资源类型、操作、状态、持续时间、响应大小、分页摘要、请求 ID 和可选的代理身份验证用户。它们默认不包括 FHIR 资源内容。
在运行身份验证代理后面时,设置 `FHIR_AUDIT_USER_HEADER` 为受信任的身份验证头,由该代理注入:
常见头:Azure EasyAuth `X-MS-CLIENT-PRINCIPAL-NAME`、OAuth2 代理 `X-Auth-Request-Email`、Cloudflare Access `Cf-Access-Authenticated-User-Email`。
仅在代理剥离或覆盖该头的副本时才使用此功能。否则,客户端可以伪造任意审计用户。
## SMART 后端身份验证和密钥
fhirHydrant 使用 SMART 后端服务:客户端凭证加上签名 JWT 断言。这是后端 FHIR 访问,而不是基于浏览器的 SMART 独立启动;MCP 路径中没有交互式重定向/登录流程。
`FHIR_ACTIVE_KEY` 包含原始 RSA PKCS#8 签名密钥。在 HTTP 模式下,内置的 `/jwks` 端点在 `FHIR_JWKS_URL` 未设置时公开活动密钥和任何已退休密钥的公钥。每个密钥的 `kid` 自动通过截断的 RFC 7638 JWK 指纹派生(SHA-256 的前 12 个 base64url 字符),并在启动时记录。
密钥轮换工作流:
1. 生成新的 RSA 密钥。
2. 将新的 PEM 添加到 `FHIR_RETIRED_KEYS` 并重新部署,以便 JWKS 包括两者。
3. 在您的身份验证服务器上注册新的 `kid`(在启动时记录),与您的身份验证服务器。
4. 将新的 PEM 移到 `FHIR_ACTIVE_KEY`,并将旧 PEM 移到 `FHIR_RETIRED_KEYS`。重新部署。
5. 在身份验证服务器缓存过期后,从 `FHIR_RETIRED_KEYS` 中删除旧密钥。
如果使用外部 JWKS,请在切换 `FHIR_ACTIVE_KEY` 之前发布新的公钥。
## 环境变量
参见 [.env.example](.env.example) 以获取完整的示例。
### 必需
| 变量 | 描述 |
| --- | --- |
| `FHIR_BASE_URL` | 用于派生 FHIR 服务器 URL 和令牌 URL 的基本 URL |
| `FHIR_CLIENT_ID` | SMART 后端服务客户端 ID |
| `FHIR_ACTIVE_KEY` | Base64 编码的 RSA PKCS#8 PEM 签名密钥 |
### 可选
| 变量 | 默认值 | 描述 |
| --- | --- | --- |
| `FHIR_RETIRED_KEYS` | 未设置 | 用于 JWKS 轮换的逗号分隔的 base64 编码 PEM |
| `FHIR_VERSION` | `R4` | 活动 R4+ FHIR 版本;控制派生的 URL、FHIRPath 模型和紧凑模式元数据 |
| `FHIR_SERVER_URL` | `<base>/api/FHIR/<FHIR_VERSION>` | 显式 FHIR API URL 重写 |
| `FHIR_TOKEN_URL` | `<base>/oauth2/token` | 显式令牌端点重写 |
| `FHIR_JWKS_URL` | 未设置 | 外部 JWKS URL。在 HTTP 模式下省略以启用内置的 `/jwks` |
| `MCP_TRANSPORT` | `http` | `http` 或 `stdio` |
| `PORT` | `5000` | HTTP 监听器端口 |
| `BIND_HOST` | `0.0.0.0`(或 `--dev` 标志下的 `127.0.0.1`) | HTTP 绑定地址 |
| `ALLOWED_HOSTS` | 未设置 | 用于 DNS 绑定保护的逗号分隔的主机名 |
| `FHIR_METADATA_MODE` | `strict` | `/metadata` 验证的 `strict`、`warn` 或 `off` |
| `FHIR_DEFAULT_COUNT` | `0` | 注入搜索的默认 `_count`;0 = 服务器决定 |
| `FHIR_MAX_COUNT` | `0` | 显式调用者 `_count` 值的上限;0 = 无上限 |
| `FHIR_MAX_RESPONSE_BYTES` | `262144` | 工具响应的字节限制;超大 Bundle 被分段 |
| `FHIR_REQUEST_TIMEOUT_MS` | `30000` | 发出的 FHIR 请求的每个尝试超时 |
| `FHIR_RESPONSE_MODE` | 未设置 | `compact`、`full` 或 `compact-locked`;未设置意味着搜索默认为 compact,直接读取默认为 full |
| `FHIR_WRITE_CAPABILITIES` | 未设置 | 写入操作:`create`、`update`、`patch`、`delete` |
| `FHIR_BUNDLE_CAPABILITIES` | 未设置 | 捆绑类型:`batch`、`transaction`;启用 `bundle` 工具 |
| `FHIR_BUNDLE_WRITES_ENABLED` | `false` | 设置为 `true` 以允许在 Bundle 中写入条目(还需要 `FHIR_WRITE_CAPABILITIES`) |
| `FHIR_OPERATIONS` | 未设置 | 逗号分隔的操作键;`none` 禁用所有目录操作。默认目录:`everything`、`lastn`、`validate`、`docref`、`expand`、`lookup`、`translate`、`summary`、`match` |
| `FHIR_TERMINOLOGY_BASE_URL` | 未设置 | 启用术语工具,例如 `https://tx.fhir.org/r4` |
| `FHIR_PAGINATION_PATHS` | 未设置 | 额外的分页链接允许路径前缀,例如 `FHIRProxy` |
| `FHIR_PREFETCH_MAX_PAGES` | `5` | 每个合并搜索获取的最大上游页面 |
| `FHIR_PREFETCH_MAX_ENTRIES` | `5000` | 停止前累积的最大上游条目 |
| `FHIR_PREFETCH_MAX_BYTES` | `2097152` | 获取前停止的最大原始字节 |
| `FHIR_PREFETCH_TIMEOUT_MS` | `25000` | 合并循环的时钟预算 |
| `FHIR_AUDIT_SINK` | 未设置 | `console`、`file` 或两者 |
| `FHIR_AUDIT_FILE` | `./audit.jsonl` | 启用文件审计接收器时使用的 JSONL 文件 |
| `FHIR_AUDIT_USER_HEADER` | 未设置 | 代理身份验证用户头复制到审计事件中 |
| `DEBUG` | `false` | 详细的 FHIR 请求日志记录;当 `NODE_ENV=production` 时被阻止 |
显式 `FHIR_SERVER_URL` 和 `FHIR_TOKEN_URL` 值始终优先于派生的 URL。
## FHIR 版本支持
设置 `FHIR_VERSION` 以选择活动的 R4+ FHIR 版本。它控制派生的 FHIR API URL、FHIRPath 模型上下文和紧凑响应模型元数据。对于术语,请使用与所选 FHIR 版本匹配的端点,例如 `https://tx.fhir.org/r4`。
## 自定义工具和消息
`config/` 中的所有内容都可以不更改源代码进行编辑。
| 文件 | 目的 |
| --- | --- |
| `resources.json` | FHIR 资源工具、搜索参数、直接读取行为和 `requireOneOf` 规则 |
| `operations.json` | `operate` 的命名操作目录 |
| `search-controls.json` | `_count`、`_sort`、`_summary`、`_elements`、`_include`、`_revinclude`、`fhirpath`、`responseMode`、`maxResults` 和 `prefetch` 的描述 |
| `instructions.md` | 显示给客户端/模型的 MCP 服务器说明 |
| `messages.json` | 用户友好消息、错误和响应注释 |
| `core-tools.json` | 内置工具描述和参数提示 |
## 传输
- [ ]
### 资源定义模式
`config/resources.json` 是资源定义的数组:
| 字段 | 类型 | 描述 |
| --- | --- | --- |
| `resource` | `字符串` | FHIR 资源类型 |
| `toolName` | `字符串` | MCP 工具名称;必须唯一 |
| `description` | `字符串` | 工具描述 |
| `supportsDirectRead` | `布尔值` | 通过 `_id` 启用 `GET /ResourceType/{id}` |
| `searchParams` | `记录<string,string>` | FHIR 搜索参数和描述 |
| `requireOneOf` | `字符串[]` | 搜索调用至少需要一个列出的参数 |
`searchParams` 值是描述,而不是完整的 FHIR 能力模型。
服务器特定的搜索行为仍然可以应用。
### 热重载
在开发环境中(`NODE_ENV` 不是 `production`),`resources.json`、`search-controls.json` 和 `operations.json` 会被监视。无效的 JSON 会保留上一次有效的快照,作用域更改会重启身份验证,行为更改会在后续工具调用时被捕获。添加/删除工具、操作模式更改和可见的参数名称更改仍然需要重启,因为 MCP 工具注册发生在启动时。生产环境在启动时只读取一次配置。
## 传输
### 标准输入/输出
设置 `MCP_TRANSPORT=stdio`。标准输出保留用于 MCP 协议;日志被重定向到标准错误流。请为 stdio 部署使用外部 `FHIR_JWKS_URL`。
### 可流式 HTTP
HTTP 传输是无状态的,并在以下地址公开 MCP:
```http
POST http://localhost:5000/mcp
Accept: application/json, text/event-stream
Content-Type: application/json
```
MCP 客户端配置:
```json
{
"mcpServers": {
"fhirhydrant": {
"url": "http://localhost:5000/mcp"
}
}
}
```
`GET /health` 返回一个无 PHI 的就绪快照:
```json
{
"status": "ok",
"mcp": true,
"metadata": true,
"tools": 22,
"auth": true,
"tokenExpiresIn": 287
}
```
在将 HTTP 公开到 localhost 之外时,请使用反向代理进行 TLS 和用户身份验证。绑定到公共接口时,请设置 `ALLOWED_HOSTS`。
## 开发
```sh
# 开发服务器
npm run dev
# 类型检查
npm run check
# 构建和运行
npm run build
npm start
```
构建输出将转到 `bin/server.js`。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器