Skip to content

Connect eClinicalWorks to ChatGPT: Manage patient medical records

A complete engineering guide to generating a secure eClinicalWorks MCP server and connecting it to ChatGPT to automate FHIR R4 medical record workflows.

Uday Gajavalli Uday Gajavalli · · 10 min read

If you need to connect eClinicalWorks to ChatGPT to automate pre-visit chart summaries, analyze lab results, or audit medication requests, you need a Model Context Protocol (MCP) server. This server acts as the translation layer between ChatGPT's JSON-RPC tool calls and eClinicalWorks's complex FHIR R4 APIs. You can either build, host, and maintain this EHR infrastructure yourself, or use a managed integration platform like Truto to dynamically generate a secure, authenticated MCP server URL in seconds.

If your team uses Claude, check out our guide on connecting eClinicalWorks to Claude or explore our broader architectural overview on connecting eClinicalWorks to AI Agents.

Giving a Large Language Model (LLM) read and write access to a production Electronic Health Record (EHR) system is a massive engineering challenge. You have to handle deeply nested FHIR data payloads, map dynamic clinical concepts to MCP tool definitions, and ensure strict zero-data-retention access controls to maintain HIPAA compliance. Every time an API schema shifts, your custom server code must be updated, tested, and redeployed.

This guide breaks down exactly how to use Truto to generate a secure, managed MCP server for eClinicalWorks, connect it natively to ChatGPT, and execute complex medical record workflows using natural language.

The Engineering Reality of the eClinicalWorks API

A custom MCP server is essentially a self-hosted integration layer. While the open MCP standard provides a predictable way for models to discover tools, implementing it against eClinicalWorks's highly specific API is exceptionally painful for engineering teams.

If you decide to build a custom MCP server for eClinicalWorks, you own the entire API lifecycle. Here are the specific integration challenges that break standard CRUD assumptions when working with this EHR platform:

The FHIR R4 Schema Complexity

eClinicalWorks exposes its data via the HL7 FHIR (Fast Healthcare Interoperability Resources) R4 standard. While standardized, FHIR is notoriously verbose and highly relational. A simple "medication" isn't a flat object; it requires querying a MedicationRequest, which contains a medicationReference, which then points to a separate Medication resource. If you try to hand-code MCP tool schemas for these payloads, you will spend weeks just writing TypeScript types to prevent the LLM from hallucinating nested clinical structures.

Mandatory Search Constraints

Unlike typical SaaS APIs where you can simply hit GET /api/encounters to list everything, the eClinicalWorks API enforces strict contextual boundaries. To retrieve clinical data, you almost always must provide a specific patient identifier. Endpoints like list_all_e_clinical_works_conditions or list_all_e_clinical_works_diagnostic_reports will outright fail without this context. Your MCP tool definitions must explicitly enforce these required query parameters so ChatGPT knows it has to retrieve the Patient ID first before asking for their vitals.

Base64 C-CDA Binary Attachments

Clinical notes and Continuity of Care Documents (C-CDAs) in eClinicalWorks are not returned as clean markdown or text. They are returned as FHIR DocumentReference resources containing attachments, which point to Binary resources. Retrieving the actual clinical narrative requires the AI agent to fetch the DocumentReference, extract the Binary ID, fetch the Binary resource, and then decode the base64 payload. Without highly curated, descriptive MCP tools, an LLM will completely fail to navigate this multi-step extraction.

Generating the eClinicalWorks MCP Server

Truto completely abstracts away the underlying FHIR schema generation and OAuth token management. Every eClinicalWorks integration connected through Truto automatically derives a set of documentation-driven MCP tools mapped to the exact resources available on the account.

You can generate the MCP server endpoint for eClinicalWorks in two ways: via the Truto dashboard or programmatically via the API.

Method 1: Via the Truto UI

