Connect Epic to ChatGPT: Manage Patient Records and History
Learn how to connect Epic to ChatGPT using a managed MCP server. This guide covers FHIR API quirks, dynamic tool generation, and building clinical AI workflows.
If you are building healthcare AI applications and need to connect Epic to ChatGPT to query patient histories, analyze lab results, or automate clinical note generation, you need a Model Context Protocol (MCP) server. This server acts as the translation layer between ChatGPT's function-calling engine and Epic's strict FHIR R4 interfaces. You can either spend months building, hosting, and passing security audits for this infrastructure, or you can use a managed integration platform like Truto to dynamically generate a secure, authenticated MCP server URL.
If your team uses Claude, check out our guide on connecting Epic to Claude or explore our broader architectural overview on connecting Epic to AI Agents.
Giving a Large Language Model (LLM) read and write access to an enterprise Electronic Health Record (EHR) system is a massive engineering liability. You have to handle complex FHIR data payloads, manage SMART on FHIR OAuth token lifecycles, map clinical endpoints to JSON-RPC tool definitions, and ensure you aren't storing Protected Health Information (PHI) in intermediary databases. Every time an API specification changes or you need to expose a new resource, custom server code must be updated, redeployed, and tested.
This guide breaks down exactly how to use Truto to generate a secure, managed MCP server for Epic, connect it natively to ChatGPT, and execute complex clinical workflows using natural language.
The Engineering Reality of the Epic FHIR API
Building a custom MCP server is essentially building a self-hosted integration layer. While the MCP standard provides a predictable way for models to discover tools, implementing it against Epic's strict interpretation of the Fast Healthcare Interoperability Resources (FHIR) standard is uniquely painful.
If you decide to build a custom MCP server for Epic, you own the entire API lifecycle. Here are the specific integration challenges you will face:
Strict Patient-Centric Search Constraints
Epic does not allow broad, unconstrained queries across its database. Unlike a CRM where you might query GET /contacts?limit=100, almost all clinical searches in Epic require a patient or subject parameter. If an LLM attempts to fetch a list of Condition or Observation resources without explicitly associating it with a specific patient FHIR ID, Epic will reject the request. Your MCP schema must enforce these strict dependencies so the LLM knows to retrieve a patient ID first before attempting secondary lookups.
The FHIR Bundle Pagination Scheme
Epic returns lists of resources wrapped in a FHIR Bundle. The actual data is nested inside entry [].resource. Pagination is not handled via standard page and offset query parameters, but by following a next link provided within the Bundle itself. If you pass raw Epic responses to an LLM, the model will waste context window tokens trying to parse the metadata wrapper instead of focusing on the clinical data. Your tools must explicitly instruct the LLM on how to extract data from the Bundle and pass cursor values unchanged.
Async Polling for Bulk Data Exports
For population health workflows or large data retrieval, Epic utilizes the FHIR Bulk Data Access standard. This is not a simple REST call. A client must initiate an export (Group/$export), receive a 202 Accepted response with a Content-Location header, periodically poll that URL for status (checking for X-Progress headers), and eventually retrieve a list of URLs pointing to newline-delimited JSON (NDJSON) files. Teaching an LLM to navigate this multi-step, asynchronous state machine via individual API tool calls requires highly specialized, state-aware tooling.
Step 1: Create the Epic MCP Server
Truto abstracts away the OAuth lifecycle and FHIR schema mapping. Once you connect an Epic account to Truto, you can generate an MCP server that exposes the EHR's resources as AI tools.
You can create this server in two ways: via the Truto dashboard or programmatically via the API.
Method A: Via the Truto UI
- Navigate to the Integrated Accounts page in your Truto dashboard.
- Click on your active Epic connection.
- Open the MCP Servers tab.
- Click Create MCP Server.
- Configure the server. You can name it "Epic Clinical AI" and apply filters (e.g., restrict to
readmethods only, or tag filter forpatients,observations, andconditions). - Click Generate and copy the resulting MCP server URL (e.g.,
https://api.truto.one/mcp/abc123def456).
Method B: Via the Truto API
For developers building AI products, you can provision MCP servers programmatically on behalf of your users. Make a POST request to the /integrated-account/:id/mcp endpoint using the Epic account's integrated_account_id.
curl -X POST https://api.truto.one/integrated-account/<epic_account_id>/mcp \
-H "Authorization: Bearer $TRUTO_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Epic ChatGPT Integration",
"config": {
"methods": ["read", "list", "get"],
"tags": ["clinical", "demographics"]
},
"expires_at": "2025-12-31T23:59:59Z"
}'The API will return a JSON object containing the secure URL. This URL contains a cryptographically hashed token that routes requests to the correct Epic instance.
Step 2: Connect the MCP Server to ChatGPT
With the Truto MCP URL in hand, you can bind the Epic tools to ChatGPT. This can be done directly in the ChatGPT interface or via a local configuration file for programmatic usage.
Method A: Via the ChatGPT UI
- Open ChatGPT and navigate to Settings -> Apps -> Advanced settings.
- Enable Developer mode (MCP support requires this feature flag, available on Pro, Plus, Business, Enterprise, and Education tiers).
- Under MCP servers / Custom connectors, click Add new server.
- Enter a name (e.g., "Epic Systems").
- Paste the Truto MCP URL into the Server URL field.
- Click Save. ChatGPT will perform a protocol handshake and immediately list the available Epic clinical tools.
Method B: Via Local Configuration File
If you are running a custom MCP host or leveraging a desktop AI environment, you can configure the connection via a JSON config file using standard SSE (Server-Sent Events) transport.
{
"mcpServers": {
"epic-clinical": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-sse",
"--url",
"https://api.truto.one/mcp/<your_truto_token>"
]
}
}
}Security and Access Control
Exposing an EHR to a generative AI model requires strict governance. Truto MCP servers enforce boundaries at the infrastructure level, so you never have to trust the LLM to "behave."
- Method Filtering: Set
config.methods: ["read"]to strictly block the LLM from executingcreate,update, ordeleteoperations, completely neutralizing the risk of hallucinated chart updates. - Tag Filtering: Group specific endpoints (e.g.,
billing,clinical,scheduling) in Truto. Passconfig.tags: ["clinical"]to hide administrative endpoints from the AI agent. - Expiration (TTL): Use the
expires_atfield to create ephemeral servers. Ideal for contractor access or temporary auditing workflows; the server self-destructs at the specified time. - Extra Authentication: By default, the URL token authenticates the request. Enable
require_api_token_auth: trueto force the client to also pass a valid Truto API Bearer token in the header, adding a secondary defense layer against leaked URLs.
Handling Epic Rate Limits
Epic environments strictly throttle API requests to maintain system stability. Truto does not retry, throttle, or apply backoff on rate limit errors. When Epic returns an HTTP 429 (Too Many Requests), Truto passes that exact error back to the caller. Truto normalizes the upstream rate limit information into standardized headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) per the IETF specification. Your ChatGPT agent or underlying client framework is entirely responsible for interpreting these headers and executing backoff logic.
Epic Hero Tools for ChatGPT
Truto automatically generates JSON-RPC tool definitions based on Epic's FHIR specifications. Here are the highest-leverage tools available for your AI agents.
1. get_single_epic_patient_by_id
Retrieves the core demographic and administrative profile for a patient using their FHIR R4 ID. This is the prerequisite step for almost all other clinical queries.
"Fetch the patient profile for FHIR ID 'er2495-241'. Extract their primary communication language and active contact addresses."
2. list_all_epic_conditions
Searches the patient's active and historical problem list. This requires the patient ID and can be filtered by category (e.g., encounter diagnoses vs. chronic health concerns).
"List all active Conditions for patient 'er2495-241'. Filter the results to only show items categorized as 'problem-list-item'."
3. list_all_epic_observations
Queries clinical measurements including vitals, lab results, and social history. Epic requires both the patient ID and a specific category or code to execute this search.
"Retrieve the most recent laboratory observations for patient 'er2495-241'. Look specifically for HbA1c codes and return the values and issued dates."
4. list_all_epic_medication_requests
Fetches active, completed, or discontinued prescriptions. Essential for medication reconciliation workflows.
"Get all active medication requests for patient 'er2495-241'. Summarize the prescribed drugs, dosages, and the authorizing practitioner."
5. list_all_epic_appointments
Searches the scheduling system for a patient's past or future visits. Useful for preparing pre-encounter briefings.
"Find the next scheduled appointment for patient 'er2495-241'. Identify the appointment type, the scheduled date, and the participating care team."
6. create_a_epic_document_reference
Writes a clinical note or CDA document back to the patient's chart. Requires a strict FHIR DocumentReference JSON body.
"Create a new DocumentReference for patient 'er2495-241'. Categorize it as a 'clinical-note' and include the following summarized text as the base64 encoded payload..."
7. get_single_epic_bulk_export_by_id
Checks the asynchronous status of a population-level data export. The tool returns the progress or the final output file URLs once the Epic batch job completes.
"Check the status of bulk export request ID 'req-9942'. If it is complete, list the URLs for the resulting NDJSON files."
For the complete inventory of Epic endpoints, supported FHIR parameters, and schema details, view the Epic integration page.
Workflows in Action
When connected to ChatGPT via Truto, these tools can be chained together to execute complex, multi-step operations.
1. Pre-Encounter Clinical Briefing
Doctors spend significant time reviewing charts before seeing a patient. ChatGPT can autonomously gather and summarize this data.
"Generate a pre-encounter briefing for patient ID 'er2495-241'. Get their demographic details, list their active problems, and retrieve any medication requests issued in the last 6 months. Summarize everything into a concise bulleted list."
Execution flow:
- Agent calls
get_single_epic_patient_by_idwithid: "er2495-241"to confirm identity and demographics. - Agent calls
list_all_epic_conditionswithpatient: "er2495-241"and filters for active clinical statuses. - Agent calls
list_all_epic_medication_requestswithpatient: "er2495-241". - The LLM parses the nested FHIR Bundles and synthesizes a human-readable summary.
sequenceDiagram
participant User as Doctor (ChatGPT)
participant Truto as Truto MCP Server
participant Epic as Epic API
User->>Truto: call get_single_epic_patient_by_id(id)
Truto->>Epic: GET /Patient/er2495-241
Epic-->>Truto: FHIR Patient Resource
Truto-->>User: tool result
User->>Truto: call list_all_epic_conditions(patient)
Truto->>Epic: GET /Condition?patient=er2495-241
Epic-->>Truto: FHIR Bundle (Conditions)
Truto-->>User: tool result
User->>Truto: call list_all_epic_medication_requests(patient)
Truto->>Epic: GET /MedicationRequest?patient=er2495-241
Epic-->>Truto: FHIR Bundle (Meds)
Truto-->>User: tool result2. Clinical Note Generation
After a telehealth session, a practitioner can instruct ChatGPT to parse the transcript and push a formal note into the EHR.
"Based on our consultation transcript, draft a SOAP note. Once drafted, create a DocumentReference in Epic for patient 'er2495-241' and attach the note."
Execution flow:
- The LLM analyzes the session context to generate the Subjective, Objective, Assessment, and Plan (SOAP) text.
- Agent calls
create_a_epic_document_referenceprovidingresourceType: "DocumentReference", the patient ID, and the base64 encoded text. - Epic returns a
201 Createdstatus with the new resource ID, which ChatGPT reports to the user.
3. Population Health Export Monitoring
Operations teams often need to monitor long-running bulk data extracts without manually checking server logs.
"Check the status of our overnight bulk export for group 'diabetic-cohort-A'. If it's done, give me the download links."
Execution flow:
- Agent calls
get_single_epic_bulk_export_by_idpassing the bulk request ID. - If Epic returns an
X-Progressstate, the agent informs the user the job is still running. - If Epic returns a completed state, the agent extracts the
outputarray from the response and presents the NDJSON file URLs to the user.
Stop Hardcoding Healthcare Integrations
Connecting an AI agent to an EHR like Epic is not a standard API integration. The strict nature of FHIR R4, complex patient-centric search constraints, and the constant overhead of OAuth token management make custom MCP servers a massive technical liability.
Truto abstracts this entire layer. By deriving MCP tools directly from standardized documentation and managing the authentication lifecycle securely in the background, Truto lets your engineering team focus on building intelligent clinical reasoning, not maintaining boilerplate infrastructure.
Stop wrangling FHIR Bundles manually. Let Truto handle the EHR plumbing so your AI agents can get to work.
FAQ
- How does ChatGPT authenticate with Epic?
- ChatGPT authenticates with the Truto MCP Server via a secure, scoped URL token (or an optional Bearer token). Truto handles the underlying SMART on FHIR OAuth 2.0 lifecycle and token refreshes with Epic, passing standardized requests to the upstream EHR.
- Can I restrict ChatGPT to read-only access for Epic patient records?
- Yes. When generating the MCP server URL in Truto, you can configure method filters to only allow 'read' operations (like 'get' and 'list'), completely blocking the LLM from executing 'create', 'update', or 'delete' actions.
- How are Epic's API rate limits handled in this integration?
- Truto does not retry, throttle, or absorb rate limits. If Epic returns an HTTP 429 error, Truto passes it directly to ChatGPT along with standardized IETF rate limit headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset). Your client agent is responsible for executing backoff and retry logic.
- Does Truto store PHI when ChatGPT queries Epic?
- No. Truto operates as a stateless proxy for MCP tool execution. Truto translates the JSON-RPC request to the REST/FHIR equivalent, forwards it to Epic, and passes the payload back to ChatGPT. No customer data or PHI is stored at rest.