Skip to main content
Glama
MCP FHIR Server

MCP FHIR Server

by mrosata

MCP FHIR Server

A generic MCP server providing read/write access to any FHIR-compliant API with built-in validation.

This server works with any FHIR server, not just Zus Health. For Zus-specific features (like getting UPIDs), see the Zus Extensions section below.

Features

Core FHIR Features

  • FHIR resource validation using consolidated FHIR schemas

  • Create and update resources (POST/PUT)

  • Read resources by type and ID

  • Search resources with query parameters

  • Granular permissions via environment configuration

  • Bearer token authentication

  • Custom HTTP headers for multi-tenant or vendor-specific requirements

  • Detailed error messages for debugging and LLM-based correction

Zus Health Extensions (Optional)

  • Zus UPID lookup - Get Universal Patient IDs from Zus FHIR servers

  • Intelligent name matching - Find best patient match when multiple results exist

  • Builder ID support - Multi-tenant access via Zus-Account header

Related MCP server: FHIR MCP Server

Installation

Prerequisites

  • Python 3.13+

  • uv (recommended) or pip

Setup

# Clone the repository
git clone <repository-url>
cd mcp-fhir

# Install dependencies (production only)
uv sync

# For development (includes test tools, linter, etc.)
uv sync --extra dev

# Or with pip
pip install -e .

Note: The make commands will automatically install development dependencies when needed, so you can also just run make test directly after cloning.

Configuration

Environment File

The server can load environment variables from a file using the --env-file command line flag:

# Load environment variables from a specific file
uv run fastmcp run server.py --env-file /path/to/your/.env

# Or for development
uv run fastmcp dev server.py --env-file /path/to/your/.env

If no --env-file flag is provided, the server will use system environment variables only.

Create a .env file:

cp .env.example .env

Environment Variables

Variable

Default

Description

FHIR_BASE_URL

http://localhost:8080/fhir

FHIR server base URL

FHIR_ALLOW_READ

true

Enable GET operations

FHIR_ALLOW_WRITE

true

Enable POST/PUT/PATCH/DELETE operations

FHIR_AUTH_TOKEN

(empty)

Bearer token for authentication

FHIR_ALLOWED_METHODS

(empty)

Comma-separated HTTP methods (overrides READ/WRITE)

Permission Model

Option 1: Simple Read/Write (default)

FHIR_ALLOW_READ=true   # Enables GET
FHIR_ALLOW_WRITE=true  # Enables POST, PUT, PATCH, DELETE

Option 2: Granular Methods (takes precedence)

FHIR_ALLOWED_METHODS=GET,POST  # Only read and create

Examples:

  • GET - Read-only

  • POST,PUT - Create and update only (no reads)

  • GET,POST - Read and create (no updates)

  • GET,POST,PUT - Full access

Running

Development

# Using make (recommended)
make dev

# Or directly
uv run fastmcp dev server.py

Production

# Using make (recommended)
make run

# Or directly
uv run fastmcp run server.py

Claude Desktop Integration

Edit your Claude Desktop config file:

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json Windows: %APPDATA%\Claude\claude_desktop_config.json Linux: ~/.config/Claude/claude_desktop_config.json

{
  "mcpServers": {
    "fhir": {
      "command": "uv",
      "args": [
        "--directory",
        "/absolute/path/to/mcp-fhir",
        "run",
        "fastmcp",
        "run",
        "server.py",
        "--env-file",
        "/absolute/path/to/mcp-fhir/.env"
      ]
    }
  }
}

Alternative: You can also set environment variables directly in the config:

{
  "mcpServers": {
    "fhir": {
      "command": "uv",
      "args": [
        "--directory",
        "/absolute/path/to/mcp-fhir",
        "run",
        "fastmcp",
        "run",
        "server.py"
      ],
      "env": {
        "FHIR_BASE_URL": "https://your-fhir-server.com/fhir",
        "FHIR_ALLOW_READ": "true",
        "FHIR_ALLOW_WRITE": "true",
        "FHIR_AUTH_TOKEN": "your-token-here"
      }
    }
  }
}

Restart Claude Desktop after editing.

Tools

Core FHIR Tools

These tools work with any FHIR-compliant server:

write_fhir_resource

Create or update a FHIR resource.

Parameters:

  • resource (object): FHIR resource JSON

  • custom_headers (object, optional): Custom HTTP headers for the request

    • For Zus servers: {"Zus-Account": "builder-id"} for multi-tenant access

    • For other servers: Any vendor-specific headers your FHIR server requires

Behavior:

  1. Validates resource against FHIR schema

  2. Uses POST if no id field (create), PUT if id exists (update)

  3. Returns validation errors for correction if invalid

  4. Returns server response on success (if FHIR_ALLOW_READ=true)

Example:

