ysnr-dev

fhir-mcp-server

Community ysnr-dev
Updated

fhir-mcp-server

FHIR R4 サーバー(JP-Core 準拠の fhir-server や HAPI FHIR 等)に接続する MCP(Model Context Protocol)サーバーです。Claude Desktop / Claude Code などの MCP クライアントから、FHIR データを自然言語で検索・参照・(オプトインで)書き込みできます。

  • fhir-server とはリポジトリ分離(接点は HTTP + Bearer トークンのみ)
  • SMART Backend Services(OAuth2 client_credentials + system/* スコープ)のクライアントとして動作
  • FHIR_BASE_URL とクレデンシャルの差し替えで任意の FHIR R4 サーバーに接続可能

セットアップ

Node.js 20+ が必要です。

npm install
npm run build

Docker / docker compose で動かす

Node.js をホストに入れずに動かす場合は Docker イメージを使います。MCP の stdio サーバーなので常駐(up)は不要で、クライアントが必要なときに docker compose run で起動します。

docker compose build

動作確認(手動で JSON-RPC を流す代わりに、後述のクライアント登録をしてもよい):

docker compose run --rm -T fhir-mcp
  • 既定の接続先は http://host.docker.internal:3000(= ホストの localhost:3000)。fhir-server をホストで直接動かしていても、docker compose(ポート 3000 公開)で動かしていてもそのままつながります
  • 接続先やクレデンシャルは環境変数で上書きできます: FHIR_BASE_URL=... FHIR_CLIENT_ID=... docker compose run --rm -T fhir-mcp
  • fhir-server(Rails)側は HostAuthorization で host.docker.internal を許可している必要があります(development.rb の config.hosts << "host.docker.internal")

Docker 経由で Claude Code に登録する場合:

claude mcp add fhir -- docker compose -f /path/to/fhir-mcp-server/compose.yaml run --rm -T fhir-mcp

Claude Desktop の場合:

{
  "mcpServers": {
    "fhir": {
      "command": "docker",
      "args": [
        "compose", "-f", "/path/to/fhir-mcp-server/compose.yaml",
        "run", "--rm", "-T", "fhir-mcp"
      ]
    }
  }
}

Claude クライアントへの接続

Claude Code

claude mcp add fhir -- node /path/to/fhir-mcp-server/dist/index.js

環境変数を渡す場合:

claude mcp add fhir \
  -e FHIR_BASE_URL=http://localhost:3000 \
  -e FHIR_CLIENT_ID=... \
  -e FHIR_CLIENT_SECRET=... \
  -- node /path/to/fhir-mcp-server/dist/index.js

Claude Desktop(claude_desktop_config.json)

{
  "mcpServers": {
    "fhir": {
      "command": "node",
      "args": ["/path/to/fhir-mcp-server/dist/index.js"],
      "env": {
        "FHIR_BASE_URL": "http://localhost:3000",
        "FHIR_CLIENT_ID": "...",
        "FHIR_CLIENT_SECRET": "..."
      }
    }
  }
}

設定(環境変数)

変数 既定 説明
FHIR_BASE_URL http://localhost:3000 接続先 FHIR サーバー
FHIR_CLIENT_ID / FHIR_CLIENT_SECRET なし SMART Backend Services のクレデンシャル。両方未設定なら無認証モード(Authorization ヘッダーを送らない。fhir-server の FHIR_AUTH_ENABLED=false 環境向け)
FHIR_MCP_ALLOW_WRITES false true のときだけ書き込みツール(create/update/patch)を登録
FHIR_MCP_MAX_COUNT 50 検索 _count の上限

認証(SMART Backend Services)

FHIR_CLIENT_ID / FHIR_CLIENT_SECRET を設定すると、POST {FHIR_BASE_URL}/oauth/tokengrant_type=client_credentials でアクセストークンを取得します。

  • トークンは expires_in の 90% 経過で先回り再取得
  • API が 401 を返した場合は 1 回だけトークンを再取得してリトライ
  • トークン・シークレットはログに出力しません

fhir-server 側のクライアント登録例:

bin/rails "fhir:register_client[fhir-mcp-server,system/*.read]"
# 書き込みも許可する場合は system/*.write スコープを付与

ツール一覧

参照系(常時登録)

ツール 対応エンドポイント 説明
get_capabilities GET /metadata 対応リソース・検索パラメータ・オペレーションの要約。使い方の自己発見の起点
search_fhir GET /{type}?... 検索。チェーン検索・_has_include 等は params でそのまま透過
read_fhir GET /{type}/{id} 単一リソース取得
patient_everything GET /Patient/{id}/$everything 患者コンパートメント一括取得(_type/_since 対応)
get_history GET [/{type}[/{id}]]/_history インスタンス/タイプ/システムレベルの履歴
validate_fhir POST /{type}/$validate 保存せずにリソースを検証

書き込み系(FHIR_MCP_ALLOW_WRITES=true のときのみ登録)

ツール 対応エンドポイント 説明
create_fhir POST /{type} 作成(If-None-Exist による条件付き作成対応)
update_fhir PUT /{type}/{id} 全置換更新(If-Match による楽観ロック対応)
patch_fhir PATCH /{type}/{id} JSON Patch(RFC 6902)による部分更新

delete はツールとして提供しません(AI からの破壊的操作は初期スコープ外)。

トークン消費を抑えるコツ

検索結果の Bundle はそのまま返さず、{ total, returned, hasNextPage, resources } に整形して返します。それでも大きい場合は件数を切り詰め、絞り込みのガイダンスを付けます。以下を活用してください:

  • _elements=id,name,birthDate — 必要なフィールドだけ取得
  • _summary=true — サマリー要素のみ取得
  • _count — ページサイズを絞る(既定 20)
  • patient_everything では types / since で範囲を限定

開発

npm run dev        # tsx で直接実行
npm test           # unit テスト(fetch モック)
npm run lint       # biome
npm run build      # tsc → dist/

integration テスト

実サーバー相手の e2e は FHIR_INTEGRATION_BASE_URL を設定したときだけ実行されます:

# fhir-server を docker compose 等で起動しておく
FHIR_INTEGRATION_BASE_URL=http://localhost:3000 npm test

# 認証ありモードを試す場合
FHIR_INTEGRATION_BASE_URL=http://localhost:3000 \
FHIR_INTEGRATION_CLIENT_ID=... \
FHIR_INTEGRATION_CLIENT_SECRET=... \
npm test

アーキテクチャ

MCP クライアント(Claude 等)
        │ stdio
        ▼
fhir-mcp-server
  ├── src/index.ts          エントリポイント(stdio transport)
  ├── src/server.ts         McpServer 構築・ツール登録
  ├── src/config.ts         環境変数の読み込み・検証
  ├── src/fhir-client.ts    FHIR REST 呼び出し(fhir+json、OperationOutcome 整形、401 リトライ)
  ├── src/token-manager.ts  SMART トークン管理(先回り更新)
  ├── src/format.ts         Bundle / CapabilityStatement の要約整形
  └── src/tools/*.ts        ツール実装(薄い層)
        │ HTTP(S) + Authorization: Bearer
        ▼
FHIR R4 サーバー(fhir-server / HAPI など)

設計の背景・rationale は docs/DESIGN.md を参照してください。

MCP Server · Populars

MCP Server · New

    laurentvv

    Web Crawler MCP

    Web crawling tool that integrates with AI assistants via the MCP

    Community laurentvv
    anypost

    emailmd

    Render markdown into email-safe HTML

    Community anypost
    dinglebear-ai

    Unraid MCP

    Query, monitor, and manage Unraid servers via GraphQL API through MCP tools. Supports system info, Docker, VMs, array/parity, notifications, plugins, rclone, and live telemetry.

    Community dinglebear-ai
    superbasedapp

    SuperBased Observer

    Local-first control plane for AI coding agents — launch browser terminals, run and remotely control sessions, and track files, tokens & cost across Claude Code, Codex, Cursor, Gemini CLI and 20+ more. 100% local, no telemetry.

    Community superbasedapp
    OpenMarkdown-dev

    OpenMarkdown

    Feather-light. Light-speed.

    Community OpenMarkdown-dev