TerminallyLazy

sharp-fhir-mcp

Community TerminallyLazy
Updated

Sharp on FHIR MCP Server w/ MCP-UI for DevPost Hackathon

sharp-fhir-mcp

A clean-room SHARP-on-MCP compliant FHIR R4MCP server with interactive MCP-UI clinical dashboards.

Built for the Prompt Opinion "Build the Future of Healthcare AI" Hackathon โ€” avendor-neutral MCP server that any SMART-on-FHIR app, agent, or LLM host canplug into without server-side OAuth, API keys, or proprietary auth flows.

Why SHARP?

The SHARP (Standardised HealthcareAgent Remote Protocol) spec describes a headers-based context model for MCPservers in healthcare:

Header Purpose
X-FHIR-Server-URL Base URL of the patient's FHIR R4 endpoint
X-FHIR-Access-Token Bearer token already minted by the agent host
X-Patient-ID Optional default Patient resource id

Per SHARP ยง3.2, the MCP server never runs an OAuth dance itself. The agenthost (e.g. a SMART-on-FHIR launch container) obtains the token and forwards iton every call. This means a single deployment of this server works againstEpic, Cerner, MEDITECH, athenahealth, eClinicalWorks, ConnectEHR, HAPI, orany other FHIR R4 endpoint โ€” there's nothing vendor-specific.

The server advertises capabilities.experimental.fhir_context_required = trueon every initialise response so SHARP-aware clients know to forward thoseheaders automatically.

What's included

๐Ÿฉบ Clinical FHIR tools

  • fhir_get_capability_statement โ€” discover the connected FHIR server
  • fhir_get_patient, fhir_search, fhir_read, fhir_patient_everything โ€” generic R4 access
  • clinical_search_patients, clinical_get_patient_summary
  • clinical_get_appointments, clinical_get_encounters
  • clinical_get_problems, clinical_get_medications, clinical_get_allergies, clinical_get_immunizations
  • clinical_get_health_record โ€” one-shot consolidated record
  • clinical_get_context โ€” full visit context (demographics + allergies + meds + problems + labs + vitals + encounters + alerts) in parallel

๐Ÿ”ฌ Labs, vitals & imaging

  • lab_get_results, lab_get_vital_signs, lab_get_diagnostic_reports
  • imaging_get_documents โ€” DocumentReference search

๐Ÿง  Optional persistent memory (SimpleMem)

When SIMPLEMEM_API_URL and SIMPLEMEM_ACCESS_TOKEN are set:

  • memory_store_encounter โ€” save a visit summary
  • memory_store_alert โ€” flag clinical concerns for next visit
  • memory_search_history โ€” semantic search across past encounters
  • memory_get_patient_history โ€” list all stored memories for the current patient

๐Ÿ“Š MCP-UI visualisations

  • visualize_lab_trend โ€” Chart.js line chart of one lab over time
  • visualize_vitals โ€” multi-chart vitals dashboard
  • visualize_patient_dashboard โ€” full HTML clinical page (demographics, alerts, allergies, meds, problems, labs, encounters, immunisations + Chart.js trends)

All visual tools return MCP-UI ui:// resources that the host renders in its inspector pane.

Quickstart

1. Install

git clone https://github.com/your-org/sharp-fhir-mcp.git
cd sharp-fhir-mcp
pip install -e .

2. Run the server

sharp-fhir-mcp                     # streamable-http on 0.0.0.0:8000
sharp-fhir-mcp --port 9000         # custom port
sharp-fhir-mcp --strict-context    # 403 on non-handshake without FHIR headers

The MCP endpoint is http://localhost:8000/mcp.

Note: localhost here refers to localhost of the machine where you arerunning the server. To access it remotely, deploy the server (see below) orport-forward to your local instance.

3. Connect from any SHARP-aware MCP client

Send these headers on every JSON-RPC request:

X-FHIR-Server-URL: https://hapi.fhir.org/baseR4
X-FHIR-Access-Token: <bearer token from your SMART launch>
X-Patient-ID: 12345          # optional

4. Try a public sandbox without writing a SMART app

The HAPI public FHIR R4 sandbox is read-only and does not require auth โ€”useful for kicking the tires:

curl -X POST http://localhost:8000/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -H 'X-FHIR-Server-URL: https://hapi.fhir.org/baseR4' \
  -H 'X-FHIR-Access-Token: anonymous' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Deployment

Vercel (Python serverless)