{
  "resourceType": "Patient",
  "name": [{"family": "Smith", "given": ["John"]}],
  "gender": "male"
}

Note: If validation schema fails to load, validation is skipped (server-side validation still applies).


read_fhir_resource

Read a resource by type and ID.

Parameters:

  • resource_type (string): e.g., "Patient", "Observation"

  • resource_id (string): Resource ID

  • custom_headers (object, optional): Custom HTTP headers for the request

Returns: JSON resource or error message


search_fhir_resources

Search resources with query parameters.

Parameters:

  • resource_type (string): Resource type to search

  • search_params (object, optional): Query parameters

    • Example: {"name": "Smith", "gender": "female"}

  • custom_headers (object, optional): Custom HTTP headers for the request

Returns: FHIR Bundle with matching resources


get_fhir_config

View current configuration.

Returns: Configuration summary including base URL, permissions, and allowed methods.


Zus Health Extensions

These tools are specific to Zus Health FHIR servers and will not work with other FHIR implementations.

get_patient_zus_upid

Get the Zus UPID (Universal Patient ID) for a Patient resource from Zus FHIR server.

Parameters:

  • first_name (string): Patient's first name

  • last_name (string): Patient's last name

  • builder_id (string, optional): Zus builder ID to filter the search

Behavior:

  1. Searches for Patient resources using name parameter (concatenated first and last name)

  2. Optionally filters by Zus builderID parameter if provided

  3. Extracts Zus UPID from Patient's identifiers with system https://zusapi.com/fhir/identifier/universal-id

  4. When multiple patients are found, uses intelligent name matching to find the best match

  5. Returns the Zus UPID value or appropriate error message

Example usage:

get_patient_zus_upid("John", "Smith")
get_patient_zus_upid("John", "Smith", "builder-123")

Response formats:

  • Single patient found: Zus UPID: zus-upid-12345

  • Multiple patients with good name match: Zus UPID: zus-upid-12345 (Best match: John Smith) + other matches if any

  • Multiple patients with no clear match: Lists all found patients with their Zus UPIDs

  • No patients found: Error: No Patient found with name 'John Smith'

  • No Zus UPID: Error: No Zus UPID found for Patient(s) with name 'John Smith'

Name Matching Logic:

  • Exact name matches get highest priority (score 1.0)

  • Partial matches (e.g., "John" matching "Johnny") get medium priority (score 0.7 for given name)

  • Family name matches are weighted more heavily than given name matches

  • Partial matches are permissive: shorter names can match longer ones (e.g., "John" matches "Johnny")

  • If the best match has a score ≥ 0.5, it's returned as the primary result

  • Other decent matches (score ≥ 0.3) are listed as alternatives

Technical Details

HTTP Headers

All requests include:

Content-Type: application/fhir+json
Accept: application/fhir+json
Authorization: Bearer {token}  (if FHIR_AUTH_TOKEN set)

