@chrischall/myatriumhealth-mcp 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "metadata": {
9
9
  "description": "MCP server for Angi — find home-service pros by trade and city, read ratings, reviews and pro profiles. Angi serves its pages only to a real browser, so requests route through the user's own angi.com tab via the fetchproxy browser extension, reusing their existing session. The trade/city taxonomy is read from Angi's public sitemaps directly.",
10
- "version": "0.2.0"
10
+ "version": "0.3.0"
11
11
  },
12
12
  "plugins": [
13
13
  {
@@ -15,7 +15,7 @@
15
15
  "displayName": "MyAtriumHealth",
16
16
  "source": "./",
17
17
  "description": "Read MyAtriumHealth (Epic MyChart) records — test results, medications, allergies, immunizations, health issues, visits — by relaying requests through the user's signed-in browser tab via the fetchproxy bridge.",
18
- "version": "0.2.0",
18
+ "version": "0.3.0",
19
19
  "author": {
20
20
  "name": "Chris Hall"
21
21
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "myatriumhealth-mcp",
3
3
  "displayName": "MyAtriumHealth",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "description": "MyAtriumHealth (Epic MyChart) access for Claude — test results, medications, allergies, immunizations, visits",
6
6
  "author": {
7
7
  "name": "Chris Hall",
package/README.md CHANGED
@@ -26,10 +26,44 @@ destinations; you pick one, the portal texts or emails **you**, and `mah_verify_
26
26
  resumes the session in place. A pending challenge is remembered, so further tool calls
27
27
  report it rather than re-submitting your password each time.
28
28
 
29
+ **Where credentials are read from.** A real `MAH_USERNAME` / `MAH_PASSWORD` in the
30
+ environment always wins. Failing that the server reads the first `.env` it finds, in
31
+ this order: `MAH_DOTENV`, then `~/.myatriumhealth-mcp/.env`, then `./.env`.
32
+
33
+ The middle one exists because MCP clients launch the server from whatever directory
34
+ they happen to be in, so a `.env` sitting in a checkout is invisible to it — and the
35
+ failure is quiet: with no credentials the server falls back to the browser bridge,
36
+ binds a port and waits for a signed-in tab. If you meant to run bridge-less and see the
37
+ bridge start, that is what happened; the startup line now says so.
38
+
29
39
  **How the session persists.** After one verification the cookie jar is stored (0600,
30
40
  bound to the account) and reused, so restarts resume the existing session rather than
31
41
  signing in again — no browser and no further codes until the session lapses.
32
42
 
43
+ **How long that lasts, measured rather than assumed.** Every one of the ten cookies
44
+ MyChart sets is a *session* cookie — none carries an `expires` or `max-age` — so the
45
+ lifetime is the server's alone and cannot be read from the jar. A jar left **idle for
46
+ 219 minutes** no longer authenticated: the next call fell through to a fresh sign-in
47
+ and was challenged for a code immediately.
48
+
49
+ What that does and does not establish: it bounds an **idle** session, and says nothing
50
+ about an active one. The measurement cannot tell an idle timeout from an absolute one,
51
+ and portals of this kind usually expire on inactivity — so a session in steady use may
52
+ outlive 3.6h comfortably, while one left alone will not. Plan re-verification around
53
+ **gaps in use**, not around wall-clock age.
54
+
55
+ **Why the jar is written back mid-session.** Every response's `Set-Cookie` is absorbed,
56
+ and the jar is re-persisted whenever a value actually changed (`transport-server.ts`
57
+ after each request; a no-op write when nothing rotated). That is not bookkeeping: if
58
+ the portal refreshes its ticket as a session is used, the refreshed one only survives a
59
+ process restart by reaching disk. On a scale-to-zero host — where the child exits
60
+ between tool calls — that write-back is the whole reason an extended session is still
61
+ there on the next call, rather than the copy frozen at sign-in.
62
+
63
+ Two things none of this changes: a lapse still costs one code rather than a reconnect,
64
+ and detection alone sends nothing — only `mah_sign_in` asks the portal to send
65
+ anything.
66
+
33
67
  > **What does NOT work, measured rather than assumed:** the `RememberDeviceId` this
34
68
  > portal returns is *not* a device-tracking id it will accept back. Sending it neither
35
69
  > skips verification nor is harmless — it breaks the challenge, leaving the
@@ -80,7 +114,11 @@ call prints a pair code — approve it once in the Transporter popup.
80
114
 
81
115
  ## Tools
82
116
 
83
- All read-only — this surface exposes no writes.
117
+ All read-only except `mah_set_active_patient`, which changes only which patient this
118
+ connector reads — it writes nothing to any chart.
119
+
120
+ Every reading tool returns `{ patient, data }`, so the chart a response belongs to is
121
+ stated rather than inferred.
84
122
 
85
123
  | Tool | What it returns |
86
124
  |---|---|
@@ -104,11 +142,26 @@ All read-only — this surface exposes no writes.
104
142
  | `mah_sign_in` | Sign in server-side; reports verification channels if a code is needed *(bridge-less only)* |
105
143
  | `mah_send_verification_code` | Ask the portal to send a code to the account holder *(bridge-less only)* |
106
144
  | `mah_verify_code` | Submit the code the user received *(bridge-less only)* |
107
-
108
- Listing tools take `compact` (default `false`). The raw envelopes are large — test
109
- results ~33 KB, medications ~30 KB — so pass `compact: true` when browsing. If the
110
- portal's shape drifts, the projection warns to stderr and returns the raw response
111
- rather than an empty list.
145
+ | `mah_list_patients` | The patients this login can open — the account holder and any proxy subjects |
146
+ | `mah_get_patient_context` | Which patient the readers are serving, confirmed with the portal |
147
+ | `mah_set_active_patient` | Point every reader at one of those patients; survives restarts |
148
+
149
+ Every reading tool takes `view`: `compact` (the default) or `full`. The raw envelopes
150
+ are large — test results ~33 KB, medications ~30 KB — so `compact` is what you want for
151
+ browsing, and `full` returns MyAtriumHealth's payload untouched.
152
+
153
+ `compact` always strips image and avatar URLs, which is subtractive and cannot drop a
154
+ field nobody knew about. Ten readers additionally reduce each record to its clinically
155
+ meaningful fields, because their real payloads were captured and a projection derived
156
+ from them: `mah_list_allergies`, `mah_list_health_issues`, `mah_list_immunizations`,
157
+ `mah_list_medications`, `mah_list_care_team`, `mah_list_goals`, `mah_list_test_results`,
158
+ `mah_list_past_visits`, `mah_list_insurance` and `mah_list_messages`.
159
+
160
+ Every other reader gets the URL strip only. That field list is applied where one was
161
+ actually established and nowhere else — the list above is generated from
162
+ `PROJECTED_ENDPOINTS` and checked against the `project()` call sites by a test, so it
163
+ cannot quietly drift out of step with the code. If the portal's shape drifts, the
164
+ projection warns to stderr and returns the raw response rather than an empty list.
112
165
 
113
166
  ## Sessions expire, and they do it quietly
114
167