@elitedcs/ghl-mcp 3.53.0 → 3.53.1
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/CHANGELOG.md +18 -0
- package/dist/capture-helper.js +5 -1
- package/dist/index.js +183 -116
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.53.1 — Laptops stop eating install slots; "cancelled" stops lying
|
|
4
|
+
|
|
5
|
+
Reported by Carlos Boyd, who hit his install cap with two physical machines.
|
|
6
|
+
|
|
7
|
+
- **Device identity is stable now.** The fingerprint was derived from the
|
|
8
|
+
machine hostname, and a Mac's `.local` hostname changes with the network
|
|
9
|
+
(new Wi-Fi, DHCP, a name collision) — so the same laptop could present a new
|
|
10
|
+
identity and claim another install slot. Identity is now a random id
|
|
11
|
+
persisted in the config dir, so it survives reinstalls and renames. On
|
|
12
|
+
upgrade it ADOPTS the fingerprint from the existing cached attestation, so no
|
|
13
|
+
current install loses the slot it already holds. `legacyDeviceFingerprint()`
|
|
14
|
+
is kept for reference.
|
|
15
|
+
- **Install-limit is no longer reported as "cancelled".** Both conditions come
|
|
16
|
+
back from the gate as 403, and the client labelled both `cancelled`, so a
|
|
17
|
+
full machine list read as a billing failure — two contradictory lines in the
|
|
18
|
+
same block. `install_limit` is its own reason, and the gate prints the
|
|
19
|
+
server's own sentence instead of a reason code beside it.
|
|
20
|
+
|
|
3
21
|
## 3.52.1 — Docs: positioning vs. HighLevel's official Anthropic MCP
|
|
4
22
|
|
|
5
23
|
No behavior changes; README only.
|
package/dist/capture-helper.js
CHANGED
|
@@ -48,7 +48,11 @@ var CredentialsSchema = import_zod.z.object({
|
|
|
48
48
|
// hand-crafted-credentials.json bypass that existed through v3.23.0).
|
|
49
49
|
// Optional in the schema only so files written by earlier versions still
|
|
50
50
|
// parse — index.ts's gate forces a re-validate when the field is missing.
|
|
51
|
-
signed_attestation: import_zod.z.string().optional()
|
|
51
|
+
signed_attestation: import_zod.z.string().optional(),
|
|
52
|
+
/** Stable machine id (2026-07-28). Replaces the hostname-derived
|
|
53
|
+
* fingerprint, which changed with the network on laptops and silently ate
|
|
54
|
+
* install slots. Written once and reused forever. */
|
|
55
|
+
device_id: import_zod.z.string().optional()
|
|
52
56
|
});
|
|
53
57
|
function appDataDir() {
|
|
54
58
|
const override = process.env.GHL_MCP_CONFIG_DIR?.trim();
|
package/dist/index.js
CHANGED
|
@@ -41,6 +41,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
41
41
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
42
42
|
mod
|
|
43
43
|
));
|
|
44
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
44
45
|
|
|
45
46
|
// src/retry.ts
|
|
46
47
|
function computeRetryDelay(retryAfterHeader, attempt, baseMs) {
|
|
@@ -214,6 +215,16 @@ ${errorBody}`
|
|
|
214
215
|
});
|
|
215
216
|
|
|
216
217
|
// src/credentials-store.ts
|
|
218
|
+
var credentials_store_exports = {};
|
|
219
|
+
__export(credentials_store_exports, {
|
|
220
|
+
appDataDir: () => appDataDir,
|
|
221
|
+
credentialsPath: () => credentialsPath,
|
|
222
|
+
ensureAppDataDir: () => ensureAppDataDir,
|
|
223
|
+
foldCredentialsIntoEnv: () => foldCredentialsIntoEnv,
|
|
224
|
+
readCredentials: () => readCredentials,
|
|
225
|
+
tokenRegistryPath: () => tokenRegistryPath,
|
|
226
|
+
writeCredentials: () => writeCredentials
|
|
227
|
+
});
|
|
217
228
|
function appDataDir() {
|
|
218
229
|
const override = process.env.GHL_MCP_CONFIG_DIR?.trim();
|
|
219
230
|
if (override) {
|
|
@@ -331,7 +342,11 @@ var init_credentials_store = __esm({
|
|
|
331
342
|
// hand-crafted-credentials.json bypass that existed through v3.23.0).
|
|
332
343
|
// Optional in the schema only so files written by earlier versions still
|
|
333
344
|
// parse — index.ts's gate forces a re-validate when the field is missing.
|
|
334
|
-
signed_attestation: import_zod.z.string().optional()
|
|
345
|
+
signed_attestation: import_zod.z.string().optional(),
|
|
346
|
+
/** Stable machine id (2026-07-28). Replaces the hostname-derived
|
|
347
|
+
* fingerprint, which changed with the network on laptops and silently ate
|
|
348
|
+
* install slots. Written once and reused forever. */
|
|
349
|
+
device_id: import_zod.z.string().optional()
|
|
335
350
|
});
|
|
336
351
|
}
|
|
337
352
|
});
|
|
@@ -962,10 +977,166 @@ var init_interactive_capture = __esm({
|
|
|
962
977
|
}
|
|
963
978
|
});
|
|
964
979
|
|
|
980
|
+
// src/attestation.ts
|
|
981
|
+
var attestation_exports = {};
|
|
982
|
+
__export(attestation_exports, {
|
|
983
|
+
ATTESTATION_GRACE_DAYS: () => ATTESTATION_GRACE_DAYS,
|
|
984
|
+
ATTESTATION_TTL_DAYS: () => ATTESTATION_TTL_DAYS,
|
|
985
|
+
ATTESTATION_VERSION: () => ATTESTATION_VERSION,
|
|
986
|
+
deviceFingerprint: () => deviceFingerprint,
|
|
987
|
+
legacyDeviceFingerprint: () => legacyDeviceFingerprint,
|
|
988
|
+
parseAttestationPayload: () => parseAttestationPayload,
|
|
989
|
+
planFromPayload: () => planFromPayload,
|
|
990
|
+
shouldRenew: () => shouldRenew,
|
|
991
|
+
tierFromPayload: () => tierFromPayload,
|
|
992
|
+
verifyAttestation: () => verifyAttestation
|
|
993
|
+
});
|
|
994
|
+
function tierFromPayload(payload) {
|
|
995
|
+
return payload?.tier === "free" ? "free" : "full";
|
|
996
|
+
}
|
|
997
|
+
function planFromPayload(payload) {
|
|
998
|
+
return payload?.plan === "command-os" ? "command-os" : "mcp";
|
|
999
|
+
}
|
|
1000
|
+
function legacyDeviceFingerprint() {
|
|
1001
|
+
const os5 = require("node:os");
|
|
1002
|
+
const crypto4 = require("node:crypto");
|
|
1003
|
+
const raw = `${os5.hostname()}:${os5.userInfo().username}:${os5.platform()}:${os5.arch()}`;
|
|
1004
|
+
return crypto4.createHash("sha256").update(raw).digest("hex").slice(0, 16);
|
|
1005
|
+
}
|
|
1006
|
+
function deviceFingerprint(opts) {
|
|
1007
|
+
if (opts?.stored) return opts.stored;
|
|
1008
|
+
if (opts?.cached) {
|
|
1009
|
+
opts.persist?.(opts.cached);
|
|
1010
|
+
return opts.cached;
|
|
1011
|
+
}
|
|
1012
|
+
const crypto4 = require("node:crypto");
|
|
1013
|
+
const fresh = crypto4.randomBytes(8).toString("hex");
|
|
1014
|
+
opts?.persist?.(fresh);
|
|
1015
|
+
return fresh;
|
|
1016
|
+
}
|
|
1017
|
+
function base64urlDecode(s) {
|
|
1018
|
+
const b64 = s.replace(/-/g, "+").replace(/_/g, "/");
|
|
1019
|
+
const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
|
|
1020
|
+
return new Uint8Array(Buffer.from(padded, "base64"));
|
|
1021
|
+
}
|
|
1022
|
+
async function getPublicKey() {
|
|
1023
|
+
if (cachedPublicKey) return cachedPublicKey;
|
|
1024
|
+
const raw = Buffer.from(ATTESTATION_PUBLIC_KEY_B64, "base64");
|
|
1025
|
+
cachedPublicKey = await import_node_crypto.webcrypto.subtle.importKey(
|
|
1026
|
+
"raw",
|
|
1027
|
+
raw,
|
|
1028
|
+
{ name: "Ed25519" },
|
|
1029
|
+
false,
|
|
1030
|
+
["verify"]
|
|
1031
|
+
);
|
|
1032
|
+
return cachedPublicKey;
|
|
1033
|
+
}
|
|
1034
|
+
function parseAttestationPayload(token) {
|
|
1035
|
+
try {
|
|
1036
|
+
const dot = token.indexOf(".");
|
|
1037
|
+
if (dot <= 0 || dot === token.length - 1) return null;
|
|
1038
|
+
const payloadJson = new TextDecoder().decode(base64urlDecode(token.slice(0, dot)));
|
|
1039
|
+
const payload = JSON.parse(payloadJson);
|
|
1040
|
+
if (typeof payload.v !== "number" || typeof payload.email !== "string" || typeof payload.license_key !== "string" || typeof payload.device_fingerprint !== "string" || typeof payload.installs_max !== "number" || typeof payload.issued_at !== "string" || typeof payload.expires_at !== "string") {
|
|
1041
|
+
return null;
|
|
1042
|
+
}
|
|
1043
|
+
return payload;
|
|
1044
|
+
} catch {
|
|
1045
|
+
return null;
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
async function verifyAttestation(token, bindings, now = /* @__PURE__ */ new Date()) {
|
|
1049
|
+
if (typeof token !== "string" || !token) return { ok: false, reason: "malformed" };
|
|
1050
|
+
const dot = token.indexOf(".");
|
|
1051
|
+
if (dot <= 0 || dot === token.length - 1) return { ok: false, reason: "malformed" };
|
|
1052
|
+
let payloadBytes;
|
|
1053
|
+
let signatureBytes;
|
|
1054
|
+
try {
|
|
1055
|
+
payloadBytes = base64urlDecode(token.slice(0, dot));
|
|
1056
|
+
signatureBytes = base64urlDecode(token.slice(dot + 1));
|
|
1057
|
+
} catch {
|
|
1058
|
+
return { ok: false, reason: "malformed" };
|
|
1059
|
+
}
|
|
1060
|
+
let payload;
|
|
1061
|
+
try {
|
|
1062
|
+
const parsed = JSON.parse(new TextDecoder().decode(payloadBytes));
|
|
1063
|
+
if (typeof parsed.v !== "number") return { ok: false, reason: "malformed" };
|
|
1064
|
+
if (parsed.v !== ATTESTATION_VERSION) return { ok: false, reason: "unsupported-version" };
|
|
1065
|
+
payload = parsed;
|
|
1066
|
+
} catch {
|
|
1067
|
+
return { ok: false, reason: "malformed" };
|
|
1068
|
+
}
|
|
1069
|
+
let signatureValid;
|
|
1070
|
+
try {
|
|
1071
|
+
const key = await getPublicKey();
|
|
1072
|
+
signatureValid = await import_node_crypto.webcrypto.subtle.verify({ name: "Ed25519" }, key, signatureBytes, payloadBytes);
|
|
1073
|
+
} catch {
|
|
1074
|
+
return { ok: false, reason: "bad-signature" };
|
|
1075
|
+
}
|
|
1076
|
+
if (!signatureValid) return { ok: false, reason: "bad-signature" };
|
|
1077
|
+
if (payload.email.toLowerCase() !== bindings.email.toLowerCase()) {
|
|
1078
|
+
return { ok: false, reason: "wrong-email" };
|
|
1079
|
+
}
|
|
1080
|
+
if (payload.license_key !== bindings.license_key) {
|
|
1081
|
+
return { ok: false, reason: "wrong-license" };
|
|
1082
|
+
}
|
|
1083
|
+
const fingerprint = bindings.expectedFingerprint ?? deviceFingerprint();
|
|
1084
|
+
if (payload.device_fingerprint !== fingerprint) {
|
|
1085
|
+
return { ok: false, reason: "wrong-device" };
|
|
1086
|
+
}
|
|
1087
|
+
const expiry = Date.parse(payload.expires_at);
|
|
1088
|
+
if (!Number.isFinite(expiry)) return { ok: false, reason: "malformed" };
|
|
1089
|
+
const graceDeadline = expiry + ATTESTATION_GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
1090
|
+
if (now.getTime() <= expiry) {
|
|
1091
|
+
return { ok: true, payload, reason: "valid" };
|
|
1092
|
+
}
|
|
1093
|
+
if (now.getTime() <= graceDeadline) {
|
|
1094
|
+
return { ok: true, payload, reason: "in-grace" };
|
|
1095
|
+
}
|
|
1096
|
+
return { ok: false, reason: "expired" };
|
|
1097
|
+
}
|
|
1098
|
+
function shouldRenew(payload, now = /* @__PURE__ */ new Date()) {
|
|
1099
|
+
const expiry = Date.parse(payload.expires_at);
|
|
1100
|
+
if (!Number.isFinite(expiry)) return true;
|
|
1101
|
+
const remainingMs = expiry - now.getTime();
|
|
1102
|
+
return remainingMs < 7 * 24 * 60 * 60 * 1e3;
|
|
1103
|
+
}
|
|
1104
|
+
var import_node_crypto, ATTESTATION_PUBLIC_KEY_B64, ATTESTATION_VERSION, ATTESTATION_TTL_DAYS, ATTESTATION_GRACE_DAYS, cachedPublicKey;
|
|
1105
|
+
var init_attestation = __esm({
|
|
1106
|
+
"src/attestation.ts"() {
|
|
1107
|
+
"use strict";
|
|
1108
|
+
import_node_crypto = require("node:crypto");
|
|
1109
|
+
ATTESTATION_PUBLIC_KEY_B64 = "8KJo8V3Z7ngeToIQfOXpKdlr/EA34hXJVEIpW0A7wqs=";
|
|
1110
|
+
ATTESTATION_VERSION = 1;
|
|
1111
|
+
ATTESTATION_TTL_DAYS = 30;
|
|
1112
|
+
ATTESTATION_GRACE_DAYS = 14;
|
|
1113
|
+
cachedPublicKey = null;
|
|
1114
|
+
}
|
|
1115
|
+
});
|
|
1116
|
+
|
|
965
1117
|
// src/setup-tool.ts
|
|
966
|
-
function
|
|
967
|
-
|
|
968
|
-
|
|
1118
|
+
function deviceFingerprint2() {
|
|
1119
|
+
try {
|
|
1120
|
+
const store = (init_credentials_store(), __toCommonJS(credentials_store_exports));
|
|
1121
|
+
const creds = store.readCredentials();
|
|
1122
|
+
if (creds?.device_id) return creds.device_id;
|
|
1123
|
+
let adopted;
|
|
1124
|
+
if (creds?.signed_attestation) {
|
|
1125
|
+
const att = (init_attestation(), __toCommonJS(attestation_exports));
|
|
1126
|
+
adopted = att.parseAttestationPayload(creds.signed_attestation)?.device_fingerprint;
|
|
1127
|
+
}
|
|
1128
|
+
const id = adopted || crypto2.randomBytes(8).toString("hex");
|
|
1129
|
+
if (creds) {
|
|
1130
|
+
try {
|
|
1131
|
+
store.writeCredentials({ ...creds, device_id: id });
|
|
1132
|
+
} catch {
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
return id;
|
|
1136
|
+
} catch {
|
|
1137
|
+
const raw = `${os2.userInfo().username}:${os2.platform()}:${os2.arch()}`;
|
|
1138
|
+
return crypto2.createHash("sha256").update(raw).digest("hex").slice(0, 16);
|
|
1139
|
+
}
|
|
969
1140
|
}
|
|
970
1141
|
async function validateLicense(email, licenseKey) {
|
|
971
1142
|
let res;
|
|
@@ -976,7 +1147,7 @@ async function validateLicense(email, licenseKey) {
|
|
|
976
1147
|
body: JSON.stringify({
|
|
977
1148
|
email: email.trim(),
|
|
978
1149
|
license_key: licenseKey.trim(),
|
|
979
|
-
device_fingerprint:
|
|
1150
|
+
device_fingerprint: deviceFingerprint2()
|
|
980
1151
|
}),
|
|
981
1152
|
signal: AbortSignal.timeout(1e4)
|
|
982
1153
|
});
|
|
@@ -997,11 +1168,12 @@ async function validateLicense(email, licenseKey) {
|
|
|
997
1168
|
};
|
|
998
1169
|
}
|
|
999
1170
|
const errorText = String(data.error || data.message || "").toLowerCase();
|
|
1000
|
-
const
|
|
1171
|
+
const isInstallLimit = errorText.includes("install limit") || errorText.includes("installs");
|
|
1172
|
+
const looksCancelled = !isInstallLimit && (res.status === 403 || errorText.includes("cancel"));
|
|
1001
1173
|
return {
|
|
1002
1174
|
ok: false,
|
|
1003
1175
|
error: data.error || data.message || `License validation failed (HTTP ${res.status})`,
|
|
1004
|
-
reason: looksCancelled ? "cancelled" : "unauthorized"
|
|
1176
|
+
reason: isInstallLimit ? "install_limit" : looksCancelled ? "cancelled" : "unauthorized"
|
|
1005
1177
|
};
|
|
1006
1178
|
}
|
|
1007
1179
|
async function validateGhl(apiKey2, locationId2) {
|
|
@@ -1907,118 +2079,12 @@ var init_question_set = __esm({
|
|
|
1907
2079
|
}
|
|
1908
2080
|
});
|
|
1909
2081
|
|
|
1910
|
-
// src/attestation.ts
|
|
1911
|
-
function tierFromPayload(payload) {
|
|
1912
|
-
return payload?.tier === "free" ? "free" : "full";
|
|
1913
|
-
}
|
|
1914
|
-
function planFromPayload(payload) {
|
|
1915
|
-
return payload?.plan === "command-os" ? "command-os" : "mcp";
|
|
1916
|
-
}
|
|
1917
|
-
function deviceFingerprint2() {
|
|
1918
|
-
const os5 = require("node:os");
|
|
1919
|
-
const crypto4 = require("node:crypto");
|
|
1920
|
-
const raw = `${os5.hostname()}:${os5.userInfo().username}:${os5.platform()}:${os5.arch()}`;
|
|
1921
|
-
return crypto4.createHash("sha256").update(raw).digest("hex").slice(0, 16);
|
|
1922
|
-
}
|
|
1923
|
-
function base64urlDecode(s) {
|
|
1924
|
-
const b64 = s.replace(/-/g, "+").replace(/_/g, "/");
|
|
1925
|
-
const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
|
|
1926
|
-
return new Uint8Array(Buffer.from(padded, "base64"));
|
|
1927
|
-
}
|
|
1928
|
-
async function getPublicKey() {
|
|
1929
|
-
if (cachedPublicKey) return cachedPublicKey;
|
|
1930
|
-
const raw = Buffer.from(ATTESTATION_PUBLIC_KEY_B64, "base64");
|
|
1931
|
-
cachedPublicKey = await import_node_crypto.webcrypto.subtle.importKey(
|
|
1932
|
-
"raw",
|
|
1933
|
-
raw,
|
|
1934
|
-
{ name: "Ed25519" },
|
|
1935
|
-
false,
|
|
1936
|
-
["verify"]
|
|
1937
|
-
);
|
|
1938
|
-
return cachedPublicKey;
|
|
1939
|
-
}
|
|
1940
|
-
function parseAttestationPayload(token) {
|
|
1941
|
-
try {
|
|
1942
|
-
const dot = token.indexOf(".");
|
|
1943
|
-
if (dot <= 0 || dot === token.length - 1) return null;
|
|
1944
|
-
const payloadJson = new TextDecoder().decode(base64urlDecode(token.slice(0, dot)));
|
|
1945
|
-
const payload = JSON.parse(payloadJson);
|
|
1946
|
-
if (typeof payload.v !== "number" || typeof payload.email !== "string" || typeof payload.license_key !== "string" || typeof payload.device_fingerprint !== "string" || typeof payload.installs_max !== "number" || typeof payload.issued_at !== "string" || typeof payload.expires_at !== "string") {
|
|
1947
|
-
return null;
|
|
1948
|
-
}
|
|
1949
|
-
return payload;
|
|
1950
|
-
} catch {
|
|
1951
|
-
return null;
|
|
1952
|
-
}
|
|
1953
|
-
}
|
|
1954
|
-
async function verifyAttestation(token, bindings, now = /* @__PURE__ */ new Date()) {
|
|
1955
|
-
if (typeof token !== "string" || !token) return { ok: false, reason: "malformed" };
|
|
1956
|
-
const dot = token.indexOf(".");
|
|
1957
|
-
if (dot <= 0 || dot === token.length - 1) return { ok: false, reason: "malformed" };
|
|
1958
|
-
let payloadBytes;
|
|
1959
|
-
let signatureBytes;
|
|
1960
|
-
try {
|
|
1961
|
-
payloadBytes = base64urlDecode(token.slice(0, dot));
|
|
1962
|
-
signatureBytes = base64urlDecode(token.slice(dot + 1));
|
|
1963
|
-
} catch {
|
|
1964
|
-
return { ok: false, reason: "malformed" };
|
|
1965
|
-
}
|
|
1966
|
-
let payload;
|
|
1967
|
-
try {
|
|
1968
|
-
const parsed = JSON.parse(new TextDecoder().decode(payloadBytes));
|
|
1969
|
-
if (typeof parsed.v !== "number") return { ok: false, reason: "malformed" };
|
|
1970
|
-
if (parsed.v !== ATTESTATION_VERSION) return { ok: false, reason: "unsupported-version" };
|
|
1971
|
-
payload = parsed;
|
|
1972
|
-
} catch {
|
|
1973
|
-
return { ok: false, reason: "malformed" };
|
|
1974
|
-
}
|
|
1975
|
-
let signatureValid;
|
|
1976
|
-
try {
|
|
1977
|
-
const key = await getPublicKey();
|
|
1978
|
-
signatureValid = await import_node_crypto.webcrypto.subtle.verify({ name: "Ed25519" }, key, signatureBytes, payloadBytes);
|
|
1979
|
-
} catch {
|
|
1980
|
-
return { ok: false, reason: "bad-signature" };
|
|
1981
|
-
}
|
|
1982
|
-
if (!signatureValid) return { ok: false, reason: "bad-signature" };
|
|
1983
|
-
if (payload.email.toLowerCase() !== bindings.email.toLowerCase()) {
|
|
1984
|
-
return { ok: false, reason: "wrong-email" };
|
|
1985
|
-
}
|
|
1986
|
-
if (payload.license_key !== bindings.license_key) {
|
|
1987
|
-
return { ok: false, reason: "wrong-license" };
|
|
1988
|
-
}
|
|
1989
|
-
const fingerprint = bindings.expectedFingerprint ?? deviceFingerprint2();
|
|
1990
|
-
if (payload.device_fingerprint !== fingerprint) {
|
|
1991
|
-
return { ok: false, reason: "wrong-device" };
|
|
1992
|
-
}
|
|
1993
|
-
const expiry = Date.parse(payload.expires_at);
|
|
1994
|
-
if (!Number.isFinite(expiry)) return { ok: false, reason: "malformed" };
|
|
1995
|
-
const graceDeadline = expiry + ATTESTATION_GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
1996
|
-
if (now.getTime() <= expiry) {
|
|
1997
|
-
return { ok: true, payload, reason: "valid" };
|
|
1998
|
-
}
|
|
1999
|
-
if (now.getTime() <= graceDeadline) {
|
|
2000
|
-
return { ok: true, payload, reason: "in-grace" };
|
|
2001
|
-
}
|
|
2002
|
-
return { ok: false, reason: "expired" };
|
|
2003
|
-
}
|
|
2004
|
-
var import_node_crypto, ATTESTATION_PUBLIC_KEY_B64, ATTESTATION_VERSION, ATTESTATION_GRACE_DAYS, cachedPublicKey;
|
|
2005
|
-
var init_attestation = __esm({
|
|
2006
|
-
"src/attestation.ts"() {
|
|
2007
|
-
"use strict";
|
|
2008
|
-
import_node_crypto = require("node:crypto");
|
|
2009
|
-
ATTESTATION_PUBLIC_KEY_B64 = "8KJo8V3Z7ngeToIQfOXpKdlr/EA34hXJVEIpW0A7wqs=";
|
|
2010
|
-
ATTESTATION_VERSION = 1;
|
|
2011
|
-
ATTESTATION_GRACE_DAYS = 14;
|
|
2012
|
-
cachedPublicKey = null;
|
|
2013
|
-
}
|
|
2014
|
-
});
|
|
2015
|
-
|
|
2016
2082
|
// package.json
|
|
2017
2083
|
var require_package = __commonJS({
|
|
2018
2084
|
"package.json"(exports2, module2) {
|
|
2019
2085
|
module2.exports = {
|
|
2020
2086
|
name: "@elitedcs/ghl-mcp",
|
|
2021
|
-
version: "3.53.
|
|
2087
|
+
version: "3.53.1",
|
|
2022
2088
|
mcpName: "io.github.drjerryrelth/ghl-command",
|
|
2023
2089
|
description: "GoHighLevel MCP Server for Claude. 232 tools \u2014 full CRM, automation, marketing control, account-wide workflow audit, live funnel-capture verification, and the only programmatic GHL workflow builder, now multi-tenant across client accounts.",
|
|
2024
2090
|
main: "dist/index.js",
|
|
@@ -16986,10 +17052,11 @@ async function renewAttestation(creds) {
|
|
|
16986
17052
|
}
|
|
16987
17053
|
return "renewed";
|
|
16988
17054
|
}
|
|
16989
|
-
if (lic.reason === "cancelled" || lic.reason === "unauthorized") {
|
|
17055
|
+
if (lic.reason === "cancelled" || lic.reason === "unauthorized" || lic.reason === "install_limit") {
|
|
16990
17056
|
try {
|
|
16991
17057
|
writeCredentials({ ...creds, signed_attestation: void 0 });
|
|
16992
|
-
process.stderr.write(`[ghl-mcp]
|
|
17058
|
+
process.stderr.write(lic.reason === "install_limit" ? `[ghl-mcp] ${lic.error}
|
|
17059
|
+
` : `[ghl-mcp] ${lic.error} Dropping to bootstrap mode.
|
|
16993
17060
|
`);
|
|
16994
17061
|
} catch {
|
|
16995
17062
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elitedcs/ghl-mcp",
|
|
3
|
-
"version": "3.53.
|
|
3
|
+
"version": "3.53.1",
|
|
4
4
|
"mcpName": "io.github.drjerryrelth/ghl-command",
|
|
5
|
-
"description": "GoHighLevel MCP Server for Claude. 232 tools
|
|
5
|
+
"description": "GoHighLevel MCP Server for Claude. 232 tools \u2014 full CRM, automation, marketing control, account-wide workflow audit, live funnel-capture verification, and the only programmatic GHL workflow builder, now multi-tenant across client accounts.",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"ghl-mcp": "dist/index.js"
|