For internal AI agents or rapid prototyping, the UI is the fastest path.

  1. Navigate to the Integrated Accounts page in your Truto dashboard.
  2. Select your connected eClinicalWorks account.
  3. Click the MCP Servers tab.
  4. Click Create MCP Server.
  5. Select your desired configuration (e.g., restrict to read methods only, or filter by specific tags like clinical or demographics).
  6. Copy the generated MCP server URL (e.g., https://api.truto.one/mcp/a1b2c3d4...). Treat this URL as a sensitive credential.

Method 2: Via the Truto API

For production multi-tenant architectures, you should provision MCP servers dynamically when your users connect their eClinicalWorks accounts.

Make a POST request to the /integrated-account/:id/mcp endpoint to generate a secure, scoped server URL:

curl -X POST https://api.truto.one/integrated-account/<INTEGRATED_ACCOUNT_ID>/mcp \
  -H "Authorization: Bearer $TRUTO_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ChatGPT Clinical Assistant",
    "config": {
      "methods": ["read"],
      "tags": ["patient", "clinical", "diagnostics"]
    },
    "expires_at": "2026-12-31T23:59:59Z"
  }'

The response returns a highly secure, hashed endpoint URL:

{
  "id": "mcp_abc123",
  "name": "ChatGPT Clinical Assistant",
  "url": "https://api.truto.one/mcp/f8e9d0c1b2a3...",
  "config": {
    "methods": ["read"],
    "tags": ["patient", "clinical", "diagnostics"]
  }
}

A Critical Note on Rate Limits

When routing LLM tool calls through the MCP server, you must account for eClinicalWorks's upstream API limits. Truto does not retry, throttle, or apply backoff on rate limit errors.

When the eClinicalWorks API returns an HTTP 429 Too Many Requests, Truto passes that exact error straight back to the caller (your LLM client or agent framework). However, Truto does normalize the upstream rate limit information into standard IETF headers across all integrations:

  • ratelimit-limit
  • ratelimit-remaining
  • ratelimit-reset

The caller (or the agent orchestrator) is strictly responsible for inspecting these headers, implementing backoff logic, and retrying the tool call. Do not rely on the integration layer to absorb these errors.

Connecting the MCP Server to ChatGPT

Once you have the url from Truto, you need to expose it to your ChatGPT instance. You can do this natively in the ChatGPT interface or via a local proxy if you are running a custom agent framework.

Method A: Via the ChatGPT UI

OpenAI now supports connecting remote MCP servers directly in the ChatGPT client for specific account tiers (Pro, Plus, Business, Enterprise, and Education) with Developer Mode enabled.

  1. Open ChatGPT and navigate to Settings -> Apps -> Advanced settings.
  2. Enable the Developer mode toggle.
  3. Under MCP servers / Custom connectors, click Add.
  4. Enter a descriptive name (e.g., "eClinicalWorks EHR (Truto)").
  5. Paste the Truto MCP URL into the Server URL field.
  6. Save the configuration.

ChatGPT will immediately ping the /initialize endpoint, parse the available tools, and make them available in your chat sessions.

Method B: Via Manual Config File (SSE Proxy)

If you are using a desktop client that only supports local stdio MCP servers (like Cursor or older configurations of Claude Desktop), you can bridge the remote Truto server using the official Server-Sent Events (SSE) proxy.

Add the following configuration to your MCP settings JSON file:

{
  "mcpServers": {
    "eclinicalworks-truto": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-sse",
        "--url",
        "https://api.truto.one/mcp/f8e9d0c1b2a3..."
      ]
    }
  }
}

Restart your client. The proxy will tunnel the local JSON-RPC stdio commands over HTTP to Truto's secure endpoint.

Hero Tools for eClinicalWorks

Truto dynamically generates tools based on the eClinicalWorks FHIR resources. Here are the highest-leverage tools your AI agents can use to orchestrate clinical data workflows.

1. Get Single Patient by ID

Fetches the foundational FHIR R4 Patient resource. This is almost always the first tool ChatGPT must call, as the id returned here is required as a query parameter for fetching downstream clinical data.

Contextual usage: The model uses this to extract demographic info (name, telecom, gender) and obtain the exact patient ID needed for querying encounters or labs.

