关于 fhirHydrant
fhirHydrant 是面向 MCP 客户端的 Node.js FHIR 服务,可通过 SMART Backend Services 访问 R4 及以上 FHIR API。它根据服务器元数据和配置提供资源操作,并支持响应精简、FHIRPath 过滤及术语查询。
主要功能
- 01SMART Backend Services 身份验证
- 02按元数据提供资源搜索与读写
- 03配置命名操作与 Bundle 提交
- 04精简响应并支持 FHIRPath 过滤
- 05安全分页与审计事件
- 06LOINC 和 SNOMED CT 查询
适用场景
- 01在临床 FHIR API 中搜索或读取资源
- 02按需启用资源创建、更新或删除
- 03浏览大型 FHIR Bundle 的后续页面
- 04查询临床术语代码
MCP 相关
该服务通过 MCP 向兼容客户端提供 FHIR 资源搜索、读取、可选 CRUD、命名操作、分页和术语查询工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y fhirhydrantMCP_TRANSPORTRun the installed package over MCP stdio.FHIR_AUTH密钥FHIR authentication mode. Use none only for an unauthenticated FHIR endpoint.FHIR_SERVER_URLFull base URL of the FHIR API, such as https://fhir.example.org/fhir/R4.FHIR_TOKEN_URL密钥SMART Backend Services token endpoint. Required when FHIR_AUTH=smart unless it can be derived from FHIR_BASE_URL.FHIR_CLIENT_IDSMART Backend Services client ID. Required when FHIR_AUTH=smart.FHIR_ACTIVE_KEY密钥Base64-encoded PKCS#8 private signing key. Required when FHIR_AUTH=smart.FHIR_JWKS_URLExternally reachable JWKS URL for the signing key. Recommended for SMART authentication over stdio.FHIR_VERSIONFHIR release used for FHIRPath and response shaping.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
28收录的工具列表 · 更新于 3 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| url | string | 是 | 来自 FHIR Bundle 链接 link[rel=next].url 值的分页 URL |
| fhirpath | string | 否 | 在 FHIR 响应上本地求值的 FHIRPath 表达式 — 当 _elements 或 _summary 不可用或不足时,用于客户端投影 |
| responseMode | enum | 否 | 响应形式:compact 或 fullcompact | full |
| maxResults | number | 否 | 紧凑结果的目标数量 — 达到此阈值后,服务器将停止获取其他页面 |
| prefetch | boolean | 否 | 设为 false 可禁用服务器端页面合并 |
详细介绍
fhirHydrant:FHIR MCP Server
一款现代、完全可配置的开源 Node.js Model Context Protocol(MCP)服务,适用于 R4+ FHIR API。它通过使用签名 JWT 客户端凭据的 SMART on FHIR v2 Backend Services,将兼容 MCP 的大模型 AI 客户端连接到临床数据。
fhirHydrant 将 FHIR 资源、命名操作、术语查询和分页转化为 MCP 工具。默认资源和操作仅为起点:资源、操作、搜索控制、说明和消息都可以通过配置文件扩展、精简或替换,无需修改源代码。
- 支持 SMART Backend Services 身份验证,提供 JWKS 托管、密钥轮换、令牌刷新和动态作用域
- 可配置资源工具,支持搜索、直接读取、vread、历史记录,以及可选的元数据控制 CRUD
- 通过配置驱动的命名操作,支持临床数据、术语、IPS、患者匹配、验证和自定义工作流
- 支持感知 CapabilityStatement 的工具、搜索控制、操作门控和运行时作用域检查
- 令牌经济功能:精简响应、FHIRPath 过滤、字节限制、
_count调整,以及超大 Bundle 重试 - 可选术语工具、轻量 PHI 审计事件(默认不包含资源内容),以及 stdio 或 Streamable HTTP 传输
注意: 通过 MCP 工具调用返回的 FHIR 数据可能包含 PHI。 请确保 MCP 客户端的对话记录存储和日志记录行为符合您的合规要求。
目录
快速开始
要求
- Node.js >= 24
- 受支持的 FHIR 服务
- 使用 SMART 身份验证(默认)时:SMART Backend Services 客户端注册,以及 RSA-2048 或 EC P-384 私钥;对应公钥需可通过 JWKS 获取
若要连接到公开、无需身份验证的 FHIR 测试服务,请设置 FHIR_AUTH=none,并完全跳过客户端和密钥(参见无需身份验证的访问)。
stdio 传输通常需要外部托管的 JWKS URL。内置的 /jwks 端点仅在 fhirHydrant 使用 SMART 身份验证并通过 HTTP 运行时可用。
安装
# install globally
npm install -g fhirhydrant
# or run without installing
npx fhirhydrant
从源代码运行:
git clone https://github.com/faulkj/fhirhydrant.git
cd fhirhydrant
npm install
npm run build
MCP 客户端配置
对于桌面 MCP 客户端,stdio 通常是最简单的传输方式:
{
"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 是经过 base64 编码的 PKCS#8 私钥(RSA 或 EC P-384)。
启动时会自动通过截断的 JWK Thumbprint 派生 kid,并记录到控制台。
无需身份验证的访问
若要让 fhirHydrant 连接到公开、无需身份验证的 FHIR 端点(适合在开放沙盒中测试),请设置 FHIR_AUTH=none。无需客户端 ID 或签名密钥,不会请求令牌,发送的请求也不包含 Authorization 标头:
{
"mcpServers": {
"fhirhydrant": {
"command": "npx",
"args": ["-y", "fhirhydrant"],
"env": {
"MCP_TRANSPORT": "stdio",
"FHIR_AUTH": "none",
"FHIR_SERVER_URL": "https://hapi.fhir.org/baseR4"
}
}
}
}
工具
fhirHydrant 根据配置和运行时能力检查注册工具。
具体列表取决于 config/resources/ 文件夹、已授予的 SMART 作用域、
/metadata、写入设置、操作设置和术语设置。
| 工具或系列 | 可用条件 | 用途 |
|---|---|---|
| 资源工具 | 已配置资源,且元数据/作用域允许 | 搜索、直接读取、vread、历史记录,以及可选的 FHIR 资源 CRUD |
system_history | 服务声明了系统级 history 交互,且作用域允许 | 获取所有资源类型的系统级变更历史记录 |
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 文件(例如 patient.json),并在启动时扫描。
随附的配置涵盖常见的临床、行政、药物、从业者、组织和文档资源。添加文件即可添加资源,或删除文件即可移除资源——无需修改源代码。
每个资源工具都支持已配置的搜索参数、可选的 _id 直接读取、
fhirpath,以及除非已锁定为精简模式,否则还支持 responseMode。只有当 _id 是唯一非空参数时才会进行直接读取;_id 与其他参数同时出现时仍会执行搜索,避免悄然忽略调用方的意图。
默认情况下,资源工具仅支持搜索/读取。设置 FHIR_WRITE_CAPABILITIES 可启用受元数据门控的 CRUD 操作:
FHIR_WRITE_CAPABILITIES=create,update,patch,delete
| 操作 | 必需参数 | FHIR 调用 |
|---|---|---|
vread | _id、_vid | GET /ResourceType/{id}/_history/{vid} |
history | _id(实例)或无(类型) | GET /ResourceType/{id}/_history 或 GET /ResourceType/_history |
create | body | POST /ResourceType |
update | _id、body | PUT /ResourceType/{id} |
patch | _id、body | 使用 JSON Patch 的 PATCH /ResourceType/{id} |
delete | _id | DELETE /ResourceType/{id} |
当资源设置了 supportsDirectRead,且服务声明支持 vread 交互时,vread 才可用。当服务声明支持 history-instance 或 history-type 时,history 才可用。两者都需要 SMART r 权限。可选的 _since 和 _at 参数可筛选历史记录结果。
历史记录响应为 Bundle,并支持精简模式、FHIRPath 和合并。
在进行 FHIR 调用前会验证写入正文:body.resourceType 必须与工具资源匹配;对于 update,如果存在 body.id,则必须与 _id 匹配;patch 则必须使用 JSON Patch 数组。作用域根据已启用的能力推导:读取/搜索使用 system/Patient.rs,创建/读取/搜索使用 system/Patient.crs,完整写入支持使用 system/Patient.cruds。
SMART v2 没有单独的 patch 字母,因此 patch 映射为 u。
核心工具
capabilities 返回缓存的 CapabilityStatement 摘要、已注册和已跳过的工具、搜索参数、操作以及元数据备注。
paginate 使用服务器返回的 next URL 获取一个 Bundle 页面,并根据 FHIR 来源和允许的路径前缀验证该 URL。启用紧凑模式时,如果获取的页面还有更多结果,paginate 会自动将多个上游页面合并为一个紧凑响应(行为与资源搜索工具相同)。传入 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。
Bundle 执行
设置 FHIR_BUNDLE_CAPABILITIES=batch(或 batch,transaction)以启用 bundle。此工具会提交一个 FHIR batch 或 transaction Bundle,并通过标准响应管道返回服务器的响应。
安全模型:
- 只读 batch Bundle(所有条目均为 GET)仅需设置
FHIR_BUNDLE_CAPABILITIES=batch即可使用。 - 写入条目(POST、PUT、PATCH、DELETE)还需要设置
FHIR_BUNDLE_WRITES_ENABLED=true,并在FHIR_WRITE_CAPABILITIES中启用相应操作。 - Transaction Bundle 需要显式设置
FHIR_BUNDLE_CAPABILITIES=transaction。 - 每个条目都会根据已配置的资源、SMART 范围和元数据交互进行预检。如果任何单个条目未通过,整个 Bundle 都会在提交前被拒绝。
**V1 不支持:**条件请求、系统级 _history、绝对 URL,以及 Bundle 条目中的 $operation URL。
**Bundle 中的历史记录:**当服务器声明了相应交互且范围允许时,Bundle 中允许使用 vread(Resource/id/_history/vid)、实例历史记录(Resource/id/_history)和类型历史记录(Resource/_history)条目。这些条目会计为读取条目。
元数据与范围门控
除非设置 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 限制每个面向模型的 JSON 响应大小;超大的 Bundle 会自动分块 |
| 自动重试 | 对超大的搜索 Bundle,先尝试本地分块,再以较小的 _count 重试作为后备方案 |
| FHIRPath | fhirpath 会在本地筛选返回的 FHIR JSON,并将匹配节点作为数组返回 |
| 紧凑模式 | responseMode=compact 会剥离常见的 FHIR 封装冗余并简化数据类型 |
| 完整模式 | responseMode=full 返回原始 FHIR JSON |
| 锁定紧凑模式 | FHIR_RESPONSE_MODE=compact-locked 会从工具架构中隐藏 responseMode |
| 原生制品 | 非 JSON 响应(文档、图像、DICOM、RTF、HTML、XML、CSV、NDJSON、ZIP、八位字节流)以及 JSON FHIR Binary 会规范化为元数据封装,并附带一个 MCP 嵌入式文本/二进制资源。受 FHIR_MAX_ARTIFACT_MB 限制(不受 JSON 限制影响),不会分块,也不会经过 FHIRPath/压缩/页面合并。仅适用于 JSON 的塑形参数会被忽略,并附带说明 |
紧凑输出是面向 AI 的 JSON,并非规范的 FHIR。它会删除或简化 FHIR 中的冗余内容和常见数据类型,例如 meta、叙述文本、扩展、
CodeableConcept、Reference、Quantity,以及 CodeableReference 等较新的数据类型。
FHIRPath 在本地运行;FHIR 服务端不会看到该表达式。如果求值失败,则不会返回原始响应,而是返回错误。
结构化响应封装
所有 FHIR 数据工具(资源工具、paginate、operate、bundle、
system_history)都会返回一个结构化封装;每个工具的
outputSchema 都会公布该封装,且封装以 structuredContent 的形式返回(文本内容为
同一封装的序列化结果)。其中包含 FHIR 负载(data)以及元数据:响应模式、分页信号
hasMore/continuation、Bundle 和页面合并统计信息,以及人类可读的
notes。完整字段列表见工具的 outputSchema。
可能的超大响应会被分块(保留 data,可通过 continuation 检索);
如果无法分块,则封装会标记为 status: "truncated",并省略 data。截断属于成功但不完整的结果,并非错误。
能力和术语工具返回各自的结构,而非此 FHIR 封装。
页面合并
搜索启用紧凑模式时(资源工具或 paginate),服务端会依次获取多个上游 FHIR 页面,立即压缩每一页,并返回一个合并后的紧凑 Bundle。这样可将多次“下一页”调用减少为一次 MCP 往返。
maxResults设置目标值 — 服务端达到此阈值后停止获取(由于会追加完整页面,结果可能略微超出)prefetch=false可为单次调用禁用页面合并_count仍控制上游 FHIR 页面的大小- 页面合并会在达到可配置的页面数、条目数、字节数和时间限制时停止
continuation.url指向服务端停止的位置;调用paginate并设置responseMode=compact即可继续(hasMore表示仍有更多内容)- 经 FHIRPath 筛选的请求仍只处理单页(不进行页面合并)
responseMode=full始终只返回一个上游页面
审计事件
将 FHIR_AUDIT_SINK 设置为 console、file 和 http 的任意组合。
http 接收器会将每条审计事件 POST 到外部收集器、SIEM 或 FHIR 审计存储库(而非 FHIR 服务本身)。将 FHIR_AUDIT_HTTP_URL 设置为目标地址,并将 FHIR_AUDIT_HTTP_FORMAT 设置为 raw(内部精简 PHI 的审计 JSON,适用于 Splunk HEC 或 Datadog 等通用收集器)或 fhir-auditevent(精简的 FHIR R4 AuditEvent 资源,适用于 ATNA 风格和原生 FHIR 审计存储库)。fhir-auditevent 映射刻意保持轻量,并非完整的 ATNA/BALP 合规配置文件。可选的 FHIR_AUDIT_HTTP_AUTH 值会原样作为 Authorization 标头发送。投递采用即发即弃方式,超时为 5s;传输失败会记录日志,且绝不会影响工具响应。
审计事件包含时间戳、工具、适用时的资源类型、操作、状态、持续时间、响应大小、分页摘要、请求 ID,以及可选的代理身份验证用户。默认情况下不会包含 FHIR 资源内容。
在身份验证代理后运行时,将 FHIR_AUDIT_USER_HEADER 设置为该代理注入的可信身份标头:
常见标头:Azure EasyAuth X-MS-CLIENT-PRINCIPAL-NAME、OAuth2 Proxy X-Auth-Request-Email、Cloudflare Access Cf-Access-Authenticated-User-Email。
仅当代理会剥除或覆盖此标头的入站副本时才使用此设置。否则,客户端可以伪造任意审计用户。
SMART 后端身份验证与密钥
fhirHydrant 使用 SMART Backend Services:客户端凭据加签名 JWT 断言。这是后端 FHIR 访问,而非基于浏览器的 SMART 独立启动;MCP 路径中没有交互式重定向/登录流程。
FHIR_ACTIVE_KEY 保存原始 PKCS#8 签名密钥(RSA,使用 RS384 签名,或 EC P-384,使用 ES384 签名)。在 HTTP 模式下,如果未设置 FHIR_JWKS_URL,内置的 /jwks 端点会公开活动密钥及所有已弃用密钥的公钥。每个密钥的 kid 会通过截断的 RFC 7638 JWK Thumbprint 自动生成(对规范公钥 JWK 成员执行 SHA-256 后,取前 12 个 base64url 字符),并在启动时记录日志。
密钥轮换工作流:
- 生成新密钥(RSA-2048 或 EC P-384)。
- 将新 PEM 添加到
FHIR_RETIRED_KEYS并重新部署,使 JWKS 同时包含两个密钥。 - 向身份验证服务注册新的 kid(启动时会记录日志)。
- 将新 PEM 移至
FHIR_ACTIVE_KEY,并将旧 PEM 移至FHIR_RETIRED_KEYS。重新部署。 - 身份验证服务的缓存过期后,从
FHIR_RETIRED_KEYS中移除旧密钥。
如果使用外部 JWKS,请先发布新公钥,再切换 FHIR_ACTIVE_KEY。
环境变量
完整示例请参见 .env.example。
必填
| 变量 | 说明 |
|---|---|
FHIR_BASE_URL | 用于推导 FHIR 服务 URL 和令牌 URL 的基础 URL。设置了 FHIR_SERVER_URL 时可选(使用 smart 身份验证时还需设置 FHIR_TOKEN_URL) |
FHIR_CLIENT_ID | SMART Backend Services 客户端 ID(FHIR_AUTH=none 时不需要) |
FHIR_ACTIVE_KEY | Base64 编码的 PKCS#8 PEM 签名密钥,RSA 或 EC P-384(FHIR_AUTH=none 时不需要) |
可选
| 变量 | 默认值 | 说明 |
|---|---|---|
FHIR_AUTH | smart | smart(SMART Backend Services)或 none(不进行身份验证,用于公开测试端点) |
FHIR_RETIRED_KEYS | 未设置 | 以逗号分隔的 base64 编码 PEM,用于 JWKS 轮换 |
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 | 面向模型的 JSON 响应字节数上限;超大的 Bundle 会被分块 |
FHIR_MAX_ARTIFACT_MB | 16 | 原生/二进制工件正文的独立字节上限(MiB);不受 JSON 上限影响(base64 传输约增加 33%) |
FHIR_REQUEST_TIMEOUT_MS | 30000 | 每次发出的 FHIR 请求尝试的超时时间 |
MCP_JSON_LIMIT | 4mb | MCP 请求正文可接受的最大尺寸(Express JSON 限制字符串);如果大型写入/Bundle 负载被拒绝,请调高此值 |
MCP_AUTHZ | none | 授权提供方:none 或 entra。按调用方控制工具访问权限(仅限 HTTP + Authorization: Bearer) |
MCP_ROLE_PREFIX | FhirHydrant | 授予的角色值前缀(例如 FhirHydrant.Patient.Read) |
MCP_ENTRA_TENANT_ID | 未设置 | Entra 租户 GUID(不是域别名);MCP_AUTHZ=entra 时必需 |
MCP_ENTRA_AUDIENCE | 未设置 | API 应用程序(客户端)ID,预期出现在 v2 访问令牌的 aud 中;MCP_AUTHZ=entra 时必需 |
FHIR_RESPONSE_MODE | 未设置 | compact、full 或 compact-locked;未设置时,搜索默认采用 compact,直接读取默认采用 full |
FHIR_WRITE_CAPABILITIES | 未设置 | 以逗号分隔的写入操作:create、update、patch、delete |
FHIR_VALIDATE_WRITES | local | off、local(客户端结构检查)或 server(本地检查 + 对 create/update 执行服务端 $validate 预检) |
FHIR_WRITE_DRY_RUN | false | 设为 true 可验证并记录写入操作,但不在 FHIR 服务上执行 |
FHIR_BUNDLE_CAPABILITIES | 未设置 | 以逗号分隔的 Bundle 类型: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、http 的任意组合 |
FHIR_AUDIT_FILE | ./audit.jsonl | 启用 file 审计目标时使用的 JSONL 文件 |
FHIR_AUDIT_HTTP_URL | 未设置 | http 审计目标的目标 URL;启用 http 时必需 |
FHIR_AUDIT_HTTP_FORMAT | raw | raw(内部 AuditEvent JSON)或 fhir-auditevent(FHIR R4 AuditEvent) |
FHIR_AUDIT_HTTP_AUTH | 未设置 | http 目标原样发送的 Authorization 标头值 |
FHIR_AUDIT_USER_HEADER | 未设置 | 复制到审计事件中的代理身份验证用户标头 |
LOG_LEVEL | info | 日志详细程度:error、warn、info 或 debug |
显式设置的 FHIR_SERVER_URL 和 FHIR_TOKEN_URL 始终优先于推导出的 URL。 |
FHIR 版本支持
设置 FHIR_VERSION 以选择当前使用的 R4+ FHIR 版本。它会控制推导出的 FHIR API URL、FHIRPath 模型上下文和精简响应模型元数据。某些版本可能会使用最接近的兼容 FHIRPath 模型。对于术语服务,请使用与所选 FHIR 版本匹配的端点。启动日志会在显式设置的 FHIR 或术语服务 URL 似乎指向不同版本时给出提示。
自定义工具和消息
config/ 下的所有内容都可以自定义,无需修改源代码。
配置按部分覆盖方式解析:对于每个文件,如果当前工作目录中存在 ./config/<file>,则会覆盖随包提供的默认文件;未指定的内容则回退到内置默认值。因此,npm 安装后即可开箱即用。要进行自定义,只需在启动服务的位置旁创建一个 ./config 文件夹,其中仅包含想要更改的文件。
覆盖有两种粒度:
- 整个文件(
resources/*.json、operations.json、search-controls.json、core-tools.json、instructions/*):你提供的文件会完全替换随包提供的文件。新增资源文件(例如./config/resources/myresource.json)会添加一个工具。覆盖配置可以修改和添加资源,但无法移除随包提供的资源——若要提供严格精简的目录,请移除随包提供的config/resources/文件(参见 compose 示例)。 - 按键覆盖(
messages/*.json):本地文件仅覆盖其中包含的单个键;其他所有键均回退到随包提供的默认值。因此,你可以调整单条描述或消息,而无需复制整个文件。未知键、空值和格式错误的 JSON 会在启动时立即导致失败,以便及时发现拼写错误。
messages/*.json 文件只会在进程启动时读取一次。修改这些文件需要重启服务(若涉及工具架构或说明,则还需客户端重新连接)才能生效。下文将介绍资源、搜索控制和操作的开发热重载。
| 文件 | 用途 |
|---|---|
resources/*.json | FHIR 资源工具(每种资源一个文件):搜索参数、直接读取行为和 requireOneOf 规则 |
operations.json | operate 的命名操作目录(每项操作的描述和说明) |
search-controls.json | _count、_sort、_summary、_elements、_include、_revinclude、_lastUpdated、fhirpath、responseMode、maxResults 和 prefetch 的描述 |
messages/output-schema.json | 每个工具 outputSchema 字段的描述(按键覆盖) |
messages/input-schema.json | 生成的资源输入参数(_id、_vid、_since、_at、action、body)以及 operate 工具标题和参数的描述(按键覆盖) |
instructions/manifest.json | 用于组合的说明片段有序列表,每个片段都可以带有可选的 when 条件。自定义构建可通过编辑此文件重新排序、添加或移除章节。 |
instructions/*.md | 清单引用的说明片段。仅在启用相应功能时才会包含受条件控制的章节;{{OPERATIONS_LIST}} 标记会替换为实时操作目录。 |
messages/*.json | 面向用户的消息、错误和响应说明(按键覆盖,按领域拆分为 core、write、operations、terminology、bundle、artifact) |
core-tools.json | 内置工具描述和参数提示 |
资源定义架构
config/resources/ 中的每个文件都是单个资源定义对象。文件按文件名顺序扫描;文件名通常为小写资源名称(例如 patient.json)。每个对象包含以下字段:
| 字段 | 类型 | 描述 |
|---|---|---|
resource | string | FHIR 资源类型 |
toolName | string | MCP 工具名称;必须唯一 |
description | string | 工具描述 |
supportsDirectRead | boolean | 启用通过 _id 执行 GET /ResourceType/{id} |
searchParams | Record<string,string> | FHIR 搜索参数及其描述 |
requireOneOf | (string | string[])[] | 搜索至少需要一个选项。字符串表示单个必需参数;嵌套数组表示一组参数,其中每个参数都是必需的。["patient"] 接受 patient;[["given","family"],["identifier"]] 接受 given 和 family 一起使用,或使用 identifier |
searchParams 的值是描述,不是完整的 FHIR 能力模型。
仍可能适用特定服务器的搜索行为。
热重载
在开发环境中(NODE_ENV 不为 production),系统会监视 config/resources/ 文件夹、search-controls.json 和 operations.json。如果 JSON 无效,则保留上一个有效快照。发生实质性变更时,会以事务方式应用重载:当派生的 SMART 作用域发生变化时,系统会先获取替换令牌,再提交新的定义和工具注册,因此获取失败不会影响正在运行的目录。添加或移除工具,以及操作和参数名称架构变更,都会实时重新注册,无需重启。语义未发生变化的保存不会触发刷新。在生产环境中,配置只会在启动时读取;但每种模式下,运行时 /metadata 变更(通过 capabilities(refresh=true))或令牌刷新时后端 SMART 作用域变更,都会重新评估可用工具。
有一个不可避免的限制:工具列表和架构会热刷新,但服务器的 instructions 只会在 MCP initialize 期间发送一次,且无法在现有连接上替换。客户端必须重新连接或重新初始化,才能接收更新后的说明文本。
传输方式
Stdio
设置 MCP_TRANSPORT=stdio。stdout 专用于 MCP 协议;日志会重定向到 stderr。使用外部 FHIR_JWKS_URL 部署 stdio。
Streamable HTTP
HTTP 传输为无状态,并在以下地址提供 MCP:
POST http://localhost:5000/mcp
Accept: application/json, text/event-stream
Content-Type: application/json
MCP 客户端配置:
{
"mcpServers": {
"fhirhydrant": {
"url": "http://localhost:5000/mcp"
}
}
}
GET /health 会返回不包含 PHI 的就绪状态快照:
{
"status": "ok",
"mcp": true,
"metadata": true,
"tools": 23,
"auth": true,
"tokenExpiresIn": 287
}
启用授权后,authz 会报告当前使用的提供方;由于注册的工具数量因调用者而异,因此会省略 tools。
如果要通过 HTTP 向 localhost 以外的地址开放服务,请使用反向代理处理 TLS 和用户身份验证。绑定到公共接口时,请设置 ALLOWED_HOSTS。
按调用方授权(Entra,可选)
默认情况下(MCP_AUTHZ=none),所有调用方都能看到完整工具集,其权限仅受
/metadata 和后端 SMART 范围限制。设置 MCP_AUTHZ=entra 后,会增加一个
可选的按调用方授权层:每个 /mcp 请求都必须携带由 Microsoft Entra 签发的
Authorization: Bearer <token>,调用方的 App Roles 决定为该请求构建哪些
工具。这只是 MCP 层面的授权——不会取代 FHIR 服务自身的授权,并且只能从
后端 SMART 令牌和配置已允许的范围中缩减权限。
API 应用注册必须在其清单中将 requestedAccessTokenVersion 设为 2。提供程序会验证特定租户的 v2 签发者,并要求 MCP_ENTRA_AUDIENCE 为 API 应用的客户端 ID。
调用方缺少相应角色的工具根本不会注册——它们不会出现在
tools/list 中,而不只是被阻止。辅助工具(capabilities、paginate、
terminology_lookup、code_search)永远不会受此限制。
App Role 值(默认前缀为 FhirHydrant):
| 角色 | 授予权限 |
|---|---|
FhirHydrant.<Resource>.Read | 对该资源进行搜索、读取、版本读取和历史记录查询 |
FhirHydrant.<Resource>.Write | 包含读取操作,以及创建、更新、修补、删除(受 FHIR_WRITE_CAPABILITIES 限制) |
FhirHydrant.Operation.<key> | 通过 operate 工具调用指定的操作(例如 FhirHydrant.Operation.everything) |
FhirHydrant.Bundle | bundle 工具 |
FhirHydrant.SystemHistory.Read | 全系统的 system_history 工具 |
FhirHydrant.Admin | 以上所有权限,但仍受后端 SMART 范围、/metadata 以及写入/捆绑/操作配置限制 |
需要使用 HTTP 传输;若设置 MCP_AUTHZ=entra 且 MCP_TRANSPORT=stdio,启动时会失败。缺少或无效的 bearer 令牌会收到 401。
添加授权提供程序
Entra 是目前唯一随附的提供程序,但授权层与提供程序无关。这属于源代码扩展,而非运行时插件:npm 包仅包含 bin/server.js(提供程序会打包在其中),因此添加提供程序需要派生或克隆仓库并重新构建。
共享管线与提供程序无关——提供程序只需将
Authorization 标头映射为 { subject, roles }。角色词汇
(.Read/.Write/Operation.<key>/Bundle/SystemHistory.Read/Admin)和
MCP_ROLE_PREFIX 处理逻辑由 decideAuthz 应用于所有提供程序。
添加一个提供程序(例如 auth0)只需修改两处:
- 创建
ts/mcp/authz/auth0.ts,导出一个AuthzProvider——实现validate(authorization)并返回{ subject, roles }(拒绝时抛出异常), 还可选择实现validateConfig(),以便在缺少提供程序环境变量时快速失败。将所有提供程序专属的环境变量保留在此模块中;不要向Config添加字段。 - 在
ts/mcp/authz/registry.ts中添加一项:auth0: () => import("./auth0.ts").then((m) => m.auth0Provider)。
就这么简单。AuthzMode 类型、MCP_AUTHZ 解析器及其错误消息都会根据注册表键自动生成,因此 MCP_AUTHZ=auth0 可直接使用,并具有完整的类型安全性——无需修改其他文件。
部署示例
examples/ 目录包含独立的部署示例,涵盖 Docker Compose、反向代理(Caddy)、Azure Container Apps、Azure App Service 和 Kubernetes。每个示例都包含一个从 npm 安装的 Dockerfile,以及一个展示如何覆盖不同配置文件的 config/ 覆盖目录。
开发
# dev server
npm run dev
# type-check
npm run check
# build and run
npm run build
npm start
构建输出位于 bin/server.js。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。