This server runs as a stateless Streamable-HTTP endpoint, which works onVercel out of the box. You can re-use an existingNext.js MCP scaffoldby either:

  1. Adding the Python ASGI handler โ€” drop the app Starlette instanceinto api/index.py:

    # api/index.py
    from sharp_fhir_mcp.server import app  # noqa: F401
    

    plus a minimal vercel.json:

    {
      "builds": [{"src": "api/index.py", "use": "@vercel/python"}],
      "routes": [{"src": "/(.*)", "dest": "api/index.py"}]
    }
    
  2. Or running it as a sidecar behind your existing Vercel front-end andreverse-proxying /mcp to a longer-lived host (Fly.io, Railway, Render).

The server respects the Vercel-injected PORT environment variable.

Local development

cp .env.example .env             # set FHIR_SERVER_URL etc. for fallbacks
sharp-fhir-mcp                   # http://localhost:8000/mcp

Docker (optional)

FROM python:3.12-slim
WORKDIR /app
COPY . .
RUN pip install -e .
EXPOSE 8000
CMD ["sharp-fhir-mcp", "--host", "0.0.0.0", "--port", "8000"]

Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  MCP Client / Agent / LLM host (Claude, Cursor, custom)     โ”‚
โ”‚  โ€ข Knows the patient's FHIR endpoint + access token         โ”‚
โ”‚  โ€ข Sends X-FHIR-Server-URL, X-FHIR-Access-Token headers     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                         โ”‚ Streamable HTTP (SHARP-on-MCP)
            POST /mcp + JSON-RPC + SHARP headers
                         โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  sharp-fhir-mcp                                             โ”‚
โ”‚                                                             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚ SharpContextMiddleware                                 โ”‚ โ”‚
โ”‚  โ”‚ โ€ข Parses X-FHIR-Server-URL / X-FHIR-Access-Token       โ”‚ โ”‚
โ”‚  โ”‚ โ€ข Stores in ContextVar for the request scope           โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚                            โ–ผ                                โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚ FastMCP tool registry                                  โ”‚ โ”‚
โ”‚  โ”‚ โ”œโ”€ fhir_*           (generic R4 search/read)           โ”‚ โ”‚
โ”‚  โ”‚ โ”œโ”€ clinical_*       (patient/encounter/medication/โ€ฆ)   โ”‚ โ”‚
โ”‚  โ”‚ โ”œโ”€ lab_* / imaging_*(observations, reports, docs)      โ”‚ โ”‚
โ”‚  โ”‚ โ”œโ”€ memory_*         (optional SimpleMem)               โ”‚ โ”‚
โ”‚  โ”‚ โ””โ”€ visualize_*      (MCP-UI Chart.js dashboards)       โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚                            โ–ผ                                โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚ Vendor-neutral FHIR R4 client (httpx, async)           โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                             โ–ผ
            FHIR R4 server (Epic / Cerner / HAPI / โ€ฆ)

See CLAUDE.md for detailed module-by-module notes and theSHARP compliance check-list.

SHARP compliance check-list

Requirement Status
Streamable-HTTP transport (stdio not in scope) โœ…
Read FHIR endpoint from X-FHIR-Server-URL header โœ…
Read bearer token from X-FHIR-Access-Token header โœ…
Optional X-Patient-ID header for default patient context โœ…
Advertise capabilities.experimental.fhir_context_required โœ…
No server-side OAuth / token storage โœ…
Vendor-neutral FHIR R4 client โœ…
Structured fhir_context_required errors when headers absent โœ…
Optional strict 403 enforcement (--strict-context) โœ…

License

MIT โ€” see LICENSE.

MCP Server ยท Populars

MCP Server ยท New

    luminarylane

    ๐ŸŽจ Fal.ai MCP Server

    MCP server for Fal.ai - Generate images, videos, music and audio with Claude

    Community luminarylane
    childrentime

    reactuse

    115+ production-ready React Hooks for sensors, UI, state & browser APIs. Tree-shakable, SSR-safe, TypeScript-first. Used by Shopee, PDD & Ctrip. Inspired by VueUse.

    Community childrentime
    agenticmail

    ๐ŸŽ€ AgenticMail

    Email & SMS infrastructure for AI agents โ€” send and receive real email and text messages programmatically

    Community agenticmail
    0xSteph

    pentest-ai

    Offensive-security MCP server with 197 wrapped tools, 17 specialist agents, and 14 SPA-aware probes that catch bugs scanners miss. CLI + MCP, BYO LLM.

    Community 0xSteph
    nostrband

    ServiceGraph Agent Skills

    AI Agent skills for a structured catalog of 100k+ US professional-services firms

    Community nostrband