
Myatriumhealth Mcp
io.github.chrischall由 GitHub 帳號 chrischall 發布v1.5.1更新於 Nov 7, 2026
MyAtriumHealth (Epic MyChart) records via your signed-in browser tab
概覽
讀取你自己的 MyAtriumHealth(Epic MyChart)病歷——檢驗結果、用藥、過敏、就診、帳單——並可回覆醫療團隊訊息。
- 可以做什麼
- 讀取病歷資料:過敏、健康問題、疫苗接種、用藥、檢驗與影像結果、健康目標、健康摘要、保險、照護團隊與帳單餘額
- 列出即將到來與過去的就診,以及訊息中心的資料夾與對話
- 以目前作用中的病人身分回覆訊息中心對話,需先預覽確認,可附加檔案
- 切換讀取工具所服務的病人(帳戶持有人或代理對象),並查看連線、工作階段與登入狀態
- 在伺服器端登入,並提交使用者收到的驗證碼
- 適用情境
- 適合讓助理彙整或回答關於你自己 Atrium Health 病歷的問題、在就診前整理問題,或草擬給照護團隊的回覆,而不必手動開啟入口網站。
- 執行需求
- 透過 npx 在本機執行(需要 Node.js)。預設的瀏覽器橋接模式需要 Chrome 中已登入 my.atriumhealth.org 的分頁、ContextMint Bridge 擴充功能,以及一次配對碼核准。無橋接模式需要 MAH_USERNAME 與 MAH_PASSWORD,並透過登入工具輸入入口網站的多因素驗證碼。選用設定包括 MAH_DEVICE_FILE、MAH_READ_ONLY 與 MCP_CONFIRM_* 變數。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Myatriumhealth Mcp,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
myatriumhealth-mcp
MCP server for MyAtriumHealth — Atrium Health's Epic MyChart
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
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
RememberDeviceIdthis 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 itstemplateContextso the antiforgery token cannot be read andSendCodereturns 500. The account reportsRememberMeSettings.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 bridge and the ContextMint Bridge
browser 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.
Install
Bridge mode needs ContextMint Bridge, installed from its
releases page — in Chrome,
unzip the chrome zip and add it via chrome://extensions → Developer mode → Load
unpacked. Use Chrome for now: the Safari build will ship inside the ContextMint app,
which has no public download yet.
ContextMint Bridge is the fetchproxy browser extension under its new name, from the
same maintainer — fetchproxy's own README
points to it. Its source is public at
nullnet-app/contextmint-bridge: build it
yourself, or check a release zip against the .sha256 file published beside it
(shasum -a 256 -c contextmint-bridge-chrome-<version>.zip.sha256).
Then sign in to my.atriumhealth.org in your browser and call mah_healthcheck. The
first call prints a pair code — approve it once in the ContextMint Bridge popup.
Tools
All read-only except two. mah_set_active_patient changes only which patient this
connector reads — it writes nothing to any chart. mah_reply_message sends a message
a provider will see, which cannot be undone: see Replying.
Every reading tool returns { patient, data }, so the chart a response belongs to is
stated rather than inferred.
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 { projectionFailed: true, endpoint, topLevelKeys, note } rather than an empty list — key names only, never the raw health record; ask for
view: 'full' to see the portal's payload.
Three readers also take view: 'brief' — one line per item, title — <ISO date | no date> — <status>, at most 120 characters, after a leading -- patient: <label> note
line naming whose chart was read (a line starting with -- is a note, not an item) — for hosts that group MCPs by context
(each tool carries _meta.mint hints; this server is in the health group):
mah_list_messages (what's new), mah_list_upcoming_visits (what's on) and
mah_list_billing_accounts (what's due; accounts with a balance only). The upcoming-visit
line reads VisitTypeName and PrimaryDate, which have not been checked against a
captured upcoming payload, so it falls back to Appointment — no date rather than guess.
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 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 endpoint that cannot be called with an empty body. It
needs a five-key request whose PageNonce is the CSP nonce of an /app/* page, and
whose externalLoadParams lists the non-local organizations only — passing the
local organization returns HTTP 500. The client assembles this from
conversations/GetOrganizations and its explicit isLocal flag.
api/item-feed/FetchItemFeed still needs parameters that have not been captured.
Replying
mah_reply_message takes a conversationId from mah_list_messages, a plain-text
body, and optionally files — attachments (base64) and/or blobKeys (hosted uploads).
It replies as whichever patient is active.
- It asks before it sends. A client that can show a confirmation prompt (Claude
Code) gets one with the thread, recipients, body and attachments, unless
MCP_CONFIRM_ELICITATION=off. Elsewhere the first call sends nothing and returns that preview plus aconfirmToken; only a repeat call with the same arguments and that token sends.MCP_CONFIRM_MODE(above) decides whether the model must get your approval in chat before using it (ask-user, the default), may use it itself (auto), or is refused (refuse). The send itself is irreversible and provider-visible. - A send must follow its own preview. The token is bound to the patient, thread,
recipients, body and attachments the preview showed (the fleet's shared mechanism from
@chrischall/mcp-utils). Anything else is refused: a different reply or thread (DRAFT_CHANGED, with the new preview and a fresh token), after 10 minutes (TOKEN_EXPIRED), a token already used (TOKEN_REUSED) or not issued for this reply (TOKEN_INVALID). Each preview authorizes one send, and the token is spent once the send is authorized, so any retry, even after a failure before anything went out, needs a fresh preview. So message text the model has read cannot talk it into a one-call send the user never saw. MAH_READ_ONLY=truerefuses every send. The tool stays registered — a hosted connector publishes the tool list of a child with no env of its own, so a tool that registered only when writes were allowed would disappear for everyone.- Limits come from the portal: 500 characters, 3 attachments, 10 MB per document or image (64 MB per video), BMP/DOC/DOCX/JPEG/JPG/PDF/PNG/TIF/TIFF and common video types.
- Two ways to attach a file.
attachmentscarries base64 inside the tool call: fine for a small file, but on a hosted deployment every byte rides in one request (mcp-host caps it at ~9.9 MiB) and the model has to emit it as text. For anything larger — a phone photo, a scanned PDF — callmah_upload_slots({files:[{filename}]})(hosted only),PUTeach file to its signeduploadUrl(each slot carries a readycurl), then pass the returnedblobKeystomah_reply_message. Both kinds count together against the portal's limit and go through the same checks. - A file is bound by its bytes. The preview reads every file — base64 is decoded
strictly, so a truncated payload is refused rather than sent corrupt; a blob is read
back from the upload store — and the confirmation binds each file's SHA-256. A blob
replaced in the store after the preview is refused (
DRAFT_CHANGED). Nothing is uploaded to the portal before the send is approved. - Uploaded copies are deleted only once the reply is sent. A reply that fails, or
may have gone out, keeps them, so the same
blobKeyscan be retried until the slot expires. A delete that fails after a send is reported underuploadStore.notDeleted, never as a failure — the store's retention reclaims it. - Attachments need bridge-less mode. fetchproxy relays a request body as text, which a binary upload does not survive, so through the browser bridge a reply with attachments is refused before anything is uploaded.
- A send is never retried. If the session re-authenticates between confirming the patient and sending, nothing is sent: a fresh sign-in serves the account holder, and the reply would go out as them. If the portal's answer to the send cannot be read, the result says the reply may have been sent — check the thread before trying again.
- On success it returns the new message's
wmgIdanddeliveryInstantISO, found by reading the thread back (the send itself returns only the thread id).
Development
License
MIT
來源:README.md,提交 c3af05d
工具
0版本歷史
18- v1.5.1最新Nov 7, 2026
- v1.4.1Nov 4, 2026
- v1.3.8Oct 20, 2026
- v1.3.7Oct 16, 2026
- v1.3.6Oct 10, 2026
- v1.3.5Oct 7, 2026
- v1.3.4Oct 5, 2026
- v1.3.3Oct 3, 2026
- v1.3.2Sep 28, 2026
- v1.3.1Sep 25, 2026
- v1.3.0Sep 24, 2026
- v1.2.2Sep 23, 2026
- v1.2.1Sep 23, 2026
- v1.2.0Sep 22, 2026
- v1.1.1Sep 21, 2026
- v1.1.0Sep 20, 2026
- v1.0.0Sep 19, 2026
- v0.4.4Sep 16, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分