How tenant isolation, access control, audit trails, and human-in-the-loop work together when AI agents access clinical data through FHIR R6 + MCP
Watch an AI agent attempt to write clinical data through 6 security guardrails in 60 seconds. Each step demonstrates a real pattern: PHI redaction, $validate, Permission $evaluate (deny then permit), HMAC step-up auth, human-in-the-loop, and immutable audit trail.
Create a sample patient, read it back with PHI redaction, and search. Identifiers are masked, addresses stripped, telecom redacted.
—
Select a tool, provide input, and execute. Read tools require no step-up; write tools require HMAC authorization. All emit AuditEvents.
Ingest a patient-centric Bundle to build a bounded context envelope (TTL 30 min). The envelope provides a policy-stamped, time-limited view for agent context windows.
—
Side-by-side comparison: standard redacted read vs. full Safe Harbor de-identification (45 CFR 164.514(b)). Names, IDs, addresses, dates generalized to year.
Clinical writes (Observation, Condition, etc.) require X-Human-Confirmed: true header. Without it, the server returns HTTP 428 Precondition Required. This prevents autonomous agent writes to clinical data without human review.
Full OAuth 2.1 flow: Dynamic client registration (RFC 7591), Authorization with PKCE S256, Token exchange, and Revocation (RFC 7009). SMART-on-FHIR v2 compatible.
Resources new or restructured in R6 (v6.0.0-ballot3): Permission (access control, separate from Consent),
SubscriptionTopic (restructured pub/sub), NutritionIntake, DeviceAlert.
Operations $stats and $lastn are standard FHIR operations (available since R4) demonstrated here with stored data.
Scope: This is a reference implementation for exploring R6 ballot resources and MCP guardrail patterns — not a production FHIR server. Validation is structural only (required fields + value constraints). Search supports code, status, patient, and _lastUpdated parameters.
R6 separates Permission (machine-readable access rules) from Consent (patient agreements).
Permission encodes attribute-based access control with deny-overrides/permit-overrides combining.
Create a Permission, then evaluate access decisions via $evaluate.
Standard FHIR operations (available since R4): $stats computes min/max/mean/count over stored numeric Observation values,
$lastn returns the most recent observations per code. Both support patient + code filtering.
Implementation limited to valueQuantity (numeric observations only).
R6 restructures Subscription around SubscriptionTopic (introduced in R5, maturing in R6). Topics define triggerable events. This demo stores topics and subscriptions but does not dispatch notifications — it demonstrates the resource model and discovery pattern only.
NutritionIntake: Records food/liquid/supplement consumption (hospitals, meal tracking, school districts). DeviceAlert: Medical device alert/alarm conditions aligned with ISO/IEEE 11073 and IEC 60601-1-8.
Patient-owned data quality evaluation. Creates a Condition with a retired ICD-9-CM code, evaluates it against live terminology APIs (NLM ICD-10-CM, tx.fhir.org), presents issues in plain language, then applies patient-approved fixes with a linked Provenance record.
Flow: Create ICD-9 Condition → $curatr-evaluate (live terminology check) → Review issues →
$curatr-apply-fix (update + Provenance). No black-box corrections — patient decides.
Validate a FHIR R6 resource against structural rules. Agent proposals must pass validation before commit.