zola-mcp 1.1.3 → 1.2.3
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 +22 -0
- package/dist/bundle.js +372 -81
- package/dist/index.js +1 -1
- package/package.json +6 -6
- package/server.json +2 -2
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"metadata": {
|
|
9
9
|
"description": "Zola wedding planning tools for Claude Code",
|
|
10
|
-
"version": "1.
|
|
10
|
+
"version": "1.2.3"
|
|
11
11
|
},
|
|
12
12
|
"plugins": [
|
|
13
13
|
{
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"displayName": "Zola",
|
|
16
16
|
"source": "./",
|
|
17
17
|
"description": "Zola wedding planning tools for Claude — vendors, budget, guests, seating, events, registry, inquiries, and more via MCP",
|
|
18
|
-
"version": "1.
|
|
18
|
+
"version": "1.2.3",
|
|
19
19
|
"author": {
|
|
20
20
|
"name": "Chris Chall"
|
|
21
21
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zola",
|
|
3
3
|
"displayName": "Zola",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.3",
|
|
5
5
|
"description": "Zola wedding planning tools for Claude — vendors, budget, guests, seating, events, registry, inquiries, and more via MCP",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Chris Chall",
|
package/README.md
CHANGED
|
@@ -25,6 +25,28 @@ Ask Claude things like:
|
|
|
25
25
|
- A [Zola](https://www.zola.com) account
|
|
26
26
|
- For the no-env-var path: the [fetchproxy 0.3.0 Chrome / Safari extension](https://github.com/chrischall/fetchproxy)
|
|
27
27
|
|
|
28
|
+
## Acknowledgement of Terms
|
|
29
|
+
|
|
30
|
+
By using this MCP server, you acknowledge and agree to the following:
|
|
31
|
+
|
|
32
|
+
**1. This server accesses your own Zola account.** Auth happens via your own credentials. It does not — and cannot — access anyone else's wedding website, registry, or guest list.
|
|
33
|
+
|
|
34
|
+
**2. [Zola's Terms of Use](https://www.zola.com/terms) govern your use of this server**, just as they govern your direct use of zola.com. The clauses most relevant here:
|
|
35
|
+
|
|
36
|
+
> [You may not use] any hardware or software intended to surreptitiously intercept or otherwise obtain any information… including but not limited to the use of any "scraping" or other data mining techniques, robots or similar data gathering and extraction tools.
|
|
37
|
+
|
|
38
|
+
And, critically, on agent-acting-as-you: *"You are responsible for maintaining the confidentiality of your account and password… You accept full responsibility for all activities that occur under your account and password, **even if such actions are undertaken by your Authorized Agent or other third party**."*
|
|
39
|
+
|
|
40
|
+
You are agreeing to those terms — read by the maintainer 2026-05-23 — every time you invoke a tool in this server. Zola's ToU is explicit: this MCP acting as your Authorized Agent counts as you.
|
|
41
|
+
|
|
42
|
+
**3. Personal, non-commercial use only.** This project is not affiliated with, endorsed by, sponsored by, or in partnership with Zola, Inc. It is a personal automation tool for one couple to manage their own wedding website, registry, vendor research, and guest list. Do not use it to bulk-extract Zola's vendor directory, scrape registries, or compete with Zola.
|
|
43
|
+
|
|
44
|
+
**4. Stability is not guaranteed.** This server may call internal Zola endpoints that change without notice. It may break.
|
|
45
|
+
|
|
46
|
+
**5. You accept full responsibility** for any consequences of using this server in connection with your Zola account — rate limiting, account warnings, suspension, or any enforcement action. Per Zola's ToU, anything this MCP does under your account is your action — review guest list edits, registry changes, and inquiries before confirming. If Zola objects to your use, stop using this server.
|
|
47
|
+
|
|
48
|
+
This section is the maintainer's good-faith summary of the terms — it is not legal advice and does not modify or supersede Zola's actual ToU.
|
|
49
|
+
|
|
28
50
|
## Installation
|
|
29
51
|
|
|
30
52
|
### Option A — MCPB (recommended)
|
package/dist/bundle.js
CHANGED
|
@@ -7571,6 +7571,10 @@ var require_receiver = __commonJS({
|
|
|
7571
7571
|
* extensions
|
|
7572
7572
|
* @param {Boolean} [options.isServer=false] Specifies whether to operate in
|
|
7573
7573
|
* client or server mode
|
|
7574
|
+
* @param {Number} [options.maxBufferedChunks=0] The maximum number of
|
|
7575
|
+
* buffered data chunks
|
|
7576
|
+
* @param {Number} [options.maxFragments=0] The maximum number of message
|
|
7577
|
+
* fragments
|
|
7574
7578
|
* @param {Number} [options.maxPayload=0] The maximum allowed message length
|
|
7575
7579
|
* @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
|
|
7576
7580
|
* not to skip UTF-8 validation for text and close messages
|
|
@@ -7581,6 +7585,8 @@ var require_receiver = __commonJS({
|
|
|
7581
7585
|
this._binaryType = options.binaryType || BINARY_TYPES[0];
|
|
7582
7586
|
this._extensions = options.extensions || {};
|
|
7583
7587
|
this._isServer = !!options.isServer;
|
|
7588
|
+
this._maxBufferedChunks = options.maxBufferedChunks | 0;
|
|
7589
|
+
this._maxFragments = options.maxFragments | 0;
|
|
7584
7590
|
this._maxPayload = options.maxPayload | 0;
|
|
7585
7591
|
this._skipUTF8Validation = !!options.skipUTF8Validation;
|
|
7586
7592
|
this[kWebSocket] = void 0;
|
|
@@ -7610,6 +7616,18 @@ var require_receiver = __commonJS({
|
|
|
7610
7616
|
*/
|
|
7611
7617
|
_write(chunk, encoding, cb) {
|
|
7612
7618
|
if (this._opcode === 8 && this._state == GET_INFO) return cb();
|
|
7619
|
+
if (this._maxBufferedChunks > 0 && this._buffers.length >= this._maxBufferedChunks) {
|
|
7620
|
+
cb(
|
|
7621
|
+
this.createError(
|
|
7622
|
+
RangeError,
|
|
7623
|
+
"Too many buffered chunks",
|
|
7624
|
+
false,
|
|
7625
|
+
1008,
|
|
7626
|
+
"WS_ERR_TOO_MANY_BUFFERED_PARTS"
|
|
7627
|
+
)
|
|
7628
|
+
);
|
|
7629
|
+
return;
|
|
7630
|
+
}
|
|
7613
7631
|
this._bufferedBytes += chunk.length;
|
|
7614
7632
|
this._buffers.push(chunk);
|
|
7615
7633
|
this.startLoop(cb);
|
|
@@ -7939,6 +7957,17 @@ var require_receiver = __commonJS({
|
|
|
7939
7957
|
return;
|
|
7940
7958
|
}
|
|
7941
7959
|
if (data.length) {
|
|
7960
|
+
if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
|
|
7961
|
+
const error48 = this.createError(
|
|
7962
|
+
RangeError,
|
|
7963
|
+
"Too many message fragments",
|
|
7964
|
+
false,
|
|
7965
|
+
1008,
|
|
7966
|
+
"WS_ERR_TOO_MANY_BUFFERED_PARTS"
|
|
7967
|
+
);
|
|
7968
|
+
cb(error48);
|
|
7969
|
+
return;
|
|
7970
|
+
}
|
|
7942
7971
|
this._messageLength = this._totalPayloadLength;
|
|
7943
7972
|
this._fragments.push(data);
|
|
7944
7973
|
}
|
|
@@ -7968,6 +7997,17 @@ var require_receiver = __commonJS({
|
|
|
7968
7997
|
cb(error48);
|
|
7969
7998
|
return;
|
|
7970
7999
|
}
|
|
8000
|
+
if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
|
|
8001
|
+
const error48 = this.createError(
|
|
8002
|
+
RangeError,
|
|
8003
|
+
"Too many message fragments",
|
|
8004
|
+
false,
|
|
8005
|
+
1008,
|
|
8006
|
+
"WS_ERR_TOO_MANY_BUFFERED_PARTS"
|
|
8007
|
+
);
|
|
8008
|
+
cb(error48);
|
|
8009
|
+
return;
|
|
8010
|
+
}
|
|
7971
8011
|
this._fragments.push(buf);
|
|
7972
8012
|
}
|
|
7973
8013
|
this.dataMessage(cb);
|
|
@@ -9174,6 +9214,10 @@ var require_websocket = __commonJS({
|
|
|
9174
9214
|
* multiple times in the same tick
|
|
9175
9215
|
* @param {Function} [options.generateMask] The function used to generate the
|
|
9176
9216
|
* masking key
|
|
9217
|
+
* @param {Number} [options.maxBufferedChunks=0] The maximum number of
|
|
9218
|
+
* buffered data chunks
|
|
9219
|
+
* @param {Number} [options.maxFragments=0] The maximum number of message
|
|
9220
|
+
* fragments
|
|
9177
9221
|
* @param {Number} [options.maxPayload=0] The maximum allowed message size
|
|
9178
9222
|
* @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
|
|
9179
9223
|
* not to skip UTF-8 validation for text and close messages
|
|
@@ -9185,6 +9229,8 @@ var require_websocket = __commonJS({
|
|
|
9185
9229
|
binaryType: this.binaryType,
|
|
9186
9230
|
extensions: this._extensions,
|
|
9187
9231
|
isServer: this._isServer,
|
|
9232
|
+
maxBufferedChunks: options.maxBufferedChunks,
|
|
9233
|
+
maxFragments: options.maxFragments,
|
|
9188
9234
|
maxPayload: options.maxPayload,
|
|
9189
9235
|
skipUTF8Validation: options.skipUTF8Validation
|
|
9190
9236
|
});
|
|
@@ -9484,6 +9530,8 @@ var require_websocket = __commonJS({
|
|
|
9484
9530
|
autoPong: true,
|
|
9485
9531
|
closeTimeout: CLOSE_TIMEOUT,
|
|
9486
9532
|
protocolVersion: protocolVersions[1],
|
|
9533
|
+
maxBufferedChunks: 1024 * 1024,
|
|
9534
|
+
maxFragments: 128 * 1024,
|
|
9487
9535
|
maxPayload: 100 * 1024 * 1024,
|
|
9488
9536
|
skipUTF8Validation: false,
|
|
9489
9537
|
perMessageDeflate: true,
|
|
@@ -9726,6 +9774,8 @@ var require_websocket = __commonJS({
|
|
|
9726
9774
|
websocket.setSocket(socket, head, {
|
|
9727
9775
|
allowSynchronousEvents: opts.allowSynchronousEvents,
|
|
9728
9776
|
generateMask: opts.generateMask,
|
|
9777
|
+
maxBufferedChunks: opts.maxBufferedChunks,
|
|
9778
|
+
maxFragments: opts.maxFragments,
|
|
9729
9779
|
maxPayload: opts.maxPayload,
|
|
9730
9780
|
skipUTF8Validation: opts.skipUTF8Validation
|
|
9731
9781
|
});
|
|
@@ -10068,6 +10118,10 @@ var require_websocket_server = __commonJS({
|
|
|
10068
10118
|
* called
|
|
10069
10119
|
* @param {Function} [options.handleProtocols] A hook to handle protocols
|
|
10070
10120
|
* @param {String} [options.host] The hostname where to bind the server
|
|
10121
|
+
* @param {Number} [options.maxBufferedChunks=1048576] The maximum number of
|
|
10122
|
+
* buffered data chunks
|
|
10123
|
+
* @param {Number} [options.maxFragments=131072] The maximum number of message
|
|
10124
|
+
* fragments
|
|
10071
10125
|
* @param {Number} [options.maxPayload=104857600] The maximum allowed message
|
|
10072
10126
|
* size
|
|
10073
10127
|
* @param {Boolean} [options.noServer=false] Enable no server mode
|
|
@@ -10089,6 +10143,8 @@ var require_websocket_server = __commonJS({
|
|
|
10089
10143
|
options = {
|
|
10090
10144
|
allowSynchronousEvents: true,
|
|
10091
10145
|
autoPong: true,
|
|
10146
|
+
maxBufferedChunks: 1024 * 1024,
|
|
10147
|
+
maxFragments: 128 * 1024,
|
|
10092
10148
|
maxPayload: 100 * 1024 * 1024,
|
|
10093
10149
|
skipUTF8Validation: false,
|
|
10094
10150
|
perMessageDeflate: false,
|
|
@@ -10368,6 +10424,8 @@ var require_websocket_server = __commonJS({
|
|
|
10368
10424
|
socket.removeListener("error", socketOnError);
|
|
10369
10425
|
ws.setSocket(socket, head, {
|
|
10370
10426
|
allowSynchronousEvents: this.options.allowSynchronousEvents,
|
|
10427
|
+
maxBufferedChunks: this.options.maxBufferedChunks,
|
|
10428
|
+
maxFragments: this.options.maxFragments,
|
|
10371
10429
|
maxPayload: this.options.maxPayload,
|
|
10372
10430
|
skipUTF8Validation: this.options.skipUTF8Validation
|
|
10373
10431
|
});
|
|
@@ -33746,6 +33804,7 @@ import { fileURLToPath } from "url";
|
|
|
33746
33804
|
|
|
33747
33805
|
// node_modules/@fetchproxy/protocol/dist/frames.js
|
|
33748
33806
|
var PROTOCOL_VERSION = 2;
|
|
33807
|
+
var HKDF_SESSION_INFO = "fetchproxy/1.0.0/session";
|
|
33749
33808
|
var KNOWN_CAPABILITIES = /* @__PURE__ */ new Set([
|
|
33750
33809
|
"fetch",
|
|
33751
33810
|
"read_cookies",
|
|
@@ -33820,7 +33879,7 @@ var ProtocolError = class extends Error {
|
|
|
33820
33879
|
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
33821
33880
|
var BASE64_RE = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
33822
33881
|
var SCOPE_KEY_RE = /^[A-Za-z0-9_.\-]{1,256}$/;
|
|
33823
|
-
var SCOPE_KEY_GLOB_RE = /^[A-Za-z0-9_.\-]{1,
|
|
33882
|
+
var SCOPE_KEY_GLOB_RE = /^[A-Za-z0-9_.\-]{1,256}\*?$/;
|
|
33824
33883
|
var HEADER_NAME_RE = /^[A-Za-z0-9_\-]{1,128}$/;
|
|
33825
33884
|
var HOSTNAME_RE = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+$/i;
|
|
33826
33885
|
function assertObject(x, label) {
|
|
@@ -33949,7 +34008,7 @@ function assertStoragePointersArray(value, label, declaredKeys) {
|
|
|
33949
34008
|
if (entry.jsonPointer === void 0) {
|
|
33950
34009
|
throw new ProtocolError(`${label}[${i}].jsonPointer: missing`);
|
|
33951
34010
|
}
|
|
33952
|
-
if (typeof entry.key !== "string" || !
|
|
34011
|
+
if (typeof entry.key !== "string" || !SCOPE_KEY_RE.test(entry.key)) {
|
|
33953
34012
|
throw new ProtocolError(`${label}[${i}].key: invalid key ${JSON.stringify(entry.key)}`);
|
|
33954
34013
|
}
|
|
33955
34014
|
if (typeof entry.jsonPointer !== "string" || !isValidJsonPointer(entry.jsonPointer)) {
|
|
@@ -34048,6 +34107,8 @@ function validateFrame(raw) {
|
|
|
34048
34107
|
return validateReady(raw);
|
|
34049
34108
|
if (t === "frame")
|
|
34050
34109
|
return validateEncrypted(raw);
|
|
34110
|
+
if (t === "pair-pending")
|
|
34111
|
+
return validatePairPending(raw);
|
|
34051
34112
|
throw new ProtocolError(`unknown frame type: ${String(t)}`);
|
|
34052
34113
|
}
|
|
34053
34114
|
function validateHello(raw) {
|
|
@@ -34149,6 +34210,17 @@ function validateEncrypted(raw) {
|
|
|
34149
34210
|
assertBase64(raw.ciphertext, "frame.ciphertext");
|
|
34150
34211
|
return raw;
|
|
34151
34212
|
}
|
|
34213
|
+
var PAIR_CODE_RE = /^\d{3}-\d{3}$/;
|
|
34214
|
+
function validatePairPending(raw) {
|
|
34215
|
+
assertString(raw.mcpId, "pair-pending.mcpId");
|
|
34216
|
+
if (!isValidMcpId(raw.mcpId))
|
|
34217
|
+
throw new ProtocolError("pair-pending.mcpId: invalid format");
|
|
34218
|
+
assertString(raw.pairCode, "pair-pending.pairCode");
|
|
34219
|
+
if (!PAIR_CODE_RE.test(raw.pairCode)) {
|
|
34220
|
+
throw new ProtocolError(`pair-pending.pairCode: must match XXX-XXX, got ${String(raw.pairCode)}`);
|
|
34221
|
+
}
|
|
34222
|
+
return { type: "pair-pending", mcpId: raw.mcpId, pairCode: raw.pairCode };
|
|
34223
|
+
}
|
|
34152
34224
|
function validateInnerFrame(raw) {
|
|
34153
34225
|
assertObject(raw, "inner");
|
|
34154
34226
|
const t = raw.type;
|
|
@@ -34731,15 +34803,22 @@ async function startHost(opts) {
|
|
|
34731
34803
|
let extensionWs = null;
|
|
34732
34804
|
const peers = /* @__PURE__ */ new Map();
|
|
34733
34805
|
const ownInnerListeners = [];
|
|
34806
|
+
const disconnectListeners = [];
|
|
34807
|
+
const pendingPairListeners = [];
|
|
34734
34808
|
let ownSession = null;
|
|
34809
|
+
let ownPendingPairCode = null;
|
|
34735
34810
|
let resolveOwnSession;
|
|
34736
34811
|
let rejectOwnSession;
|
|
34737
|
-
|
|
34738
|
-
|
|
34739
|
-
|
|
34740
|
-
|
|
34741
|
-
|
|
34742
|
-
|
|
34812
|
+
let ownSessionReady;
|
|
34813
|
+
function resetSessionPromise() {
|
|
34814
|
+
ownSessionReady = new Promise((resolve, reject) => {
|
|
34815
|
+
resolveOwnSession = resolve;
|
|
34816
|
+
rejectOwnSession = reject;
|
|
34817
|
+
});
|
|
34818
|
+
ownSessionReady.catch(() => {
|
|
34819
|
+
});
|
|
34820
|
+
}
|
|
34821
|
+
resetSessionPromise();
|
|
34743
34822
|
let extensionHello = null;
|
|
34744
34823
|
wss.on("connection", (ws) => {
|
|
34745
34824
|
let identified = null;
|
|
@@ -34808,11 +34887,12 @@ async function startHost(opts) {
|
|
|
34808
34887
|
}
|
|
34809
34888
|
const extPub = fromB64(frame.extensionSessionPub);
|
|
34810
34889
|
const shared = await ecdhX25519(opts.ownIdentity.x25519Priv, extPub);
|
|
34811
|
-
const key = await hkdfSha256(shared, ownSessionNonce, enc2.encode(
|
|
34812
|
-
if (
|
|
34813
|
-
|
|
34814
|
-
|
|
34815
|
-
|
|
34890
|
+
const key = await hkdfSha256(shared, ownSessionNonce, enc2.encode(HKDF_SESSION_INFO), 32);
|
|
34891
|
+
if (extensionWs !== ws)
|
|
34892
|
+
return;
|
|
34893
|
+
ownSession = new SessionState(key);
|
|
34894
|
+
ownPendingPairCode = null;
|
|
34895
|
+
resolveOwnSession(ownSession);
|
|
34816
34896
|
} else {
|
|
34817
34897
|
const slot = peers.get(frame.mcpId);
|
|
34818
34898
|
if (slot)
|
|
@@ -34839,6 +34919,16 @@ async function startHost(opts) {
|
|
|
34839
34919
|
extensionWs.send(JSON.stringify(frame));
|
|
34840
34920
|
}
|
|
34841
34921
|
}
|
|
34922
|
+
if (frame.type === "pair-pending" && identified === "extension") {
|
|
34923
|
+
if (frame.mcpId === opts.ownMcpId) {
|
|
34924
|
+
ownPendingPairCode = frame.pairCode;
|
|
34925
|
+
pendingPairListeners.forEach((cb) => cb(frame.pairCode));
|
|
34926
|
+
} else {
|
|
34927
|
+
const slot = peers.get(frame.mcpId);
|
|
34928
|
+
if (slot)
|
|
34929
|
+
slot.ws.send(JSON.stringify(frame));
|
|
34930
|
+
}
|
|
34931
|
+
}
|
|
34842
34932
|
} catch (e) {
|
|
34843
34933
|
console.error("[fetchproxy] host: message handler error:", e);
|
|
34844
34934
|
try {
|
|
@@ -34854,6 +34944,9 @@ async function startHost(opts) {
|
|
|
34854
34944
|
if (!ownSession) {
|
|
34855
34945
|
rejectOwnSession(new Error("extension disconnected before ready"));
|
|
34856
34946
|
}
|
|
34947
|
+
ownSession = null;
|
|
34948
|
+
resetSessionPromise();
|
|
34949
|
+
disconnectListeners.forEach((cb) => cb());
|
|
34857
34950
|
}
|
|
34858
34951
|
if (identified === "peer" && peerMcpId)
|
|
34859
34952
|
peers.delete(peerMcpId);
|
|
@@ -34878,7 +34971,14 @@ async function startHost(opts) {
|
|
|
34878
34971
|
},
|
|
34879
34972
|
onOwnInner: (cb) => {
|
|
34880
34973
|
ownInnerListeners.push(cb);
|
|
34881
|
-
}
|
|
34974
|
+
},
|
|
34975
|
+
onExtensionDisconnect: (cb) => {
|
|
34976
|
+
disconnectListeners.push(cb);
|
|
34977
|
+
},
|
|
34978
|
+
onPendingPair: (cb) => {
|
|
34979
|
+
pendingPairListeners.push(cb);
|
|
34980
|
+
},
|
|
34981
|
+
pendingPairCode: () => ownPendingPairCode
|
|
34882
34982
|
};
|
|
34883
34983
|
}
|
|
34884
34984
|
|
|
@@ -34908,36 +35008,57 @@ async function startPeer(opts) {
|
|
|
34908
35008
|
const sessionNonce = fromB64(hello.sessionNonce);
|
|
34909
35009
|
ws.send(JSON.stringify(hello));
|
|
34910
35010
|
const innerListeners = [];
|
|
35011
|
+
const renegotiateListeners = [];
|
|
35012
|
+
const pendingPairListeners = [];
|
|
34911
35013
|
let session = null;
|
|
35014
|
+
let pendingPairCode = null;
|
|
35015
|
+
let resolveFirstReady;
|
|
35016
|
+
let rejectFirstReady;
|
|
34912
35017
|
const sessionPromise = new Promise((resolve, reject) => {
|
|
34913
|
-
|
|
34914
|
-
|
|
34915
|
-
|
|
34916
|
-
|
|
34917
|
-
|
|
34918
|
-
|
|
34919
|
-
|
|
34920
|
-
|
|
34921
|
-
|
|
34922
|
-
|
|
34923
|
-
|
|
35018
|
+
resolveFirstReady = resolve;
|
|
35019
|
+
rejectFirstReady = reject;
|
|
35020
|
+
});
|
|
35021
|
+
const onMessage = async (data) => {
|
|
35022
|
+
try {
|
|
35023
|
+
const raw = JSON.parse(data.toString());
|
|
35024
|
+
const frame = validateFrame(raw);
|
|
35025
|
+
if (frame.type === "ready" && frame.mcpId === opts.mcpId) {
|
|
35026
|
+
const extPub = fromB64(frame.extensionSessionPub);
|
|
35027
|
+
const shared = await ecdhX25519(opts.identity.x25519Priv, extPub);
|
|
35028
|
+
const sessionKey = await hkdfSha256(shared, sessionNonce, enc3.encode(HKDF_SESSION_INFO), 32);
|
|
35029
|
+
const isRenegotiation = session !== null;
|
|
35030
|
+
session = new SessionState(sessionKey);
|
|
35031
|
+
pendingPairCode = null;
|
|
35032
|
+
if (isRenegotiation) {
|
|
35033
|
+
renegotiateListeners.forEach((cb) => cb());
|
|
35034
|
+
} else {
|
|
35035
|
+
resolveFirstReady(session);
|
|
34924
35036
|
}
|
|
34925
|
-
|
|
34926
|
-
|
|
34927
|
-
|
|
34928
|
-
|
|
34929
|
-
|
|
35037
|
+
return;
|
|
35038
|
+
}
|
|
35039
|
+
if (frame.type === "pair-pending" && frame.mcpId === opts.mcpId) {
|
|
35040
|
+
pendingPairCode = frame.pairCode;
|
|
35041
|
+
pendingPairListeners.forEach((cb) => cb(frame.pairCode));
|
|
35042
|
+
return;
|
|
35043
|
+
}
|
|
35044
|
+
if (frame.type === "frame" && frame.mcpId === opts.mcpId) {
|
|
35045
|
+
if (!session)
|
|
35046
|
+
return;
|
|
35047
|
+
if (!session.acceptInboundSeq(frame.seq))
|
|
35048
|
+
return;
|
|
35049
|
+
try {
|
|
34930
35050
|
const inner = await openEncryptedFrame(session.sessionKey, frame);
|
|
34931
35051
|
innerListeners.forEach((cb) => cb(inner));
|
|
35052
|
+
} catch {
|
|
34932
35053
|
}
|
|
34933
|
-
} catch (e) {
|
|
34934
|
-
reject(e instanceof Error ? e : new Error(String(e)));
|
|
34935
35054
|
}
|
|
34936
|
-
}
|
|
34937
|
-
|
|
34938
|
-
|
|
34939
|
-
|
|
34940
|
-
|
|
35055
|
+
} catch (e) {
|
|
35056
|
+
rejectFirstReady(e instanceof Error ? e : new Error(String(e)));
|
|
35057
|
+
}
|
|
35058
|
+
};
|
|
35059
|
+
ws.on("message", onMessage);
|
|
35060
|
+
ws.once("close", () => {
|
|
35061
|
+
rejectFirstReady(new Error("peer WS closed before ready"));
|
|
34941
35062
|
});
|
|
34942
35063
|
sessionPromise.catch(() => {
|
|
34943
35064
|
});
|
|
@@ -34945,13 +35066,21 @@ async function startPeer(opts) {
|
|
|
34945
35066
|
ws,
|
|
34946
35067
|
session: sessionPromise,
|
|
34947
35068
|
sendInner: async (inner) => {
|
|
34948
|
-
|
|
35069
|
+
await sessionPromise;
|
|
35070
|
+
const s = session;
|
|
34949
35071
|
const sealed = await sealInnerFrame(s.sessionKey, opts.mcpId, s.nextOutboundSeq(), inner);
|
|
34950
35072
|
ws.send(JSON.stringify(sealed));
|
|
34951
35073
|
},
|
|
34952
35074
|
onInner: (cb) => {
|
|
34953
35075
|
innerListeners.push(cb);
|
|
34954
35076
|
},
|
|
35077
|
+
onRenegotiate: (cb) => {
|
|
35078
|
+
renegotiateListeners.push(cb);
|
|
35079
|
+
},
|
|
35080
|
+
onPendingPair: (cb) => {
|
|
35081
|
+
pendingPairListeners.push(cb);
|
|
35082
|
+
},
|
|
35083
|
+
pendingPairCode: () => pendingPairCode,
|
|
34955
35084
|
close: () => ws.close()
|
|
34956
35085
|
};
|
|
34957
35086
|
return handle;
|
|
@@ -35008,6 +35137,32 @@ async function loadOrCreateIdentity(serverName, dir = defaultIdentityDir()) {
|
|
|
35008
35137
|
return id;
|
|
35009
35138
|
}
|
|
35010
35139
|
|
|
35140
|
+
// node_modules/@fetchproxy/server/dist/error-kind.js
|
|
35141
|
+
function classifyFetchError(error48) {
|
|
35142
|
+
if (/Could not establish connection/i.test(error48) || /Receiving end does not exist/i.test(error48)) {
|
|
35143
|
+
return "content_script_unreachable";
|
|
35144
|
+
}
|
|
35145
|
+
if (/^tab fetch failed:/.test(error48)) {
|
|
35146
|
+
return "tab_fetch_failed";
|
|
35147
|
+
}
|
|
35148
|
+
if (/^fetch threw:/.test(error48)) {
|
|
35149
|
+
return "tab_fetch_failed";
|
|
35150
|
+
}
|
|
35151
|
+
if (/^no tab matching /.test(error48)) {
|
|
35152
|
+
return "no_tab";
|
|
35153
|
+
}
|
|
35154
|
+
if (/not in domains \[/.test(error48)) {
|
|
35155
|
+
return "domain_denied";
|
|
35156
|
+
}
|
|
35157
|
+
if (/^capability .+ not granted/.test(error48)) {
|
|
35158
|
+
return "capability_denied";
|
|
35159
|
+
}
|
|
35160
|
+
if (/^(request|response) body too large:/.test(error48)) {
|
|
35161
|
+
return "body_too_large";
|
|
35162
|
+
}
|
|
35163
|
+
return "other";
|
|
35164
|
+
}
|
|
35165
|
+
|
|
35011
35166
|
// node_modules/@fetchproxy/server/dist/ws-server.js
|
|
35012
35167
|
var FetchproxyProtocolError = class extends Error {
|
|
35013
35168
|
constructor(message) {
|
|
@@ -35050,7 +35205,11 @@ function assertUrlInDomains(field, url2, domains) {
|
|
|
35050
35205
|
}
|
|
35051
35206
|
var DEFAULT_JSON_OK_STATUSES = [200, 201, 202, 204];
|
|
35052
35207
|
var FetchproxyServer = class {
|
|
35053
|
-
/**
|
|
35208
|
+
/**
|
|
35209
|
+
* Bridge role. `null` until the first verb call (or an explicit
|
|
35210
|
+
* `connect()`) — `listen()` no longer triggers the role election
|
|
35211
|
+
* as of 0.5.3+. Reset to `null` on `close()`.
|
|
35212
|
+
*/
|
|
35054
35213
|
role = null;
|
|
35055
35214
|
opts;
|
|
35056
35215
|
hostHandle = null;
|
|
@@ -35072,6 +35231,12 @@ var FetchproxyServer = class {
|
|
|
35072
35231
|
pendingIdb = /* @__PURE__ */ new Map();
|
|
35073
35232
|
mcpId = null;
|
|
35074
35233
|
identity = null;
|
|
35234
|
+
// 0.5.3+: in-flight role-election / handle-start promise. Set the
|
|
35235
|
+
// first time a verb call runs `ensureConnected`, awaited by concurrent
|
|
35236
|
+
// callers, cleared once the connection is up. Single source of truth
|
|
35237
|
+
// for "we're connecting right now" so two parallel first-calls don't
|
|
35238
|
+
// race the port bind.
|
|
35239
|
+
connectingPromise = null;
|
|
35075
35240
|
constructor(opts) {
|
|
35076
35241
|
if (!Array.isArray(opts.domains) || opts.domains.length === 0) {
|
|
35077
35242
|
throw new Error("FetchproxyServer: opts.domains must be a non-empty array of hostnames");
|
|
@@ -35123,23 +35288,87 @@ var FetchproxyServer = class {
|
|
|
35123
35288
|
};
|
|
35124
35289
|
}
|
|
35125
35290
|
/**
|
|
35126
|
-
*
|
|
35127
|
-
* from disk (creating it on first call)
|
|
35128
|
-
*
|
|
35129
|
-
*
|
|
35130
|
-
* `
|
|
35131
|
-
*
|
|
35291
|
+
* Prepare the bridge for use. Loads the long-term identity keypair
|
|
35292
|
+
* from disk (creating it on first call) and computes this instance's
|
|
35293
|
+
* `mcpId`. Does NOT bind the bridge port or dial any WebSocket — the
|
|
35294
|
+
* connection is established lazily on the first verb call (see
|
|
35295
|
+
* `ensureConnected` / `getOrConnect`).
|
|
35296
|
+
*
|
|
35297
|
+
* Pre-0.5.3 behavior: `listen()` also did role election and started
|
|
35298
|
+
* the host/peer immediately, which meant every configured-but-unused
|
|
35299
|
+
* MCP claimed bridge resources at MCP-client boot. Several MCPs
|
|
35300
|
+
* starting in parallel under Claude Desktop also produced noisy
|
|
35301
|
+
* `ERR_CONNECTION_REFUSED` errors in the extension if it raced ahead
|
|
35302
|
+
* of the first MCP's port bind. Deferring keeps boot quiet and
|
|
35303
|
+
* leaves the port unowned until something actually needs it.
|
|
35304
|
+
*
|
|
35305
|
+
* Calling `listen()` twice without an intervening `close()` is a
|
|
35306
|
+
* no-op (the second call's identity load is idempotent).
|
|
35132
35307
|
*/
|
|
35133
35308
|
async listen() {
|
|
35134
|
-
|
|
35135
|
-
|
|
35309
|
+
if (!this.identity) {
|
|
35310
|
+
this.identity = await loadOrCreateIdentity(this.opts.serverName, this.opts.identityDir);
|
|
35311
|
+
}
|
|
35312
|
+
if (!this.mcpId) {
|
|
35313
|
+
this.mcpId = generateMcpId(this.opts.serverName, this.opts.version);
|
|
35314
|
+
}
|
|
35315
|
+
}
|
|
35316
|
+
/**
|
|
35317
|
+
* Force an eager bridge connection (role-election + host/peer handle
|
|
35318
|
+
* start + listener wiring) without waiting for the first verb call.
|
|
35319
|
+
* Useful for callers that want to surface the role / connection
|
|
35320
|
+
* outcome at boot, or for tests whose harness dials a mock extension
|
|
35321
|
+
* immediately after server construction. Production MCPs that just
|
|
35322
|
+
* answer tool calls should NOT call this — the lazy connect via
|
|
35323
|
+
* `ensureConnected` will do the right thing on first use, keeping
|
|
35324
|
+
* boot cheap and avoiding port-bind contention for MCPs that never
|
|
35325
|
+
* actually get invoked.
|
|
35326
|
+
*
|
|
35327
|
+
* Idempotent: a second call after the first has resolved is a no-op
|
|
35328
|
+
* (the existing handle is reused). Throws if `listen()` was never
|
|
35329
|
+
* called.
|
|
35330
|
+
*/
|
|
35331
|
+
async connect() {
|
|
35332
|
+
await this.ensureConnected();
|
|
35333
|
+
}
|
|
35334
|
+
/**
|
|
35335
|
+
* Establish the bridge connection (role-election + host/peer handle
|
|
35336
|
+
* start + listener wiring) the first time a verb is invoked.
|
|
35337
|
+
* Idempotent after the connection is up; concurrent first-callers
|
|
35338
|
+
* share the same in-flight promise so only one election happens.
|
|
35339
|
+
*
|
|
35340
|
+
* Throws if `listen()` was never called — the contract is that the
|
|
35341
|
+
* MCP author still must wire `transport.start()` at boot to load
|
|
35342
|
+
* identity / set mcpId, even though the WS doesn't open until a
|
|
35343
|
+
* verb runs.
|
|
35344
|
+
*/
|
|
35345
|
+
async ensureConnected() {
|
|
35346
|
+
if (this.hostHandle || this.peerHandle)
|
|
35347
|
+
return;
|
|
35348
|
+
if (this.connectingPromise) {
|
|
35349
|
+
await this.connectingPromise;
|
|
35350
|
+
return;
|
|
35351
|
+
}
|
|
35352
|
+
if (!this.identity || !this.mcpId) {
|
|
35353
|
+
throw new Error("FetchproxyServer: ensureConnected called before listen() \u2014 call listen() at MCP boot to load identity");
|
|
35354
|
+
}
|
|
35355
|
+
this.connectingPromise = this.doConnect();
|
|
35356
|
+
try {
|
|
35357
|
+
await this.connectingPromise;
|
|
35358
|
+
} finally {
|
|
35359
|
+
this.connectingPromise = null;
|
|
35360
|
+
}
|
|
35361
|
+
}
|
|
35362
|
+
async doConnect() {
|
|
35363
|
+
const identity = this.identity;
|
|
35364
|
+
const mcpId = this.mcpId;
|
|
35136
35365
|
const el = await electRole({ host: this.opts.host, port: this.opts.port });
|
|
35137
35366
|
if (el.role === "host") {
|
|
35138
35367
|
this.role = "host";
|
|
35139
35368
|
this.hostHandle = await startHost({
|
|
35140
35369
|
httpServer: el.server,
|
|
35141
|
-
ownIdentity:
|
|
35142
|
-
ownMcpId:
|
|
35370
|
+
ownIdentity: identity,
|
|
35371
|
+
ownMcpId: mcpId,
|
|
35143
35372
|
ownServerName: this.opts.serverName,
|
|
35144
35373
|
ownVersion: this.opts.version,
|
|
35145
35374
|
ownDomains: this.opts.domains,
|
|
@@ -35154,13 +35383,17 @@ var FetchproxyServer = class {
|
|
|
35154
35383
|
onPairCode: this.opts.onPairCode
|
|
35155
35384
|
});
|
|
35156
35385
|
this.hostHandle.onOwnInner((inner) => this.onInner(inner));
|
|
35386
|
+
this.hostHandle.onExtensionDisconnect(() => this.rejectAllPending());
|
|
35387
|
+
this.hostHandle.onPendingPair((code) => {
|
|
35388
|
+
this.rejectAllPending(this.pairingErrorMessage(code));
|
|
35389
|
+
});
|
|
35157
35390
|
} else {
|
|
35158
35391
|
this.role = "peer";
|
|
35159
35392
|
this.peerHandle = await startPeer({
|
|
35160
35393
|
host: this.opts.host,
|
|
35161
35394
|
port: this.opts.port,
|
|
35162
|
-
identity
|
|
35163
|
-
mcpId
|
|
35395
|
+
identity,
|
|
35396
|
+
mcpId,
|
|
35164
35397
|
serverName: this.opts.serverName,
|
|
35165
35398
|
version: this.opts.version,
|
|
35166
35399
|
domains: this.opts.domains,
|
|
@@ -35174,8 +35407,19 @@ var FetchproxyServer = class {
|
|
|
35174
35407
|
sessionStoragePointers: this.opts.sessionStoragePointers
|
|
35175
35408
|
});
|
|
35176
35409
|
this.peerHandle.onInner((inner) => this.onInner(inner));
|
|
35410
|
+
this.peerHandle.onRenegotiate(() => this.rejectAllPending());
|
|
35411
|
+
this.peerHandle.onPendingPair((code) => {
|
|
35412
|
+
this.rejectAllPending(this.pairingErrorMessage(code));
|
|
35413
|
+
});
|
|
35414
|
+
if (this.opts.onPairCode) {
|
|
35415
|
+
const cb = this.opts.onPairCode;
|
|
35416
|
+
this.peerHandle.onPendingPair((code) => cb(code));
|
|
35417
|
+
}
|
|
35177
35418
|
}
|
|
35178
35419
|
}
|
|
35420
|
+
pairingErrorMessage(code) {
|
|
35421
|
+
return `fetchproxy: pairing required for ${this.opts.serverName} \u2014 open the fetchproxy extension popup in Chrome and approve the pair request. Verify the pair code matches: ${code}`;
|
|
35422
|
+
}
|
|
35179
35423
|
/**
|
|
35180
35424
|
* Raw single-shot fetch through the bridge. Most callers should prefer
|
|
35181
35425
|
* the verb shortcuts (`get` / `post` / `getJson` / `postJson` / `getHtml`)
|
|
@@ -35191,8 +35435,11 @@ var FetchproxyServer = class {
|
|
|
35191
35435
|
* offline, etc.).
|
|
35192
35436
|
*/
|
|
35193
35437
|
async fetch(init) {
|
|
35194
|
-
|
|
35195
|
-
|
|
35438
|
+
await this.ensureConnected();
|
|
35439
|
+
const pendingCode = this.currentPendingPairCode();
|
|
35440
|
+
if (pendingCode !== null) {
|
|
35441
|
+
const error48 = this.pairingErrorMessage(pendingCode);
|
|
35442
|
+
return { ok: false, error: error48, kind: classifyFetchError(error48) };
|
|
35196
35443
|
}
|
|
35197
35444
|
const id = this.nextRequestId++;
|
|
35198
35445
|
const inner = { type: "request", id, op: "fetch", init };
|
|
@@ -35333,9 +35580,8 @@ var FetchproxyServer = class {
|
|
|
35333
35580
|
if (!this.opts.capabilities.includes("read_cookies")) {
|
|
35334
35581
|
throw new Error('FetchproxyServer.readCookies(): MCP did not declare "read_cookies" in capabilities \u2014 add it to FetchproxyServerOpts.capabilities to enable this verb');
|
|
35335
35582
|
}
|
|
35336
|
-
|
|
35337
|
-
|
|
35338
|
-
}
|
|
35583
|
+
await this.ensureConnected();
|
|
35584
|
+
this.throwIfPendingPair();
|
|
35339
35585
|
if (opts.subdomain !== void 0)
|
|
35340
35586
|
assertSubdomainLabel(opts.subdomain);
|
|
35341
35587
|
const baseDomain = this.resolveBaseDomain(opts.domain);
|
|
@@ -35392,9 +35638,8 @@ var FetchproxyServer = class {
|
|
|
35392
35638
|
if (!this.opts.capabilities.includes(op)) {
|
|
35393
35639
|
throw new Error(`FetchproxyServer.${op === "read_local_storage" ? "readLocalStorage" : "readSessionStorage"}(): MCP did not declare ${JSON.stringify(op)} in capabilities`);
|
|
35394
35640
|
}
|
|
35395
|
-
|
|
35396
|
-
|
|
35397
|
-
}
|
|
35641
|
+
await this.ensureConnected();
|
|
35642
|
+
this.throwIfPendingPair();
|
|
35398
35643
|
if (!Array.isArray(opts.keys) || opts.keys.length === 0) {
|
|
35399
35644
|
throw new Error(`FetchproxyServer.${op}: opts.keys must be a non-empty array`);
|
|
35400
35645
|
}
|
|
@@ -35449,9 +35694,8 @@ var FetchproxyServer = class {
|
|
|
35449
35694
|
if (!this.opts.capabilities.includes("capture_request_header")) {
|
|
35450
35695
|
throw new Error('FetchproxyServer.captureRequestHeader(): MCP did not declare "capture_request_header" in capabilities');
|
|
35451
35696
|
}
|
|
35452
|
-
|
|
35453
|
-
|
|
35454
|
-
}
|
|
35697
|
+
await this.ensureConnected();
|
|
35698
|
+
this.throwIfPendingPair();
|
|
35455
35699
|
const declared = this.opts.captureHeaders.find((d) => d.urlPattern === opts.urlPattern && d.headerName === opts.headerName);
|
|
35456
35700
|
if (!declared) {
|
|
35457
35701
|
throw new Error(`FetchproxyServer.captureRequestHeader: (urlPattern=${JSON.stringify(opts.urlPattern)}, headerName=${JSON.stringify(opts.headerName)}) not declared in captureHeaders`);
|
|
@@ -35492,9 +35736,8 @@ var FetchproxyServer = class {
|
|
|
35492
35736
|
if (!this.opts.capabilities.includes("read_indexed_db")) {
|
|
35493
35737
|
throw new Error('FetchproxyServer.readIndexedDb(): MCP did not declare "read_indexed_db" in capabilities');
|
|
35494
35738
|
}
|
|
35495
|
-
|
|
35496
|
-
|
|
35497
|
-
}
|
|
35739
|
+
await this.ensureConnected();
|
|
35740
|
+
this.throwIfPendingPair();
|
|
35498
35741
|
if (!Array.isArray(opts.keys) || opts.keys.length === 0) {
|
|
35499
35742
|
throw new Error("FetchproxyServer.readIndexedDb: opts.keys must be a non-empty array");
|
|
35500
35743
|
}
|
|
@@ -35572,10 +35815,11 @@ var FetchproxyServer = class {
|
|
|
35572
35815
|
if (inner.op === void 0 || inner.op === "fetch") {
|
|
35573
35816
|
fetchCb({ ok: true, status: inner.status, url: inner.url, body: inner.body });
|
|
35574
35817
|
} else {
|
|
35575
|
-
|
|
35818
|
+
const error48 = `unexpected ${inner.op} response on fetch awaiter`;
|
|
35819
|
+
fetchCb({ ok: false, error: error48, kind: classifyFetchError(error48) });
|
|
35576
35820
|
}
|
|
35577
35821
|
} else {
|
|
35578
|
-
fetchCb({ ok: false, error: inner.error });
|
|
35822
|
+
fetchCb({ ok: false, error: inner.error, kind: classifyFetchError(inner.error) });
|
|
35579
35823
|
}
|
|
35580
35824
|
return;
|
|
35581
35825
|
}
|
|
@@ -35642,6 +35886,52 @@ var FetchproxyServer = class {
|
|
|
35642
35886
|
}
|
|
35643
35887
|
}
|
|
35644
35888
|
}
|
|
35889
|
+
rejectAllPending(reason = "extension disconnected") {
|
|
35890
|
+
const err = new FetchproxyProtocolError(reason);
|
|
35891
|
+
for (const cb of this.pending.values()) {
|
|
35892
|
+
cb({ ok: false, error: err.message, kind: classifyFetchError(err.message) });
|
|
35893
|
+
}
|
|
35894
|
+
this.pending.clear();
|
|
35895
|
+
for (const cb of this.pendingReadCookies.values()) {
|
|
35896
|
+
cb({ ok: false, error: err.message });
|
|
35897
|
+
}
|
|
35898
|
+
this.pendingReadCookies.clear();
|
|
35899
|
+
for (const { reject } of this.pendingStorage.values())
|
|
35900
|
+
reject(err);
|
|
35901
|
+
this.pendingStorage.clear();
|
|
35902
|
+
for (const { reject } of this.pendingCapture.values())
|
|
35903
|
+
reject(err);
|
|
35904
|
+
this.pendingCapture.clear();
|
|
35905
|
+
for (const { reject } of this.pendingIdb.values())
|
|
35906
|
+
reject(err);
|
|
35907
|
+
this.pendingIdb.clear();
|
|
35908
|
+
}
|
|
35909
|
+
/**
|
|
35910
|
+
* 0.5.2+: read the current pair-pending pair code from whichever handle
|
|
35911
|
+
* is active, returning null when none is pending. Public verbs call this
|
|
35912
|
+
* at the top so that a tool invoked while the bridge is waiting on user
|
|
35913
|
+
* approval fails fast with the actionable error rather than hanging on a
|
|
35914
|
+
* sealed frame the extension will never process.
|
|
35915
|
+
*/
|
|
35916
|
+
currentPendingPairCode() {
|
|
35917
|
+
if (this.hostHandle)
|
|
35918
|
+
return this.hostHandle.pendingPairCode();
|
|
35919
|
+
if (this.peerHandle)
|
|
35920
|
+
return this.peerHandle.pendingPairCode();
|
|
35921
|
+
return null;
|
|
35922
|
+
}
|
|
35923
|
+
/**
|
|
35924
|
+
* 0.5.2+: throw `FetchproxyProtocolError` with the actionable pair-code
|
|
35925
|
+
* message if the bridge is waiting on user approval. Used by the verb
|
|
35926
|
+
* methods (readCookies, readLocalStorage, etc.) that surface errors via
|
|
35927
|
+
* thrown exceptions rather than `ok:false` discriminated unions.
|
|
35928
|
+
*/
|
|
35929
|
+
throwIfPendingPair() {
|
|
35930
|
+
const code = this.currentPendingPairCode();
|
|
35931
|
+
if (code !== null) {
|
|
35932
|
+
throw new FetchproxyProtocolError(this.pairingErrorMessage(code));
|
|
35933
|
+
}
|
|
35934
|
+
}
|
|
35645
35935
|
/**
|
|
35646
35936
|
* Shut down the bridge. Host: terminates the WebSocket server and any
|
|
35647
35937
|
* still-attached extension/peer clients. Peer: closes the upstream
|
|
@@ -35649,6 +35939,10 @@ var FetchproxyServer = class {
|
|
|
35649
35939
|
* twice in a row.
|
|
35650
35940
|
*/
|
|
35651
35941
|
async close() {
|
|
35942
|
+
this.rejectAllPending();
|
|
35943
|
+
if (this.connectingPromise) {
|
|
35944
|
+
await this.connectingPromise.catch(() => void 0);
|
|
35945
|
+
}
|
|
35652
35946
|
if (this.hostHandle)
|
|
35653
35947
|
await this.hostHandle.close();
|
|
35654
35948
|
if (this.peerHandle)
|
|
@@ -35656,6 +35950,7 @@ var FetchproxyServer = class {
|
|
|
35656
35950
|
this.hostHandle = null;
|
|
35657
35951
|
this.peerHandle = null;
|
|
35658
35952
|
this.role = null;
|
|
35953
|
+
this.connectingPromise = null;
|
|
35659
35954
|
}
|
|
35660
35955
|
};
|
|
35661
35956
|
|
|
@@ -35744,8 +36039,7 @@ async function bootstrap(opts) {
|
|
|
35744
36039
|
for (const p of localStoragePointers) {
|
|
35745
36040
|
pointers[p.outputKey] = { storageKey: p.storageKey, jsonPointer: p.jsonPointer };
|
|
35746
36041
|
}
|
|
35747
|
-
|
|
35748
|
-
localStorage = await stub.readLocalStorage({
|
|
36042
|
+
localStorage = await server2.readLocalStorage({
|
|
35749
36043
|
keys: allKeys,
|
|
35750
36044
|
...storageDomainOpts,
|
|
35751
36045
|
...localStoragePointers.length > 0 ? { pointers } : {}
|
|
@@ -35758,8 +36052,7 @@ async function bootstrap(opts) {
|
|
|
35758
36052
|
for (const p of sessionStoragePointers) {
|
|
35759
36053
|
pointers[p.outputKey] = { storageKey: p.storageKey, jsonPointer: p.jsonPointer };
|
|
35760
36054
|
}
|
|
35761
|
-
|
|
35762
|
-
sessionStorage = await stub.readSessionStorage({
|
|
36055
|
+
sessionStorage = await server2.readSessionStorage({
|
|
35763
36056
|
keys: allKeys,
|
|
35764
36057
|
...storageDomainOpts,
|
|
35765
36058
|
...sessionStoragePointers.length > 0 ? { pointers } : {}
|
|
@@ -35782,9 +36075,6 @@ async function bootstrap(opts) {
|
|
|
35782
36075
|
}
|
|
35783
36076
|
const indexedDbBucket = {};
|
|
35784
36077
|
for (const d of indexedDb) {
|
|
35785
|
-
if (!server2.readIndexedDb) {
|
|
35786
|
-
throw new Error("bootstrap: server factory does not implement readIndexedDb (declared indexedDb but server stub omits it)");
|
|
35787
|
-
}
|
|
35788
36078
|
const values = await server2.readIndexedDb({
|
|
35789
36079
|
database: d.database,
|
|
35790
36080
|
store: d.store,
|
|
@@ -35821,7 +36111,7 @@ var BootstrapDisabledError = class extends Error {
|
|
|
35821
36111
|
// package.json
|
|
35822
36112
|
var package_default = {
|
|
35823
36113
|
name: "zola-mcp",
|
|
35824
|
-
version: "1.
|
|
36114
|
+
version: "1.2.3",
|
|
35825
36115
|
mcpName: "io.github.chrischall/zola-mcp",
|
|
35826
36116
|
description: "Zola wedding MCP server for Claude",
|
|
35827
36117
|
author: "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
@@ -35867,16 +36157,16 @@ var package_default = {
|
|
|
35867
36157
|
"test:watch": "vitest"
|
|
35868
36158
|
},
|
|
35869
36159
|
dependencies: {
|
|
35870
|
-
"@fetchproxy/bootstrap": "^0.
|
|
36160
|
+
"@fetchproxy/bootstrap": "^0.6.0",
|
|
35871
36161
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
35872
|
-
dotenv: "^17.4.
|
|
36162
|
+
dotenv: "^17.4.2"
|
|
35873
36163
|
},
|
|
35874
36164
|
devDependencies: {
|
|
35875
|
-
"@types/node": "^25.
|
|
35876
|
-
"@vitest/coverage-v8": "^4.1.
|
|
36165
|
+
"@types/node": "^25.9.1",
|
|
36166
|
+
"@vitest/coverage-v8": "^4.1.7",
|
|
35877
36167
|
esbuild: "^0.28.0",
|
|
35878
36168
|
typescript: "^6.0.3",
|
|
35879
|
-
vitest: "^4.1.
|
|
36169
|
+
vitest: "^4.1.7"
|
|
35880
36170
|
}
|
|
35881
36171
|
};
|
|
35882
36172
|
|
|
@@ -37618,7 +37908,8 @@ function registerRegistryItemTools(server2) {
|
|
|
37618
37908
|
// src/index.ts
|
|
37619
37909
|
var server = new McpServer({
|
|
37620
37910
|
name: "zola-mcp",
|
|
37621
|
-
version: "1.
|
|
37911
|
+
version: "1.2.3"
|
|
37912
|
+
// x-release-please-version
|
|
37622
37913
|
});
|
|
37623
37914
|
registerVendorTools(server);
|
|
37624
37915
|
registerBudgetTools(server);
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import { registerWebsiteThemeTools } from './tools/website-theme.js';
|
|
|
13
13
|
import { registerRegistryItemTools } from './tools/registry-items.js';
|
|
14
14
|
const server = new McpServer({
|
|
15
15
|
name: 'zola-mcp',
|
|
16
|
-
version: '1.
|
|
16
|
+
version: '1.2.3', // x-release-please-version
|
|
17
17
|
});
|
|
18
18
|
registerVendorTools(server);
|
|
19
19
|
registerBudgetTools(server);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zola-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"mcpName": "io.github.chrischall/zola-mcp",
|
|
5
5
|
"description": "Zola wedding MCP server for Claude",
|
|
6
6
|
"author": "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
@@ -46,15 +46,15 @@
|
|
|
46
46
|
"test:watch": "vitest"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@fetchproxy/bootstrap": "^0.
|
|
49
|
+
"@fetchproxy/bootstrap": "^0.6.0",
|
|
50
50
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
51
|
-
"dotenv": "^17.4.
|
|
51
|
+
"dotenv": "^17.4.2"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@types/node": "^25.
|
|
55
|
-
"@vitest/coverage-v8": "^4.1.
|
|
54
|
+
"@types/node": "^25.9.1",
|
|
55
|
+
"@vitest/coverage-v8": "^4.1.7",
|
|
56
56
|
"esbuild": "^0.28.0",
|
|
57
57
|
"typescript": "^6.0.3",
|
|
58
|
-
"vitest": "^4.1.
|
|
58
|
+
"vitest": "^4.1.7"
|
|
59
59
|
}
|
|
60
60
|
}
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/chrischall/zola-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.2.3",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "zola-mcp",
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.2.3",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|