Skip to content

Connect eClinicalWorks to Claude: Analyze clinical notes and labs

Learn how to build a managed MCP server to connect eClinicalWorks to Claude. Automate clinical note analysis, FHIR R4 queries, and lab summaries.

Uday Gajavalli Uday Gajavalli · · 9 min read

If you need to connect eClinicalWorks to Claude to automate patient chart summarization, audit diagnostic lab reports, or extract actionable insights from clinical notes, you need a Model Context Protocol (MCP) server. This server acts as the translation layer between Claude's function calling capabilities and the eClinicalWorks FHIR R4 API. You can either build and maintain this infrastructure yourself, or use a managed integration platform like Truto to dynamically generate a secure, authenticated MCP server URL. If your team uses ChatGPT, check out our guide on connecting eClinicalWorks to ChatGPT or explore our broader architectural overview on connecting eClinicalWorks to AI Agents.

Giving a Large Language Model (LLM) read and write access to an Electronic Health Record (EHR) system like eClinicalWorks is an engineering challenge with high stakes. You must handle complex OAuth scopes, map deeply nested FHIR R4 JSON schemas to MCP tool definitions, and deal with strict security perimeters. Every time an endpoint behavior shifts, you have to update your server code, redeploy, and rigorously test the integration to ensure clinical data integrity.

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

The Engineering Reality of the eClinicalWorks API

A custom MCP server is a self-hosted integration layer. While the open MCP standard provides a predictable way for models to discover tools (via the tools/list JSON-RPC method), the reality of implementing it against eClinicalWorks is painful. You are dealing with the Fast Healthcare Interoperability Resources (FHIR) R4 standard, which is inherently complex and deeply relational.

If you decide to build a custom MCP server for eClinicalWorks, here are the specific integration challenges you will face:

Deeply Nested Resource Resolution Unlike standard B2B APIs where a GET /patient/123 might return a flat object with their recent lab results, FHIR APIs rely heavily on references. If Claude wants to read a patient's clinical note, it cannot just call a single endpoint. It must first query DocumentReference to find the metadata, extract the attachment.url or binary reference, and then query the Binary resource to retrieve the actual Base64-encoded C-CDA (Consolidated Clinical Document Architecture) file. A custom MCP server must either build macro-tools to wrap these requests, or present the raw FHIR tools and rely on the LLM to understand this exact chaining sequence.

Polymorphic Query Parameters eClinicalWorks search endpoints support complex query parameters that change meaning based on modifiers (e.g., date=gt2023-01-01, category=vital-signs). Mapping these dynamic search capabilities into strict JSON Schema for an LLM tool definition requires extensive manual configuration. If the schema is too loose, the LLM will hallucinate invalid FHIR queries resulting in HTTP 400 errors. If it is too strict, you lose the search flexibility of the EHR.

Rate Limits and Data Governance EHR APIs are strictly monitored. Hitting rate limits is common when bulk-exporting patient history. Your integration architecture must respect these limits. Furthermore, you must ensure your MCP server operates with zero data retention - caching FHIR bundles locally to speed up LLM prompts introduces massive HIPAA compliance risks.

Creating the Managed MCP Server

Truto solves these problems by dynamically generating MCP tools based on your eClinicalWorks integration configuration and documentation records. When an MCP client connects, Truto reads the available resources, derives the query and body JSON Schemas, and builds the tool definitions on the fly. This ensures the tools perfectly match the connected environment.

You can generate the MCP server URL through the Truto UI or programmatically via the API.

Method 1: Via the Truto UI

For ad-hoc agent building or testing, the UI is the fastest path.

  1. Navigate to the Integrated Accounts page in your Truto dashboard and select your active eClinicalWorks connection.
  2. Click the MCP Servers tab.
  3. Click Create MCP Server.
  4. Configure your server: provide a name, select allowed methods (e.g., restricting the AI to read operations only), and optionally set an expiration date.
  5. Click Save. Copy the generated MCP server URL (e.g., https://api.truto.one/mcp/a1b2c3...).

Method 2: Via the Truto API

For production workflows - such as provisioning a unique MCP server for every physician using your app - you should use the API. This endpoint validates the configuration, generates a secure cryptographic token backed by edge KV storage, and returns the URL.

// POST https://api.truto.one/integrated-account/{integrated_account_id}/mcp
 
const response = await fetch(
  'https://api.truto.one/integrated-account/ecw_acc_01HQ.../mcp',
  {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_TRUTO_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      name: "Dr. Smith - Read Only Access",
      config: {
        methods: ["read"] // Enforce read-only access at the server level
      },
      expires_at: "2024-12-31T23:59:59Z"
    })
  }
)
 
const mcpServer = await response.json();
console.log(mcpServer.url);
// Output: https://api.truto.one/mcp/f8e9d0c1b2a3...

This URL is fully self-contained. It encodes the tenant mapping and handles the underlying eClinicalWorks OAuth token lifecycle automatically.

