MCP server for MyAtriumHealth (Atrium Health's Epic MyChart patient portal) — reads test results, medications, allergies, immunizations and visits by routing requests through the user's signed-in browser tab via the fetchproxy bridge, reusing their authenticated session.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Documented (README)
git clone https://github.com/chrischall/myatriumhealth-mcp{
"mcpServers": {
"myatriumhealth-mcp": {
"command": "node",
"args": ["/path/to/myatriumhealth-mcp/dist/index.js"]
}
}
}MCP Servers overview
# myatriumhealth-mcp
MCP server for **MyAtriumHealth** — Atrium Health's [Epic MyChart](https://www.mychart.com/)
patient portal at `my.atriumhealth.org`. Reads test results, medications, allergies,
immunizations, health issues, goals and visits.
> This project was developed and is maintained by AI. Use at your own discretion.
> It reads personal health information, and only ever from the signed-in user's own account.
## Two ways to authenticate
| Mode | When | Credentials held |
|---|---|---|
| **Browser bridge** (default) | no credentials configured | **none** |
| **Bridge-less** | `MAH_USERNAME` + `MAH_PASSWORD` set | your portal password, on disk |
Bridge-less logs in server-side — no browser, no extension — which is what makes
hosting possible. Verification is **human-in-the-loop**: the portal challenges,
`mah_sign_in` reports the channels your account allows, the portal sends a code to
**you**, and `mah_verify_code` submits only what you provide. Nothing here bypasses the
second factor.
**When the session expires** you do *not* reconnect the MCP or restart anything. The
next tool call returns an actionable error naming the channels and your masked
destinations; you pick one, the portal texts or emails **you**, and `mah_verify_code`
resumes the session in place. A pending challenge is remembered, so further tool calls
report it rather than re-submitting your password each time.
**Where credentials are read from.** A real `MAH_USERNAME` / `MAH_PASSWORD` in the
environment always wins. Failing that the server reads the first `.env` it finds, in
this order: `MAH_DOTENV`, then `~/.myatriumhealth-mcp/.env`, then `./.env`.
The middle one exists because MCP clients launch the server from whatever directory
they happen to be in, so a `.env` sitting in a checkout is invisible to it — and the
failure is quiet: with no credentials the server falls back to the browser bridge,
binds a port and waits for a signed-in tab. If you meant to run bridge-less and see the
bridge start, that is what happened; the startup line now says so.
**How the session persists.** After one verification the cookie jar is stored (0600,
bound to the account) and reused, so restarts resume the existing session rather than
signing in again — no browser and no further codes until the session lapses.
**How long that lasts, measured rather than assumed.** Every one of the ten cookies
MyChart sets is a *session* cookie — none carries an `expires` or `max-age` — so the
lifetime is the server's alone and cannot be read from the jar. A jar left **idle for
219 minutes** no longer authenticated: the next call fell through to a fresh sign-in
and was challenged for a code immediately.
What that does and does not establish: it bounds an **idle** session, and says nothing
about an active one. The measurement cannot tell an idle timeout from an absolute one,
and portals of this kind usually expire on inactivity — so a session in steady use may
outlive 3.6h comfortably, while one left alone will not. Plan re-verification around
**gaps in use**, not around wall-clock age.
**Why the jar is written back mid-session.** Every response's `Set-Cookie` is absorbed,
and the jar is re-persisted whenever a value actually changed (`transport-server.ts`
after each request; a no-op write when nothing rotated). That is not bookkeeping: if
the portal refreshes its ticket as a session is used, the refreshed one only survives a
process restart by reaching disk. On a scale-to-zero host — where the child exits
between tool calls — that write-back is the whole reason an extended session is still
there on the next call, rather than the copy frozen at sign-in.
Two things none of this changes: a lapse still costs one code rather than a reconnect,
and detection alone sends nothing — only `mah_sign_in` asks the portal to send
anything.
> **What does NOT work, measured rather than assumed:** the `RememberDeviceId` this
> portal returns is *not* a device-tracking id it will accept back. Sending it neither
> skips verification nor is harmless — it breaks the challenge, leaving the
> SecondaryValidation page without its `templateContext` so the antiforgery token
> cannot be read and `SendCode` returns 500. The account reports
> `RememberMeSettings.EnrollDeviceTracking: False`, which fits. The token is therefore
> stored but deliberately never sent.
The bridge mode's real virtue is that it holds **no credentials at all**. Prefer it
unless you specifically need bridge-less.
## How it works
Every MyChart cookie is `HttpOnly` and login is MFA-gated, so the session cannot be
copied out of the browser and replayed from Node. Requests are therefore relayed
through the user's own signed-in tab via the
[fetchproxy](https://github.com/chrischall/fetchproxy) bridge and the Transporter
extension, reusing their authenticated session. **The server never reads or stores the
session cookie.**
The portal's web app talks to a JSON API in two generations — modern
`POST api/<area>/<Action>` and legacy form-encoded `POST <Area>/<Controller>/<Action>`.
Both are documented, with live-captured shapes, in
[`docs/MYATRIUMHEALTH-API.md`](docs/MYATRIUMHEALTH-API.md).
## Install
```jsonc
{
"mcpServers": {
"myatriumhealth": {
"command": "npx",
"args": ["-y", "@chrischall/myatriumhealth-mcp"]
}
}
}
```
Then sign in to `my.atriumhealth.org` in Chrome and call `mah_healthcheck`. The first
call prints a pair code — approve it once in the Transporter popup.
| Env | Default | Purpose |
|---|---|---|
| `MAH_USERNAME` | — | MyAtriumHealth username. Set **with** `MAH_PASSWORD` to enable bridge-less mode. |
| `MAH_PASSWORD` | — | Portal password. Both are required; setting only one falls back to the bridge (with a warning). |
| `MAH_DEVICE_FILE` | `~/.myatriumhealth-mcp/device.json` | Session state (0600). Holds the **live cookie jar** as well as the device token — treat as a credential. |
| `MAH_WS_PORT` | `37149` | fetchproxy concentrator port (bridge mode only). The whole fleet shares this one port; override only when hosting. |
## Tools
All read-only except `mah_set_active_patient`, which changes only which patient this
connector reads — it writes nothing to any chart.
Every reading tool returns `{ patient, data }`, so the chart a response belongs to is
stated rather than inferred.
| Tool | What it returns |
|---|---|
| `mah_list_allergies` | Allergies with reactions and severity |
| `mah_list_health_issues` | The problem list |
| `mah_list_immunizations` | Immunizations and dates, by organization |
| `mah_list_medications` | Medications with dosing instructions (sig) and prescriber |
| `mah_list_test_results` | Labs and imaging: name, abnormal flag, date, provider comments |
| `mah_list_upcoming_visits` | Upcoming and in-progress appointments |
| `mah_list_past_visits` | Past visits, grouped by organization |
| `mah_list_goals` | Patient goals |
| `mah_get_health_summary` | Health-summary header and action plans |
| `mah_list_message_folders` | Message Center folders with unread counts |
| `mah_list_messages` | Message Center conversations for a folder |
| `mah_list_insurance` | Insurance coverages on file |
| `mah_list_care_team` | Care team providers, internal and external |
| `mah_list_billing_accounts` | Billing accounts and balances (parsed from HTML) |
| `mah_get_menu` | Which portal features this account exposes |
| `mah_healthcheck` | Connection health — bridge status when relaying, credential and session status when signing in server-side |
| `mah_auth_status` | Whether a session can be resumed and whether a device token is stored |
| `mah_sign_in` | Sign in server-side; reports verification channels if a code is needed *(needs credentials)* |
| `mah_send_verification_code` | Ask the portal to send a code to the account holder *(needs credentials)* |
| `mah_verify_code` | Submit the code the user received *(needs credentials)* |
| `mah_list_patients` | The patients this login can open — the account holder and any proxy subjects |
| `mah_get_patient_context` | Which patient the readers are serving, confirmed with the portal |
| `mah_set_active_patient` | Point every reader at one of those patients; survives restarts |
Every reading tool takes `view`: `compact` (the default) or `full`. The raw envelopes
are large — test results ~33 KB, medications ~30 KB — so `compact` is what you want for
browsing, and `full` returns MyAtriumHealth's payload untouched.
`compact` always strips image and avatar URLs, which is subtractive and cannot drop a
field nobody knew about. Ten readers additionally reduce each record to its clinically
meaningful fields, because their real payloads were captured and a projection derived
from them: `mah_list_allergies`, `mah_list_health_issues`, `mah_list_immunizations`,
`mah_list_medications`, `mah_list_care_team`, `mah_list_goals`, `mah_list_test_results`,
`mah_list_past_visits`, `mah_list_insurance` and `mah_list_messages`.
Every other reader gets the URL strip only. That field list is applied where one was
actually established and nowhere else — the list above is generated from
`PROJECTED_ENDPOINTS` and checked against the `project()` call sites by a test, so it
cannot quietly drift out of step with the code. If the portal's shape drifts, the
projection warns to stderr and returns the raw response rather than an empty list.
## Sessions expire, and they do it quietly
MyChart answers an **expired session with HTTP 200 whose body is the login page**, never
a 401, and the JSON endpoints then return `{}`. Tools raise a "Not signed in" error with
the remedy rather than reporting empty results. Sessions are short-lived; expect to sign
in again between uses.
## Without the MCP
[`skills/myatriumhealth-fpx`](skills/myatriumhealth-fpx) does the same thing from a
shell with the `fpx` CLI — no server to run. Its `references/endpoints.md` carries
live-verified `jq` recipes for every endpoint here.
## Messages
`mah_list_messages` is the one endpoinWhat people ask about myatriumhealth-mcp
What is chrischall/myatriumhealth-mcp?
+
chrischall/myatriumhealth-mcp is mcp servers for the Claude AI ecosystem. MCP server for MyAtriumHealth (Atrium Health's Epic MyChart patient portal) — reads test results, medications, allergies, immunizations and visits by routing requests through the user's signed-in browser tab via the fetchproxy bridge, reusing their authenticated session. It has 0 GitHub stars and its last recorded update is dated 2026-09-10.
How do I install myatriumhealth-mcp?
+
You can install myatriumhealth-mcp by cloning the repository (https://github.com/chrischall/myatriumhealth-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is chrischall/myatriumhealth-mcp safe to use?
+
Our security agent has analyzed chrischall/myatriumhealth-mcp and assigned a Trust Score of 87/100 (tier: Trusted). See the full breakdown of passed checks and flags on this page.
Who maintains chrischall/myatriumhealth-mcp?
+
chrischall/myatriumhealth-mcp is maintained by chrischall. The last recorded GitHub activity is dated 2026-09-10, with 0 open issues.
Are there alternatives to myatriumhealth-mcp?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy myatriumhealth-mcp to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/chrischall-myatriumhealth-mcp)<a href="https://claudewave.com/repo/chrischall-myatriumhealth-mcp"><img src="https://claudewave.com/api/badge/chrischall-myatriumhealth-mcp" alt="Featured on ClaudeWave: chrischall/myatriumhealth-mcp" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
The fastest path to AI-powered full stack observability, even for lean teams.
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!