smart-fhir
smart-fhir
A connector that will not invent a patient.
Install · Tools · How it works · Limits
Install
stdio only. After the TypeScript build, add a local connector:
name: smart-fhir
command: node
args: dist/index.jsnpm install
npm run buildEnv for that add (defaults, not secrets):
FHIR_ISS = https://launch.smarthealthit.org/v/r4/fhir
FHIR_VERSION = R4
FHIR_AUTH_MODE = open
FHIR_WRITE = off
FHIR_AUDIT_PATH = ./audit/audit.jsonlDo not put secret values in the repo. No public HTTP port. Do not bind TCP.
Vendor sandbox (Epic / Oracle Health) is backend_jwt plus a registered non-production client_id. See docs/SANDBOX-EMR.md.
Morning shortcut (same env)
npx -y tsx src/index.tsSee package.json scripts: install, build, test, prove, keygen.
Tools
Four tools. No create / update / delete.
Tool | Action |
| GET |
|
|
| GET |
| GET |
resourceType allowlist: Patient | Observation | Condition | MedicationRequest | Encounter. Anything else → { ok: false, error: "resourceType not in v1 allowlist" }.
How it works
FHIR_VERSION must be R4. Anything else refuses to start.
What | URL | How to read it |
FHIR index (published page is R5 5.0.0) | Official index only. Not implemented. | |
FHIR R4 (v1) | FHIR Release 4, 4.0.1. Resource model. | |
SMART App Launch 2.2.0 (STU 2.2) | Current published SMART IG. Based on FHIR R4. | |
App launch + authorization | Discovery, standalone/EHR launch, PKCE, token. App Launch (code+PKCE) is out of v1. | |
Backend Services | client_credentials + private-key JWT. |
ISS allowlist (trailing slash stripped, anything else refused):
https://launch.smarthealthit.org/v/r4/fhir(default)https://r4.smarthealthit.orghttps://hapi.fhir.org/baseR4https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4(Epic sandbox)https://fhir-open.cerner.com/r4/ec2458f2-1e24-41c8-b71b-0e701af7583d(Oracle open sandbox)https://fhir-ehr-code.cerner.com/r4/ec2458f2-1e24-41c8-b71b-0e701af7583d(Oracle secure sandbox)
Production EHR ISS is refused. A new ISS needs a review first.
FHIR_AUTH_MODE | Behavior |
| Discover, then FHIR GET without Authorization. Discovery 404 is not fatal in open (logged; continue). 401/403 FHIR → |
| Same discovery. FHIR GET with Authorization Bearer token. |
| Requires |
App Launch (code+PKCE) is out. FHIR_REDIRECT_URI is reserved and unused.
Auth failure shape: { ok: false, http_status, issue?, error? }. Never a synthetic Patient.
FHIR_WRITE defaults off. v1 has no write tools even if someone sets on. Writes never POST AuditEvent to FHIR.
Name | Default | Notes |
FHIR_ISS | default launcher R4 | Must stay allowlisted |
FHIR_VERSION | R4 | Reject anything else |
FHIR_AUTH_MODE | open | open / bearer / backend_jwt |
FHIR_WRITE | off | Writes stay off in v1 |
FHIR_AUDIT_PATH |
| Append-only JSONL |
FHIR_ACCESS_TOKEN | unset | Bearer only |
FHIR_CLIENT_ID | unset | Backend Services |
SMART_CLIENT_ID | unset | Alias of FHIR_CLIENT_ID |
FHIR_PRIVATE_KEY_PEM | unset | Backend Services JWT |
FHIR_JWT_KID | unset | Required in backend_jwt |
FHIR_JWKS_URL | unset | Optional |
FHIR_SCOPE | five system/*.rs types | JWT mode override |
FHIR_REDIRECT_URI | unset | Reserved for later App Launch |
Audit lines: ts, tool, iss, mode, resourceType, id?, http_status, entry_count?. No resource body, no token, no PEM, no name/MRN query values.
Limits
R5 / R4B as default. Extra resource types. CRUD. Bulk. App Launch browser/PKCE.
Real EHR / real PHI. Production deploy. Public bind or Streamable HTTP.
momentum / fhirhydrant / Atrium / Pinecone / Medplum.
Not a medical product. Does not diagnose, treat, or store PHI.
No PHI. No live EHR.