@chrischall/myatriumhealth-mcp 1.3.4 → 1.3.5
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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +4 -2
- package/dist/bundle.js +338 -52
- package/package.json +3 -3
- package/server.json +2 -2
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"metadata": {
|
|
9
9
|
"description": "MCP server for MyAtriumHealth (Atrium Health's Epic MyChart patient portal) — test results, medications, allergies, immunizations, health issues, visits and messages. Requests relay through the user's own signed-in browser tab via the ContextMint Bridge extension, reusing their existing session.",
|
|
10
|
-
"version": "1.3.
|
|
10
|
+
"version": "1.3.5"
|
|
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 ContextMint Bridge extension.",
|
|
18
|
-
"version": "1.3.
|
|
18
|
+
"version": "1.3.5",
|
|
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": "1.3.
|
|
4
|
+
"version": "1.3.5",
|
|
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
|
@@ -125,7 +125,8 @@ first call prints a pair code — approve it once in the ContextMint Bridge popu
|
|
|
125
125
|
| `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. |
|
|
126
126
|
| `MAH_WS_PORT` | `37149` | fetchproxy concentrator port (bridge mode only). The whole fleet shares this one port; override only when hosting. |
|
|
127
127
|
| `MAH_READ_ONLY` | `false` | `true` refuses `mah_reply_message` sends (previews still work). The tool stays listed either way. |
|
|
128
|
-
| `MCP_CONFIRM_MODE` | `ask-user` | What a reply does on a client that cannot show a confirmation prompt (claude.ai, Claude Desktop). `ask-user`: two steps — the first call sends nothing and returns a preview plus a token, and the model must get your approval in chat before calling again with it. `auto`: the same two steps, but the model may use the token after reviewing the preview itself. `refuse`: replies are refused on such clients. A client that can show prompts (Claude Code) always gets the real prompt
|
|
128
|
+
| `MCP_CONFIRM_MODE` | `ask-user` | What a reply does on a client that cannot show a confirmation prompt (claude.ai, Claude Desktop). `ask-user`: two steps — the first call sends nothing and returns a preview plus a token, and the model must get your approval in chat before calling again with it. `auto`: the same two steps, but the model may use the token after reviewing the preview itself. `refuse`: replies are refused on such clients. A client that can show prompts (Claude Code) always gets the real prompt, unless `MCP_CONFIRM_ELICITATION=off`. An unrecognised value is treated as `refuse`. |
|
|
129
|
+
| `MCP_CONFIRM_ELICITATION` | `on` | `off` never shows a confirmation prompt, so every client gets the `MCP_CONFIRM_MODE` path. Set it for a client that claims to support prompts but never shows one (the reply hangs — opencode 2.0.x). Any other value stays `on`, with a warning on stderr. |
|
|
129
130
|
| `MCP_CONFIRM_TTL_SECONDS` | `600` | How long a token stays valid. |
|
|
130
131
|
| `MCP_CONFIRM_SECRET` | random per process | Signing key; set it only if tokens must survive a server restart. |
|
|
131
132
|
|
|
@@ -213,7 +214,8 @@ local organization returns HTTP 500. The client assembles this from
|
|
|
213
214
|
`body`, and optionally `attachments`. It replies **as whichever patient is active**.
|
|
214
215
|
|
|
215
216
|
- **It asks before it sends.** A client that can show a confirmation prompt (Claude
|
|
216
|
-
Code) gets one with the thread, recipients, body and attachments
|
|
217
|
+
Code) gets one with the thread, recipients, body and attachments, unless
|
|
218
|
+
`MCP_CONFIRM_ELICITATION=off`. Elsewhere the first
|
|
217
219
|
call sends nothing and returns that preview plus a `confirmToken`; only a repeat call
|
|
218
220
|
with the same arguments and that token sends. `MCP_CONFIRM_MODE` (above) decides
|
|
219
221
|
whether the model must get your approval in chat before using it (`ask-user`, the
|
package/dist/bundle.js
CHANGED
|
@@ -20693,8 +20693,8 @@ var require_schemas2 = __commonJS({
|
|
|
20693
20693
|
return core._stringFormat(exports.ZodCustomStringFormat, "currency_code", regexes.currencyCode, _params);
|
|
20694
20694
|
}
|
|
20695
20695
|
function hash2(alg, params) {
|
|
20696
|
-
const
|
|
20697
|
-
const format = `${alg}_${
|
|
20696
|
+
const enc7 = params?.enc ?? "hex";
|
|
20697
|
+
const format = `${alg}_${enc7}`;
|
|
20698
20698
|
const regex = core.regexes[format];
|
|
20699
20699
|
if (!regex)
|
|
20700
20700
|
throw new Error(`Unrecognized hash format: ${format}`);
|
|
@@ -25993,11 +25993,23 @@ var require_websocket = __commonJS({
|
|
|
25993
25993
|
this._isServer = false;
|
|
25994
25994
|
this._redirects = 0;
|
|
25995
25995
|
if (protocols === void 0) {
|
|
25996
|
-
protocols
|
|
25996
|
+
if (!options || options.protocols === void 0) {
|
|
25997
|
+
protocols = [];
|
|
25998
|
+
} else if (Array.isArray(options.protocols)) {
|
|
25999
|
+
protocols = options.protocols;
|
|
26000
|
+
} else {
|
|
26001
|
+
protocols = [options.protocols];
|
|
26002
|
+
}
|
|
25997
26003
|
} else if (!Array.isArray(protocols)) {
|
|
25998
26004
|
if (typeof protocols === "object" && protocols !== null) {
|
|
25999
26005
|
options = protocols;
|
|
26000
|
-
protocols
|
|
26006
|
+
if (options.protocols === void 0) {
|
|
26007
|
+
protocols = [];
|
|
26008
|
+
} else if (Array.isArray(options.protocols)) {
|
|
26009
|
+
protocols = options.protocols;
|
|
26010
|
+
} else {
|
|
26011
|
+
protocols = [options.protocols];
|
|
26012
|
+
}
|
|
26001
26013
|
} else {
|
|
26002
26014
|
protocols = [protocols];
|
|
26003
26015
|
}
|
|
@@ -26194,7 +26206,6 @@ var require_websocket = __commonJS({
|
|
|
26194
26206
|
}
|
|
26195
26207
|
return;
|
|
26196
26208
|
}
|
|
26197
|
-
this._readyState = _WebSocket.CLOSING;
|
|
26198
26209
|
this._sender.close(code2, data, !this._isServer, (err) => {
|
|
26199
26210
|
if (err) return;
|
|
26200
26211
|
this._closeFrameSent = true;
|
|
@@ -26202,6 +26213,7 @@ var require_websocket = __commonJS({
|
|
|
26202
26213
|
this._socket.end();
|
|
26203
26214
|
}
|
|
26204
26215
|
});
|
|
26216
|
+
this._readyState = _WebSocket.CLOSING;
|
|
26205
26217
|
setCloseTimer(this);
|
|
26206
26218
|
}
|
|
26207
26219
|
/**
|
|
@@ -26426,6 +26438,7 @@ var require_websocket = __commonJS({
|
|
|
26426
26438
|
socketPath: void 0,
|
|
26427
26439
|
hostname: void 0,
|
|
26428
26440
|
protocol: void 0,
|
|
26441
|
+
protocols: void 0,
|
|
26429
26442
|
timeout: void 0,
|
|
26430
26443
|
method: "GET",
|
|
26431
26444
|
host: void 0,
|
|
@@ -60033,8 +60046,8 @@ function currencyCode2(_params) {
|
|
|
60033
60046
|
return _stringFormat(ZodCustomStringFormat, "currency_code", currencyCode, _params);
|
|
60034
60047
|
}
|
|
60035
60048
|
function hash(alg, params) {
|
|
60036
|
-
const
|
|
60037
|
-
const format = `${alg}_${
|
|
60049
|
+
const enc7 = params?.enc ?? "hex";
|
|
60050
|
+
const format = `${alg}_${enc7}`;
|
|
60038
60051
|
const regex = regexes_exports[format];
|
|
60039
60052
|
if (!regex)
|
|
60040
60053
|
throw new Error(`Unrecognized hash format: ${format}`);
|
|
@@ -62109,6 +62122,7 @@ function escapeKey(key) {
|
|
|
62109
62122
|
var DEFAULT_REQUEST_KEY = "confirmation";
|
|
62110
62123
|
var DEFAULT_CONFIRMATION_LABEL = "Confirm this action should proceed.";
|
|
62111
62124
|
var UNSUPPORTED_NOTE = "Nothing was done because this client cannot show a confirmation prompt (it declares no MCP elicitation capability), and this action is never taken without one";
|
|
62125
|
+
var DISABLED_NOTE = "Nothing was done because confirmation prompts are turned off for this server, and this action is never taken without one";
|
|
62112
62126
|
var STATE_PREFIX = "mcpu.confirm.v1.";
|
|
62113
62127
|
function bindingKey(binding) {
|
|
62114
62128
|
if (binding.ttlSeconds !== void 0 && !(Number.isFinite(binding.ttlSeconds) && binding.ttlSeconds > 0)) {
|
|
@@ -62181,6 +62195,15 @@ ${JSON.stringify(preview, null, 2)}`,
|
|
|
62181
62195
|
};
|
|
62182
62196
|
const response = inputResponse(ctx.mcpReq.inputResponses, requestKey);
|
|
62183
62197
|
const accepted = acceptedContent(ctx.mcpReq.inputResponses, requestKey, confirmationSchema);
|
|
62198
|
+
if (options.elicitation === false) {
|
|
62199
|
+
return textResult({
|
|
62200
|
+
confirmed: false,
|
|
62201
|
+
dispatched: false,
|
|
62202
|
+
action: options.action,
|
|
62203
|
+
reason: "confirmation-unsupported",
|
|
62204
|
+
note: options.unsupportedNote ? `${DISABLED_NOTE}. ${options.unsupportedNote}` : `${DISABLED_NOTE}.`
|
|
62205
|
+
});
|
|
62206
|
+
}
|
|
62184
62207
|
if (response.kind === "missing") {
|
|
62185
62208
|
if (callerAcceptsFormElicitation(ctx) === false) {
|
|
62186
62209
|
return textResult({
|
|
@@ -62375,7 +62398,7 @@ async function tokenConfirmation(action, fb) {
|
|
|
62375
62398
|
}
|
|
62376
62399
|
async function requireConfirmationWithFallback(ctx, options) {
|
|
62377
62400
|
const { tokenFallback, ...confirmation } = options;
|
|
62378
|
-
if (tokenFallback && callerAcceptsFormElicitation(ctx) === false) {
|
|
62401
|
+
if (tokenFallback && (options.elicitation === false || callerAcceptsFormElicitation(ctx) === false)) {
|
|
62379
62402
|
return tokenConfirmation(options.action, tokenFallback);
|
|
62380
62403
|
}
|
|
62381
62404
|
return requireConfirmation(ctx, confirmation);
|
|
@@ -62534,6 +62557,20 @@ function readConfirmMode(env = process.env) {
|
|
|
62534
62557
|
}
|
|
62535
62558
|
return "refuse";
|
|
62536
62559
|
}
|
|
62560
|
+
function readConfirmElicitation(env = process.env) {
|
|
62561
|
+
const raw = readEnvVar("MCP_CONFIRM_ELICITATION", { env })?.trim().toLowerCase();
|
|
62562
|
+
if (!raw || raw === "on")
|
|
62563
|
+
return "on";
|
|
62564
|
+
if (raw === "off")
|
|
62565
|
+
return "off";
|
|
62566
|
+
const key = `elicitation:${raw}`;
|
|
62567
|
+
if (!warned.has(key)) {
|
|
62568
|
+
warned.add(key);
|
|
62569
|
+
process.stderr.write(`MCP_CONFIRM_ELICITATION="${raw}" is not one of on, off; treating it as on.
|
|
62570
|
+
`);
|
|
62571
|
+
}
|
|
62572
|
+
return "on";
|
|
62573
|
+
}
|
|
62537
62574
|
function readConfirmTtl(env) {
|
|
62538
62575
|
const raw = readEnvVar("MCP_CONFIRM_TTL_SECONDS", { env })?.trim();
|
|
62539
62576
|
if (!raw)
|
|
@@ -62578,6 +62615,7 @@ function spentTokenStoreFromEnv(env = process.env) {
|
|
|
62578
62615
|
}
|
|
62579
62616
|
var CONFIRM_TOKEN_AUTO_INSTRUCTION = "Nothing has been done yet. Review this preview; if it is what was intended, call again with the same arguments plus confirmToken. (This server runs with MCP_CONFIRM_MODE=auto, so the user's approval in chat is not required.)";
|
|
62580
62617
|
var REFUSE_HINT = "Set MCP_CONFIRM_MODE=ask-user on the server to allow two-step confirmation instead.";
|
|
62618
|
+
var ELICITATION_OFF_HINT = "MCP_CONFIRM_ELICITATION=off on the server turns confirmation prompts off.";
|
|
62581
62619
|
var BAD_TTL_HINT = "MCP_CONFIRM_TTL_SECONDS on the server is not a positive whole number of seconds; fix it to allow two-step confirmation.";
|
|
62582
62620
|
function boundArgs(args) {
|
|
62583
62621
|
if (args === null || typeof args !== "object" || Array.isArray(args) || !("confirmToken" in args))
|
|
@@ -62591,10 +62629,13 @@ function confirmationFromEnv(options) {
|
|
|
62591
62629
|
const spent = callerSpent ?? spentTokenStoreFromEnv(env);
|
|
62592
62630
|
const mode = readConfirmMode(env);
|
|
62593
62631
|
const ttlSeconds = readConfirmTtl(env);
|
|
62632
|
+
const elicitationOff = readConfirmElicitation(env) === "off";
|
|
62594
62633
|
const bound = args === void 0 ? void 0 : boundArgs(args);
|
|
62595
|
-
const
|
|
62634
|
+
const bindingAdded = bound === void 0 || rest.binding ? rest : { ...rest, binding: { key: confirmKeyFromEnv(env), args: bound, ttlSeconds: ttlSeconds ?? DEFAULT_TTL_SECONDS2 } };
|
|
62635
|
+
const confirmation = elicitationOff ? { ...bindingAdded, elicitation: false } : bindingAdded;
|
|
62596
62636
|
if (mode === "refuse" || ttlSeconds === void 0) {
|
|
62597
|
-
const
|
|
62637
|
+
const reason = mode === "refuse" ? REFUSE_HINT : BAD_TTL_HINT;
|
|
62638
|
+
const hint = elicitationOff ? `${ELICITATION_OFF_HINT} ${reason}` : reason;
|
|
62598
62639
|
return {
|
|
62599
62640
|
...confirmation,
|
|
62600
62641
|
unsupportedNote: confirmation.unsupportedNote ? `${confirmation.unsupportedNote} ${hint}` : hint
|
|
@@ -64529,6 +64570,60 @@ var KNOWN_CAPABILITIES = /* @__PURE__ */ new Set([
|
|
|
64529
64570
|
"graphql",
|
|
64530
64571
|
"write_cookies"
|
|
64531
64572
|
]);
|
|
64573
|
+
var ACCOUNT_KEY_FRAME = "account-key";
|
|
64574
|
+
var ACCOUNT_ATTEST_FRAME = "account-attest";
|
|
64575
|
+
var BRIDGE_ROLE_FRAME = "bridge-role";
|
|
64576
|
+
var BRIDGE_SERVE_FRAME = "bridge-serve";
|
|
64577
|
+
var ROOM_PING_FRAME = "room-ping";
|
|
64578
|
+
var ROOM_PONG_FRAME = "room-pong";
|
|
64579
|
+
var BRIDGE_ROLE_LABEL_MAX = 64;
|
|
64580
|
+
var ROOM_FRAME_ACCEPTS = Object.freeze({
|
|
64581
|
+
[BRIDGE_ROLE_FRAME]: BRIDGE_ROLE_FRAME,
|
|
64582
|
+
[BRIDGE_SERVE_FRAME]: BRIDGE_SERVE_FRAME,
|
|
64583
|
+
[ROOM_PING_FRAME]: ROOM_PING_FRAME,
|
|
64584
|
+
[ROOM_PONG_FRAME]: ROOM_PING_FRAME
|
|
64585
|
+
});
|
|
64586
|
+
|
|
64587
|
+
// node_modules/@fetchproxy/protocol/dist/mcp-id.js
|
|
64588
|
+
var ID_RE = /^([^:]+):([^:]+):([0-9a-f]{16})$/;
|
|
64589
|
+
function generateMcpId(serverName, version2) {
|
|
64590
|
+
if (serverName.includes(":")) {
|
|
64591
|
+
throw new Error(`serverName cannot contain ':': ${serverName}`);
|
|
64592
|
+
}
|
|
64593
|
+
if (version2.includes(":")) {
|
|
64594
|
+
throw new Error(`version cannot contain ':': ${version2}`);
|
|
64595
|
+
}
|
|
64596
|
+
const rand = randomHex(8);
|
|
64597
|
+
return `${serverName}:${version2}:${rand}`;
|
|
64598
|
+
}
|
|
64599
|
+
function isValidMcpId(id) {
|
|
64600
|
+
return typeof id === "string" && ID_RE.test(id);
|
|
64601
|
+
}
|
|
64602
|
+
function randomHex(bytes) {
|
|
64603
|
+
const arr = new Uint8Array(bytes);
|
|
64604
|
+
globalThis.crypto.getRandomValues(arr);
|
|
64605
|
+
return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
64606
|
+
}
|
|
64607
|
+
|
|
64608
|
+
// node_modules/@fetchproxy/protocol/dist/account-attest.js
|
|
64609
|
+
var ACCOUNT_ATTEST_CONSENTS = Object.freeze([
|
|
64610
|
+
"silent",
|
|
64611
|
+
"confirm",
|
|
64612
|
+
"confirm-each"
|
|
64613
|
+
]);
|
|
64614
|
+
var NO_SCOPE_DIGEST = "0".repeat(64);
|
|
64615
|
+
var ACCOUNT_ID_RE = /^[A-Za-z0-9_.\-]{1,128}$/;
|
|
64616
|
+
var HEX64_RE = /^[0-9a-f]{64}$/;
|
|
64617
|
+
var ACCOUNT_KID_RE = /^[0-9a-f]{16}$/;
|
|
64618
|
+
var enc2 = new TextEncoder();
|
|
64619
|
+
|
|
64620
|
+
// node_modules/@fetchproxy/protocol/dist/awaiting-approval.js
|
|
64621
|
+
var AWAITING_APPROVAL_REASON_PREFIX = "awaiting-approval:";
|
|
64622
|
+
function parseAwaitingApprovalReason(reason) {
|
|
64623
|
+
if (!reason.startsWith(AWAITING_APPROVAL_REASON_PREFIX))
|
|
64624
|
+
return null;
|
|
64625
|
+
return reason.slice(AWAITING_APPROVAL_REASON_PREFIX.length).trim();
|
|
64626
|
+
}
|
|
64532
64627
|
|
|
64533
64628
|
// node_modules/@fetchproxy/protocol/dist/capability-availability.js
|
|
64534
64629
|
var CAPABILITY_UNAVAILABLE_CODE = "capability_unavailable";
|
|
@@ -64554,27 +64649,6 @@ function parseUnsupportedCapabilityReason(reason) {
|
|
|
64554
64649
|
return rest.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
64555
64650
|
}
|
|
64556
64651
|
|
|
64557
|
-
// node_modules/@fetchproxy/protocol/dist/mcp-id.js
|
|
64558
|
-
var ID_RE = /^([^:]+):([^:]+):([0-9a-f]{16})$/;
|
|
64559
|
-
function generateMcpId(serverName, version2) {
|
|
64560
|
-
if (serverName.includes(":")) {
|
|
64561
|
-
throw new Error(`serverName cannot contain ':': ${serverName}`);
|
|
64562
|
-
}
|
|
64563
|
-
if (version2.includes(":")) {
|
|
64564
|
-
throw new Error(`version cannot contain ':': ${version2}`);
|
|
64565
|
-
}
|
|
64566
|
-
const rand = randomHex(8);
|
|
64567
|
-
return `${serverName}:${version2}:${rand}`;
|
|
64568
|
-
}
|
|
64569
|
-
function isValidMcpId(id) {
|
|
64570
|
-
return typeof id === "string" && ID_RE.test(id);
|
|
64571
|
-
}
|
|
64572
|
-
function randomHex(bytes) {
|
|
64573
|
-
const arr = new Uint8Array(bytes);
|
|
64574
|
-
globalThis.crypto.getRandomValues(arr);
|
|
64575
|
-
return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
64576
|
-
}
|
|
64577
|
-
|
|
64578
64652
|
// node_modules/@fetchproxy/protocol/dist/json-pointer.js
|
|
64579
64653
|
function matchesDeclaredKey(requested, declared) {
|
|
64580
64654
|
for (const decl of declared) {
|
|
@@ -65170,6 +65244,16 @@ function validateFrame(raw) {
|
|
|
65170
65244
|
return { type: "extension-disconnected" };
|
|
65171
65245
|
if (t === "peer-gone")
|
|
65172
65246
|
return validatePeerGone(raw);
|
|
65247
|
+
if (t === ACCOUNT_KEY_FRAME)
|
|
65248
|
+
return validateAccountKey(raw);
|
|
65249
|
+
if (t === ACCOUNT_ATTEST_FRAME)
|
|
65250
|
+
return validateAccountAttest(raw);
|
|
65251
|
+
if (t === BRIDGE_ROLE_FRAME)
|
|
65252
|
+
return validateBridgeRole(raw);
|
|
65253
|
+
if (t === BRIDGE_SERVE_FRAME || t === ROOM_PING_FRAME || t === ROOM_PONG_FRAME) {
|
|
65254
|
+
assertExactFields(raw, TYPE_ONLY_FIELDS, t);
|
|
65255
|
+
return { type: t };
|
|
65256
|
+
}
|
|
65173
65257
|
throw new ProtocolError3(`unknown frame type: ${String(t)}`);
|
|
65174
65258
|
}
|
|
65175
65259
|
function validateHello(raw) {
|
|
@@ -65373,6 +65457,165 @@ function validateHelloRejected(raw) {
|
|
|
65373
65457
|
}
|
|
65374
65458
|
return { type: "hello-rejected", mcpId: raw.mcpId, reason: raw.reason };
|
|
65375
65459
|
}
|
|
65460
|
+
var DISPLAY_FORBIDDEN_RE = /[\u0000-\u001f\u007f-\u009f\u200e\u200f\u202a-\u202e\u2066-\u2069]/;
|
|
65461
|
+
function assertExactFields(raw, allowed, label) {
|
|
65462
|
+
for (const k of Object.keys(raw)) {
|
|
65463
|
+
if (!allowed.includes(k)) {
|
|
65464
|
+
throw new ProtocolError3(`${label}: unexpected field ${JSON.stringify(k)}`);
|
|
65465
|
+
}
|
|
65466
|
+
}
|
|
65467
|
+
}
|
|
65468
|
+
function assertMatch(x, re, label, what) {
|
|
65469
|
+
assertString(x, label);
|
|
65470
|
+
if (!re.test(x))
|
|
65471
|
+
throw new ProtocolError3(`${label}: must be ${what}`);
|
|
65472
|
+
}
|
|
65473
|
+
function assertPositiveSafeInt(x, label) {
|
|
65474
|
+
if (typeof x !== "number" || !Number.isSafeInteger(x) || x <= 0) {
|
|
65475
|
+
throw new ProtocolError3(`${label}: expected positive safe integer`);
|
|
65476
|
+
}
|
|
65477
|
+
}
|
|
65478
|
+
function assertDisplayString(x, label, min, max) {
|
|
65479
|
+
assertString(x, label);
|
|
65480
|
+
if (x.length < min || x.length > max) {
|
|
65481
|
+
throw new ProtocolError3(`${label}: must be ${min}-${max} characters`);
|
|
65482
|
+
}
|
|
65483
|
+
if (DISPLAY_FORBIDDEN_RE.test(x)) {
|
|
65484
|
+
throw new ProtocolError3(`${label}: control or bidi-override character`);
|
|
65485
|
+
}
|
|
65486
|
+
}
|
|
65487
|
+
var ACCOUNT_KEY_FIELDS = [
|
|
65488
|
+
"type",
|
|
65489
|
+
"accountId",
|
|
65490
|
+
"slug",
|
|
65491
|
+
"displayName",
|
|
65492
|
+
"confirmedBy",
|
|
65493
|
+
"tokenId",
|
|
65494
|
+
"kid",
|
|
65495
|
+
"publicKey",
|
|
65496
|
+
"generation",
|
|
65497
|
+
"bridgedRegistrations"
|
|
65498
|
+
];
|
|
65499
|
+
function validateAccountKey(raw) {
|
|
65500
|
+
const L = "account-key";
|
|
65501
|
+
assertMatch(raw.accountId, ACCOUNT_ID_RE, `${L}.accountId`, "an account id");
|
|
65502
|
+
assertMatch(raw.slug, ACCOUNT_ID_RE, `${L}.slug`, "a slug");
|
|
65503
|
+
assertDisplayString(raw.displayName, `${L}.displayName`, 0, 128);
|
|
65504
|
+
assertDisplayString(raw.confirmedBy, `${L}.confirmedBy`, 1, 256);
|
|
65505
|
+
assertMatch(raw.tokenId, ACCOUNT_ID_RE, `${L}.tokenId`, "a token id");
|
|
65506
|
+
assertMatch(raw.kid, ACCOUNT_KID_RE, `${L}.kid`, "16 lowercase hex");
|
|
65507
|
+
assertBase64Bytes(raw.publicKey, `${L}.publicKey`, 32);
|
|
65508
|
+
assertPositiveSafeInt(raw.generation, `${L}.generation`);
|
|
65509
|
+
const n = raw.bridgedRegistrations;
|
|
65510
|
+
if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 0) {
|
|
65511
|
+
throw new ProtocolError3(`${L}.bridgedRegistrations: expected non-negative safe integer`);
|
|
65512
|
+
}
|
|
65513
|
+
assertExactFields(raw, ACCOUNT_KEY_FIELDS, L);
|
|
65514
|
+
return {
|
|
65515
|
+
type: ACCOUNT_KEY_FRAME,
|
|
65516
|
+
accountId: raw.accountId,
|
|
65517
|
+
slug: raw.slug,
|
|
65518
|
+
displayName: raw.displayName,
|
|
65519
|
+
confirmedBy: raw.confirmedBy,
|
|
65520
|
+
tokenId: raw.tokenId,
|
|
65521
|
+
kid: raw.kid,
|
|
65522
|
+
publicKey: raw.publicKey,
|
|
65523
|
+
generation: raw.generation,
|
|
65524
|
+
bridgedRegistrations: n
|
|
65525
|
+
};
|
|
65526
|
+
}
|
|
65527
|
+
var ACCOUNT_ATTEST_FIELDS = [
|
|
65528
|
+
"type",
|
|
65529
|
+
"mcpId",
|
|
65530
|
+
"accountId",
|
|
65531
|
+
"generation",
|
|
65532
|
+
"tokenId",
|
|
65533
|
+
"kid",
|
|
65534
|
+
"registrationId",
|
|
65535
|
+
"slug",
|
|
65536
|
+
"identityHash",
|
|
65537
|
+
"identityEd25519Pub",
|
|
65538
|
+
"scopeDigest",
|
|
65539
|
+
"consent",
|
|
65540
|
+
"notAfter",
|
|
65541
|
+
"sig"
|
|
65542
|
+
];
|
|
65543
|
+
function validateAccountAttest(raw) {
|
|
65544
|
+
const L = "account-attest";
|
|
65545
|
+
if (!isValidMcpId(raw.mcpId))
|
|
65546
|
+
throw new ProtocolError3(`${L}.mcpId: invalid format`);
|
|
65547
|
+
assertMatch(raw.accountId, ACCOUNT_ID_RE, `${L}.accountId`, "an account id");
|
|
65548
|
+
assertPositiveSafeInt(raw.generation, `${L}.generation`);
|
|
65549
|
+
assertMatch(raw.tokenId, ACCOUNT_ID_RE, `${L}.tokenId`, "a token id");
|
|
65550
|
+
assertMatch(raw.kid, ACCOUNT_KID_RE, `${L}.kid`, "16 lowercase hex");
|
|
65551
|
+
assertMatch(raw.registrationId, ACCOUNT_ID_RE, `${L}.registrationId`, "a registration id");
|
|
65552
|
+
assertMatch(raw.slug, ACCOUNT_ID_RE, `${L}.slug`, "a slug");
|
|
65553
|
+
assertMatch(raw.identityHash, HEX64_RE, `${L}.identityHash`, "64 lowercase hex");
|
|
65554
|
+
assertBase64Bytes(raw.identityEd25519Pub, `${L}.identityEd25519Pub`, 32);
|
|
65555
|
+
assertMatch(raw.scopeDigest, HEX64_RE, `${L}.scopeDigest`, "64 lowercase hex");
|
|
65556
|
+
assertString(raw.consent, `${L}.consent`);
|
|
65557
|
+
const consent = raw.consent;
|
|
65558
|
+
const known = ACCOUNT_ATTEST_CONSENTS.find((c) => c === consent);
|
|
65559
|
+
if (known === void 0) {
|
|
65560
|
+
throw new ProtocolError3(`${L}.consent: must be one of ${ACCOUNT_ATTEST_CONSENTS.join(", ")}`);
|
|
65561
|
+
}
|
|
65562
|
+
assertPositiveSafeInt(raw.notAfter, `${L}.notAfter`);
|
|
65563
|
+
assertBase64Bytes(raw.sig, `${L}.sig`, 64);
|
|
65564
|
+
assertExactFields(raw, ACCOUNT_ATTEST_FIELDS, L);
|
|
65565
|
+
return {
|
|
65566
|
+
type: ACCOUNT_ATTEST_FRAME,
|
|
65567
|
+
mcpId: raw.mcpId,
|
|
65568
|
+
accountId: raw.accountId,
|
|
65569
|
+
generation: raw.generation,
|
|
65570
|
+
tokenId: raw.tokenId,
|
|
65571
|
+
kid: raw.kid,
|
|
65572
|
+
registrationId: raw.registrationId,
|
|
65573
|
+
slug: raw.slug,
|
|
65574
|
+
identityHash: raw.identityHash,
|
|
65575
|
+
identityEd25519Pub: raw.identityEd25519Pub,
|
|
65576
|
+
scopeDigest: raw.scopeDigest,
|
|
65577
|
+
consent: known,
|
|
65578
|
+
notAfter: raw.notAfter,
|
|
65579
|
+
sig: raw.sig
|
|
65580
|
+
};
|
|
65581
|
+
}
|
|
65582
|
+
var TYPE_ONLY_FIELDS = ["type"];
|
|
65583
|
+
var BRIDGE_ROLE_FIELDS = ["type", "role", "canServe", "serving"];
|
|
65584
|
+
var BRIDGE_ROLE_SERVING_FIELDS = ["label", "since"];
|
|
65585
|
+
function validateBridgeRole(raw) {
|
|
65586
|
+
const L = BRIDGE_ROLE_FRAME;
|
|
65587
|
+
const role = raw.role;
|
|
65588
|
+
if (role !== "serving" && role !== "standby") {
|
|
65589
|
+
throw new ProtocolError3(`${L}.role: must be one of serving, standby`);
|
|
65590
|
+
}
|
|
65591
|
+
const canServe = raw.canServe;
|
|
65592
|
+
assertBoolean(canServe, `${L}.canServe`);
|
|
65593
|
+
assertExactFields(raw, BRIDGE_ROLE_FIELDS, L);
|
|
65594
|
+
const serving = raw.serving;
|
|
65595
|
+
if (role === "serving") {
|
|
65596
|
+
if (serving !== void 0) {
|
|
65597
|
+
throw new ProtocolError3(`${L}.serving: must be absent when role is serving`);
|
|
65598
|
+
}
|
|
65599
|
+
return { type: BRIDGE_ROLE_FRAME, role, canServe };
|
|
65600
|
+
}
|
|
65601
|
+
if (serving === void 0) {
|
|
65602
|
+
throw new ProtocolError3(`${L}.serving: required when role is standby`);
|
|
65603
|
+
}
|
|
65604
|
+
assertObject(serving, `${L}.serving`);
|
|
65605
|
+
const label = serving.label;
|
|
65606
|
+
assertDisplayString(label, `${L}.serving.label`, 1, BRIDGE_ROLE_LABEL_MAX);
|
|
65607
|
+
const since = serving.since;
|
|
65608
|
+
if (typeof since !== "number" || !Number.isSafeInteger(since) || since < 0) {
|
|
65609
|
+
throw new ProtocolError3(`${L}.serving.since: expected non-negative safe integer (Unix ms)`);
|
|
65610
|
+
}
|
|
65611
|
+
assertExactFields(serving, BRIDGE_ROLE_SERVING_FIELDS, `${L}.serving`);
|
|
65612
|
+
return {
|
|
65613
|
+
type: BRIDGE_ROLE_FRAME,
|
|
65614
|
+
role,
|
|
65615
|
+
canServe,
|
|
65616
|
+
serving: { label, since }
|
|
65617
|
+
};
|
|
65618
|
+
}
|
|
65376
65619
|
function validateInnerFrame(raw) {
|
|
65377
65620
|
assertObject(raw, "inner");
|
|
65378
65621
|
const t = raw.type;
|
|
@@ -65840,10 +66083,10 @@ function validateInnerResponse(raw) {
|
|
|
65840
66083
|
}
|
|
65841
66084
|
|
|
65842
66085
|
// node_modules/@fetchproxy/protocol/dist/pair-code.js
|
|
65843
|
-
var
|
|
66086
|
+
var enc3 = new TextEncoder();
|
|
65844
66087
|
var PAIR_LABEL = "fetchproxy/4/pair";
|
|
65845
66088
|
async function pairTranscript(mcpIdentityPub, extIdentityPub, mcpNonce, extNonce, mcpSessionPub) {
|
|
65846
|
-
const label =
|
|
66089
|
+
const label = enc3.encode(PAIR_LABEL);
|
|
65847
66090
|
const parts = [mcpIdentityPub, extIdentityPub, mcpNonce, extNonce, mcpSessionPub];
|
|
65848
66091
|
const out = new Uint8Array(label.length + 1 + parts.reduce((n, p) => n + p.length, 0));
|
|
65849
66092
|
out.set(label, 0);
|
|
@@ -65864,7 +66107,7 @@ function digits(hash2) {
|
|
|
65864
66107
|
}
|
|
65865
66108
|
|
|
65866
66109
|
// node_modules/@fetchproxy/protocol/dist/seal.js
|
|
65867
|
-
var
|
|
66110
|
+
var enc4 = new TextEncoder();
|
|
65868
66111
|
var dec = new TextDecoder();
|
|
65869
66112
|
function randomIv() {
|
|
65870
66113
|
const iv = new Uint8Array(12);
|
|
@@ -65877,14 +66120,14 @@ function base64Length(byteLength) {
|
|
|
65877
66120
|
return Math.ceil(byteLength / 3) * 4;
|
|
65878
66121
|
}
|
|
65879
66122
|
function encodeInnerFrame(inner) {
|
|
65880
|
-
return
|
|
66123
|
+
return enc4.encode(JSON.stringify(inner));
|
|
65881
66124
|
}
|
|
65882
66125
|
function plaintextOf(inner) {
|
|
65883
66126
|
return inner instanceof Uint8Array ? inner : encodeInnerFrame(inner);
|
|
65884
66127
|
}
|
|
65885
66128
|
function sealedFrameWireBytes(mcpId, seq, inner) {
|
|
65886
66129
|
const plaintext = plaintextOf(inner).length;
|
|
65887
|
-
const envelope =
|
|
66130
|
+
const envelope = enc4.encode(JSON.stringify({ type: "frame", mcpId, seq, iv: "", ciphertext: "" })).length;
|
|
65888
66131
|
return envelope + IV_B64_BYTES + base64Length(plaintext + AES_GCM_TAG_BYTES);
|
|
65889
66132
|
}
|
|
65890
66133
|
var MAX_FRAME_BYTES = 42 * 1024 * 1024;
|
|
@@ -66224,14 +66467,23 @@ var FetchproxyHelloRejectedError = class extends Error {
|
|
|
66224
66467
|
platform;
|
|
66225
66468
|
/**
|
|
66226
66469
|
* #418: the remedy, when the reason is one this package knows how to
|
|
66227
|
-
* explain —
|
|
66228
|
-
*
|
|
66470
|
+
* explain — `unsupported-capability`, which blames the browser rather than
|
|
66471
|
+
* the MCP, and (D12) `awaiting-approval`, which says to approve in the
|
|
66472
|
+
* browser. `null` otherwise.
|
|
66229
66473
|
*/
|
|
66230
66474
|
hint;
|
|
66475
|
+
/**
|
|
66476
|
+
* D12: `true` only for an `awaiting-approval:` refusal — the extension has
|
|
66477
|
+
* queued an approval card and nobody is at the browser yet, so the same call
|
|
66478
|
+
* succeeds once the person approves. Every other refusal is the extension's
|
|
66479
|
+
* final answer, and retrying unchanged is refused the same way.
|
|
66480
|
+
*/
|
|
66481
|
+
retryable;
|
|
66231
66482
|
constructor(info) {
|
|
66232
66483
|
const unavailable = parseUnsupportedCapabilityReason(info.reason);
|
|
66484
|
+
const awaiting = parseAwaitingApprovalReason(info.reason);
|
|
66233
66485
|
const platform = info.platform ?? null;
|
|
66234
|
-
const hint = unavailable !== null ? `${platform ? `this browser (${platform})` : "this browser"} cannot serve any of the capabilities this MCP needs (${unavailable.join(", ")}) \u2014 ContextMint Bridge checked for the browser APIs and they are missing. Nothing is wrong with the MCP or your pairing, and updating will not change it: use this MCP from a browser that provides them (for example Chrome).` : null;
|
|
66486
|
+
const hint = awaiting !== null ? `The extension is waiting for you to approve this MCP` + (awaiting !== "" ? ` (${awaiting})` : "") + ` \u2014 open ContextMint Bridge in your browser, approve it there, then retry. Nothing is wrong with the MCP or your sign-in.` : unavailable !== null ? `${platform ? `this browser (${platform})` : "this browser"} cannot serve any of the capabilities this MCP needs (${unavailable.join(", ")}) \u2014 ContextMint Bridge checked for the browser APIs and they are missing. Nothing is wrong with the MCP or your pairing, and updating will not change it: use this MCP from a browser that provides them (for example Chrome).` : null;
|
|
66235
66487
|
super(`fetchproxy: the extension refused the connection for "${info.mcpId}": ${info.reason}. ` + (hint !== null ? hint : `This is the extension's own reason \u2014 it is not a timeout, and retrying unchanged will be refused the same way.`));
|
|
66236
66488
|
this.name = "FetchproxyHelloRejectedError";
|
|
66237
66489
|
this.mcpId = info.mcpId;
|
|
@@ -66239,6 +66491,7 @@ var FetchproxyHelloRejectedError = class extends Error {
|
|
|
66239
66491
|
this.unavailableCapabilities = unavailable ?? [];
|
|
66240
66492
|
this.platform = platform;
|
|
66241
66493
|
this.hint = hint;
|
|
66494
|
+
this.retryable = awaiting !== null;
|
|
66242
66495
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
66243
66496
|
}
|
|
66244
66497
|
};
|
|
@@ -66791,7 +67044,7 @@ function originVerdict(origin, allowLocal) {
|
|
|
66791
67044
|
}
|
|
66792
67045
|
var HANDSHAKE_TIMEOUT_MS = 15e3;
|
|
66793
67046
|
var MAX_PAYLOAD_BYTES = MAX_FRAME_BYTES;
|
|
66794
|
-
var
|
|
67047
|
+
var enc5 = new TextEncoder();
|
|
66795
67048
|
var OWN_DECRYPT_FAILURES_BEFORE_REHANDSHAKE = 3;
|
|
66796
67049
|
async function startHost(opts) {
|
|
66797
67050
|
const allowLocalOrigins = envAllowsLocalOrigins();
|
|
@@ -66862,10 +67115,20 @@ async function startHost(opts) {
|
|
|
66862
67115
|
let resolveOwnSession;
|
|
66863
67116
|
let rejectOwnSession;
|
|
66864
67117
|
let ownSessionReady;
|
|
67118
|
+
let ownRetryableRefusal = false;
|
|
67119
|
+
let ownSessionSettled = false;
|
|
66865
67120
|
function resetSessionPromise() {
|
|
67121
|
+
ownRetryableRefusal = false;
|
|
67122
|
+
ownSessionSettled = false;
|
|
66866
67123
|
ownSessionReady = new Promise((resolve2, reject) => {
|
|
66867
|
-
resolveOwnSession =
|
|
66868
|
-
|
|
67124
|
+
resolveOwnSession = (st) => {
|
|
67125
|
+
ownSessionSettled = true;
|
|
67126
|
+
resolve2(st);
|
|
67127
|
+
};
|
|
67128
|
+
rejectOwnSession = (e) => {
|
|
67129
|
+
ownSessionSettled = true;
|
|
67130
|
+
reject(e);
|
|
67131
|
+
};
|
|
66869
67132
|
});
|
|
66870
67133
|
ownSessionReady.catch(() => {
|
|
66871
67134
|
});
|
|
@@ -67132,13 +67395,15 @@ async function startHost(opts) {
|
|
|
67132
67395
|
const extPub = fromB64(frame.extensionSessionPub);
|
|
67133
67396
|
const shared = await ecdhX25519(held.priv, extPub);
|
|
67134
67397
|
const salt = await transcriptHash(held.nonce, extNonce, held.pub, extPub);
|
|
67135
|
-
const key = await hkdfSha256(shared, salt,
|
|
67398
|
+
const key = await hkdfSha256(shared, salt, enc5.encode(HKDF_SESSION_INFO), 32);
|
|
67136
67399
|
if (extensionWs !== ws)
|
|
67137
67400
|
return;
|
|
67138
67401
|
ownSession = new SessionState(key);
|
|
67139
67402
|
ownSessionInfo = sessionInfoFromHello(verifiedHello);
|
|
67140
67403
|
ownDecryptFailures = 0;
|
|
67141
67404
|
ownPendingPairCode = null;
|
|
67405
|
+
if (ownRetryableRefusal)
|
|
67406
|
+
resetSessionPromise();
|
|
67142
67407
|
resolveOwnSession(ownSession);
|
|
67143
67408
|
} else {
|
|
67144
67409
|
const slot = peers.get(frame.mcpId);
|
|
@@ -67207,11 +67472,17 @@ async function startHost(opts) {
|
|
|
67207
67472
|
}
|
|
67208
67473
|
if (frame.type === "hello-rejected" && identified === "extension") {
|
|
67209
67474
|
if (frame.mcpId === opts.ownMcpId) {
|
|
67210
|
-
|
|
67475
|
+
const refusal = new FetchproxyHelloRejectedError({
|
|
67211
67476
|
mcpId: frame.mcpId,
|
|
67212
67477
|
reason: frame.reason,
|
|
67213
67478
|
platform: extensionHello?.platform ?? null
|
|
67214
|
-
})
|
|
67479
|
+
});
|
|
67480
|
+
if (ownRetryableRefusal)
|
|
67481
|
+
resetSessionPromise();
|
|
67482
|
+
const settlesPending = !ownSessionSettled;
|
|
67483
|
+
rejectOwnSession(refusal);
|
|
67484
|
+
if (refusal.retryable && settlesPending)
|
|
67485
|
+
ownRetryableRefusal = true;
|
|
67215
67486
|
} else {
|
|
67216
67487
|
const slot = peers.get(frame.mcpId);
|
|
67217
67488
|
if (slot?.helloFrame.accepts?.includes("hello-rejected")) {
|
|
@@ -67327,7 +67598,7 @@ async function startHost(opts) {
|
|
|
67327
67598
|
|
|
67328
67599
|
// node_modules/@fetchproxy/server/dist/peer.js
|
|
67329
67600
|
var PEER_DIAL_TIMEOUT_MS = 5e3;
|
|
67330
|
-
var
|
|
67601
|
+
var enc6 = new TextEncoder();
|
|
67331
67602
|
function notSentError() {
|
|
67332
67603
|
return new Error("fetchproxy: request not sent \u2014 the connection to the bridge host closed before it went out, so nothing reached the browser. It is safe to retry.");
|
|
67333
67604
|
}
|
|
@@ -67427,7 +67698,9 @@ async function startPeer(opts) {
|
|
|
67427
67698
|
let rejectFirstReady;
|
|
67428
67699
|
let sessionPromise;
|
|
67429
67700
|
let sessionPromiseSettled = false;
|
|
67701
|
+
let retryableRefusal = false;
|
|
67430
67702
|
function resetSessionPromise() {
|
|
67703
|
+
retryableRefusal = false;
|
|
67431
67704
|
sessionPromiseSettled = false;
|
|
67432
67705
|
sessionPromise = new Promise((resolve2, reject) => {
|
|
67433
67706
|
resolveFirstReady = (st) => {
|
|
@@ -67524,6 +67797,8 @@ async function startPeer(opts) {
|
|
|
67524
67797
|
raw = JSON.parse(data.toString());
|
|
67525
67798
|
const frame = validateFrame(raw);
|
|
67526
67799
|
if (frame.type === "hello" && frame.role === "extension") {
|
|
67800
|
+
if (retryableRefusal)
|
|
67801
|
+
resetSessionPromise();
|
|
67527
67802
|
extensionHello = frame;
|
|
67528
67803
|
const mintedKeypair = await generateSessionKeypair();
|
|
67529
67804
|
const mintedHello = await buildServerHello({
|
|
@@ -67553,6 +67828,8 @@ async function startPeer(opts) {
|
|
|
67553
67828
|
session = null;
|
|
67554
67829
|
if (sessionPromiseSettled)
|
|
67555
67830
|
resetSessionPromise();
|
|
67831
|
+
} else if (retryableRefusal) {
|
|
67832
|
+
resetSessionPromise();
|
|
67556
67833
|
}
|
|
67557
67834
|
extensionDisconnectListeners.forEach((cb) => cb());
|
|
67558
67835
|
return;
|
|
@@ -67574,7 +67851,7 @@ async function startPeer(opts) {
|
|
|
67574
67851
|
const extNonce = fromB64(authenticated.sessionNonce);
|
|
67575
67852
|
const shared = await ecdhX25519(held.priv, extPub);
|
|
67576
67853
|
const salt = await transcriptHash(held.nonce, extNonce, held.pub, extPub);
|
|
67577
|
-
const sessionKey = await hkdfSha256(shared, salt,
|
|
67854
|
+
const sessionKey = await hkdfSha256(shared, salt, enc6.encode(HKDF_SESSION_INFO), 32);
|
|
67578
67855
|
if (sessionEphemeral !== held) {
|
|
67579
67856
|
console.warn(`[fetchproxy] ${opts.serverName}: dropping a session derived against an ephemeral that was superseded while it was being derived`);
|
|
67580
67857
|
return;
|
|
@@ -67587,16 +67864,24 @@ async function startPeer(opts) {
|
|
|
67587
67864
|
if (isRenegotiation) {
|
|
67588
67865
|
renegotiateListeners.forEach((cb) => cb());
|
|
67589
67866
|
} else {
|
|
67867
|
+
if (retryableRefusal)
|
|
67868
|
+
resetSessionPromise();
|
|
67590
67869
|
resolveFirstReady(session);
|
|
67591
67870
|
}
|
|
67592
67871
|
return;
|
|
67593
67872
|
}
|
|
67594
67873
|
if (frame.type === "hello-rejected" && frame.mcpId === opts.mcpId) {
|
|
67595
|
-
|
|
67874
|
+
const refusal = new FetchproxyHelloRejectedError({
|
|
67596
67875
|
mcpId: frame.mcpId,
|
|
67597
67876
|
reason: frame.reason,
|
|
67598
67877
|
platform: extensionHello?.platform ?? null
|
|
67599
|
-
})
|
|
67878
|
+
});
|
|
67879
|
+
if (retryableRefusal)
|
|
67880
|
+
resetSessionPromise();
|
|
67881
|
+
const settlesPending = !sessionPromiseSettled;
|
|
67882
|
+
rejectFirstReady(refusal);
|
|
67883
|
+
if (refusal.retryable && settlesPending)
|
|
67884
|
+
retryableRefusal = true;
|
|
67600
67885
|
}
|
|
67601
67886
|
if (frame.type === "pair-pending" && frame.mcpId === opts.mcpId) {
|
|
67602
67887
|
const hello2 = extensionHello;
|
|
@@ -67760,8 +68045,9 @@ function classifyFetchError(error62, code2) {
|
|
|
67760
68045
|
|
|
67761
68046
|
// node_modules/@fetchproxy/server/dist/classify-bridge-error.js
|
|
67762
68047
|
function classifyBridgeError(err) {
|
|
67763
|
-
if (err instanceof FetchproxyHelloRejectedError)
|
|
67764
|
-
return "hello_rejected";
|
|
68048
|
+
if (err instanceof FetchproxyHelloRejectedError) {
|
|
68049
|
+
return err.retryable ? "awaiting_approval" : "hello_rejected";
|
|
68050
|
+
}
|
|
67765
68051
|
if (err instanceof FetchproxySessionNotReadyError)
|
|
67766
68052
|
return "session_not_ready";
|
|
67767
68053
|
if (err instanceof FetchproxyTimeoutError)
|
|
@@ -75968,7 +76254,7 @@ function registerVisitTools(server, client2, patients2) {
|
|
|
75968
76254
|
}
|
|
75969
76255
|
|
|
75970
76256
|
// src/version.ts
|
|
75971
|
-
var VERSION = "1.3.
|
|
76257
|
+
var VERSION = "1.3.5";
|
|
75972
76258
|
|
|
75973
76259
|
// src/index.ts
|
|
75974
76260
|
var dotenvCandidates = [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrischall/myatriumhealth-mcp",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.5",
|
|
4
4
|
"description": "MCP server for MyAtriumHealth (Atrium Health's Epic MyChart patient portal) via the fetchproxy browser bridge.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"access": "public"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@chrischall/mcp-utils": "^2.
|
|
46
|
-
"@fetchproxy/server": "^3.
|
|
45
|
+
"@chrischall/mcp-utils": "^2.15.0",
|
|
46
|
+
"@fetchproxy/server": "^3.6.0",
|
|
47
47
|
"@modelcontextprotocol/server": "^2.3.0",
|
|
48
48
|
"dotenv": "^18.0.1",
|
|
49
49
|
"node-html-parser": "^9.0.3",
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/chrischall/myatriumhealth-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "1.3.
|
|
9
|
+
"version": "1.3.5",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@chrischall/myatriumhealth-mcp",
|
|
14
|
-
"version": "1.3.
|
|
14
|
+
"version": "1.3.5",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|