Custom Headers: You can provide additional custom headers via the custom_headers parameter in any tool. This is useful for:

  • Multi-tenant systems (e.g., Zus's Zus-Account header)

  • Vendor-specific authentication or routing headers

  • Any other FHIR server-specific requirements

Example (Zus):

{"Zus-Account": "builder-123"}

Timeouts

All requests timeout after 30 seconds.

Error Handling

The server returns detailed errors for:

Code

Description

400

Invalid request/validation error

401

Authentication failed

403

Insufficient permissions

404

Resource or endpoint not found

422

Business rule violation

Timeout

Connection timeout (30s)

Errors include full server response when available for debugging.

Validation

Resources are validated using the fhir-validator library before submission:

  • Checks FHIR spec compliance

  • Validates required fields and data types

  • Verifies resource structure

If validation schema loading fails at startup, a warning is logged and validation is bypassed (server-side validation still occurs).

Development

Testing

# Run tests (automatically installs dev dependencies if needed)
make test

# With coverage
make test-cov

# Watch mode
make test-watch

Or directly:

uv run pytest
uv run pytest --cov=. --cov-report=term-missing

Note: All make commands automatically install development dependencies when needed, so new developers can simply run make test after cloning the repository.

Code Quality

make lint    # Run linter (automatically installs dev dependencies)
make format  # Format code (automatically installs dev dependencies)
make check   # Lint + format check (automatically installs dev dependencies)

Project Structure

mcp-fhir/
├── server.py          # Generic MCP FHIR server implementation
├── zus_extensions.py  # Zus Health-specific tools (optional)
├── fhir_validator.py  # FHIR validation logic
├── pyproject.toml     # Dependencies
├── .env.example       # Example configuration
└── tests/             # Test suite

Architecture

The server is designed with modularity in mind:

  • server.py: Contains generic FHIR operations that work with any FHIR server

  • zus_extensions.py: Contains Zus Health-specific functionality (UPID lookup, etc.)

  • Generic tools accept custom_headers for flexibility with different FHIR vendors

  • Zus tools use builder_id for Zus-specific multi-tenancy

This separation allows you to:

  1. Use the generic tools with any FHIR server

  2. Add your own vendor-specific extensions by following the zus_extensions.py pattern

  3. Keep the core FHIR functionality clean and standards-compliant

License

[Add license information]

Contributing

[Add contribution guidelines]

Available Tools

5 tools
get_fhir_configB

Get the current FHIR server configuration.

Returns: Current configuration settings

Inputs: no named parameters. Returns: result

get_patient_zus_upidA

Get the Zus UPID (Universal Patient ID) for a Patient resource from Zus FHIR server.

This is a Zus-specific tool for working with Zus Health's FHIR API. Searches for a Patient by first and last name, optionally filtered by builderID, then extracts the Zus UPID from the Patient's identifiers.

Args: first_name: Patient's first name last_name: Patient's last name builder_id: Optional Zus builder ID (string) to filter the search

Returns: The Zus UPID value or an error message if not found

Inputs: first_name (required), last_name (required), builder_id. Returns: result

read_fhir_resourceA

Read a FHIR resource by type and ID from the FHIR server.

Args: resource_type: The FHIR resource type (e.g., "Patient", "Observation") resource_id: The ID of the resource to read custom_headers: Optional dictionary of custom HTTP headers to include in the request. For Zus servers, use {"Zus-Account": "builder-id"} for multi-tenant access.

Returns: The FHIR resource as JSON or an error message

Inputs: resource_type (required), resource_id (required), custom_headers. Returns: result

search_fhir_resourcesB

Search for FHIR resources using query parameters.

Args: resource_type: The FHIR resource type to search (e.g., "Patient", "Observation") search_params: Optional dictionary of search parameters (e.g., {"name": "Smith", "gender": "female"}) custom_headers: Optional dictionary of custom HTTP headers to include in the request. For Zus servers, use {"Zus-Account": "builder-id"} for multi-tenant access.

Returns: A FHIR Bundle containing matching resources or an error message

Inputs: resource_type (required), search_params, custom_headers. Returns: result

write_fhir_resourceA

Write a FHIR resource to the FHIR server.

This tool:

  1. Validates the FHIR resource using fhir-validator

  2. Determines the appropriate endpoint based on resource type

  3. POSTs or PUTs the resource to the FHIR server

  4. Returns validation errors or server errors for correction

Args: resource: A FHIR resource as a JSON object (dict) custom_headers: Optional dictionary of custom HTTP headers to include in the request. For Zus servers, use {"Zus-Account": "builder-id"} for multi-tenant access.

Returns: A status message indicating success or detailed error information

Inputs: resource (required), custom_headers. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.5/5.0

    Scored across 5 tools

    Disambiguation4/5

    Most tools have distinct purposes, but get_fhir_config overlaps slightly with general FHIR operations as it's a configuration tool rather than a core FHIR resource operation. The other tools (read, search, write, get_patient_zus_upid) are clearly differentiated by their specific actions and targets.

    Naming Consistency4/5

    Tools follow a consistent verb_noun pattern (get_fhir_config, read_fhir_resource, search_fhir_resources, write_fhir_resource), with get_patient_zus_upid being a minor deviation due to its Zus-specific naming. Overall, the naming is predictable and readable.

    Tool Count4/5

    Five tools is reasonable for a FHIR server, covering core operations like read, search, and write, plus configuration and a Zus-specific utility. It's slightly thin for full FHIR coverage but well-scoped for basic interactions.

    Completeness3/5

    The toolset covers read, search, and write operations, but lacks update and delete for full CRUD lifecycle management. The inclusion of get_fhir_config and a Zus-specific tool adds utility, but the absence of update/delete operations is a notable gap for FHIR resource management.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      Enables LLM-based agents to interact with FHIR healthcare data through natural language prompts, providing full CRUD operations on FHIR resources, document processing, and semantic search capabilities.
      13
      102
      MIT
    • A
      license
      Not graded
      quality
      Not graded
      maintenance
      Enables seamless integration with FHIR APIs for healthcare applications, allowing users to search, retrieve, create, update, and analyze clinical information through natural language interactions. Supports SMART-on-FHIR authentication and works with various healthcare systems like EPIC and HAPI FHIR servers.
      Apache 2.0
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables LLMs to securely interact with FHIR healthcare servers and HL7 terminology services. Provides comprehensive healthcare data operations with built-in PHI protection, audit logging, and SMART on FHIR authentication.
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Provides seamless integration with FHIR APIs, enabling AI/LLM tools to search, retrieve, and analyze clinical healthcare data with support for SMART-on-FHIR authentication and multiple transport protocols.
      7
      1,026 PyPI
      137
      Apache 2.0