"Find the patient record for ID 'pt-8472' and tell me their active contact information."

2. List All Conditions

Searches the patient's active and historical problem list, encounter diagnoses, and health concerns.

Contextual usage: Requires the patient ID parameter. The AI uses this to build a summary of the patient's chronic conditions or acute issues prior to an upcoming visit.

"Fetch all active conditions for the patient we just looked up. Filter out anything marked as resolved or inactive in the clinicalStatus."

3. List All Medication Requests

Retrieves the FHIR R4 MedicationRequest resources, representing the patient's active prescriptions and historical medication orders.

Contextual usage: Requires the patient ID parameter. ChatGPT can use this to review medication adherence or prepare refill summaries. Note that the actual medication name often requires resolving the medicationReference if not provided inline.

"List all medication requests for this patient. Give me a clean table showing the medication intent, status, and priority."

4. List All Encounters

Retrieves the history of patient visits, admissions, or telehealth sessions.

Contextual usage: Requires the patient ID parameter. Essential for building timelines of care. The response includes status, class, and serviceType to help the AI differentiate between an ER visit and a routine checkup.

"Get the encounter history for this patient over the last six months. Summarize the dates and the service types provided."

5. List All Diagnostic Reports

Searches for lab results, imaging reports, and associated clinical notes for the patient.

Contextual usage: Requires the patient ID parameter. The AI uses this to pull the metadata for critical lab results before deciding if it needs to fetch the underlying binary document.

"Check the diagnostic reports for this patient. Are there any recent lipid panels or A1C results?"

6. Get Single Binary by ID

Fetches a base64 encoded C-CDA clinical document or raw attachment associated with a DocumentReference.

Contextual usage: Requires the id of the Binary resource. ChatGPT is highly capable of taking the base64 string, decoding it in its execution environment, and parsing the raw clinical text to summarize discharge notes or specialist consults.

"Fetch the Binary resource ID 'bin-9921' attached to that last diagnostic report. Decode the base64 content and summarize the radiologist's findings."

To view the full schema details, required parameters, and the complete inventory of available EHR tools, visit the eClinicalWorks integration page.

Workflows in Action

Once connected, ChatGPT can autonomously chain these tools together to execute complex clinical workflows. Here are two real-world scenarios.

Scenario 1: Pre-Visit Chart Summarization

Persona: Triage Nurse / Medical Assistant

"I have a patient coming in this afternoon. Their ID is 'pt-445'. Please build a pre-visit summary including their active conditions, recent encounters from the last 30 days, and any pending medication requests."

Execution Steps:

  1. get_single_e_clinical_works_patient_by_id: ChatGPT fetches the demographic baseline to confirm identity.
  2. list_all_e_clinical_works_conditions: It queries the active problem list, filtering for active clinical statuses.
  3. list_all_e_clinical_works_encounters: It fetches recent visits, looking for context on why the patient is returning.
  4. list_all_e_clinical_works_medication_requests: It pulls the current prescription list to prep the physician for medication reconciliation.

Result: The user receives a neatly formatted, Markdown-based clinical summary derived directly from real-time EHR data, ready to be reviewed before stepping into the exam room.

sequenceDiagram
    participant User as User (Nurse)
    participant GPT as ChatGPT
    participant MCP as Truto MCP Server
    participant Upstream as "Upstream API (eClinicalWorks)"

    User->>GPT: "Build a pre-visit summary for ID pt-445"
    GPT->>MCP: Call get_single_e_clinical_works_patient_by_id(id: "pt-445")
    MCP->>Upstream: GET /Patient/pt-445
    Upstream-->>MCP: FHIR R4 Patient Resource
    MCP-->>GPT: Patient Demographics
    GPT->>MCP: Call list_all_e_clinical_works_conditions(patient: "pt-445")
    MCP->>Upstream: GET /Condition?patient=pt-445
    Upstream-->>MCP: FHIR R4 Condition Bundle
    MCP-->>GPT: Active Conditions
    GPT->>MCP: Call list_all_e_clinical_works_medication_requests(patient: "pt-445")
    MCP->>Upstream: GET /MedicationRequest?patient=pt-445
    Upstream-->>MCP: FHIR R4 MedicationRequest Bundle
    MCP-->>GPT: Active Prescriptions
    GPT-->>User: Markdown Pre-Visit Summary

