mcpField
F
fhirHydrant

fhirHydrant

已认证精选本地服务
github.com/faulkjAI 与智能体186 周前更新

关于 fhirHydrant

fhirHydrant 是面向 MCP 客户端的 Node.js FHIR 服务,可通过 SMART Backend Services 访问 R4 及以上 FHIR API。它根据服务器元数据和配置提供资源操作,并支持响应精简、FHIRPath 过滤及术语查询。

主要功能

  1. 01SMART Backend Services 身份验证
  2. 02按元数据提供资源搜索与读写
  3. 03配置命名操作与 Bundle 提交
  4. 04精简响应并支持 FHIRPath 过滤
  5. 05安全分页与审计事件
  6. 06LOINC 和 SNOMED CT 查询

适用场景

  1. 01在临床 FHIR API 中搜索或读取资源
  2. 02按需启用资源创建、更新或删除
  3. 03浏览大型 FHIR Bundle 的后续页面
  4. 04查询临床术语代码

MCP 相关

该服务通过 MCP 向兼容客户端提供 FHIR 资源搜索、读取、可选 CRUD、命名操作、分页和术语查询工具。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"fhirhydrant": {
"command": "npx",
"args": [
"-y",
"fhirhydrant"
],
"env": {
"MCP_TRANSPORT": "<MCP_TRANSPORT>",
"FHIR_AUTH": "<FHIR_AUTH>",
"FHIR_SERVER_URL": "<FHIR_SERVER_URL>",
"FHIR_TOKEN_URL": "<FHIR_TOKEN_URL>",
"FHIR_CLIENT_ID": "<FHIR_CLIENT_ID>",
"FHIR_ACTIVE_KEY": "<FHIR_ACTIVE_KEY>",
"FHIR_JWKS_URL": "<FHIR_JWKS_URL>",
"FHIR_VERSION": "<FHIR_VERSION>"
}
}
}
}
启动命令npx -y fhirhydrant
需要配置的环境变量
MCP_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+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmfhirhydrant0.17.3

工具

28

收录的工具列表 · 更新于 3 周前

参数类型必填说明
urlstring是来自 FHIR Bundle 链接 link[rel=next].url 值的分页 URL
fhirpathstring否在 FHIR 响应上本地求值的 FHIRPath 表达式 — 当 _elements 或 _summary 不可用或不足时,用于客户端投影
responseModeenum否响应形式:compact 或 fullcompact | full
maxResultsnumber否紧凑结果的目标数量 — 达到此阈值后,服务器将停止获取其他页面
prefetchboolean否设为 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、_vidGET /ResourceType/{id}/_history/{vid}
history_id(实例)或无(类型)GET /ResourceType/{id}/_history 或 GET /ResourceType/_history
createbodyPOST /ResourceType
update_id、bodyPUT /ResourceType/{id}
patch_id、body使用 JSON Patch 的 PATCH /ResourceType/{id}
delete_idDELETE /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 重试作为后备方案
FHIRPathfhirpath 会在本地筛选返回的 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 字符),并在启动时记录日志。

密钥轮换工作流:

  1. 生成新密钥(RSA-2048 或 EC P-384)。
  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。

