@elitedcs/ghl-mcp 3.55.0 → 3.57.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 +125 -0
- package/README.md +37 -5
- package/dist/index.js +194 -50
- package/package.json +2 -2
- package/skills/clone-site/README.md +42 -0
- package/skills/clone-site/SKILL.md +247 -0
- package/skills/clone-site/references/facts-and-substitution.md +96 -0
- package/skills/clone-site/references/hosting-verify-and-audit.md +101 -0
- package/skills/clone-site/references/rights-and-lanes.md +72 -0
- package/skills/clone-site/scripts/audit.mjs +364 -0
- package/skills/clone-site/scripts/extract-design.mjs +372 -0
- package/skills/clone-site/scripts/lib.mjs +262 -0
- package/skills/clone-site/scripts/mirror.mjs +489 -0
- package/skills/clone-site/scripts/repair.mjs +113 -0
- package/skills/clone-site/scripts/substitute.mjs +418 -0
- package/skills/clone-site/scripts/verify.mjs +193 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,130 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.57.0 — Clone Site: copy a live page for a client, with the guardrails built in
|
|
4
|
+
|
|
5
|
+
A second bundled skill. Point Claude at any live URL and get a working,
|
|
6
|
+
rebranded copy for a client — same layout, images, video and CSS, with the
|
|
7
|
+
new business's details in place of the original's. It installs itself like
|
|
8
|
+
Blueprint; there is nothing to download and no new tools to learn.
|
|
9
|
+
|
|
10
|
+
Cloning normally fails because the model *regenerates* the page instead of
|
|
11
|
+
copying it, and you get a worse version of what you pointed at. This skill
|
|
12
|
+
runs real scripts: they download the bytes, swap the strings, and verify the
|
|
13
|
+
result. Nothing is retyped from memory.
|
|
14
|
+
|
|
15
|
+
- **The rights question is step 0 and cannot be skipped.** Before anything is
|
|
16
|
+
copied, the skill asks who owns the page — you, your client (authorized),
|
|
17
|
+
written permission, or none — and records the answer in the run report and
|
|
18
|
+
in the final report header. It does not verify ownership; the declaration is
|
|
19
|
+
yours to make. The mirror script refuses to run without it.
|
|
20
|
+
- **"None" gets a real lane, not a refusal.** It extracts the page's actual
|
|
21
|
+
design system — palette, CSS variables, font stack and type scale, spacing
|
|
22
|
+
rhythm, radii, shadows, breakpoints, and the section skeleton as shape — so
|
|
23
|
+
the rebuild starts from the real design instead of a from-memory redraw. No
|
|
24
|
+
bytes, images, video or copy are copied in that lane.
|
|
25
|
+
- **Substitution that doesn't leak the old brand.** Derives the bare brand word,
|
|
26
|
+
every phone format, the address as a unit (not just the city), and domain and
|
|
27
|
+
email variants; runs across JS bundles as well as HTML and CSS, because
|
|
28
|
+
compiled sites keep contact details only in the bundle. Asset filenames are
|
|
29
|
+
protected from rewriting. Dry-run counts first, a zero-check after, and a
|
|
30
|
+
NEAR MISS warning when one of your facts is *almost* right.
|
|
31
|
+
- **Catches the leak a string search cannot see.** A brand mark is usually
|
|
32
|
+
two-tone — `GHL <span style="color:#D4AF37;">Command</span>` — which reads as
|
|
33
|
+
the old brand on screen while that string appears nowhere in the file. Every
|
|
34
|
+
literal check calls it clean. Clone Site renders the page to text while
|
|
35
|
+
keeping a map back to source offsets, so it reports exactly which occurrences
|
|
36
|
+
are split by markup, shows the markup, and fails the zero-check until they are
|
|
37
|
+
hand-edited. Found on a real page, in the header and the footer, after a
|
|
38
|
+
file-level rebrand had already "passed."
|
|
39
|
+
- **Asset capture from all four places** — HTML, CSS `url()`, CDN URLs in JS
|
|
40
|
+
bundles, and root-relative paths inside JS bundles (the one that silently
|
|
41
|
+
breaks images). Oversized files are reported for object storage, never
|
|
42
|
+
hot-linked back to the original owner's CDN.
|
|
43
|
+
- **A mandatory pre-launch REVIEW REQUIRED report** on every run: form endpoints,
|
|
44
|
+
webhooks, payment links and publishable keys, booking embeds, analytics and ad
|
|
45
|
+
pixels (MUST REPOINT); names, addresses, testimonials and likenesses; and
|
|
46
|
+
inherited claims with regulated health/efficacy language flagged separately.
|
|
47
|
+
Nothing is auto-deleted — findings go to a human.
|
|
48
|
+
- **Verification by content-type, not status code**, because static hosts answer
|
|
49
|
+
200 with the page shell for assets that don't exist. It retries once before
|
|
50
|
+
calling anything broken (a CDN rollout can answer a single request with HTML),
|
|
51
|
+
and separates references the *source* page was already serving badly from
|
|
52
|
+
breakage the clone caused.
|
|
53
|
+
- Reports are written outside the deployable folder, so a rights declaration and
|
|
54
|
+
a liability list can never be published with the site.
|
|
55
|
+
|
|
56
|
+
Everything below was found by running the tool against real production sites
|
|
57
|
+
rather than test fixtures, and every one of them shipped a fix:
|
|
58
|
+
|
|
59
|
+
- **Whole-site cloning.** A one-page mirror inherits the original's entire
|
|
60
|
+
navigation, so every menu item 404s the moment a client clicks it.
|
|
61
|
+
`--crawl --depth N --max-pages N` follows the site's own navigation, writes
|
|
62
|
+
each page at its own path, and rewrites links between your pages as
|
|
63
|
+
root-relative so the nav works locally and after deploy — while canonical and
|
|
64
|
+
og:url keep their host so the rebrand can point them at the client's domain.
|
|
65
|
+
The skill asks how deep to go rather than assuming. Real numbers: a 36-page
|
|
66
|
+
contractor site came to 2,104 files and 935 MB at depth 2.
|
|
67
|
+
- **Assets that only exist at runtime.** Page-builders publish an asset base
|
|
68
|
+
path and concatenate chunk filenames onto it in JavaScript, so those files
|
|
69
|
+
appear in no attribute, stylesheet or string literal. Six missing Elementor
|
|
70
|
+
chunks meant no section background was painted at all: the hero rendered blank
|
|
71
|
+
and its white headline was invisible on white, while every file-level check
|
|
72
|
+
reported success. New `repair.mjs` plus a mandatory render-and-repair loop
|
|
73
|
+
fetches whatever the running page asks for and cannot find.
|
|
74
|
+
- **Media hidden in escaped JSON.** Background slideshows and galleries store
|
|
75
|
+
image URLs inside entity-encoded, backslash-escaped JSON attributes. Those are
|
|
76
|
+
now extracted and localised, escaping preserved.
|
|
77
|
+
- **Brand marks split across tags.** `GHL <span style="color:#D4AF37">Command</span>`
|
|
78
|
+
reads as the old brand on screen while that string exists nowhere in the file.
|
|
79
|
+
Detected exactly via a rendered-text-to-source offset map; the zero-check now
|
|
80
|
+
fails until they are hand-edited instead of reporting a false clean.
|
|
81
|
+
- **HTML-entity brand forms.** A brand containing `&` is stored as `&`. On
|
|
82
|
+
one page the plain token matched twice and the encoded form 56 times.
|
|
83
|
+
- **Brand baked into image pixels.** Logos and graphics carrying the old phone
|
|
84
|
+
number or web address are flagged — substitution cannot edit artwork, and the
|
|
85
|
+
logo is the most visible way a clone gives itself away.
|
|
86
|
+
- **New audit rules from real pages:** contractor and professional licence
|
|
87
|
+
numbers (the highest-severity item on any trades or medical clone), consumer
|
|
88
|
+
financing links, review widgets that load the original's reviews at runtime,
|
|
89
|
+
and internal links with no page in the clone.
|
|
90
|
+
- **Bare-word derivation is now cautioned**, because a brand beginning with a
|
|
91
|
+
place name ("Arizona AC & Heating") would otherwise rewrite ordinary sentences.
|
|
92
|
+
- **Style lane returns the brand's palette, not the framework's.** Plugin CSS
|
|
93
|
+
repeats neutral greys hundreds of times while the real brand colours appear
|
|
94
|
+
twice; vendor stylesheets are now separated, accents are attributed to their
|
|
95
|
+
source file, declared colour tokens are surfaced first, and CSS variables are
|
|
96
|
+
resolved so the type scale comes back as real pixel values.
|
|
97
|
+
- **The style lane's deliverable is a page, not a document.** Its rebuild is now
|
|
98
|
+
five explicit steps, including a media step and a leak check against the
|
|
99
|
+
original page.
|
|
100
|
+
|
|
101
|
+
## 3.56.0 — Security off-switches: any tool can be disabled; sub-account create/delete is opt-in
|
|
102
|
+
|
|
103
|
+
Shaped directly by subscriber feedback: some teams keep account-level
|
|
104
|
+
operations human-only, so a prompt-injected or misbehaving AI session can
|
|
105
|
+
never touch them. Two new controls, both enforced at server startup from
|
|
106
|
+
your config — there is deliberately NO way to change them from inside a
|
|
107
|
+
Claude conversation.
|
|
108
|
+
|
|
109
|
+
- **Sub-account create/delete is now OFF by default.** `create_sub_account`
|
|
110
|
+
and `delete_sub_account` register only when `GHL_ENABLE_ACCOUNT_ADMIN=1`
|
|
111
|
+
is set. The setup wizard asks (default No). The allowlist cannot bypass
|
|
112
|
+
the flag. If you were using these tools, add the flag and restart.
|
|
113
|
+
- **Universal deny-list**: `GHL_DISABLED_TOOLS` / `GHL_DISABLED_MODULES`
|
|
114
|
+
switch off any tool or module. A disabled tool never registers — it is
|
|
115
|
+
invisible to the model, so it can't be called *or discovered* from a
|
|
116
|
+
conversation. Deny wins over the allowlist and the always-on set,
|
|
117
|
+
including the credential helpers (`enable_workflow_builder`,
|
|
118
|
+
`auto_capture_firebase_script`, `capture_firebase_interactive`) and
|
|
119
|
+
`install_skills` (denying it also skips the bundled-skills auto-install).
|
|
120
|
+
- **Un-brickable**: the recovery core (`setup_ghl_mcp`, `request_license`,
|
|
121
|
+
`get_mcp_version`, `health_check`) ignores denial, with a logged warning.
|
|
122
|
+
- **Verifiable**: `health_check` gained a "Tool gating" section reporting
|
|
123
|
+
exactly what's disabled, whether account admin is on, and any misspelled
|
|
124
|
+
name in your gating vars (typos do NOT disable anything — they warn).
|
|
125
|
+
- Advertised default tool count is now 233 (235 with account admin enabled).
|
|
126
|
+
- README: new "Turning tools off (security)" section with examples.
|
|
127
|
+
|
|
3
128
|
## 3.55.0 — Skills ship inside the package: Blueprint installs itself
|
|
4
129
|
|
|
5
130
|
The gap between "the tools exist" and "the guided experience exists" is
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# GHL Command — GoHighLevel MCP Server
|
|
2
2
|
|
|
3
|
-
**Full GoHighLevel API access for Claude.**
|
|
3
|
+
**Full GoHighLevel API access for Claude.** 233 tools across 49 modules — manage contacts, conversations, pipelines, calendars, funnels, workflows, invoices, custom objects, webhooks, and more. **Includes full workflow builder, funnel/page editor, form builder, pipeline builder, bulk operations, account export, and workflow cloning** — capabilities no other GHL tool offers. **Multi-tenant:** one install can run the workflow builder across multiple clients' GHL accounts.
|
|
4
4
|
|
|
5
5
|
**Distributed via npm as [`@elitedcs/ghl-mcp`](https://www.npmjs.com/package/@elitedcs/ghl-mcp).** Buyers install with one config block — no git, no Node.js setup, no terminal commands. Updates flow automatically (`npx @latest` re-resolves on every Claude restart).
|
|
6
6
|
|
|
@@ -12,7 +12,7 @@ Works with **both the Claude Desktop App and Claude Code terminal** — your cho
|
|
|
12
12
|
|
|
13
13
|
**How this differs from HighLevel's official MCP.** HighLevel ships an official Anthropic MCP that reads and writes your CRM (contacts, conversations, calendars, opportunities, payments, social) over the public API — it's free and it's good; use it for that. What it *cannot* do, because the public API doesn't expose it: **build or edit workflows, build funnels/landing pages, or build forms.** That's exactly what GHL Command does — the programmatic Workflow Builder, funnel/page builder, form builder, deep workflow cloning, the silent-failure `audit_workflows`, and Blueprint (build a whole client account from one intake — ships as a guided skill that **installs itself automatically** with this package; nothing to download), all on GHL's internal APIs. **Official MCP = read/write your CRM. GHL Command = build and fix it.** They stack fine together.
|
|
14
14
|
|
|
15
|
-
**Bundled skills (install automatically).** The package ships guided skills that teach Claude complete multi-step workflows on top of the raw tools. On every start the server installs/updates them into your `~/.claude/skills/` (never overwriting files you've edited — your version wins and is reported). Current skills: **Blueprint** — turn one client intake into a complete reviewed GHL account build. Verify or repair any time by asking Claude to `run install_skills`, then fully restart Claude so new skills load.
|
|
15
|
+
**Bundled skills (install automatically).** The package ships guided skills that teach Claude complete multi-step workflows on top of the raw tools. On every start the server installs/updates them into your `~/.claude/skills/` (never overwriting files you've edited — your version wins and is reported). Current skills: **Blueprint** — turn one client intake into a complete reviewed GHL account build; **Clone Site** — point at a live URL and get a rebranded, deploy-ready copy for a client, with a recorded rights declaration, a style-only lane when you have no rights, and a mandatory pre-launch report of every lead/booking/payment destination, borrowed testimonial and inherited claim still belonging to the original owner. Verify or repair any time by asking Claude to `run install_skills`, then fully restart Claude so new skills load.
|
|
16
16
|
|
|
17
17
|
Built by [Elite DCs, LLC](https://elitedcs.com).
|
|
18
18
|
|
|
@@ -122,7 +122,7 @@ Run setup_ghl_mcp to activate GHL Command:
|
|
|
122
122
|
ghl_location_id: YOUR_LOCATION_ID
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
Approve the tool call. Server validates your license, verifies your GHL credentials, writes them to a per-user config file. **Quit Claude one more time and reopen** — the full core toolset is now unlocked (
|
|
125
|
+
Approve the tool call. Server validates your license, verifies your GHL credentials, writes them to a per-user config file. **Quit Claude one more time and reopen** — the full core toolset is now unlocked (233 tools total with the optional Workflow Builder Firebase add-on).
|
|
126
126
|
|
|
127
127
|
### 4. Try it
|
|
128
128
|
|
|
@@ -162,7 +162,7 @@ https://app.gohighlevel.com/v2/location/YOUR_LOCATION_ID/dashboard
|
|
|
162
162
|
|
|
163
163
|
## Enable the Workflow Builder
|
|
164
164
|
|
|
165
|
-
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
|
|
165
|
+
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 179 tools work fine — you just won't have workflow/funnel/form/pipeline editing. This is the flagship feature: do this step.
|
|
166
166
|
|
|
167
167
|
**One-click capture (v3.49.0+, the supported path):**
|
|
168
168
|
|
|
@@ -751,7 +751,7 @@ Source repo is private. Contributors need an invitation from `drjerryrelth`. The
|
|
|
751
751
|
|
|
752
752
|
### Reducing context / token usage
|
|
753
753
|
|
|
754
|
-
Every registered MCP tool's schema is shipped to the model on every message. With
|
|
754
|
+
Every registered MCP tool's schema is shipped to the model on every message. With 233 tools that's a meaningful per-message context cost even in chats that never touch GHL. If you only use a slice of GHL Command, restrict the tool surface with `GHL_ENABLED_MODULES` and/or `GHL_ENABLED_TOOLS`:
|
|
755
755
|
|
|
756
756
|
```jsonc
|
|
757
757
|
// Claude Desktop config — enable whole modules
|
|
@@ -786,6 +786,38 @@ Rules of the road:
|
|
|
786
786
|
|
|
787
787
|
`contacts`, `conversations`, `opportunities`, `calendars`, `locations`, `workflows`, `funnels`, `forms`, `surveys`, `payments`, `products`, `invoices`, `campaigns`, `users`, `media`, `social-planner`, `courses`, `businesses`, `blogs`, `emails`, `trigger-links`, `custom-objects`, `associations`, `estimates`, `coupons`, `webhooks`, `documents`, `bulk-operations`, `account-export`, `template-deployer`, `workflow-builder`, `funnel-builder`, `form-builder`, `pipeline-builder`, `workflow-cloner`, `smart-lists`, `reputation`, `email-campaigns`, `email-builder`, `memberships`, `validators`, `diagnostics`, `location-switcher`
|
|
788
788
|
|
|
789
|
+
### Turning tools off (security)
|
|
790
|
+
|
|
791
|
+
Some teams keep certain operations human-only — for example sub-account management or messaging — so that a prompt-injected or misbehaving AI session can never touch them. Two controls exist for exactly that:
|
|
792
|
+
|
|
793
|
+
**1. Sub-account create/delete is OFF by default.** `create_sub_account` and `delete_sub_account` do not register unless you explicitly opt in:
|
|
794
|
+
|
|
795
|
+
```jsonc
|
|
796
|
+
"env": {
|
|
797
|
+
"GHL_ENABLE_ACCOUNT_ADMIN": "1" // exactly "1" — nothing else enables it
|
|
798
|
+
}
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
The setup wizard asks this question during install (default No). Listing these tools in `GHL_ENABLED_TOOLS` does **not** bypass the flag.
|
|
802
|
+
|
|
803
|
+
**2. Any tool or module can be switched off** with a deny-list:
|
|
804
|
+
|
|
805
|
+
```jsonc
|
|
806
|
+
"env": {
|
|
807
|
+
"GHL_DISABLED_TOOLS": "send_message,bulk_delete_contacts",
|
|
808
|
+
"GHL_DISABLED_MODULES": "snapshots"
|
|
809
|
+
}
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
How the deny-list behaves:
|
|
813
|
+
|
|
814
|
+
- **Deny wins over everything** — the allowlist, the always-on set, and `GHL_ENABLE_ACCOUNT_ADMIN`. A denied tool **never registers**: it is invisible to the model, so it cannot be called *or discovered* from a conversation.
|
|
815
|
+
- **There is deliberately no tool to change gating from inside Claude.** Turning something back on requires editing your config file and fully restarting Claude — a human action.
|
|
816
|
+
- **Recovery core stays reachable:** `setup_ghl_mcp`, `request_license`, `get_mcp_version`, and `health_check` ignore denial (with a logged warning) so you can never brick your install. Everything else — including the Firebase credential helpers `enable_workflow_builder`, `auto_capture_firebase_script`, `capture_firebase_interactive`, and `install_skills` (denying it also skips the bundled-skills auto-install) — is deniable.
|
|
817
|
+
- **Verify it took effect:** run `health_check` in Claude. Its "Tool gating" section shows exactly what's disabled, whether account admin is on, and flags any misspelled name in your gating vars (typos do NOT disable anything — they warn instead).
|
|
818
|
+
- Single-location shops that never want cross-account movement can also deny `switch_location` and `register_location`.
|
|
819
|
+
- Honest limit: this gate is enforced at server startup from your config file, so it is as strong as your machine's file permissions. What it guarantees is that nothing *inside a Claude conversation* can widen the tool surface.
|
|
820
|
+
|
|
789
821
|
---
|
|
790
822
|
|
|
791
823
|
## Troubleshooting
|
package/dist/index.js
CHANGED
|
@@ -1235,7 +1235,7 @@ async function validateFirebase(firebaseKey, refreshToken) {
|
|
|
1235
1235
|
function registerSetupTool(server2) {
|
|
1236
1236
|
server2.tool(
|
|
1237
1237
|
"setup_ghl_mcp",
|
|
1238
|
-
"First-run setup for GHL Command MCP. Validates your license and GHL credentials, then writes them to a per-user credentials file. Restart Claude after this completes to load all
|
|
1238
|
+
"First-run setup for GHL Command MCP. Validates your license and GHL credentials, then writes them to a per-user credentials file. Restart Claude after this completes to load all 233 tools (179 if you skip the optional Firebase fields; add Firebase later with enable_workflow_builder).",
|
|
1239
1239
|
{
|
|
1240
1240
|
email: import_zod40.z.string().email().describe("Email used at purchase."),
|
|
1241
1241
|
license_key: import_zod40.z.string().min(20).describe("License key from your purchase email."),
|
|
@@ -1317,7 +1317,7 @@ Note: Firebase credentials rejected (${fb.error}). Saved without Workflow Builde
|
|
|
1317
1317
|
signed_attestation: lic.signedAttestation
|
|
1318
1318
|
});
|
|
1319
1319
|
const isFree = lic.tier === "free";
|
|
1320
|
-
const toolCount = isFree ? workflowBuilderEnabled ? "107" : "89" : workflowBuilderEnabled ? "
|
|
1320
|
+
const toolCount = isFree ? workflowBuilderEnabled ? "107" : "89" : workflowBuilderEnabled ? "233" : "179";
|
|
1321
1321
|
const wfLine = workflowBuilderEnabled ? "Workflow Builder: enabled." : "Workflow Builder: not configured (optional).";
|
|
1322
1322
|
const wfTip = workflowBuilderEnabled ? "" : isFree ? `
|
|
1323
1323
|
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.";
|
|
@@ -1347,7 +1347,7 @@ Unlock the account auditor next (the free tier's best tool): say "Unlock the Wor
|
|
|
1347
1347
|
function registerEnableWorkflowBuilderTool(server2) {
|
|
1348
1348
|
server2.tool(
|
|
1349
1349
|
"enable_workflow_builder",
|
|
1350
|
-
"Add Firebase credentials to an existing GHL Command install to unlock 54 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
|
|
1350
|
+
"Add Firebase credentials to an existing GHL Command install to unlock 54 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 179 to 233 after the next Claude restart.",
|
|
1351
1351
|
{
|
|
1352
1352
|
// v3.25.0: one-paste path. Tool runs `auto_capture_firebase_script` to
|
|
1353
1353
|
// get the console script; the script returns a JSON object that pastes
|
|
@@ -1428,7 +1428,7 @@ DevTools steps: https://elitedcs.com/ghl-mcp-firebase`
|
|
|
1428
1428
|
"",
|
|
1429
1429
|
"**You MUST restart Claude before using any workflow-builder tool.** Quit Claude completely (Cmd+Q on Mac, full exit on Windows) and reopen. Without a restart, the workflow builder tools will keep using the OLD Firebase auth from before this call and fail with 401 errors \u2014 even though this tool reported success.",
|
|
1430
1430
|
"",
|
|
1431
|
-
'After restart, all
|
|
1431
|
+
'After restart, all 233 tools load. Try: "List my workflows in full detail" or "Validate workflow <id>".',
|
|
1432
1432
|
"",
|
|
1433
1433
|
"Note: Firebase refresh tokens rotate every few weeks. If workflow tools stop working in a few weeks (run `health_check` to confirm Firebase auth: FAIL), run `auto_capture_firebase_script` for fresh values and re-run this tool with the new firebase_paste."
|
|
1434
1434
|
].join("\n")
|
|
@@ -1524,7 +1524,7 @@ The login in the capture window may belong to the wrong GHL account, or the sess
|
|
|
1524
1524
|
"",
|
|
1525
1525
|
"**You MUST restart Claude before using any workflow-builder tool.** Quit Claude completely (Cmd+Q on Mac, full exit on Windows) and reopen.",
|
|
1526
1526
|
"",
|
|
1527
|
-
'After restart, all
|
|
1527
|
+
'After restart, all 233 tools load. Try: "List my workflows in full detail".',
|
|
1528
1528
|
"",
|
|
1529
1529
|
"Future token rotations re-capture silently \u2014 if workflow tools ever 401, just run capture_firebase_interactive again; no window should appear."
|
|
1530
1530
|
].join("\n")
|
|
@@ -2102,9 +2102,9 @@ var require_package = __commonJS({
|
|
|
2102
2102
|
"package.json"(exports2, module2) {
|
|
2103
2103
|
module2.exports = {
|
|
2104
2104
|
name: "@elitedcs/ghl-mcp",
|
|
2105
|
-
version: "3.
|
|
2105
|
+
version: "3.57.0",
|
|
2106
2106
|
mcpName: "io.github.drjerryrelth/ghl-command",
|
|
2107
|
-
description: "GoHighLevel MCP Server for Claude.
|
|
2107
|
+
description: "GoHighLevel MCP Server for Claude. 233 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.",
|
|
2108
2108
|
main: "dist/index.js",
|
|
2109
2109
|
bin: {
|
|
2110
2110
|
"ghl-mcp": "dist/index.js"
|
|
@@ -5683,6 +5683,25 @@ var ALWAYS_ON_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
|
5683
5683
|
"enable_workflow_builder",
|
|
5684
5684
|
"health_check"
|
|
5685
5685
|
]);
|
|
5686
|
+
var HARD_CORE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
5687
|
+
"setup_ghl_mcp",
|
|
5688
|
+
"request_license",
|
|
5689
|
+
"get_mcp_version",
|
|
5690
|
+
"health_check"
|
|
5691
|
+
]);
|
|
5692
|
+
var ACCOUNT_ADMIN_TOOLS = /* @__PURE__ */ new Set([
|
|
5693
|
+
"create_sub_account",
|
|
5694
|
+
"delete_sub_account"
|
|
5695
|
+
]);
|
|
5696
|
+
var OUT_OF_BAND_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
5697
|
+
"setup_ghl_mcp",
|
|
5698
|
+
"request_license",
|
|
5699
|
+
"get_mcp_version",
|
|
5700
|
+
"enable_workflow_builder",
|
|
5701
|
+
"auto_capture_firebase_script",
|
|
5702
|
+
"capture_firebase_interactive",
|
|
5703
|
+
"install_skills"
|
|
5704
|
+
]);
|
|
5686
5705
|
var FREE_TIER_EXTRA_READ_TOOLS = /* @__PURE__ */ new Set([
|
|
5687
5706
|
"audit_workflows",
|
|
5688
5707
|
// account-wide silent-failure audit — the free tier's wow moment
|
|
@@ -5732,17 +5751,39 @@ function parseList(raw) {
|
|
|
5732
5751
|
function parseAllowlist(env) {
|
|
5733
5752
|
const moduleList = parseList(env.GHL_ENABLED_MODULES);
|
|
5734
5753
|
const toolList = parseList(env.GHL_ENABLED_TOOLS);
|
|
5754
|
+
const disabledModuleList = parseList(env.GHL_DISABLED_MODULES);
|
|
5755
|
+
const disabledToolList = parseList(env.GHL_DISABLED_TOOLS);
|
|
5735
5756
|
return {
|
|
5736
5757
|
enabledModules: moduleList ? new Set(moduleList) : null,
|
|
5737
5758
|
enabledTools: toolList ? new Set(toolList) : null,
|
|
5759
|
+
disabledModules: disabledModuleList ? new Set(disabledModuleList) : null,
|
|
5760
|
+
disabledTools: disabledToolList ? new Set(disabledToolList) : null,
|
|
5761
|
+
accountAdminEnabled: env.GHL_ENABLE_ACCOUNT_ADMIN === "1",
|
|
5738
5762
|
rawModuleInput: moduleList,
|
|
5739
|
-
rawToolInput: toolList
|
|
5763
|
+
rawToolInput: toolList,
|
|
5764
|
+
rawDisabledModuleInput: disabledModuleList,
|
|
5765
|
+
rawDisabledToolInput: disabledToolList
|
|
5740
5766
|
};
|
|
5741
5767
|
}
|
|
5742
5768
|
function isAllowlistActive(config3) {
|
|
5743
5769
|
return config3.enabledModules !== null || config3.enabledTools !== null;
|
|
5744
5770
|
}
|
|
5771
|
+
function isDenyListActive(config3) {
|
|
5772
|
+
return config3.disabledModules !== null || config3.disabledTools !== null;
|
|
5773
|
+
}
|
|
5774
|
+
function isGatingActive(config3) {
|
|
5775
|
+
return isAllowlistActive(config3) || isDenyListActive(config3) || config3.accountAdminEnabled;
|
|
5776
|
+
}
|
|
5777
|
+
function isToolDenied(toolName, moduleName, config3) {
|
|
5778
|
+
if (HARD_CORE_TOOL_NAMES.has(toolName)) return false;
|
|
5779
|
+
const toolDenied = config3.disabledTools?.has(toolName.toLowerCase()) ?? false;
|
|
5780
|
+
const moduleDenied = moduleName.length > 0 && (config3.disabledModules?.has(moduleName.toLowerCase()) ?? false);
|
|
5781
|
+
return toolDenied || moduleDenied;
|
|
5782
|
+
}
|
|
5745
5783
|
function shouldRegister(toolName, moduleName, config3) {
|
|
5784
|
+
if (HARD_CORE_TOOL_NAMES.has(toolName)) return true;
|
|
5785
|
+
if (isToolDenied(toolName, moduleName, config3)) return false;
|
|
5786
|
+
if (ACCOUNT_ADMIN_TOOLS.has(toolName) && !config3.accountAdminEnabled) return false;
|
|
5746
5787
|
if (ALWAYS_ON_TOOL_NAMES.has(toolName)) return true;
|
|
5747
5788
|
if (!isAllowlistActive(config3)) return true;
|
|
5748
5789
|
const toolLower = toolName.toLowerCase();
|
|
@@ -5782,32 +5823,57 @@ function wrapServerForModule(realServer, moduleName, config3, attemptedTools, re
|
|
|
5782
5823
|
}
|
|
5783
5824
|
});
|
|
5784
5825
|
}
|
|
5826
|
+
function buildGatingReport(config3, knownModules, attemptedTools, registeredTools, outOfBand) {
|
|
5827
|
+
const knownLower = new Set([...knownModules].map((m) => m.toLowerCase()));
|
|
5828
|
+
const knownToolsLower = /* @__PURE__ */ new Set([
|
|
5829
|
+
...[...attemptedTools].map((t) => t.toLowerCase()),
|
|
5830
|
+
...[...OUT_OF_BAND_TOOL_NAMES].map((t) => t.toLowerCase())
|
|
5831
|
+
]);
|
|
5832
|
+
const unknownModules = (raw) => (raw ?? []).filter((m) => !knownLower.has(m));
|
|
5833
|
+
const unknownTools = (raw) => (raw ?? []).filter((t) => !knownToolsLower.has(t));
|
|
5834
|
+
const hardCoreLower = new Set([...HARD_CORE_TOOL_NAMES].map((t) => t.toLowerCase()));
|
|
5835
|
+
return {
|
|
5836
|
+
gatingActive: isGatingActive(config3),
|
|
5837
|
+
allowlistActive: isAllowlistActive(config3),
|
|
5838
|
+
denyListActive: isDenyListActive(config3),
|
|
5839
|
+
accountAdminEnabled: config3.accountAdminEnabled,
|
|
5840
|
+
enabledModules: [...config3.enabledModules ?? []].sort(),
|
|
5841
|
+
enabledTools: [...config3.enabledTools ?? []].sort(),
|
|
5842
|
+
disabledModules: [...config3.disabledModules ?? []].sort(),
|
|
5843
|
+
disabledTools: [...config3.disabledTools ?? []].sort(),
|
|
5844
|
+
ignoredHardCoreDenials: (config3.rawDisabledToolInput ?? []).filter((t) => hardCoreLower.has(t)),
|
|
5845
|
+
unknownEnabledModules: unknownModules(config3.rawModuleInput),
|
|
5846
|
+
unknownEnabledTools: unknownTools(config3.rawToolInput),
|
|
5847
|
+
unknownDisabledModules: unknownModules(config3.rawDisabledModuleInput),
|
|
5848
|
+
unknownDisabledTools: unknownTools(config3.rawDisabledToolInput),
|
|
5849
|
+
outOfBandDenied: [...outOfBand?.denied ?? []].sort(),
|
|
5850
|
+
registeredCount: registeredTools.size + (outOfBand?.registered.size ?? 0),
|
|
5851
|
+
attemptedCount: attemptedTools.size + (outOfBand?.registered.size ?? 0) + (outOfBand?.denied.size ?? 0)
|
|
5852
|
+
};
|
|
5853
|
+
}
|
|
5785
5854
|
function validateAndLog(config3, knownModules, attemptedTools, registeredTools, log = (m) => process.stderr.write(m)) {
|
|
5786
|
-
if (!
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
`[ghl-mcp] WARNING: GHL_ENABLED_MODULES has unrecognized name(s): ${unknown.join(", ")}. Known modules: ${[...knownModules].sort().join(", ")}.
|
|
5793
|
-
`
|
|
5794
|
-
);
|
|
5855
|
+
if (!isGatingActive(config3)) return;
|
|
5856
|
+
const report = buildGatingReport(config3, knownModules, attemptedTools, registeredTools);
|
|
5857
|
+
const warnUnknown = (varName, names, hint = "") => {
|
|
5858
|
+
if (names.length > 0) {
|
|
5859
|
+
log(`[ghl-mcp] WARNING: ${varName} has unrecognized name(s): ${names.join(", ")}.${hint}
|
|
5860
|
+
`);
|
|
5795
5861
|
}
|
|
5796
|
-
}
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5862
|
+
};
|
|
5863
|
+
const modulesHint = ` Known modules: ${[...knownModules].sort().join(", ")}.`;
|
|
5864
|
+
warnUnknown("GHL_ENABLED_MODULES", report.unknownEnabledModules, modulesHint);
|
|
5865
|
+
warnUnknown("GHL_ENABLED_TOOLS", report.unknownEnabledTools);
|
|
5866
|
+
warnUnknown("GHL_DISABLED_MODULES", report.unknownDisabledModules, modulesHint);
|
|
5867
|
+
warnUnknown("GHL_DISABLED_TOOLS", report.unknownDisabledTools);
|
|
5868
|
+
if (report.ignoredHardCoreDenials.length > 0) {
|
|
5869
|
+
log(
|
|
5870
|
+
`[ghl-mcp] WARNING: GHL_DISABLED_TOOLS lists recovery-core tool(s) that cannot be disabled (ignored): ${report.ignoredHardCoreDenials.join(", ")}.
|
|
5803
5871
|
`
|
|
5804
|
-
|
|
5805
|
-
}
|
|
5872
|
+
);
|
|
5806
5873
|
}
|
|
5807
|
-
const
|
|
5808
|
-
const toolSummary = config3.enabledTools && config3.enabledTools.size > 0 ? `explicit-tools=[${[...config3.enabledTools].sort().join(",")}]` : "explicit-tools=(none)";
|
|
5874
|
+
const listOr = (label, items) => items.length > 0 ? `${label}=[${items.join(",")}]` : `${label}=(none)`;
|
|
5809
5875
|
log(
|
|
5810
|
-
`[ghl-mcp] Tool
|
|
5876
|
+
`[ghl-mcp] Tool gating active: registered ${registeredTools.size} of ${attemptedTools.size} tools (${listOr("modules", report.enabledModules)}; ${listOr("explicit-tools", report.enabledTools)}; ${listOr("disabled-modules", report.disabledModules)}; ${listOr("disabled-tools", report.disabledTools)}; account-admin=${report.accountAdminEnabled ? "ENABLED" : "off (default)"}).
|
|
5811
5877
|
`
|
|
5812
5878
|
);
|
|
5813
5879
|
}
|
|
@@ -14083,10 +14149,10 @@ async function getVersionStatus(installed) {
|
|
|
14083
14149
|
}
|
|
14084
14150
|
|
|
14085
14151
|
// src/tools/diagnostics.ts
|
|
14086
|
-
function registerDiagnosticTools(server2, installedVersion, client, builderClient, registry2) {
|
|
14152
|
+
function registerDiagnosticTools(server2, installedVersion, client, builderClient, registry2, getGatingReport) {
|
|
14087
14153
|
server2.tool(
|
|
14088
14154
|
"health_check",
|
|
14089
|
-
"Run a full health check of the GHL Command MCP install. Reports on: npm registry + version status, GHL API key validity, default location reachability, Firebase auth status (workflow builder), and
|
|
14155
|
+
"Run a full health check of the GHL Command MCP install. Reports on: npm registry + version status, GHL API key validity, default location reachability, Firebase auth status (workflow builder), token registry, and the tool-gating policy (disabled tools/modules, account-admin opt-in, typos in gating env vars). Returns a structured pass/fail/warn list with detail per check. Use this when something feels broken or after credentials change.",
|
|
14090
14156
|
{},
|
|
14091
14157
|
async () => {
|
|
14092
14158
|
const checks = [];
|
|
@@ -14136,7 +14202,7 @@ function registerDiagnosticTools(server2, installedVersion, client, builderClien
|
|
|
14136
14202
|
})();
|
|
14137
14203
|
const firebasePromise = (async () => {
|
|
14138
14204
|
if (!builderClient) {
|
|
14139
|
-
return { name: "Firebase auth (workflow builder)", status: "skip", detail: "Not configured. The
|
|
14205
|
+
return { name: "Firebase auth (workflow builder)", status: "skip", detail: "Not configured. The 54 Firebase-gated tools need Firebase credentials. The other 179 tools work fine without. To add it: run enable_workflow_builder with the three Firebase values from your GHL browser session (see elitedcs.com/ghl-mcp-firebase for DevTools steps). Do NOT put Firebase values as env vars in your Claude Desktop config \u2014 that path is unreliable and is the usual reason this still shows skip after a restart. enable_workflow_builder saves and verifies them for you." };
|
|
14140
14206
|
}
|
|
14141
14207
|
const result = await builderClient.checkAuth();
|
|
14142
14208
|
const tokenCompany = builderClient.getTokenCompanyId();
|
|
@@ -14185,7 +14251,32 @@ function registerDiagnosticTools(server2, installedVersion, client, builderClien
|
|
|
14185
14251
|
} else {
|
|
14186
14252
|
versionCheck = { name: "npm registry + version", status: "warn", detail: `Installed v${versionStatus.installed} but latest is v${versionStatus.latest}. Quit Claude (Cmd+Q) and reopen to upgrade.` };
|
|
14187
14253
|
}
|
|
14188
|
-
|
|
14254
|
+
const gatingCheck = (() => {
|
|
14255
|
+
const r = getGatingReport?.();
|
|
14256
|
+
if (!r) {
|
|
14257
|
+
return { name: "Tool gating", status: "skip", detail: "Gating report unavailable in this mode." };
|
|
14258
|
+
}
|
|
14259
|
+
if (!r.gatingActive) {
|
|
14260
|
+
return { name: "Tool gating", status: "pass", detail: `No gating configured \u2014 all ${r.registeredCount} tools registered. Sub-account create/delete stays OFF unless GHL_ENABLE_ACCOUNT_ADMIN=1 is set.` };
|
|
14261
|
+
}
|
|
14262
|
+
const parts = [`${r.registeredCount} of ${r.attemptedCount} tools registered.`];
|
|
14263
|
+
if (r.disabledTools.length > 0) parts.push(`Disabled tools: ${r.disabledTools.join(", ")}.`);
|
|
14264
|
+
if (r.disabledModules.length > 0) parts.push(`Disabled modules: ${r.disabledModules.join(", ")}.`);
|
|
14265
|
+
if (r.outOfBandDenied.length > 0) parts.push(`Confirmed unregistered (setup/helper tools): ${r.outOfBandDenied.join(", ")}.`);
|
|
14266
|
+
if (r.allowlistActive) parts.push(`Allowlist: modules=[${r.enabledModules.join(",") || "-"}], tools=[${r.enabledTools.join(",") || "-"}].`);
|
|
14267
|
+
parts.push(`Account admin (sub-account create/delete): ${r.accountAdminEnabled ? "ENABLED via GHL_ENABLE_ACCOUNT_ADMIN=1" : "OFF (default)"}.`);
|
|
14268
|
+
const problems = [];
|
|
14269
|
+
if (r.ignoredHardCoreDenials.length > 0) problems.push(`recovery-core tool(s) in GHL_DISABLED_TOOLS cannot be disabled and were IGNORED: ${r.ignoredHardCoreDenials.join(", ")}`);
|
|
14270
|
+
if (r.unknownDisabledTools.length > 0) problems.push(`unrecognized name(s) in GHL_DISABLED_TOOLS (possible typo \u2014 those tools are NOT disabled): ${r.unknownDisabledTools.join(", ")}`);
|
|
14271
|
+
if (r.unknownDisabledModules.length > 0) problems.push(`unrecognized name(s) in GHL_DISABLED_MODULES (possible typo): ${r.unknownDisabledModules.join(", ")}`);
|
|
14272
|
+
if (r.unknownEnabledTools.length > 0) problems.push(`unrecognized name(s) in GHL_ENABLED_TOOLS: ${r.unknownEnabledTools.join(", ")}`);
|
|
14273
|
+
if (r.unknownEnabledModules.length > 0) problems.push(`unrecognized name(s) in GHL_ENABLED_MODULES: ${r.unknownEnabledModules.join(", ")}`);
|
|
14274
|
+
if (problems.length > 0) {
|
|
14275
|
+
return { name: "Tool gating", status: "warn", detail: `${parts.join(" ")} PROBLEMS: ${problems.join("; ")}. Fix the env var in your Claude config and fully restart Claude.` };
|
|
14276
|
+
}
|
|
14277
|
+
return { name: "Tool gating", status: "pass", detail: parts.join(" ") };
|
|
14278
|
+
})();
|
|
14279
|
+
checks.push(versionCheck, apiKeyCheck, locationCheck, firebaseCheck, registryCheck, gatingCheck);
|
|
14189
14280
|
const symbols = { pass: "\u2713", fail: "\u2717", warn: "!", skip: "\u2014" };
|
|
14190
14281
|
const lines = [];
|
|
14191
14282
|
lines.push("GHL Command \u2014 Health Check");
|
|
@@ -17677,7 +17768,7 @@ var KNOWN_MODULES = /* @__PURE__ */ new Set([
|
|
|
17677
17768
|
LOCATION_SWITCHER_MODULE,
|
|
17678
17769
|
SNAPSHOTS_MODULE
|
|
17679
17770
|
]);
|
|
17680
|
-
function registerAllTools(server2, client, registry2, mcpVersion, env = process.env, tier = "full") {
|
|
17771
|
+
function registerAllTools(server2, client, registry2, mcpVersion, env = process.env, tier = "full", outOfBand) {
|
|
17681
17772
|
const config3 = parseAllowlist(env);
|
|
17682
17773
|
const attemptedTools = /* @__PURE__ */ new Set();
|
|
17683
17774
|
const registeredTools = /* @__PURE__ */ new Set();
|
|
@@ -17699,7 +17790,8 @@ function registerAllTools(server2, client, registry2, mcpVersion, env = process.
|
|
|
17699
17790
|
mcpVersion ?? "unknown",
|
|
17700
17791
|
client,
|
|
17701
17792
|
builderClient,
|
|
17702
|
-
registry2 ?? null
|
|
17793
|
+
registry2 ?? null,
|
|
17794
|
+
() => buildGatingReport(config3, KNOWN_MODULES, attemptedTools, registeredTools, outOfBand)
|
|
17703
17795
|
);
|
|
17704
17796
|
registerSnapshotTools(wrap(SNAPSHOTS_MODULE), client, registry2);
|
|
17705
17797
|
registerLocationSwitcherTools(
|
|
@@ -17709,7 +17801,7 @@ function registerAllTools(server2, client, registry2, mcpVersion, env = process.
|
|
|
17709
17801
|
registry2,
|
|
17710
17802
|
mcpVersion
|
|
17711
17803
|
);
|
|
17712
|
-
if (
|
|
17804
|
+
if (isGatingActive(config3)) {
|
|
17713
17805
|
validateAndLog(config3, KNOWN_MODULES, attemptedTools, registeredTools);
|
|
17714
17806
|
}
|
|
17715
17807
|
if (tier === "free") {
|
|
@@ -17721,6 +17813,26 @@ function registerAllTools(server2, client, registry2, mcpVersion, env = process.
|
|
|
17721
17813
|
return { registeredTools, gatedTools };
|
|
17722
17814
|
}
|
|
17723
17815
|
|
|
17816
|
+
// src/out-of-band.ts
|
|
17817
|
+
function makeOutOfBandTracker() {
|
|
17818
|
+
return { registered: /* @__PURE__ */ new Set(), denied: /* @__PURE__ */ new Set() };
|
|
17819
|
+
}
|
|
17820
|
+
function registerOutOfBand(entries, config3, tracker, log = (m) => process.stderr.write(m)) {
|
|
17821
|
+
for (const entry of entries) {
|
|
17822
|
+
if (isToolDenied(entry.name, "", config3)) {
|
|
17823
|
+
tracker.denied.add(entry.name);
|
|
17824
|
+
log(
|
|
17825
|
+
`[ghl-mcp] Tool disabled by GHL_DISABLED_TOOLS: ${entry.name}${entry.deniedNote ? ` (${entry.deniedNote})` : ""}
|
|
17826
|
+
`
|
|
17827
|
+
);
|
|
17828
|
+
continue;
|
|
17829
|
+
}
|
|
17830
|
+
tracker.registered.add(entry.name);
|
|
17831
|
+
entry.register();
|
|
17832
|
+
entry.sideEffect?.();
|
|
17833
|
+
}
|
|
17834
|
+
}
|
|
17835
|
+
|
|
17724
17836
|
// src/index.ts
|
|
17725
17837
|
init_credentials_store();
|
|
17726
17838
|
init_setup_tool();
|
|
@@ -17844,7 +17956,7 @@ function summarizeInstall(r) {
|
|
|
17844
17956
|
function registerSkillsTool(server2, packageVersion, baseDir) {
|
|
17845
17957
|
server2.tool(
|
|
17846
17958
|
"install_skills",
|
|
17847
|
-
"Install (or repair) the guided skills bundled with GHL Command \u2014
|
|
17959
|
+
"Install (or repair) the guided skills bundled with GHL Command \u2014 Blueprint (build a whole client account from one intake) and Clone Site (clone and rebrand a live web page for a client, with a rights declaration and a pre-launch liability report) \u2014 into your ~/.claude/skills/ so Claude can use them. Runs automatically on startup; call this to verify what is installed, or to re-install after deleting a skill. NEVER overwrites files you have edited (your version is kept and reported). Restart Claude after install for new skills to load.",
|
|
17848
17960
|
{
|
|
17849
17961
|
targetDir: import_zod57.z.string().optional().describe("Override the install directory. Default: ~/.claude/skills")
|
|
17850
17962
|
},
|
|
@@ -18408,6 +18520,9 @@ async function resolveAccessAndRegister() {
|
|
|
18408
18520
|
`);
|
|
18409
18521
|
}
|
|
18410
18522
|
inBootstrapMode = !apiKey || !locationId || !licenseVerified;
|
|
18523
|
+
const gatingConfig = parseAllowlist(process.env);
|
|
18524
|
+
const outOfBandTracker = makeOutOfBandTracker();
|
|
18525
|
+
outOfBandTracker.registered.add("get_mcp_version");
|
|
18411
18526
|
if (inBootstrapMode) {
|
|
18412
18527
|
process.stderr.write(
|
|
18413
18528
|
`[ghl-mcp] Bootstrap mode.
|
|
@@ -18417,23 +18532,52 @@ async function resolveAccessAndRegister() {
|
|
|
18417
18532
|
);
|
|
18418
18533
|
registerSetupTool(server);
|
|
18419
18534
|
registerLeadCaptureTool(server);
|
|
18420
|
-
|
|
18535
|
+
registerOutOfBand(
|
|
18536
|
+
[{ name: "auto_capture_firebase_script", register: () => registerFirebaseCaptureScriptTool(server) }],
|
|
18537
|
+
gatingConfig,
|
|
18538
|
+
outOfBandTracker
|
|
18539
|
+
);
|
|
18421
18540
|
} else {
|
|
18422
18541
|
const client = new GHLClient({ apiKey, locationId });
|
|
18423
|
-
registerAllTools(server, client, registry, pkg.version, process.env, sessionTier);
|
|
18424
|
-
|
|
18425
|
-
|
|
18426
|
-
|
|
18427
|
-
|
|
18428
|
-
|
|
18429
|
-
|
|
18430
|
-
|
|
18431
|
-
|
|
18542
|
+
registerAllTools(server, client, registry, pkg.version, process.env, sessionTier, outOfBandTracker);
|
|
18543
|
+
registerOutOfBand(
|
|
18544
|
+
[
|
|
18545
|
+
// Available in normal mode so buyers can add Firebase later without
|
|
18546
|
+
// re-running setup_ghl_mcp with all 7 fields, and so they can re-grab
|
|
18547
|
+
// a fresh refresh token when it rotates. Registered on the FREE tier too:
|
|
18548
|
+
// the Firebase login powers the read-only auditor tools (audit_workflows,
|
|
18549
|
+
// validate_workflow, *_full reads) — only the write tools stay gated.
|
|
18550
|
+
{ name: "enable_workflow_builder", register: () => registerEnableWorkflowBuilderTool(server) },
|
|
18551
|
+
{ name: "auto_capture_firebase_script", register: () => registerFirebaseCaptureScriptTool(server) },
|
|
18552
|
+
// One-click Builder unlock — buyer just logs into a Chrome window the
|
|
18553
|
+
// helper opens; also the silent re-capture path for token rotations.
|
|
18554
|
+
{ name: "capture_firebase_interactive", register: () => registerInteractiveCaptureTool(server) },
|
|
18555
|
+
// Skills rail (2026-07-28): bundled skills (Blueprint) install themselves
|
|
18556
|
+
// into ~/.claude/skills — subscribers never download anything separately.
|
|
18557
|
+
// Auto-runs on every start (idempotent, never clobbers user edits);
|
|
18558
|
+
// the tool exists for verification/repair. Every tier: local file copy
|
|
18559
|
+
// only. Denying install_skills also skips the auto-install — a buyer who
|
|
18560
|
+
// gated it clearly doesn't want this server writing files into ~/.claude.
|
|
18561
|
+
{
|
|
18562
|
+
name: "install_skills",
|
|
18563
|
+
register: () => registerSkillsTool(server, pkg.version, __dirname),
|
|
18564
|
+
deniedNote: "bundled-skills auto-install skipped too",
|
|
18565
|
+
sideEffect: () => {
|
|
18566
|
+
try {
|
|
18567
|
+
const skillsResult = installBundledSkills({ packageVersion: pkg.version, baseDir: __dirname });
|
|
18568
|
+
const line = summarizeInstall(skillsResult);
|
|
18569
|
+
if (line) process.stderr.write(`[ghl-mcp] ${line}
|
|
18432
18570
|
`);
|
|
18433
|
-
|
|
18434
|
-
|
|
18571
|
+
} catch (e) {
|
|
18572
|
+
process.stderr.write(`[ghl-mcp] Skills install skipped: ${String(e).slice(0, 120)}
|
|
18435
18573
|
`);
|
|
18436
|
-
|
|
18574
|
+
}
|
|
18575
|
+
}
|
|
18576
|
+
}
|
|
18577
|
+
],
|
|
18578
|
+
gatingConfig,
|
|
18579
|
+
outOfBandTracker
|
|
18580
|
+
);
|
|
18437
18581
|
if (fileCreds && !process.env.GHL_API_KEY) {
|
|
18438
18582
|
process.stderr.write(`[ghl-mcp] Loaded credentials from ${credentialsPath()}
|
|
18439
18583
|
`);
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elitedcs/ghl-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.57.0",
|
|
4
4
|
"mcpName": "io.github.drjerryrelth/ghl-command",
|
|
5
|
-
"description": "GoHighLevel MCP Server for Claude.
|
|
5
|
+
"description": "GoHighLevel MCP Server for Claude. 233 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",
|
|
7
7
|
"bin": {
|
|
8
8
|
"ghl-mcp": "dist/index.js"
|