Connecting the MCP Server to Claude

Once you have the URL, connecting it to Claude requires zero additional code. You can configure it via the user interface or by modifying the local configuration file.

Method A: Via the Claude UI (or ChatGPT)

If you are using the web interfaces that support custom remote connectors (like ChatGPT's developer mode or Claude for Enterprise):

  1. Go to Settings -> Integrations (or Connectors).
  2. Click Add MCP Server.
  3. Paste the Truto MCP Server URL.
  4. Click Add. Claude will instantly perform a JSON-RPC initialize handshake and load the eClinicalWorks tools.

Method B: Via Manual Config File (Claude Desktop)

For Claude Desktop, you connect to remote SSE (Server-Sent Events) MCP servers using a standardized utility block in your claude_desktop_config.json file.

Open your configuration file (located at ~/Library/Application Support/Claude/claude_desktop_config.json on macOS or %APPDATA%\Claude\claude_desktop_config.json on Windows) and add the server:

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

Restart Claude Desktop. You will now see the eClinicalWorks tools available via the hammer icon in your input bar.

eClinicalWorks Hero Tools for Claude

Truto provides a comprehensive mapping of the eClinicalWorks FHIR R4 API. When Claude calls tools/list, Truto translates its internal documentation schemas into MCP-compliant JSON Schema.

Here are the highest-leverage tools available for clinical analysis workflows:

1. list_all_e_clinical_works_patients

Searches for patients within the eClinicalWorks practice. This is almost always the starting point for any chart review. It returns matching FHIR R4 Patient resources including identifiers, demographics, and contact info.

Contextual note: Because FHIR heavily relies on IDs, you must prompt Claude to first search for the patient by name or DOB to retrieve the id, which is required for all subsequent queries.

"Search eClinicalWorks for a patient named John Doe and give me his internal patient ID."

2. get_single_e_clinical_works_encounter_by_id

Retrieves a specific FHIR R4 Encounter resource by its ID. This provides context on a specific visit, including the class (ambulatory, inpatient), the participating practitioners, and the period of the encounter.

Contextual note: Use this to understand the metadata of a specific visit before attempting to pull associated notes or diagnoses.

"Get the details for encounter ID 84752. Who was the attending physician and what was the service type?"

3. list_all_e_clinical_works_diagnostic_reports

Searches DiagnosticReports for a specific patient. This endpoint returns the metadata for lab results, imaging reports, and general clinical notes.

Contextual note: The DiagnosticReport resource usually does not contain the raw text of the lab results. It contains presentedForm attachments that point to Binary resources. Claude must read this list to find the specific report it wants to analyze.

"List all diagnostic reports for patient ID 123 from the last 6 months. Filter for lab results if possible."

4. get_single_e_clinical_works_binary_by_id

Retrieves a single Binary resource from eClinicalWorks. This is arguably the most critical tool for deep clinical analysis, as it carries the actual C-CDA clinical documents or raw text as base64 content.

Contextual note: The id for this tool comes from the attachment reference found inside a DocumentReference or DiagnosticReport. Instruct the LLM to decode the base64 content once retrieved.

"Fetch the binary document with ID 99281. Decode the base64 content and summarize the primary lab findings."

5. list_all_e_clinical_works_medication_requests

Searches MedicationRequests (active or historical orders) for a patient. Returns FHIR R4 MedicationRequest resources outlining the intent, status, and dosage instructions.

Contextual note: Essential for medication reconciliation workflows. The LLM can use this to cross-reference active prescriptions against newly proposed treatments.

"Get all active medication requests for patient ID 123. Are they currently prescribed any beta blockers?"

6. list_all_e_clinical_works_document_references

Searches DocumentReferences for a patient. This includes clinical notes, care plans, and transition of care documents.

Contextual note: Similar to DiagnosticReports, this endpoint provides the index. Claude will use this tool to find the ID of a specific clinical note, and then use the binary tool to read it.

"Search the document references for patient ID 123 to find their most recent progress note."

For the complete tool inventory and detailed FHIR schema mappings, visit the Truto eClinicalWorks integration page.

Workflows in Action

Exposing raw FHIR endpoints to Claude is powerful because the LLM can dynamically orchestrate multi-step data gathering. Here is how specific personas can leverage these tools in the real world.

Scenario 1: Pre-Encounter Chart Summarization (Physician Assistant)

A Physician Assistant needs a quick summary of a complex patient before walking into the exam room.

"Find the patient named Sarah Jenkins. Summarize her last two encounters, list her active medications, and flag any recent abnormal lab results."

How the agent executes this:

  1. Calls list_all_e_clinical_works_patients(name="Sarah Jenkins") to acquire the patient ID (e.g., pt-555).
  2. Calls list_all_e_clinical_works_encounters(patient="pt-555") and identifies the IDs of the two most recent visits.
  3. Calls list_all_e_clinical_works_medication_requests(patient="pt-555", status="active") to pull the current medication list.
  4. Calls list_all_e_clinical_works_diagnostic_reports(patient="pt-555") to find recent lab reports.
  5. Calls get_single_e_clinical_works_binary_by_id for the specific lab report to read the actual results.
sequenceDiagram
  participant PA as Physician Assistant
  participant Claude as Claude
  participant Truto as Truto MCP
  participant eCW as eClinicalWorks API

  PA->>Claude: Summarize chart for Sarah Jenkins
  Claude->>Truto: list_all_e_clinical_works_patients<br>(name: "Sarah Jenkins")
  Truto->>eCW: GET /Patient?name=Sarah%20Jenkins
  eCW-->>Truto: Return Patient bundle
  Truto-->>Claude: JSON response (ID: pt-555)
  
  Claude->>Truto: list_all_e_clinical_works_medication_requests<br>(patient: "pt-555")
  Truto->>eCW: GET /MedicationRequest?subject=pt-555
  eCW-->>Truto: Return MedicationRequest bundle
  Truto-->>Claude: JSON response
  
  Claude-->>PA: Delivers synthesized pre-encounter brief

The PA receives a highly structured, natural language brief aggregating data from three separate FHIR resources, saving them 10 minutes of manual clicking in the EHR.

Scenario 2: Lab Result Auditing (Care Coordinator)

A Care Coordinator needs to ensure a patient's recent lipid panel was reviewed and actionable notes were attached.

"Find the most recent lipid panel diagnostic report for patient ID pt-882. Fetch the actual report document and tell me what the LDL levels were."

How the agent executes this:

  1. Calls list_all_e_clinical_works_diagnostic_reports(patient="pt-882") and scans the returned JSON for the lipid panel.
  2. Extracts the attachment.url or binary reference ID from the report.
  3. Calls get_single_e_clinical_works_binary_by_id(id="binary-921") to pull the C-CDA or text payload.
  4. Analyzes the decoded content to extract the LDL values and reports back to the coordinator.

Handling eClinicalWorks Rate Limits

When exposing APIs to autonomous agents, rate limiting is a major concern. LLMs can execute loops incredibly fast, quickly exhausting EHR API quotas.

It is critical to understand that Truto does not retry, throttle, or apply backoff on rate limit errors. If the eClinicalWorks API returns an HTTP 429 Too Many Requests, Truto passes that error directly to the caller (Claude).

To help your system handle this gracefully, Truto normalizes the upstream rate limit information into standardized HTTP headers per the IETF specification:

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

The caller (your application or the LLM framework) is entirely responsible for reading these headers and implementing the necessary sleep or backoff logic before retrying the tool call.

Security and Access Control

Healthcare integrations require strict governance. Handing an LLM unrestricted access to eClinicalWorks is dangerous. Truto MCP servers include built-in controls to limit the blast radius:

  • Method Filtering: Enforce read-only configurations. Setting config.methods: ["read"] ensures the server will drop any create, update, or delete tools at the generation stage. The LLM simply won't know those tools exist.
  • Tag Filtering: Restrict tools by functional domain. You can filter the MCP server to only expose tools tagged with labs or patient-demographics.
  • Additional Authentication (require_api_token_auth): By default, possessing the MCP URL grants access. For higher security, enabling this flag forces the client to also pass a valid Truto API token in the Authorization header, adding a secondary identity check.
  • Time-to-Live (expires_at): Truto uses edge-based distributed alarms to enforce strict expirations. Setting an expires_at datetime ensures the underlying cryptographic token is permanently destroyed from KV storage exactly when time runs out, instantly revoking the AI's access.

Architecting a resilient, FHIR-compliant AI agent requires separating the integration complexity from your core business logic. By utilizing a managed MCP server, you eliminate the need to write and maintain complex OAuth state machines, pagination loops, and schema mappers, allowing your engineering team to focus entirely on building better clinical AI workflows.

FAQ

How do I connect eClinicalWorks to Claude?
You can connect eClinicalWorks to Claude by generating a Model Context Protocol (MCP) server URL using a managed platform like Truto, and adding that URL to Claude's integration settings or desktop configuration file.
Does Truto store eClinicalWorks patient data when Claude calls a tool?
No. Truto operates on a zero data retention (pass-through) architecture. Tool calls are proxied directly to the eClinicalWorks API, and the response is returned to Claude without caching the underlying clinical data.
How does Truto handle eClinicalWorks API rate limits?
Truto passes upstream HTTP 429 rate limit errors directly back to the caller. It normalizes the rate limit information into standard headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) per the IETF specification. The caller (or the LLM framework) is responsible for implementing retry and backoff logic.
Can I restrict which eClinicalWorks operations Claude can perform?
Yes. When generating the MCP server in Truto, you can apply method filters (e.g., read-only) or tag filters to restrict the AI to specific tools, preventing unauthorized write operations.

More from our Blog