必填
变量说明
FHIR_BASE_URL用于推导 FHIR 服务 URL 和令牌 URL 的基础 URL。设置了 FHIR_SERVER_URL 时可选(使用 smart 身份验证时还需设置 FHIR_TOKEN_URL)
FHIR_CLIENT_IDSMART Backend Services 客户端 ID(FHIR_AUTH=none 时不需要)
FHIR_ACTIVE_KEYBase64 编码的 PKCS#8 PEM 签名密钥,RSA 或 EC P-384(FHIR_AUTH=none 时不需要)
可选
变量默认值说明
FHIR_AUTHsmartsmart(SMART Backend Services)或 none(不进行身份验证,用于公开测试端点)
FHIR_RETIRED_KEYS未设置以逗号分隔的 base64 编码 PEM,用于 JWKS 轮换
FHIR_VERSIONR4当前启用的 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_TRANSPORThttphttp 或 stdio
PORT5000HTTP 监听端口
BIND_HOST0.0.0.0(使用 --dev 标志时为 127.0.0.1)HTTP 绑定地址
ALLOWED_HOSTS未设置以逗号分隔的主机名,用于防止 DNS 重绑定
FHIR_METADATA_MODEstrict用于 /metadata 验证的 strict、warn 或 off
FHIR_DEFAULT_COUNT0允许时注入搜索的默认 _count;0 = 由服务端决定
FHIR_MAX_COUNT0显式调用方 _count 值的上限;0 = 不设上限
FHIR_MAX_RESPONSE_BYTES262144面向模型的 JSON 响应字节数上限;超大的 Bundle 会被分块
FHIR_MAX_ARTIFACT_MB16原生/二进制工件正文的独立字节上限(MiB);不受 JSON 上限影响(base64 传输约增加 33%)
FHIR_REQUEST_TIMEOUT_MS30000每次发出的 FHIR 请求尝试的超时时间
MCP_JSON_LIMIT4mbMCP 请求正文可接受的最大尺寸(Express JSON 限制字符串);如果大型写入/Bundle 负载被拒绝,请调高此值
MCP_AUTHZnone授权提供方:none 或 entra。按调用方控制工具访问权限(仅限 HTTP + Authorization: Bearer)
MCP_ROLE_PREFIXFhirHydrant授予的角色值前缀(例如 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_WRITESlocaloff、local(客户端结构检查)或 server(本地检查 + 对 create/update 执行服务端 $validate 预检)
FHIR_WRITE_DRY_RUNfalse设为 true 可验证并记录写入操作,但不在 FHIR 服务上执行
FHIR_BUNDLE_CAPABILITIES未设置以逗号分隔的 Bundle 类型:batch、transaction;启用 bundle 工具
FHIR_BUNDLE_WRITES_ENABLEDfalse设为 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_PAGES5每次合并紧凑搜索最多获取的上游页面数
FHIR_PREFETCH_MAX_ENTRIES5000达到上限后停止累积的上游条目数
FHIR_PREFETCH_MAX_BYTES2097152停止前获取的原始字节数上限
FHIR_PREFETCH_TIMEOUT_MS25000合并循环的总时长预算
FHIR_AUDIT_SINK未设置console、file、http 的任意组合
FHIR_AUDIT_FILE./audit.jsonl启用 file 审计目标时使用的 JSONL 文件
FHIR_AUDIT_HTTP_URL未设置http 审计目标的目标 URL;启用 http 时必需
FHIR_AUDIT_HTTP_FORMATrawraw(内部 AuditEvent JSON)或 fhir-auditevent(FHIR R4 AuditEvent)
FHIR_AUDIT_HTTP_AUTH未设置http 目标原样发送的 Authorization 标头值
FHIR_AUDIT_USER_HEADER未设置复制到审计事件中的代理身份验证用户标头
LOG_LEVELinfo日志详细程度: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/*.jsonFHIR 资源工具(每种资源一个文件):搜索参数、直接读取行为和 requireOneOf 规则
operations.jsonoperate 的命名操作目录(每项操作的描述和说明)
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)。每个对象包含以下字段:

字段类型描述
resourcestringFHIR 资源类型
toolNamestringMCP 工具名称;必须唯一
descriptionstring工具描述
supportsDirectReadboolean启用通过 _id 执行 GET /ResourceType/{id}
searchParamsRecord<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.Bundlebundle 工具
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)只需修改两处:

  1. 创建 ts/mcp/authz/auth0.ts,导出一个 AuthzProvider——实现 validate(authorization) 并返回 { subject, roles }(拒绝时抛出异常), 还可选择实现 validateConfig(),以便在缺少提供程序环境变量时快速失败。将所有提供程序专属的环境变量保留在此模块中;不要向 Config 添加字段。
  2. 在 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。

评论

支持 Markdown

第一次接触 MCP?

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

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