@wix/mcp 1.0.45 → 1.0.46
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/README.md +17 -0
- package/build/bin-standalone.js +232 -16
- package/build/bin-standalone.js.map +4 -4
- package/build/dts/bin.d.ts.map +1 -1
- package/build/dts/bin.js +19 -0
- package/build/dts/bin.js.map +1 -1
- package/build/dts/cli-tools/account-auth-strategy.d.ts +17 -0
- package/build/dts/cli-tools/account-auth-strategy.d.ts.map +1 -0
- package/build/dts/cli-tools/account-auth-strategy.js +49 -0
- package/build/dts/cli-tools/account-auth-strategy.js.map +1 -0
- package/build/dts/cli-tools/account-token-store.d.ts +44 -0
- package/build/dts/cli-tools/account-token-store.d.ts.map +1 -0
- package/build/dts/cli-tools/account-token-store.js +154 -0
- package/build/dts/cli-tools/account-token-store.js.map +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,6 +8,23 @@
|
|
|
8
8
|
npx @wix/mcp
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
### Authentication via Wix CLI (`--wixCliAuth`)
|
|
12
|
+
|
|
13
|
+
After `npx @wix/cli login` writes your OAuth token to `~/.wix/auth/account.json`, pass `--wixCliAuth` to enable the auth-requiring tools — `CallWixSiteAPI`, `ListWixSites`, `ManageWixSite`, site-creation widgets, and `SupportAndFeedback`. The access token is refreshed transparently via the Wix OAuth endpoint when it nears expiry, and the refreshed token is written back atomically.
|
|
14
|
+
|
|
15
|
+
```jsonc
|
|
16
|
+
{
|
|
17
|
+
"mcpServers": {
|
|
18
|
+
"wix": {
|
|
19
|
+
"command": "npx",
|
|
20
|
+
"args": ["-y", "@wix/mcp", "--wixCliAuth"]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Without `--wixCliAuth`, `@wix/mcp` runs in docs-only mode (same as before). If `--wixCliAuth` is set but `~/.wix/auth/account.json` is missing, the process exits with an error telling you to run `wix login` first.
|
|
27
|
+
|
|
11
28
|
### Local Development
|
|
12
29
|
|
|
13
30
|
1. Clone the repository
|
package/build/bin-standalone.js
CHANGED
|
@@ -474,13 +474,13 @@ function __disposeResources(env) {
|
|
|
474
474
|
}
|
|
475
475
|
return next();
|
|
476
476
|
}
|
|
477
|
-
function __rewriteRelativeImportExtension(
|
|
478
|
-
if (typeof
|
|
479
|
-
return
|
|
477
|
+
function __rewriteRelativeImportExtension(path5, preserveJsx) {
|
|
478
|
+
if (typeof path5 === "string" && /^\.\.?\//.test(path5)) {
|
|
479
|
+
return path5.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
|
|
480
480
|
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
|
|
481
481
|
});
|
|
482
482
|
}
|
|
483
|
-
return
|
|
483
|
+
return path5;
|
|
484
484
|
}
|
|
485
485
|
var extendStatics, __assign, __createBinding, __setModuleDefault, ownKeys, _SuppressedError, tslib_es6_default;
|
|
486
486
|
var init_tslib_es6 = __esm({
|
|
@@ -1117,8 +1117,8 @@ var require_utils2 = __commonJS({
|
|
|
1117
1117
|
}
|
|
1118
1118
|
}
|
|
1119
1119
|
exports.silent = silent;
|
|
1120
|
-
function extractProp(data,
|
|
1121
|
-
return
|
|
1120
|
+
function extractProp(data, path5) {
|
|
1121
|
+
return path5.split(".").filter((prop) => prop).reduce((result, prop) => result[prop], data);
|
|
1122
1122
|
}
|
|
1123
1123
|
exports.extractProp = extractProp;
|
|
1124
1124
|
function resolveHost(opts) {
|
|
@@ -2118,7 +2118,7 @@ var require_has_flag = __commonJS({
|
|
|
2118
2118
|
var require_supports_color = __commonJS({
|
|
2119
2119
|
"../../node_modules/supports-color/index.js"(exports, module) {
|
|
2120
2120
|
"use strict";
|
|
2121
|
-
var
|
|
2121
|
+
var os2 = __require("os");
|
|
2122
2122
|
var hasFlag = require_has_flag();
|
|
2123
2123
|
var env = process.env;
|
|
2124
2124
|
var forceColor;
|
|
@@ -2156,7 +2156,7 @@ var require_supports_color = __commonJS({
|
|
|
2156
2156
|
}
|
|
2157
2157
|
const min = forceColor ? 1 : 0;
|
|
2158
2158
|
if (process.platform === "win32") {
|
|
2159
|
-
const osRelease =
|
|
2159
|
+
const osRelease = os2.release().split(".");
|
|
2160
2160
|
if (Number(process.versions.node.split(".")[0]) >= 8 && Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
2161
2161
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
2162
2162
|
}
|
|
@@ -3920,14 +3920,14 @@ var require_cookies2 = __commonJS({
|
|
|
3920
3920
|
// Standard browser envs support document.cookie
|
|
3921
3921
|
/* @__PURE__ */ (function standardBrowserEnv() {
|
|
3922
3922
|
return {
|
|
3923
|
-
write: function write(name, value, expires,
|
|
3923
|
+
write: function write(name, value, expires, path5, domain, secure) {
|
|
3924
3924
|
var cookie = [];
|
|
3925
3925
|
cookie.push(name + "=" + encodeURIComponent(value));
|
|
3926
3926
|
if (utils.isNumber(expires)) {
|
|
3927
3927
|
cookie.push("expires=" + new Date(expires).toGMTString());
|
|
3928
3928
|
}
|
|
3929
|
-
if (utils.isString(
|
|
3930
|
-
cookie.push("path=" +
|
|
3929
|
+
if (utils.isString(path5)) {
|
|
3930
|
+
cookie.push("path=" + path5);
|
|
3931
3931
|
}
|
|
3932
3932
|
if (utils.isString(domain)) {
|
|
3933
3933
|
cookie.push("domain=" + domain);
|
|
@@ -8002,8 +8002,8 @@ var require_utils7 = __commonJS({
|
|
|
8002
8002
|
}
|
|
8003
8003
|
}
|
|
8004
8004
|
exports.silent = silent;
|
|
8005
|
-
function extractProp(data,
|
|
8006
|
-
return
|
|
8005
|
+
function extractProp(data, path5) {
|
|
8006
|
+
return path5.split(".").filter((prop) => prop).reduce((result, prop) => result[prop], data);
|
|
8007
8007
|
}
|
|
8008
8008
|
exports.extractProp = extractProp;
|
|
8009
8009
|
function resolveHost(opts) {
|
|
@@ -8926,14 +8926,14 @@ var require_cookies4 = __commonJS({
|
|
|
8926
8926
|
// Standard browser envs support document.cookie
|
|
8927
8927
|
/* @__PURE__ */ (function standardBrowserEnv() {
|
|
8928
8928
|
return {
|
|
8929
|
-
write: function write(name, value, expires,
|
|
8929
|
+
write: function write(name, value, expires, path5, domain, secure) {
|
|
8930
8930
|
var cookie = [];
|
|
8931
8931
|
cookie.push(name + "=" + encodeURIComponent(value));
|
|
8932
8932
|
if (utils.isNumber(expires)) {
|
|
8933
8933
|
cookie.push("expires=" + new Date(expires).toGMTString());
|
|
8934
8934
|
}
|
|
8935
|
-
if (utils.isString(
|
|
8936
|
-
cookie.push("path=" +
|
|
8935
|
+
if (utils.isString(path5)) {
|
|
8936
|
+
cookie.push("path=" + path5);
|
|
8937
8937
|
}
|
|
8938
8938
|
if (utils.isString(domain)) {
|
|
8939
8939
|
cookie.push("domain=" + domain);
|
|
@@ -10231,6 +10231,9 @@ Sentry.init({
|
|
|
10231
10231
|
|
|
10232
10232
|
// src/bin.ts
|
|
10233
10233
|
import minimist from "minimist";
|
|
10234
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
10235
|
+
import { homedir as homedir3 } from "node:os";
|
|
10236
|
+
import path4 from "node:path";
|
|
10234
10237
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10235
10238
|
|
|
10236
10239
|
// src/docs/docs.ts
|
|
@@ -14136,6 +14139,206 @@ function getCliAuthToken(siteIdOrAccountsFileName) {
|
|
|
14136
14139
|
);
|
|
14137
14140
|
}
|
|
14138
14141
|
|
|
14142
|
+
// src/cli-tools/account-token-store.ts
|
|
14143
|
+
import fs2 from "node:fs/promises";
|
|
14144
|
+
import path3 from "node:path";
|
|
14145
|
+
import os from "node:os";
|
|
14146
|
+
var DEFAULT_ACCOUNT_FILE = path3.join(
|
|
14147
|
+
os.homedir(),
|
|
14148
|
+
".wix",
|
|
14149
|
+
"auth",
|
|
14150
|
+
"account.json"
|
|
14151
|
+
);
|
|
14152
|
+
var DEFAULT_CLIENT_ID = "f234ac48-6cab-4ef2-9ea0-03d56a376da4";
|
|
14153
|
+
var WixCliAuthError = class extends Error {
|
|
14154
|
+
constructor(message) {
|
|
14155
|
+
super(message);
|
|
14156
|
+
this.name = "WixCliAuthError";
|
|
14157
|
+
}
|
|
14158
|
+
};
|
|
14159
|
+
var TokenStore = class {
|
|
14160
|
+
current;
|
|
14161
|
+
currentMtimeMs;
|
|
14162
|
+
inflight;
|
|
14163
|
+
accountFile;
|
|
14164
|
+
clientId;
|
|
14165
|
+
bufferSeconds;
|
|
14166
|
+
constructor(opts = {}) {
|
|
14167
|
+
this.accountFile = opts.accountFile ?? DEFAULT_ACCOUNT_FILE;
|
|
14168
|
+
this.clientId = opts.clientId ?? DEFAULT_CLIENT_ID;
|
|
14169
|
+
this.bufferSeconds = opts.expiryBufferSeconds ?? 5 * 60;
|
|
14170
|
+
}
|
|
14171
|
+
async load() {
|
|
14172
|
+
let raw;
|
|
14173
|
+
let mtimeMs;
|
|
14174
|
+
try {
|
|
14175
|
+
const [content, stat] = await Promise.all([
|
|
14176
|
+
fs2.readFile(this.accountFile, "utf-8"),
|
|
14177
|
+
fs2.stat(this.accountFile)
|
|
14178
|
+
]);
|
|
14179
|
+
raw = content;
|
|
14180
|
+
mtimeMs = stat.mtimeMs;
|
|
14181
|
+
} catch (err) {
|
|
14182
|
+
const code = err?.code;
|
|
14183
|
+
if (code === "ENOENT") {
|
|
14184
|
+
throw new WixCliAuthError(
|
|
14185
|
+
`Wix CLI auth file not found at ${this.accountFile}.
|
|
14186
|
+
Run \`npx @wix/cli login\` first, then retry.`
|
|
14187
|
+
);
|
|
14188
|
+
}
|
|
14189
|
+
throw err;
|
|
14190
|
+
}
|
|
14191
|
+
let parsed;
|
|
14192
|
+
try {
|
|
14193
|
+
parsed = JSON.parse(raw);
|
|
14194
|
+
} catch (err) {
|
|
14195
|
+
throw new WixCliAuthError(
|
|
14196
|
+
`Failed to parse ${this.accountFile}: ${err.message}`
|
|
14197
|
+
);
|
|
14198
|
+
}
|
|
14199
|
+
if (!parsed?.accessToken || !parsed?.refreshToken) {
|
|
14200
|
+
throw new WixCliAuthError(
|
|
14201
|
+
`${this.accountFile} is missing accessToken or refreshToken. Re-run \`npx @wix/cli login\`.`
|
|
14202
|
+
);
|
|
14203
|
+
}
|
|
14204
|
+
this.current = parsed;
|
|
14205
|
+
this.currentMtimeMs = mtimeMs;
|
|
14206
|
+
return parsed;
|
|
14207
|
+
}
|
|
14208
|
+
getUserId() {
|
|
14209
|
+
const id = this.current?.userInfo?.userId;
|
|
14210
|
+
if (!id) {
|
|
14211
|
+
throw new WixCliAuthError(
|
|
14212
|
+
`Wix CLI auth file ${this.accountFile} is missing userInfo.userId. Re-run \`npx @wix/cli login\`.`
|
|
14213
|
+
);
|
|
14214
|
+
}
|
|
14215
|
+
return id;
|
|
14216
|
+
}
|
|
14217
|
+
isExpired(token) {
|
|
14218
|
+
const expirationMs = (token.issuedAt + token.expiresIn) * 1e3;
|
|
14219
|
+
return Date.now() > expirationMs - this.bufferSeconds * 1e3;
|
|
14220
|
+
}
|
|
14221
|
+
/**
|
|
14222
|
+
* Re-read the token file if another process has updated it on disk since we
|
|
14223
|
+
* last loaded it. Avoids a redundant refresh when a sibling bridge process
|
|
14224
|
+
* has already done the work.
|
|
14225
|
+
*/
|
|
14226
|
+
async refreshFromDiskIfChanged() {
|
|
14227
|
+
try {
|
|
14228
|
+
const stat = await fs2.stat(this.accountFile);
|
|
14229
|
+
if (this.currentMtimeMs === void 0 || stat.mtimeMs > this.currentMtimeMs) {
|
|
14230
|
+
await this.load();
|
|
14231
|
+
}
|
|
14232
|
+
} catch {
|
|
14233
|
+
}
|
|
14234
|
+
}
|
|
14235
|
+
/** Returns a non-expired access token, refreshing and persisting if needed. */
|
|
14236
|
+
async getFreshToken() {
|
|
14237
|
+
if (!this.current) await this.load();
|
|
14238
|
+
else await this.refreshFromDiskIfChanged();
|
|
14239
|
+
const token = this.current;
|
|
14240
|
+
if (!this.isExpired(token)) return token;
|
|
14241
|
+
if (!this.inflight) {
|
|
14242
|
+
this.inflight = this.refresh(token).finally(() => {
|
|
14243
|
+
this.inflight = void 0;
|
|
14244
|
+
});
|
|
14245
|
+
}
|
|
14246
|
+
return this.inflight;
|
|
14247
|
+
}
|
|
14248
|
+
async refresh(token) {
|
|
14249
|
+
const res = await fetch("https://www.wixapis.com/oauth2/token", {
|
|
14250
|
+
method: "POST",
|
|
14251
|
+
headers: {
|
|
14252
|
+
"Content-Type": "application/json",
|
|
14253
|
+
Authorization: token.accessToken
|
|
14254
|
+
},
|
|
14255
|
+
body: JSON.stringify({
|
|
14256
|
+
clientId: this.clientId,
|
|
14257
|
+
grantType: "refresh_token",
|
|
14258
|
+
scope: "offline_access",
|
|
14259
|
+
refreshToken: token.refreshToken
|
|
14260
|
+
})
|
|
14261
|
+
});
|
|
14262
|
+
if (!res.ok) {
|
|
14263
|
+
const text = await res.text().catch(() => "");
|
|
14264
|
+
throw new WixCliAuthError(
|
|
14265
|
+
`Failed to refresh Wix access token (HTTP ${res.status}): ${text.slice(0, 500)}
|
|
14266
|
+
Run \`npx @wix/cli login\` to re-authenticate.`
|
|
14267
|
+
);
|
|
14268
|
+
}
|
|
14269
|
+
const data = await res.json();
|
|
14270
|
+
const next = {
|
|
14271
|
+
...token,
|
|
14272
|
+
accessToken: data.access_token,
|
|
14273
|
+
refreshToken: data.refresh_token,
|
|
14274
|
+
issuedAt: Math.floor(Date.now() / 1e3),
|
|
14275
|
+
expiresIn: data.expires_in
|
|
14276
|
+
};
|
|
14277
|
+
this.current = next;
|
|
14278
|
+
await this.persist(next);
|
|
14279
|
+
return next;
|
|
14280
|
+
}
|
|
14281
|
+
/** Atomic write: writes to a sibling .tmp file then renames into place. */
|
|
14282
|
+
async persist(token) {
|
|
14283
|
+
const tmp = `${this.accountFile}.tmp-${process.pid}-${Date.now()}`;
|
|
14284
|
+
try {
|
|
14285
|
+
await fs2.writeFile(tmp, JSON.stringify(token), {
|
|
14286
|
+
encoding: "utf-8",
|
|
14287
|
+
mode: 384
|
|
14288
|
+
});
|
|
14289
|
+
await fs2.rename(tmp, this.accountFile);
|
|
14290
|
+
const stat = await fs2.stat(this.accountFile).catch(() => void 0);
|
|
14291
|
+
if (stat) this.currentMtimeMs = stat.mtimeMs;
|
|
14292
|
+
} catch (err) {
|
|
14293
|
+
console.error(
|
|
14294
|
+
`[wix-mcp] Warning: could not persist refreshed token to ${this.accountFile}: ${err.message}`
|
|
14295
|
+
);
|
|
14296
|
+
await fs2.unlink(tmp).catch(() => void 0);
|
|
14297
|
+
}
|
|
14298
|
+
}
|
|
14299
|
+
};
|
|
14300
|
+
|
|
14301
|
+
// src/cli-tools/account-auth-strategy.ts
|
|
14302
|
+
var WIX_OAUTH_TOKEN_URL = "https://www.wixapis.com/oauth2/token";
|
|
14303
|
+
var WIX_CLIENT_ID = "f234ac48-6cab-4ef2-9ea0-03d56a376da4";
|
|
14304
|
+
function createAccountFileAuthStrategy({
|
|
14305
|
+
tokens
|
|
14306
|
+
}) {
|
|
14307
|
+
return {
|
|
14308
|
+
getAccountAuthHeaders: async () => {
|
|
14309
|
+
const token = await tokens.getFreshToken();
|
|
14310
|
+
return {
|
|
14311
|
+
Authorization: token.accessToken,
|
|
14312
|
+
"wix-account-id": tokens.getUserId()
|
|
14313
|
+
};
|
|
14314
|
+
},
|
|
14315
|
+
getSiteAuthHeaders: async (siteId) => {
|
|
14316
|
+
const token = await tokens.getFreshToken();
|
|
14317
|
+
const res = await fetch(WIX_OAUTH_TOKEN_URL, {
|
|
14318
|
+
method: "POST",
|
|
14319
|
+
headers: { "Content-Type": "application/json" },
|
|
14320
|
+
body: JSON.stringify({
|
|
14321
|
+
clientId: WIX_CLIENT_ID,
|
|
14322
|
+
grantType: "refresh_token",
|
|
14323
|
+
refreshToken: token.refreshToken,
|
|
14324
|
+
siteId
|
|
14325
|
+
})
|
|
14326
|
+
});
|
|
14327
|
+
if (!res.ok) {
|
|
14328
|
+
const body = await res.text().catch(() => "");
|
|
14329
|
+
throw new WixCliAuthError(
|
|
14330
|
+
`Site token exchange failed for site ${siteId} (HTTP ${res.status}): ${body.slice(0, 300)}`
|
|
14331
|
+
);
|
|
14332
|
+
}
|
|
14333
|
+
const data = await res.json();
|
|
14334
|
+
return {
|
|
14335
|
+
Authorization: data.access_token,
|
|
14336
|
+
"wix-site-id": siteId
|
|
14337
|
+
};
|
|
14338
|
+
}
|
|
14339
|
+
};
|
|
14340
|
+
}
|
|
14341
|
+
|
|
14139
14342
|
// src/bin.ts
|
|
14140
14343
|
var PUBLIC_TOOLS = [...VALID_DOCS_TOOLS];
|
|
14141
14344
|
var EXPERIMENTAL_TOOLS = [
|
|
@@ -14268,6 +14471,19 @@ if (cliTools.length > 0) {
|
|
|
14268
14471
|
}
|
|
14269
14472
|
}
|
|
14270
14473
|
}
|
|
14474
|
+
if (parsedArgs["wixCliAuth"]) {
|
|
14475
|
+
const accountFile = path4.join(homedir3(), ".wix", "auth", "account.json");
|
|
14476
|
+
if (!existsSync2(accountFile)) {
|
|
14477
|
+
logger.error(
|
|
14478
|
+
`--wixCliAuth was set but ${accountFile} does not exist. Run \`npx @wix/cli login\` first.`
|
|
14479
|
+
);
|
|
14480
|
+
process.exit(1);
|
|
14481
|
+
}
|
|
14482
|
+
logger.log("Enabling Wix CLI auth from ~/.wix/auth/account.json");
|
|
14483
|
+
const tokens = new TokenStore({ accountFile });
|
|
14484
|
+
const accountAuthStrategy = createAccountFileAuthStrategy({ tokens });
|
|
14485
|
+
addApiCallTool(server, accountAuthStrategy);
|
|
14486
|
+
}
|
|
14271
14487
|
try {
|
|
14272
14488
|
const portals = parsedArgs["portals"]?.split(",") || [];
|
|
14273
14489
|
if (portals.length > 0) {
|