zola-mcp 1.1.2 → 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 +36 -14
- package/dist/auth.js +125 -0
- package/dist/bundle.js +11798 -5680
- package/dist/client.js +7 -4
- package/dist/index.js +1 -1
- package/package.json +7 -8
- package/server.json +4 -4
|
@@ -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
|
@@ -23,7 +23,29 @@ Ask Claude things like:
|
|
|
23
23
|
- [Claude Desktop](https://claude.ai/download) or [Claude Code](https://docs.anthropic.com/en/docs/claude-code)
|
|
24
24
|
- [Node.js](https://nodejs.org) 20.6 or later
|
|
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
|
+
|
|
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.
|
|
27
49
|
|
|
28
50
|
## Installation
|
|
29
51
|
|
|
@@ -89,16 +111,17 @@ Add to Claude Desktop config:
|
|
|
89
111
|
|
|
90
112
|
### Getting your refresh token
|
|
91
113
|
|
|
92
|
-
|
|
114
|
+
You have two options. Both produce the same `usr` cookie value — a ~1-year JWT that doubles as the refresh token.
|
|
93
115
|
|
|
94
|
-
#### Option A —
|
|
116
|
+
#### Option A — fetchproxy extension (recommended)
|
|
95
117
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
118
|
+
1. Install the [fetchproxy 0.3.0 extension](https://github.com/chrischall/fetchproxy) (Chrome Web Store or Safari `.dmg`).
|
|
119
|
+
2. Sign in at [zola.com/account/login](https://www.zola.com/account/login) in that browser.
|
|
120
|
+
3. Leave `ZOLA_REFRESH_TOKEN` **unset** in your Claude config.
|
|
121
|
+
|
|
122
|
+
On the first tool call, the MCP asks the extension for the HttpOnly `usr` cookie via `chrome.cookies.get`, then operates direct-to-API from Node. No persistent storage of the token in any env file. To re-auth (e.g. after Zola signs you out), just sign back in to zola.com.
|
|
100
123
|
|
|
101
|
-
|
|
124
|
+
You can opt out of this fallback with `ZOLA_DISABLE_FETCHPROXY=1` (e.g. in headless / CI environments where no extension is available).
|
|
102
125
|
|
|
103
126
|
#### Option B — manual (DevTools)
|
|
104
127
|
|
|
@@ -117,11 +140,10 @@ Ask Claude: *"How's wedding planning going?"* — it should show your wedding da
|
|
|
117
140
|
|
|
118
141
|
## Credentials
|
|
119
142
|
|
|
120
|
-
Only one credential is required:
|
|
121
|
-
|
|
122
143
|
| Env var | Required | Notes |
|
|
123
144
|
|---------|----------|-------|
|
|
124
|
-
| `ZOLA_REFRESH_TOKEN` |
|
|
145
|
+
| `ZOLA_REFRESH_TOKEN` | Conditional | Refresh token JWT (~1 year lifetime). When unset, the MCP falls back to the [fetchproxy extension](https://github.com/chrischall/fetchproxy) to read the `usr` cookie from your signed-in zola.com tab. |
|
|
146
|
+
| `ZOLA_DISABLE_FETCHPROXY` | No | Set to `1` to opt out of the fetchproxy fallback (headless / CI). |
|
|
125
147
|
| `ZOLA_ACCOUNT_ID` | No | Auto-resolved from API on first use |
|
|
126
148
|
| `ZOLA_REGISTRY_ID` | No | Auto-resolved from API on first use |
|
|
127
149
|
|
|
@@ -198,9 +220,9 @@ Only one credential is required:
|
|
|
198
220
|
|
|
199
221
|
## Troubleshooting
|
|
200
222
|
|
|
201
|
-
**"ZOLA_REFRESH_TOKEN
|
|
223
|
+
**"Zola auth: set ZOLA_REFRESH_TOKEN, or install the fetchproxy extension…"** — either set `ZOLA_REFRESH_TOKEN` in your config or install the fetchproxy extension and sign into zola.com.
|
|
202
224
|
|
|
203
|
-
**"Zola session refresh failed"** — your refresh token has expired (~1 year).
|
|
225
|
+
**"Zola session refresh failed"** — your refresh token has expired (~1 year) or been revoked. Either capture a new `usr` cookie (DevTools) or sign back into zola.com with the fetchproxy extension installed.
|
|
204
226
|
|
|
205
227
|
**403 from mobile API** — the `x-zola-session-id` header may be missing. Update to the latest version.
|
|
206
228
|
|
|
@@ -208,7 +230,7 @@ Only one credential is required:
|
|
|
208
230
|
|
|
209
231
|
## Security
|
|
210
232
|
|
|
211
|
-
- The refresh token lives only in your local `.env` or config file
|
|
233
|
+
- The refresh token lives only in your local `.env` or config file (when set) or in the user's browser cookie store (fetchproxy path)
|
|
212
234
|
- It is passed as an environment variable and never logged
|
|
213
235
|
- The server authenticates with Zola's mobile API using the same flow as the iOS app
|
|
214
236
|
- Account and registry IDs are auto-resolved from the API (no manual configuration needed)
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// Auth resolution — Pattern A template
|
|
3
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
//
|
|
5
|
+
// Mirrors the canonical "browser-bootstrap + Node-direct" shape from
|
|
6
|
+
// ofw-mcp/src/auth.ts. Other MCPs in this family (resy-mcp, opentable-mcp,
|
|
7
|
+
// signupgenius-mcp, …) use the same selector — keep the structure flat,
|
|
8
|
+
// the path-selection explicit, and the error messages actionable.
|
|
9
|
+
//
|
|
10
|
+
// THE THREE PATHS, in priority order:
|
|
11
|
+
//
|
|
12
|
+
// 1. Env-var credential (existing behavior)
|
|
13
|
+
// ZOLA_REFRESH_TOKEN set → use it directly. This is the ~1-year JWT
|
|
14
|
+
// that doubles as the `usr` cookie on zola.com. Legacy users keep
|
|
15
|
+
// working without action.
|
|
16
|
+
//
|
|
17
|
+
// 2. fetchproxy fallback (new)
|
|
18
|
+
// When no token is set, lift the user's session out of their
|
|
19
|
+
// signed-in zola.com browser tab via the fetchproxy 0.3.0 extension.
|
|
20
|
+
// The `@fetchproxy/bootstrap` helper spins up a one-shot WebSocket
|
|
21
|
+
// bridge, asks the extension for the HttpOnly `usr` cookie via
|
|
22
|
+
// `chrome.cookies.get`, then closes the bridge. From there, all
|
|
23
|
+
// Zola API calls go out via plain Node `fetch()` to
|
|
24
|
+
// mobile-api.zola.com — fetchproxy is NOT in the hot path.
|
|
25
|
+
//
|
|
26
|
+
// Users opt out with ZOLA_DISABLE_FETCHPROXY=1 (anyone who wants the
|
|
27
|
+
// old behavior of "fail loudly when creds are missing").
|
|
28
|
+
//
|
|
29
|
+
// 3. Error
|
|
30
|
+
// Nothing to authenticate with. We throw a message that tells the
|
|
31
|
+
// user exactly what to do: set the env var, OR install the extension
|
|
32
|
+
// and sign in.
|
|
33
|
+
//
|
|
34
|
+
// Why fetchproxy is only a one-shot read:
|
|
35
|
+
// The bootstrap call snapshots the `usr` cookie and returns. The MCP
|
|
36
|
+
// then operates from Node with direct fetch — latency and reliability
|
|
37
|
+
// are not coupled to the browser bridge for normal tool calls. The
|
|
38
|
+
// captured refresh token is fed into the existing
|
|
39
|
+
// `POST /v3/sessions/refresh` flow which mints 30-min session tokens
|
|
40
|
+
// (also in pure Node).
|
|
41
|
+
//
|
|
42
|
+
// Testability:
|
|
43
|
+
// - `@fetchproxy/bootstrap` is mocked at the module boundary in tests.
|
|
44
|
+
// - This module exposes a single async `resolveRefreshToken()` that
|
|
45
|
+
// returns the JWT plus the source — callers (the client) treat the
|
|
46
|
+
// return value as opaque credentials.
|
|
47
|
+
import { bootstrap } from '@fetchproxy/bootstrap';
|
|
48
|
+
import pkg from '../package.json' with { type: 'json' };
|
|
49
|
+
/**
|
|
50
|
+
* Read an env var, trim, and treat blank / `${UNEXPANDED}` placeholders as
|
|
51
|
+
* unset. Defends against MCP hosts that pass `.mcp.json` env blocks through
|
|
52
|
+
* without variable expansion.
|
|
53
|
+
*/
|
|
54
|
+
function readEnv(key) {
|
|
55
|
+
const raw = process.env[key];
|
|
56
|
+
if (typeof raw !== 'string')
|
|
57
|
+
return undefined;
|
|
58
|
+
const trimmed = raw.trim();
|
|
59
|
+
if (trimmed.length === 0)
|
|
60
|
+
return undefined;
|
|
61
|
+
if (trimmed === 'undefined' || trimmed === 'null')
|
|
62
|
+
return undefined;
|
|
63
|
+
if (/^\$\{[^}]*\}$/.test(trimmed))
|
|
64
|
+
return undefined;
|
|
65
|
+
return trimmed;
|
|
66
|
+
}
|
|
67
|
+
/** True if the user has explicitly disabled the fetchproxy fallback. */
|
|
68
|
+
function fetchproxyDisabled() {
|
|
69
|
+
const raw = readEnv('ZOLA_DISABLE_FETCHPROXY');
|
|
70
|
+
if (raw === undefined)
|
|
71
|
+
return false;
|
|
72
|
+
return ['1', 'true', 'yes', 'on'].includes(raw.toLowerCase());
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Resolve the Zola refresh token using the three-path priority described
|
|
76
|
+
* above. Throws with an actionable error message when no path succeeds.
|
|
77
|
+
*
|
|
78
|
+
* Callers (i.e. `ZolaClient.refresh()`) should treat the return value as
|
|
79
|
+
* opaque credentials — do not branch on `source`. The field exists for
|
|
80
|
+
* logging / future cache-keying only.
|
|
81
|
+
*/
|
|
82
|
+
export async function resolveRefreshToken() {
|
|
83
|
+
// ── Path 1: env-var refresh token (unchanged from pre-fetchproxy behavior).
|
|
84
|
+
const envToken = readEnv('ZOLA_REFRESH_TOKEN');
|
|
85
|
+
if (envToken) {
|
|
86
|
+
return { token: envToken, source: 'env' };
|
|
87
|
+
}
|
|
88
|
+
// ── Path 2: fetchproxy fallback (new).
|
|
89
|
+
if (!fetchproxyDisabled()) {
|
|
90
|
+
try {
|
|
91
|
+
const session = await bootstrap({
|
|
92
|
+
serverName: pkg.name,
|
|
93
|
+
version: pkg.version,
|
|
94
|
+
// Zola serves www.zola.com (web app) and mobile-api.zola.com (API).
|
|
95
|
+
// The `usr` cookie lives on the web app's apex domain; the extension
|
|
96
|
+
// matches on suffix so listing the apex covers any subdomain.
|
|
97
|
+
domains: ['zola.com'],
|
|
98
|
+
declare: {
|
|
99
|
+
// `usr` is HttpOnly → invisible to page JS, but fetchproxy 0.3.0's
|
|
100
|
+
// read_cookies uses `chrome.cookies.get` which DOES see HttpOnly
|
|
101
|
+
// cookies. The value IS the ~1-year refresh JWT.
|
|
102
|
+
cookies: ['usr'],
|
|
103
|
+
localStorage: [],
|
|
104
|
+
sessionStorage: [],
|
|
105
|
+
captureHeaders: [],
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
const token = session.cookies['usr'];
|
|
109
|
+
if (!token) {
|
|
110
|
+
throw new Error('zola: no `usr` cookie found. ' +
|
|
111
|
+
'Sign into zola.com in your browser (with the fetchproxy extension installed) and retry.');
|
|
112
|
+
}
|
|
113
|
+
return { token, source: 'fetchproxy' };
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
117
|
+
throw new Error(`Zola auth: no ZOLA_REFRESH_TOKEN set, and fetchproxy fallback failed: ${msg}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// ── Path 3: nothing configured. Surface both fixes side-by-side so the
|
|
121
|
+
// user can pick whichever fits their setup.
|
|
122
|
+
throw new Error('Zola auth: set ZOLA_REFRESH_TOKEN, ' +
|
|
123
|
+
'or install the fetchproxy extension and sign into zola.com ' +
|
|
124
|
+
'(unset ZOLA_DISABLE_FETCHPROXY if it is set).');
|
|
125
|
+
}
|