Scenario 2: Post-Encounter Lab Review

Persona: Primary Care Physician

"Look up the patient with ID 'pt-892'. Find their most recent diagnostic report. If it has an attachment, fetch the document and summarize the lab results."

Execution Steps:

  1. get_single_e_clinical_works_patient_by_id: Verifies the patient.
  2. list_all_e_clinical_works_diagnostic_reports: ChatGPT searches for recent labs and identifies a report with a presentedForm attachment pointing to a Binary ID.
  3. get_single_e_clinical_works_binary_by_id: ChatGPT requests the specific attachment.
  4. Internal Decoding: The model receives the base64 payload, processes the text, and extracts the core findings.

Result: The physician receives an immediate natural language breakdown of the lab results without having to click through five different nested menus in the eClinicalWorks UI.

Security and Access Control

Exposing EHR data to an LLM requires strict boundary enforcement. Truto's MCP servers are designed with security primitives that ensure ChatGPT only accesses exactly what you authorize.

  • Zero Data Retention: Truto acts purely as a pass-through proxy. It routes the JSON-RPC tool calls, normalizes the FHIR payload, and returns the response to ChatGPT. Truto never caches or stores the underlying PHI.
  • Method Filtering: When creating the MCP server, you can restrict the config.methods to ["read"]. This guarantees the server will never generate create, update, or delete tools, preventing the AI from accidentally altering clinical records.
  • Tag Filtering: You can aggressively scope the available toolset by providing config.tags (e.g., ["demographics"]). Tools belonging to untagged resources (like medication_requests or binary) simply won't exist on that server URL.
  • Time-To-Live (TTL): By passing an expires_at ISO datetime during server creation, you can generate ephemeral access. Once the timestamp passes, the endpoint is cryptographically destroyed, instantly revoking ChatGPT's access.
  • Required API Token Auth: By enabling require_api_token_auth: true, possession of the MCP URL is no longer sufficient. The ChatGPT client must also pass a valid Truto API token in the Authorization header, providing a secondary layer of enterprise authentication.

Final Thoughts

Connecting an AI agent to an EHR like eClinicalWorks used to require months of wrangling OAuth flows, studying FHIR specifications, and building custom integration microservices.

By leveraging the open Model Context Protocol and Truto's dynamic, documentation-driven tool generation, you can completely sidestep that infrastructure burden. You get a secure, FHIR-compliant bridge between ChatGPT and eClinicalWorks in minutes, allowing your engineering team to focus on building agentic clinical workflows rather than maintaining point-to-point API connectors.

FAQ

How does Truto handle eClinicalWorks API rate limits?
Truto does not retry or apply backoff on rate limit errors. It passes the HTTP 429 error directly to the caller and normalizes the upstream rate limit data into standard IETF headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset). The caller is responsible for implementing retry logic.
Does Truto store eClinicalWorks patient data?
No. Truto operates on a zero-data-retention architecture. It acts purely as a pass-through proxy for the MCP tool calls, parsing the request and normalizing the response without ever caching or storing the underlying PHI in its databases.
How do I prevent ChatGPT from modifying clinical records?
When generating the MCP server URL, you can configure method filtering by setting config.methods to ["read"]. This ensures the server only exposes read-only tools, mathematically preventing the LLM from executing create, update, or delete operations.
How does the MCP server handle eClinicalWorks C-CDA attachments?
eClinicalWorks exposes clinical notes and C-CDAs as Binary resources encoded in base64. Truto provides the get_single_e_clinical_works_binary_by_id tool, allowing ChatGPT to fetch the payload and decode the base64 content natively within its environment.

More from our Blog