@elitedcs/ghl-mcp 3.49.0 → 3.50.0
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 +54 -0
- package/README.md +13 -2
- package/dist/index.js +107 -16
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,59 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.50.0 — FREE read-only tier
|
|
4
|
+
|
|
5
|
+
A free license (`ghlcommand.com/free`, key by email, no card) now runs the same
|
|
6
|
+
npm package in read-only mode on the user's own GHL account.
|
|
7
|
+
|
|
8
|
+
- **Tier gating in the tool registry** (`tool-filter.ts`, second axis alongside
|
|
9
|
+
the env allowlist). Free tier: every read-only tool works for real — all
|
|
10
|
+
`get_*`/`list_*`/`search_*` plus `audit_workflows`, `validate_workflow`,
|
|
11
|
+
`get_account_health_summary`, `compare_locations`, `verify_funnel`,
|
|
12
|
+
`check_blog_slug`, `workflow_builder_status`. That's **105 usable tools with
|
|
13
|
+
the Firebase login (87 before it)**, enumerated from the registry by the
|
|
14
|
+
drift-guard test. Write tools still register with full schemas but their
|
|
15
|
+
handlers return a clean upgrade message (checkout link, same-key upgrade
|
|
16
|
+
note) — never a stack trace, never a half-executed write. Excluded from free
|
|
17
|
+
by design: `export_account`, the whole Blueprint (`intake-to-build`) module,
|
|
18
|
+
and the multi-location registry writes (`register_location`,
|
|
19
|
+
`register_agency_key`, `switch_location`, …) — free is 1 location, 1 machine.
|
|
20
|
+
- **Tier is cryptographically bound.** The license server now signs `tier`
|
|
21
|
+
inside the Ed25519 attestation payload; the MCP derives the session tier ONLY
|
|
22
|
+
from a verified attestation (legacy attestations without the field = 'full').
|
|
23
|
+
Hand-editing credentials.json cannot unlock writes. Old MCP versions ignore
|
|
24
|
+
the extra payload field — fully backward compatible.
|
|
25
|
+
- **Firebase capture stays available on free** (`capture_firebase_interactive`,
|
|
26
|
+
`enable_workflow_builder`, `auto_capture_firebase_script`): the one-time GHL
|
|
27
|
+
login is what powers the read-only auditor suite. Builder writes stay gated.
|
|
28
|
+
- **setup_ghl_mcp / request_license** are tier-aware: free installs see the
|
|
29
|
+
read-only counts and the auditor-unlock next step; request_license now offers
|
|
30
|
+
the free tier (`ghlcommand.com/free`) alongside purchase.
|
|
31
|
+
- **Drift guard extended** (`tool-count.test.ts`): free-tier counts (105/87)
|
|
32
|
+
are computed from the registry and asserted against README + setup-tool copy;
|
|
33
|
+
a classification change breaks the build until the claims are re-synced. The
|
|
34
|
+
ghlcommand.com `/free` page and the key-delivery email carry the same number —
|
|
35
|
+
re-sync those manually when this test moves (different repos).
|
|
36
|
+
- Server side (elite-dcs/website + Supabase, deployed separately): `licenses.status`
|
|
37
|
+
gains `'free'`; `register_device` returns the row status; `validate-license`
|
|
38
|
+
returns + signs `tier`; the Stripe webhook upgrades a free row IN PLACE on
|
|
39
|
+
purchase (same key, installs 1→3, `source: stripe_97mo_from_free`) — proven
|
|
40
|
+
against a live throwaway row and a mocked-fetch webhook harness. New
|
|
41
|
+
`/api/free-license` provisioning endpoint (signup → row → key email → 3NA51
|
|
42
|
+
tag `ghl-command-free-tier`).
|
|
43
|
+
|
|
44
|
+
## 3.49.1 — Docs patch: one-click capture is now the primary Milestone-2 path
|
|
45
|
+
|
|
46
|
+
No behavior changes; text only.
|
|
47
|
+
|
|
48
|
+
- README "Enable the Workflow Builder": `capture_firebase_interactive` (log into a
|
|
49
|
+
Chrome window, zero pasting) is the supported path; the console-paste script is
|
|
50
|
+
demoted to a collapsed fallback (still the path for locked-down machines and for
|
|
51
|
+
capturing CLIENT accounts in multi-tenant). Rotation note now points at the
|
|
52
|
+
silent re-capture.
|
|
53
|
+
- `enable_workflow_builder` and `auto_capture_firebase_script` tool descriptions
|
|
54
|
+
point to `capture_firebase_interactive` first.
|
|
55
|
+
|
|
56
|
+
|
|
3
57
|
## 3.49.0 — One-click Workflow Builder unlock (`capture_firebase_interactive`)
|
|
4
58
|
|
|
5
59
|
The buyer's whole job is now: log into GHL in a Chrome window the tool opens.
|
package/README.md
CHANGED
|
@@ -8,6 +8,8 @@ Works with **both the Claude Desktop App and Claude Code terminal** — your cho
|
|
|
8
8
|
|
|
9
9
|
**License required.** Get it at [ghlcommand.com](https://ghlcommand.com?utm_source=npm&utm_medium=readme) — $97/mo, covering UNLIMITED GoHighLevel sub-accounts on up to 3 machines (never billed per account). **30-day time-back guarantee**: save 5+ hours on one client build or your first month back.
|
|
10
10
|
|
|
11
|
+
**Try it FREE (read-only tier).** Grab an instant free key at [ghlcommand.com/free](https://ghlcommand.com/free?utm_source=npm&utm_medium=readme) — 105 read-only tools on your own GHL account (87 before the one-login auditor unlock): the account-wide workflow audit (`audit_workflows` finds the silently broken references GHL never warns you about), account health, and every read across contacts, pipelines, funnels, and workflows. Write tools stay visible and answer with upgrade info. Buying later with the same email upgrades your key in place — 1 machine on free, 3 when you upgrade.
|
|
12
|
+
|
|
11
13
|
Built by [Elite DCs, LLC](https://elitedcs.com).
|
|
12
14
|
|
|
13
15
|
---
|
|
@@ -158,7 +160,16 @@ https://app.gohighlevel.com/v2/location/YOUR_LOCATION_ID/dashboard
|
|
|
158
160
|
|
|
159
161
|
The builder + cloner + validator tools (workflow builder, funnel builder, form builder, pipeline builder, workflow cloner, validate_workflow) use GHL's internal API and require Firebase credentials. Without them, the other 177 tools work fine — you just won't have workflow/funnel/form/pipeline editing. This is the flagship feature: do this step.
|
|
160
162
|
|
|
161
|
-
**One-
|
|
163
|
+
**One-click capture (v3.49.0+, the supported path):**
|
|
164
|
+
|
|
165
|
+
1. In Claude, ask: `Run capture_firebase_interactive`. Your installed Chrome opens a dedicated window on the GHL login page (no browser download; it never touches your daily browsing profile).
|
|
166
|
+
2. Log into your GHL account in that window. That's the whole job — the tool reads the three Firebase values itself, validates them against Firebase, and saves them. If the call says it's still waiting, finish logging in and run the same tool again.
|
|
167
|
+
3. Restart Claude. The Firebase-gated tools are live.
|
|
168
|
+
|
|
169
|
+
> Firebase refresh tokens can rotate. If workflow tools stop working after a few weeks (`health_check` shows Firebase auth: FAIL), just re-run `capture_firebase_interactive` — after your first login it re-captures silently, no window at all.
|
|
170
|
+
|
|
171
|
+
<details>
|
|
172
|
+
<summary><strong>Console-paste fallback</strong> (no Chrome/Edge installed, the window path fails, or you're capturing a CLIENT account for multi-tenant)</summary>
|
|
162
173
|
|
|
163
174
|
1. In Claude, ask: `Run auto_capture_firebase_script`. It returns a small browser-console script.
|
|
164
175
|
2. In Chrome, open a tab logged into your GHL account. Press **F12** (Windows) or **Cmd+Option+I** (Mac), click the **Console** tab, paste the script, press Enter. If Chrome blocks the paste, type `allow pasting` in the Console first, then paste again.
|
|
@@ -168,7 +179,7 @@ The builder + cloner + validator tools (workflow builder, funnel builder, form b
|
|
|
168
179
|
|
|
169
180
|
Screenshots and the same script behind a copy button: [elitedcs.com/ghl-mcp-firebase](https://elitedcs.com/ghl-mcp-firebase)
|
|
170
181
|
|
|
171
|
-
>
|
|
182
|
+
</details>
|
|
172
183
|
|
|
173
184
|
<details>
|
|
174
185
|
<summary><strong>Manual fallback</strong> (locked-down browsers that block console pasting or clipboard access)</summary>
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ var require_package = __commonJS({
|
|
|
31
31
|
"package.json"(exports2, module2) {
|
|
32
32
|
module2.exports = {
|
|
33
33
|
name: "@elitedcs/ghl-mcp",
|
|
34
|
-
version: "3.
|
|
34
|
+
version: "3.50.0",
|
|
35
35
|
mcpName: "io.github.drjerryrelth/ghl-command",
|
|
36
36
|
description: "GoHighLevel MCP Server for Claude. 229 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.",
|
|
37
37
|
main: "dist/index.js",
|
|
@@ -1947,6 +1947,47 @@ var ALWAYS_ON_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
|
1947
1947
|
"enable_workflow_builder",
|
|
1948
1948
|
"health_check"
|
|
1949
1949
|
]);
|
|
1950
|
+
var FREE_TIER_EXTRA_READ_TOOLS = /* @__PURE__ */ new Set([
|
|
1951
|
+
"audit_workflows",
|
|
1952
|
+
// account-wide silent-failure audit — the free tier's wow moment
|
|
1953
|
+
"validate_workflow",
|
|
1954
|
+
// single-workflow pre-flight validation (read-only)
|
|
1955
|
+
"compare_locations",
|
|
1956
|
+
// cross-location config diff (reads only)
|
|
1957
|
+
"verify_funnel",
|
|
1958
|
+
// live funnel QA (reads + public URL probes)
|
|
1959
|
+
"check_blog_slug",
|
|
1960
|
+
// slug availability lookup
|
|
1961
|
+
"workflow_builder_status"
|
|
1962
|
+
// no-Firebase fallback diagnostic (pure status read)
|
|
1963
|
+
]);
|
|
1964
|
+
var FREE_TIER_EXCLUDED_TOOLS = /* @__PURE__ */ new Set([
|
|
1965
|
+
"export_account"
|
|
1966
|
+
// full-account export is a paid capability
|
|
1967
|
+
]);
|
|
1968
|
+
var FREE_TIER_EXCLUDED_MODULES = /* @__PURE__ */ new Set([
|
|
1969
|
+
"intake-to-build"
|
|
1970
|
+
// Blueprint lane is paid end-to-end
|
|
1971
|
+
]);
|
|
1972
|
+
var READ_PREFIXES = ["get_", "list_", "search_"];
|
|
1973
|
+
function isFreeTierTool(toolName, moduleName) {
|
|
1974
|
+
if (ALWAYS_ON_TOOL_NAMES.has(toolName)) return true;
|
|
1975
|
+
if (FREE_TIER_EXCLUDED_MODULES.has(moduleName.toLowerCase())) return false;
|
|
1976
|
+
if (FREE_TIER_EXCLUDED_TOOLS.has(toolName)) return false;
|
|
1977
|
+
if (FREE_TIER_EXTRA_READ_TOOLS.has(toolName)) return true;
|
|
1978
|
+
return READ_PREFIXES.some((p) => toolName.startsWith(p));
|
|
1979
|
+
}
|
|
1980
|
+
var FREE_TIER_DESC_SUFFIX = " [PAID TIER \u2014 this free license is read-only; calling this returns upgrade info, it will NOT perform the action.]";
|
|
1981
|
+
function freeTierUpgradeMessage(toolName) {
|
|
1982
|
+
return [
|
|
1983
|
+
`\`${toolName}\` needs the full GHL Command license \u2014 your free key is the read-only tier.`,
|
|
1984
|
+
"",
|
|
1985
|
+
"Free tier (what you have): every read \u2014 audits, account health, pipelines, contacts, conversations, funnels, workflows \u2014 on your own account.",
|
|
1986
|
+
"Full tier ($97/mo founding rate): Claude actually builds and fixes things \u2014 workflows, funnels, forms, pipelines, campaigns \u2014 plus the Workflow Builder, multi-location, and 3-machine activation.",
|
|
1987
|
+
"",
|
|
1988
|
+
"Upgrade at https://ghlcommand.com with the SAME email you used for the free key \u2014 your license upgrades in place (no reinstall, same key). Then fully restart Claude and this tool goes live."
|
|
1989
|
+
].join("\n");
|
|
1990
|
+
}
|
|
1950
1991
|
function parseList(raw) {
|
|
1951
1992
|
if (raw === void 0) return null;
|
|
1952
1993
|
const items = raw.split(/[,\s]+/).map((x) => x.trim().toLowerCase()).filter((x) => x.length > 0);
|
|
@@ -1974,7 +2015,7 @@ function shouldRegister(toolName, moduleName, config3) {
|
|
|
1974
2015
|
const toolEnabled = config3.enabledTools?.has(toolLower) ?? false;
|
|
1975
2016
|
return moduleEnabled || toolEnabled;
|
|
1976
2017
|
}
|
|
1977
|
-
function wrapServerForModule(realServer, moduleName, config3, attemptedTools, registeredTools) {
|
|
2018
|
+
function wrapServerForModule(realServer, moduleName, config3, attemptedTools, registeredTools, tier = "full", gatedTools) {
|
|
1978
2019
|
return new Proxy(realServer, {
|
|
1979
2020
|
get(target, prop, receiver) {
|
|
1980
2021
|
if (prop === "tool") {
|
|
@@ -1984,7 +2025,21 @@ function wrapServerForModule(realServer, moduleName, config3, attemptedTools, re
|
|
|
1984
2025
|
return void 0;
|
|
1985
2026
|
}
|
|
1986
2027
|
registeredTools.add(name);
|
|
1987
|
-
|
|
2028
|
+
let args = rest;
|
|
2029
|
+
if (tier === "free" && !isFreeTierTool(name, moduleName)) {
|
|
2030
|
+
gatedTools?.add(name);
|
|
2031
|
+
args = [...rest];
|
|
2032
|
+
const last = args.length - 1;
|
|
2033
|
+
if (last >= 0 && typeof args[last] === "function") {
|
|
2034
|
+
args[last] = async () => ({
|
|
2035
|
+
content: [{ type: "text", text: freeTierUpgradeMessage(name) }]
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
2038
|
+
if (typeof args[0] === "string") {
|
|
2039
|
+
args[0] = args[0] + FREE_TIER_DESC_SUFFIX;
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
return target.tool(name, ...args);
|
|
1988
2043
|
};
|
|
1989
2044
|
}
|
|
1990
2045
|
return Reflect.get(target, prop, receiver);
|
|
@@ -7146,6 +7201,7 @@ async function validateLicense(email, licenseKey) {
|
|
|
7146
7201
|
return {
|
|
7147
7202
|
ok: true,
|
|
7148
7203
|
installs: `${data.installs_used}/${data.installs_max}`,
|
|
7204
|
+
tier: data.tier === "free" ? "free" : data.tier === "full" ? "full" : void 0,
|
|
7149
7205
|
signedAttestation: typeof data.signed_attestation === "string" ? data.signed_attestation : void 0
|
|
7150
7206
|
};
|
|
7151
7207
|
}
|
|
@@ -7279,24 +7335,27 @@ Note: Firebase credentials rejected (${fb.error}). Saved without Workflow Builde
|
|
|
7279
7335
|
// verified on every MCP startup. Closes the hand-crafted creds bypass.
|
|
7280
7336
|
signed_attestation: lic.signedAttestation
|
|
7281
7337
|
});
|
|
7282
|
-
const
|
|
7338
|
+
const isFree = lic.tier === "free";
|
|
7339
|
+
const toolCount = isFree ? workflowBuilderEnabled ? "105" : "87" : workflowBuilderEnabled ? "229" : "177";
|
|
7283
7340
|
const wfLine = workflowBuilderEnabled ? "Workflow Builder: enabled." : "Workflow Builder: not configured (optional).";
|
|
7284
|
-
const wfTip = workflowBuilderEnabled ? "" :
|
|
7341
|
+
const wfTip = workflowBuilderEnabled ? "" : isFree ? `
|
|
7342
|
+
Unlock the account auditor next (the free tier's best tool): say "Unlock the Workflow Builder" \u2014 one browser login enables audit_workflows, validate_workflow, and the full-detail reads.` : "\nTo enable Workflow Builder later (52 extra Firebase-gated tools): run enable_workflow_builder with your three Firebase values. No need to re-enter license/API key/location ID.";
|
|
7343
|
+
const freeTip = isFree ? "\n\nFree tier: 105 read-only tools (87 before the one-login auditor unlock). Write tools stay visible but answer with upgrade info instead of acting. Full version ($97/mo founding rate, same key upgrades in place): https://ghlcommand.com" : "";
|
|
7285
7344
|
return {
|
|
7286
7345
|
content: [{
|
|
7287
7346
|
type: "text",
|
|
7288
7347
|
text: [
|
|
7289
7348
|
`Setup complete!`,
|
|
7290
7349
|
``,
|
|
7291
|
-
`License: verified (installs ${lic.installs}).`,
|
|
7350
|
+
`License: verified (installs ${lic.installs})${isFree ? " \u2014 FREE read-only tier" : ""}.`,
|
|
7292
7351
|
`GHL: connected to "${ghl.locationName}".`,
|
|
7293
7352
|
wfLine,
|
|
7294
7353
|
``,
|
|
7295
7354
|
`Credentials saved to: ${credentialsPath()}`,
|
|
7296
7355
|
``,
|
|
7297
|
-
`**Restart Claude (quit fully and reopen) to load all ${toolCount} tools.**`,
|
|
7356
|
+
`**Restart Claude (quit fully and reopen) to load all ${toolCount} ${isFree ? "read-only " : ""}tools.**`,
|
|
7298
7357
|
``,
|
|
7299
|
-
`After restart, try: "List my GHL contacts" or "Show my pipelines".${wfTip}`,
|
|
7358
|
+
`After restart, try: "List my GHL contacts" or "Show my pipelines".${wfTip}${freeTip}`,
|
|
7300
7359
|
workflowBuilderNote
|
|
7301
7360
|
].join("\n")
|
|
7302
7361
|
}]
|
|
@@ -7307,7 +7366,7 @@ Note: Firebase credentials rejected (${fb.error}). Saved without Workflow Builde
|
|
|
7307
7366
|
function registerEnableWorkflowBuilderTool(server2) {
|
|
7308
7367
|
server2.tool(
|
|
7309
7368
|
"enable_workflow_builder",
|
|
7310
|
-
"Add Firebase credentials to an existing GHL Command install to unlock 52 additional tools across the internal-API modules: workflow builder (create/edit/clone/delete/publish/validate workflows, build_if_else_branch, build_goal_event, get_trigger_registry), funnel + page builder, form builder, pipeline builder, workflow cloner, smart lists, reputation, email campaigns, email templates, and memberships, plus the pre-deploy validator. Requires you've already run setup_ghl_mcp. EASIEST PATH: run `
|
|
7369
|
+
"Add Firebase credentials to an existing GHL Command install to unlock 52 additional tools across the internal-API modules: workflow builder (create/edit/clone/delete/publish/validate workflows, build_if_else_branch, build_goal_event, get_trigger_registry), funnel + page builder, form builder, pipeline builder, workflow cloner, smart lists, reputation, email campaigns, email templates, and memberships, plus the pre-deploy validator. On the FREE tier this same login unlocks the read-only auditor suite (audit_workflows, validate_workflow, full-detail workflow/funnel/pipeline reads). Requires you've already run setup_ghl_mcp. EASIEST PATH: run `capture_firebase_interactive` instead \u2014 a Chrome window opens, you log into GHL, zero pasting. Use THIS tool when you have JSON from `auto_capture_firebase_script` (console-paste path) to put in `firebase_paste`, or the three manual DevTools fields. Tool count goes from 177 to 229 after the next Claude restart.",
|
|
7311
7370
|
{
|
|
7312
7371
|
// v3.25.0: one-paste path. Tool runs `auto_capture_firebase_script` to
|
|
7313
7372
|
// get the console script; the script returns a JSON object that pastes
|
|
@@ -7400,7 +7459,7 @@ DevTools steps: https://elitedcs.com/ghl-mcp-firebase`
|
|
|
7400
7459
|
function registerFirebaseCaptureScriptTool(server2) {
|
|
7401
7460
|
server2.tool(
|
|
7402
7461
|
"auto_capture_firebase_script",
|
|
7403
|
-
"Get the browser-console script that auto-extracts the 3 Firebase fields needed to enable the Workflow Builder. Run this, copy the script, paste it into Chrome DevTools Console on a tab logged into GHL, press Enter, and the result lands in your clipboard. Then paste the JSON into setup_ghl_mcp's firebase_paste field (or enable_workflow_builder's).
|
|
7462
|
+
"Get the browser-console script that auto-extracts the 3 Firebase fields needed to enable the Workflow Builder. PREFER `capture_firebase_interactive` when Chrome/Edge is installed (one-click, zero pasting); this script is the fallback for locked-down machines and the path for capturing a CLIENT account's Firebase (multi-tenant). Run this, copy the script, paste it into Chrome DevTools Console on a tab logged into GHL, press Enter, and the result lands in your clipboard. Then paste the JSON into setup_ghl_mcp's firebase_paste field (or enable_workflow_builder's).",
|
|
7404
7463
|
{},
|
|
7405
7464
|
async () => {
|
|
7406
7465
|
const steps = [
|
|
@@ -7437,7 +7496,7 @@ function registerFirebaseCaptureScriptTool(server2) {
|
|
|
7437
7496
|
function registerInteractiveCaptureTool(server2) {
|
|
7438
7497
|
server2.tool(
|
|
7439
7498
|
"capture_firebase_interactive",
|
|
7440
|
-
"One-click Workflow Builder unlock (EASIEST PATH \u2014 try this before auto_capture_firebase_script). Opens a Chrome window where you just log into GHL; the MCP captures the Firebase credentials itself and saves them. No DevTools, no pasting. Re-run the same tool if the first call says it's still waiting for your login. After the first successful run, future re-captures (refresh-token rotations) happen silently with no window at all. Falls back cleanly: if no Chrome/Edge is installed, use auto_capture_firebase_script instead.",
|
|
7499
|
+
"One-click Workflow Builder unlock (EASIEST PATH \u2014 try this before auto_capture_firebase_script). Also the unlock for the FREE tier's account auditor (audit_workflows, validate_workflow) \u2014 same one-time login. Opens a Chrome window where you just log into GHL; the MCP captures the Firebase credentials itself and saves them. No DevTools, no pasting. Re-run the same tool if the first call says it's still waiting for your login. After the first successful run, future re-captures (refresh-token rotations) happen silently with no window at all. Falls back cleanly: if no Chrome/Edge is installed, use auto_capture_firebase_script instead.",
|
|
7441
7500
|
{},
|
|
7442
7501
|
async () => {
|
|
7443
7502
|
const existing = readCredentials();
|
|
@@ -7568,7 +7627,7 @@ ${fallbackNote}`
|
|
|
7568
7627
|
function registerLeadCaptureTool(server2) {
|
|
7569
7628
|
server2.tool(
|
|
7570
7629
|
"request_license",
|
|
7571
|
-
"Get a GHL Command license. Use this if you installed from npm but don't have a license yet (or setup_ghl_mcp says your license is missing/invalid). GHL Command is $97/mo \u2014 every sub-account you manage, 3-machine activation, includes the only programmatic GHL workflow builder. Leave your email and we'll send the purchase link + setup help; the tool also returns where to buy right now.",
|
|
7630
|
+
"Get a GHL Command license. Use this if you installed from npm but don't have a license yet (or setup_ghl_mcp says your license is missing/invalid). GHL Command is $97/mo \u2014 every sub-account you manage, 3-machine activation, includes the only programmatic GHL workflow builder. There's also a FREE read-only tier (account audits + all reads on your own account) \u2014 instant key at https://ghlcommand.com/free. Leave your email and we'll send the purchase link + setup help; the tool also returns where to buy right now.",
|
|
7572
7631
|
{
|
|
7573
7632
|
email: import_zod39.z.string().email().describe("Your email \u2014 where to send the purchase link and setup help."),
|
|
7574
7633
|
name: import_zod39.z.string().optional().describe("Your name (optional).")
|
|
@@ -7592,6 +7651,7 @@ function registerLeadCaptureTool(server2) {
|
|
|
7592
7651
|
"GHL Command is $97/mo: every sub-account you manage, 3 machines, including the only programmatic GHL workflow builder. Cancel anytime.",
|
|
7593
7652
|
"",
|
|
7594
7653
|
`Buy now: ${url}`,
|
|
7654
|
+
"Want to try it first? FREE read-only tier (account audits + every read tool on your own account): https://ghlcommand.com/free",
|
|
7595
7655
|
"Your license key arrives by email within a couple minutes. Then run setup_ghl_mcp with your email + key."
|
|
7596
7656
|
].join("\n")
|
|
7597
7657
|
}]
|
|
@@ -13986,11 +14046,12 @@ var KNOWN_MODULES = /* @__PURE__ */ new Set([
|
|
|
13986
14046
|
LOCATION_SWITCHER_MODULE,
|
|
13987
14047
|
SNAPSHOTS_MODULE
|
|
13988
14048
|
]);
|
|
13989
|
-
function registerAllTools(server2, client, registry2, mcpVersion, env = process.env) {
|
|
14049
|
+
function registerAllTools(server2, client, registry2, mcpVersion, env = process.env, tier = "full") {
|
|
13990
14050
|
const config3 = parseAllowlist(env);
|
|
13991
14051
|
const attemptedTools = /* @__PURE__ */ new Set();
|
|
13992
14052
|
const registeredTools = /* @__PURE__ */ new Set();
|
|
13993
|
-
const
|
|
14053
|
+
const gatedTools = /* @__PURE__ */ new Set();
|
|
14054
|
+
const wrap = (moduleName) => wrapServerForModule(server2, moduleName, config3, attemptedTools, registeredTools, tier, gatedTools);
|
|
13994
14055
|
for (const [register, moduleName] of publicApiTools) {
|
|
13995
14056
|
register(wrap(moduleName), client);
|
|
13996
14057
|
}
|
|
@@ -14020,6 +14081,13 @@ function registerAllTools(server2, client, registry2, mcpVersion, env = process.
|
|
|
14020
14081
|
if (isAllowlistActive(config3)) {
|
|
14021
14082
|
validateAndLog(config3, KNOWN_MODULES, attemptedTools, registeredTools);
|
|
14022
14083
|
}
|
|
14084
|
+
if (tier === "free") {
|
|
14085
|
+
process.stderr.write(
|
|
14086
|
+
`[ghl-mcp] FREE tier: ${registeredTools.size - gatedTools.size} read-only tools live; ${gatedTools.size} write tools answer with upgrade info. Full version: https://ghlcommand.com
|
|
14087
|
+
`
|
|
14088
|
+
);
|
|
14089
|
+
}
|
|
14090
|
+
return { registeredTools, gatedTools };
|
|
14023
14091
|
}
|
|
14024
14092
|
|
|
14025
14093
|
// src/attestation.ts
|
|
@@ -14027,6 +14095,9 @@ var import_node_crypto = require("node:crypto");
|
|
|
14027
14095
|
var ATTESTATION_PUBLIC_KEY_B64 = "8KJo8V3Z7ngeToIQfOXpKdlr/EA34hXJVEIpW0A7wqs=";
|
|
14028
14096
|
var ATTESTATION_VERSION = 1;
|
|
14029
14097
|
var ATTESTATION_GRACE_DAYS = 14;
|
|
14098
|
+
function tierFromPayload(payload) {
|
|
14099
|
+
return payload?.tier === "free" ? "free" : "full";
|
|
14100
|
+
}
|
|
14030
14101
|
function deviceFingerprint2() {
|
|
14031
14102
|
const os3 = require("node:os");
|
|
14032
14103
|
const crypto4 = require("node:crypto");
|
|
@@ -14051,6 +14122,20 @@ async function getPublicKey() {
|
|
|
14051
14122
|
);
|
|
14052
14123
|
return cachedPublicKey;
|
|
14053
14124
|
}
|
|
14125
|
+
function parseAttestationPayload(token) {
|
|
14126
|
+
try {
|
|
14127
|
+
const dot = token.indexOf(".");
|
|
14128
|
+
if (dot <= 0 || dot === token.length - 1) return null;
|
|
14129
|
+
const payloadJson = new TextDecoder().decode(base64urlDecode(token.slice(0, dot)));
|
|
14130
|
+
const payload = JSON.parse(payloadJson);
|
|
14131
|
+
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") {
|
|
14132
|
+
return null;
|
|
14133
|
+
}
|
|
14134
|
+
return payload;
|
|
14135
|
+
} catch {
|
|
14136
|
+
return null;
|
|
14137
|
+
}
|
|
14138
|
+
}
|
|
14054
14139
|
async function verifyAttestation(token, bindings, now = /* @__PURE__ */ new Date()) {
|
|
14055
14140
|
if (typeof token !== "string" || !token) return { ok: false, reason: "malformed" };
|
|
14056
14141
|
const dot = token.indexOf(".");
|
|
@@ -14538,6 +14623,8 @@ function renewAttestationInBackground(creds) {
|
|
|
14538
14623
|
async function resolveAccessAndRegister() {
|
|
14539
14624
|
let licenseVerified = false;
|
|
14540
14625
|
let attestationStatus = "no-creds";
|
|
14626
|
+
let sessionTier = "full";
|
|
14627
|
+
const tierFromDisk = () => tierFromPayload(parseAttestationPayload(readCredentials()?.signed_attestation ?? ""));
|
|
14541
14628
|
if (fileCreds?.email && fileCreds?.license_key && fileCreds.signed_attestation) {
|
|
14542
14629
|
const verify = await verifyAttestation(fileCreds.signed_attestation, {
|
|
14543
14630
|
email: fileCreds.email,
|
|
@@ -14546,6 +14633,7 @@ async function resolveAccessAndRegister() {
|
|
|
14546
14633
|
if (verify.ok) {
|
|
14547
14634
|
licenseVerified = true;
|
|
14548
14635
|
attestationStatus = verify.reason;
|
|
14636
|
+
sessionTier = tierFromPayload(verify.payload);
|
|
14549
14637
|
void renewAttestationInBackground(fileCreds);
|
|
14550
14638
|
} else {
|
|
14551
14639
|
process.stderr.write(`[ghl-mcp] Stored attestation rejected: ${verify.reason}. Re-validating online.
|
|
@@ -14554,6 +14642,7 @@ async function resolveAccessAndRegister() {
|
|
|
14554
14642
|
if (renewed === "renewed") {
|
|
14555
14643
|
licenseVerified = true;
|
|
14556
14644
|
attestationStatus = "renewed-after-tamper";
|
|
14645
|
+
sessionTier = tierFromDisk();
|
|
14557
14646
|
} else if (renewed === "renewed-unsigned" && Date.now() < TRANSITIONAL_ATTESTATION_DEADLINE) {
|
|
14558
14647
|
licenseVerified = true;
|
|
14559
14648
|
attestationStatus = "renewed-after-tamper";
|
|
@@ -14567,6 +14656,7 @@ async function resolveAccessAndRegister() {
|
|
|
14567
14656
|
if (renewed === "renewed") {
|
|
14568
14657
|
licenseVerified = true;
|
|
14569
14658
|
attestationStatus = "renewed-from-legacy";
|
|
14659
|
+
sessionTier = tierFromDisk();
|
|
14570
14660
|
} else if (renewed === "renewed-unsigned" && Date.now() < TRANSITIONAL_ATTESTATION_DEADLINE) {
|
|
14571
14661
|
licenseVerified = true;
|
|
14572
14662
|
attestationStatus = "renewed-from-legacy";
|
|
@@ -14591,6 +14681,7 @@ async function resolveAccessAndRegister() {
|
|
|
14591
14681
|
if (lic.ok && acceptUnsigned) {
|
|
14592
14682
|
licenseVerified = true;
|
|
14593
14683
|
attestationStatus = "renewed";
|
|
14684
|
+
sessionTier = lic.signedAttestation ? tierFromPayload(parseAttestationPayload(lic.signedAttestation)) : lic.tier === "free" ? "free" : "full";
|
|
14594
14685
|
try {
|
|
14595
14686
|
writeCredentials({
|
|
14596
14687
|
license_key: licKey,
|
|
@@ -14618,7 +14709,7 @@ async function resolveAccessAndRegister() {
|
|
|
14618
14709
|
}
|
|
14619
14710
|
}
|
|
14620
14711
|
if (licenseVerified) {
|
|
14621
|
-
process.stderr.write(`[ghl-mcp] License gate: ${attestationStatus}.
|
|
14712
|
+
process.stderr.write(`[ghl-mcp] License gate: ${attestationStatus}${sessionTier === "free" ? " (FREE read-only tier)" : ""}.
|
|
14622
14713
|
`);
|
|
14623
14714
|
}
|
|
14624
14715
|
inBootstrapMode = !apiKey || !locationId || !licenseVerified;
|
|
@@ -14634,7 +14725,7 @@ async function resolveAccessAndRegister() {
|
|
|
14634
14725
|
registerFirebaseCaptureScriptTool(server);
|
|
14635
14726
|
} else {
|
|
14636
14727
|
const client = new GHLClient({ apiKey, locationId });
|
|
14637
|
-
registerAllTools(server, client, registry, pkg.version);
|
|
14728
|
+
registerAllTools(server, client, registry, pkg.version, process.env, sessionTier);
|
|
14638
14729
|
registerEnableWorkflowBuilderTool(server);
|
|
14639
14730
|
registerFirebaseCaptureScriptTool(server);
|
|
14640
14731
|
registerInteractiveCaptureTool(server);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elitedcs/ghl-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.50.0",
|
|
4
4
|
"mcpName": "io.github.drjerryrelth/ghl-command",
|
|
5
5
|
"description": "GoHighLevel MCP Server for Claude. 229 tools — 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",
|