@elitedcs/ghl-mcp 3.6.0 → 3.8.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 +101 -0
- package/README.md +6 -6
- package/dist/index.js +234 -73
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,106 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.8.0 — Bundle re-extraction wins (triggers + goal events) + correctness fixes
|
|
4
|
+
|
|
5
|
+
**178 tools across 38 modules. Bundle: 291.3 KB.**
|
|
6
|
+
|
|
7
|
+
Three improvements that all flow from one bundle dive into `client-app-automation-workflows.leadconnectorhq.com`:
|
|
8
|
+
|
|
9
|
+
### Goal-event catalogue — all 10 conditions documented (was 1)
|
|
10
|
+
v3.6.0 shipped `build_goal_event` with one verified `goal_condition` (`review_request_clicked`) and a permissive string for everything else. The bundle's `GoalCondition` enum reveals the full set:
|
|
11
|
+
|
|
12
|
+
- `email_event` — extras: `{ stepIds: [] }`
|
|
13
|
+
- `link_click` — extras: `{ linkIds: [] }`
|
|
14
|
+
- `add_contact_tag` — extras: `{ tags: [] }` (inferred)
|
|
15
|
+
- `remove_contact_tag` — extras: `{ tags: [] }` (inferred)
|
|
16
|
+
- `appointment_status` — extras: `{ calendarId }`
|
|
17
|
+
- `payment_received` — extras: `{ globalProductIds: [] }`
|
|
18
|
+
- `form_submission` — extras: `{ formIds: [] }`
|
|
19
|
+
- `document_status` — extras: `{ templateId }`
|
|
20
|
+
- `invoice_paid` — extras: `{ invoiceStepId }`
|
|
21
|
+
- `review_request_clicked` — extras: `{ reviewTypes, reviewLinkId }`
|
|
22
|
+
|
|
23
|
+
`build_goal_event`'s `goal_condition` is now a `z.enum` of these 10 values (was permissive `z.string()`). The per-condition extras shapes are documented in the tool description.
|
|
24
|
+
|
|
25
|
+
### Goal-event action enum fixed
|
|
26
|
+
v3.6.0's tool advertised `action: "exit" | "continue" | "goto"`. The actual `GoalAction` enum in the bundle is `continue | wait | exit` — **no `goto`**. Fixed. Also removed the `target_node_id` parameter that paired with the bogus goto. `WorkflowGoalAttributes` type updated to match.
|
|
27
|
+
|
|
28
|
+
### 7 of 9 previously-uncaptured triggers now documented
|
|
29
|
+
Trigger field paths extracted from per-trigger validator functions in the bundle:
|
|
30
|
+
|
|
31
|
+
- `affiliate_created` → `affiliate.id, contact.tags`
|
|
32
|
+
- `scheduler_trigger` → `scheduler.interval, scheduler.cron, scheduler.frequency`
|
|
33
|
+
- `user_log_in` → `product.id, category.id, lesson.id, offer.id, contact.tags` (shares membership-course validator)
|
|
34
|
+
- `order_submission` → `order.funnel_id, order.line_item_global_product_ids, order.line_item_funnel_product_ids, payment.calendar.id, payment.global_product_ids, payment.form.id`
|
|
35
|
+
- `facebook_lead_gen` → `facebook.formId, facebook.pageId, contact.tags`
|
|
36
|
+
|
|
37
|
+
Plus 2 more handled explicitly:
|
|
38
|
+
- `conv_ai_trigger`, `conv_ai_autonomous_trigger` — confirmed fieldless (no specific validator in the bundle)
|
|
39
|
+
- `custom_object_created`, `custom_object_changed` — fields are user-defined per object using the `customObject.<field>` prefix; schema now documents this dynamic shape
|
|
40
|
+
|
|
41
|
+
Coverage: **57/57 native triggers, 0 type-only-pending** (was 9 type-only-pending).
|
|
42
|
+
|
|
43
|
+
### Bug fix: `remove_from_workflow` read/write asymmetry
|
|
44
|
+
Don Harris flagged at the end of his 2026-05-14 funnel audit that some GHL workflows return only the `workflow_id` array on read, while writes require both that AND the `workflowId` string. Couldn't reproduce in MCP Testing — both reads I checked returned both fields — but added defensive symmetric normalization to both paths in `workflow-builder-client.ts`. If only one form is present in either direction, the other is synthesized. No-op when both are already present.
|
|
45
|
+
|
|
46
|
+
### Bug fix: accurate "without Firebase" tool count
|
|
47
|
+
Empirical audit: basic-creds mode (no Firebase) actually exposes **148 tools**, not 168 as the v3.5.1 messaging claimed. Firebase adds **30 tools** across 6 modules (workflow builder, funnel builder, form builder, pipeline builder, workflow cloner, validate_workflow). `setup_ghl_mcp`, `enable_workflow_builder`, README, and CLAUDE.md all corrected.
|
|
48
|
+
|
|
49
|
+
### Bundle re-extraction methodology (for future audits)
|
|
50
|
+
1. Fetch `https://client-app-automation-workflows.leadconnectorhq.com/` → find current `index-*.js` bundle URL
|
|
51
|
+
2. Pull the bundle (~9.5 MB minified)
|
|
52
|
+
3. Search for `var GoalCondition=(...)` and `var GoalAction=(...)` for enum extraction
|
|
53
|
+
4. Search for `<triggerName>Validator=n=>` patterns for per-trigger field paths
|
|
54
|
+
5. Watch for i18n translation pollution — filter out windows containing non-ASCII Danish/German/Swedish characters
|
|
55
|
+
|
|
56
|
+
### Files changed
|
|
57
|
+
- `src/trigger-schemas.ts` — 7 uncaptured triggers now documented; 2 confirmed fieldless; 2 use dynamic `customObject.*` schema
|
|
58
|
+
- `src/tools/workflow-builder.ts` — `build_goal_event` enum tightened; goto removed; description lists all 10 goal_condition values + extras shapes
|
|
59
|
+
- `src/workflow-action-types.ts` — `WorkflowGoalAttributes.action` corrected to `continue | wait | exit`
|
|
60
|
+
- `src/workflow-builder-client.ts` — `normalizeRemoveFromWorkflowAction()` helper applied symmetrically on read + write
|
|
61
|
+
- `src/setup-tool.ts` — 168 → 148; "9 workflow builder tools" → "30 tools across 6 modules"
|
|
62
|
+
- `README.md`, `CLAUDE.md` — synced
|
|
63
|
+
|
|
64
|
+
## 3.7.0 — Funnel-builder fixes (Don Harris audit)
|
|
65
|
+
|
|
66
|
+
**178 tools across 38 modules. Bundle: 288.4 KB.**
|
|
67
|
+
|
|
68
|
+
Implements all 7 fixes from Don Harris's 2026-05-14 audit. Don captured the correct endpoints via Chrome DevTools against `page-builder.leadconnectorhq.com` and `app.gohighlevel.com`, then verified each fix with curl round-trips against two live sub-accounts. Full credit to Don for the diagnostic work.
|
|
69
|
+
|
|
70
|
+
### The root cause
|
|
71
|
+
All funnel write tools were hitting endpoints that don't exist on `backend.leadconnectorhq.com/funnels/...`. The real save paths live on the same host but with different verbs, methods, and body shapes. Plus, mutating endpoints require `Origin` + `Referer` headers that `funnelRequest()` wasn't sending, causing 401 `{"message":"Error calling IAM service"}` on every write.
|
|
72
|
+
|
|
73
|
+
### Header fix (unblocks every funnel write)
|
|
74
|
+
Added `Origin: https://app.gohighlevel.com` and `Referer: https://app.gohighlevel.com/` to `funnelRequest()`. Without these, GHL's IAM rejects writes regardless of bearer token validity.
|
|
75
|
+
|
|
76
|
+
### Endpoint fixes
|
|
77
|
+
| Tool | Was | Now |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| `update_page_content` | `PUT /page/{pageId}` | `POST /builder/prebuilt-section/sync/changes` with `{ locationId, pageId, pageData, write: true, isPublished }` |
|
|
80
|
+
| `update_funnel` | `PUT /funnel/{funnelId}` | `POST /funnel/update-settings` with full settings body. Rewritten with fetch-then-merge so you can change one field without blowing away the others. |
|
|
81
|
+
| `create_funnel_page` | `POST /page` | `POST /funnel/create-step` with client-generated step UUID + nested `step` object. Now also returns the generated `stepId` so the caller can use it with `update_funnel_step` / `delete_funnel_page` without a separate lookup. |
|
|
82
|
+
| `delete_funnel_page` | `DELETE /page/{pageId}` | `POST /funnel/delete-step` with `{ funnelId, stepId }`. **SIGNATURE CHANGED**: now takes `funnelId + stepId` instead of `pageId`. |
|
|
83
|
+
| `delete_funnel` | `DELETE /funnel/{id}` | `POST /funnel/delete` with `{ funnelId, locationId, userId }` |
|
|
84
|
+
|
|
85
|
+
### `update_funnel_step` (NEW)
|
|
86
|
+
Per-step renames, URL slugs, and domain attachments. `PUT /funnel/step/{funnelId}` with `{ stepId, name, url, domainName }`. Use this when you want to rename a single page entry inside a funnel without touching funnel-level settings.
|
|
87
|
+
|
|
88
|
+
### `WorkflowBuilderClient.getUserId()` (NEW, internal)
|
|
89
|
+
Public getter on the builder client. Required because `delete_funnel` needs `userId` in the request body. Not exposed via MCP.
|
|
90
|
+
|
|
91
|
+
### Round-trip verified in MCP Testing
|
|
92
|
+
- 6/6 tested funnel writes return success against real GHL backend (the 7th, `update_page_content`, was already verified by Don's 112KB real-page round-trip in his audit email).
|
|
93
|
+
- Created → renamed → added step → renamed step → deleted step → deleted funnel, all in one test pass.
|
|
94
|
+
|
|
95
|
+
### Honest scoping
|
|
96
|
+
- The 168/178 "without Firebase / with Firebase" split documented in `setup_ghl_mcp` and `enable_workflow_builder` is carried forward from v3.5.1 and hasn't been audited empirically. It's likely off in absolute terms (funnel/form/pipeline builders all gate on Firebase too). TODO to do a real audit.
|
|
97
|
+
- The bonus `update_workflow_actions` / `remove_from_workflow` read/write asymmetry Don flagged at the end of his email is not addressed in this release — separate concern, separate fix when prioritized.
|
|
98
|
+
|
|
99
|
+
### Files changed
|
|
100
|
+
- `src/tools/funnel-builder.ts` — full rewrite of all 6 broken endpoints + `update_funnel_step` added
|
|
101
|
+
- `src/workflow-builder-client.ts` — `getUserId()` public getter
|
|
102
|
+
- `src/setup-tool.ts` — tool counts refreshed
|
|
103
|
+
|
|
3
104
|
## 3.6.0 — `build_goal_event` (closes Don-e's last open complaint)
|
|
4
105
|
|
|
5
106
|
**177 tools across 38 modules. Bundle: 281.9 KB.**
|
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.** 178 tools across 36 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.
|
|
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
|
|
|
@@ -138,7 +138,7 @@ https://app.gohighlevel.com/v2/location/YOUR_LOCATION_ID/dashboard
|
|
|
138
138
|
|
|
139
139
|
## Enable Workflow Builder (Optional)
|
|
140
140
|
|
|
141
|
-
The
|
|
141
|
+
The 30 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 148 tools work fine — you just won'''t have workflow/funnel/form/pipeline editing.
|
|
142
142
|
|
|
143
143
|
Grab the three values from your GHL browser session, then re-run `setup_ghl_mcp` with them:
|
|
144
144
|
|
|
@@ -167,9 +167,9 @@ Re-run setup_ghl_mcp with workflow builder:
|
|
|
167
167
|
|
|
168
168
|
---
|
|
169
169
|
|
|
170
|
-
## Tools (
|
|
170
|
+
## Tools (178)
|
|
171
171
|
|
|
172
|
-
> **v3.
|
|
172
|
+
> **v3.7.0 fixes Don Harris's 2026-05-14 funnel-builder audit.** All six previously-broken funnel write tools (`update_funnel`, `create_funnel_page`, `delete_funnel_page`, `delete_funnel`, `update_page_content`, plus `create_funnel` which 401'd) now hit the correct GHL endpoints. New: `update_funnel_step` for per-step renames / slugs / domains. Origin + Referer headers added to all funnel writes — required by GHL's IAM, missing before.
|
|
173
173
|
|
|
174
174
|
### CRM & Contacts (15 tools)
|
|
175
175
|
|
|
@@ -420,7 +420,7 @@ Re-run setup_ghl_mcp with workflow builder:
|
|
|
420
420
|
|---|---|
|
|
421
421
|
| `get_mcp_version` | Check installed version against the latest published to npm. Confirms an upgrade landed after restarting Claude. Available even before GHL credentials are configured. |
|
|
422
422
|
| `health_check` | Run a full health check: npm registry + version status, GHL API key validity, default location reachability, Firebase auth status, token registry presence. Use when something feels broken. |
|
|
423
|
-
| `enable_workflow_builder` | Add Firebase credentials to an existing install to unlock
|
|
423
|
+
| `enable_workflow_builder` | Add Firebase credentials to an existing install to unlock 30 additional tools across 6 modules (workflow builder, funnel builder, form builder, pipeline builder, workflow cloner, validate_workflow). No need to re-enter license / API key / location ID. Run this any time after the basic setup, on the buyer's schedule. |
|
|
424
424
|
|
|
425
425
|
### Other Modules
|
|
426
426
|
|
|
@@ -542,7 +542,7 @@ ghl-command-mcp/
|
|
|
542
542
|
│ ├── emails.ts # 1 tool — email campaign listing
|
|
543
543
|
│ ├── trigger-links.ts # 1 tool — trigger link listing
|
|
544
544
|
│ ├── workflow-builder.ts # 6 tools — full workflow CRUD (internal API)
|
|
545
|
-
│ ├── funnel-builder.ts #
|
|
545
|
+
│ ├── funnel-builder.ts # 10 tools — funnel/page builder (internal API)
|
|
546
546
|
│ ├── form-builder.ts # 5 tools — form builder (internal API)
|
|
547
547
|
│ ├── pipeline-builder.ts # 5 tools — pipeline/stage builder (internal API)
|
|
548
548
|
│ ├── bulk-operations.ts # 5 tools — batch contact operations
|
package/dist/index.js
CHANGED
|
@@ -31,8 +31,8 @@ var require_package = __commonJS({
|
|
|
31
31
|
"package.json"(exports2, module2) {
|
|
32
32
|
module2.exports = {
|
|
33
33
|
name: "@elitedcs/ghl-mcp",
|
|
34
|
-
version: "3.
|
|
35
|
-
description: "GoHighLevel MCP Server for Claude.
|
|
34
|
+
version: "3.8.0",
|
|
35
|
+
description: "GoHighLevel MCP Server for Claude. 178 tools \u2014 full CRM, automation, marketing control, and the only programmatic GHL workflow builder.",
|
|
36
36
|
main: "dist/index.js",
|
|
37
37
|
bin: {
|
|
38
38
|
"ghl-mcp": "dist/index.js"
|
|
@@ -651,15 +651,60 @@ var FacebookCommentOnPostTriggerSchema = typedTrigger("facebook_comment_on_post"
|
|
|
651
651
|
var IgCommentOnPostTriggerSchema = typedTrigger("ig_comment_on_post", [], "partial");
|
|
652
652
|
var InboundWebhookTriggerSchema = typedTrigger("inbound_webhook", [], "fieldless");
|
|
653
653
|
var PaymentReceivedTriggerSchema = typedTrigger("payment_received", [], "fieldless");
|
|
654
|
-
var AffiliateCreatedTriggerSchema = typedTrigger("affiliate_created", [
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
var
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
654
|
+
var AffiliateCreatedTriggerSchema = typedTrigger("affiliate_created", [
|
|
655
|
+
"affiliate.id",
|
|
656
|
+
"contact.tags"
|
|
657
|
+
]);
|
|
658
|
+
var SchedulerTriggerTriggerSchema = typedTrigger("scheduler_trigger", [
|
|
659
|
+
"scheduler.interval",
|
|
660
|
+
"scheduler.cron",
|
|
661
|
+
"scheduler.frequency"
|
|
662
|
+
]);
|
|
663
|
+
var UserLogInTriggerSchema = typedTrigger("user_log_in", [
|
|
664
|
+
// Shares membershipCourseValidator with course/lesson/category triggers.
|
|
665
|
+
"product.id",
|
|
666
|
+
"category.id",
|
|
667
|
+
"lesson.id",
|
|
668
|
+
"offer.id",
|
|
669
|
+
"contact.tags"
|
|
670
|
+
]);
|
|
671
|
+
var OrderSubmissionTriggerSchema = typedTrigger("order_submission", [
|
|
672
|
+
"order.funnel_id",
|
|
673
|
+
"order.line_item_global_product_ids",
|
|
674
|
+
"order.line_item_funnel_product_ids",
|
|
675
|
+
"payment.calendar.id",
|
|
676
|
+
"payment.global_product_ids",
|
|
677
|
+
"payment.form.id"
|
|
678
|
+
]);
|
|
679
|
+
var FacebookLeadGenTriggerSchema = typedTrigger("facebook_lead_gen", [
|
|
680
|
+
"facebook.formId",
|
|
681
|
+
"facebook.pageId",
|
|
682
|
+
"contact.tags"
|
|
683
|
+
]);
|
|
684
|
+
var CustomObjectCreatedTriggerSchema = TriggerCommonSchema.extend({
|
|
685
|
+
type: import_zod2.z.literal("custom_object_created"),
|
|
686
|
+
conditions: import_zod2.z.array(import_zod2.z.object({
|
|
687
|
+
operator: import_zod2.z.string(),
|
|
688
|
+
field: import_zod2.z.string().describe("Custom-object field paths use the `customObject.<your_field_name>` prefix. Field names are user-defined per custom object \u2014 query the location's custom objects to discover valid field paths."),
|
|
689
|
+
value: import_zod2.z.unknown().optional(),
|
|
690
|
+
title: import_zod2.z.string().optional(),
|
|
691
|
+
type: import_zod2.z.string().optional(),
|
|
692
|
+
id: import_zod2.z.string().optional()
|
|
693
|
+
}).passthrough()).optional()
|
|
694
|
+
});
|
|
695
|
+
var CustomObjectChangedTriggerSchema = TriggerCommonSchema.extend({
|
|
696
|
+
type: import_zod2.z.literal("custom_object_changed"),
|
|
697
|
+
conditions: import_zod2.z.array(import_zod2.z.object({
|
|
698
|
+
operator: import_zod2.z.string(),
|
|
699
|
+
field: import_zod2.z.string().describe("Custom-object field paths use the `customObject.<your_field_name>` prefix. Field names are user-defined per custom object \u2014 query the location's custom objects to discover valid field paths."),
|
|
700
|
+
value: import_zod2.z.unknown().optional(),
|
|
701
|
+
title: import_zod2.z.string().optional(),
|
|
702
|
+
type: import_zod2.z.string().optional(),
|
|
703
|
+
id: import_zod2.z.string().optional()
|
|
704
|
+
}).passthrough()).optional()
|
|
705
|
+
});
|
|
706
|
+
var ConvAiTriggerTriggerSchema = typedTrigger("conv_ai_trigger", [], "fieldless");
|
|
707
|
+
var ConvAiAutonomousTriggerTriggerSchema = typedTrigger("conv_ai_autonomous_trigger", [], "fieldless");
|
|
663
708
|
var UnknownTriggerSchema = TriggerCommonSchema.extend({
|
|
664
709
|
type: import_zod2.z.string(),
|
|
665
710
|
conditions: import_zod2.z.array(import_zod2.z.record(import_zod2.z.unknown())).optional()
|
|
@@ -770,6 +815,23 @@ var CreateWorkflowResponseSchema = import_zod3.z.union([
|
|
|
770
815
|
version: typeof data.version === "number" ? data.version : 1
|
|
771
816
|
});
|
|
772
817
|
});
|
|
818
|
+
function normalizeRemoveFromWorkflowAction(action) {
|
|
819
|
+
if (action.type !== "remove_from_workflow") return action;
|
|
820
|
+
const attrs = action.attributes;
|
|
821
|
+
if (!attrs || typeof attrs !== "object") return action;
|
|
822
|
+
const a = attrs;
|
|
823
|
+
const hasArr = Array.isArray(a.workflow_id) && a.workflow_id.length > 0;
|
|
824
|
+
const hasStr = typeof a.workflowId === "string" && a.workflowId.length > 0;
|
|
825
|
+
if (hasArr && hasStr) return action;
|
|
826
|
+
if (!hasArr && !hasStr) return action;
|
|
827
|
+
const next = { ...a };
|
|
828
|
+
if (hasArr && !hasStr) {
|
|
829
|
+
next.workflowId = a.workflow_id[0];
|
|
830
|
+
} else if (hasStr && !hasArr) {
|
|
831
|
+
next.workflow_id = [a.workflowId];
|
|
832
|
+
}
|
|
833
|
+
return { ...action, attributes: next };
|
|
834
|
+
}
|
|
773
835
|
function hasId(action) {
|
|
774
836
|
return typeof action.id === "string" && action.id.length > 0;
|
|
775
837
|
}
|
|
@@ -869,6 +931,14 @@ var WorkflowBuilderClient = class _WorkflowBuilderClient {
|
|
|
869
931
|
getApiKey() {
|
|
870
932
|
return this.apiKey;
|
|
871
933
|
}
|
|
934
|
+
/**
|
|
935
|
+
* Return the current Firebase user ID. Required by the funnel-builder's
|
|
936
|
+
* delete_funnel endpoint which needs `userId` in the request body. Not
|
|
937
|
+
* exposed via MCP.
|
|
938
|
+
*/
|
|
939
|
+
getUserId() {
|
|
940
|
+
return this.userId;
|
|
941
|
+
}
|
|
872
942
|
/**
|
|
873
943
|
* Probe Firebase auth by refreshing the ID token. Used by the health_check
|
|
874
944
|
* diagnostic tool. Does not touch GHL backend — just exchanges the refresh
|
|
@@ -1066,7 +1136,11 @@ ${errorBody}`
|
|
|
1066
1136
|
workflowData: isRecord(raw.workflowData.workflowData) ? raw.workflowData.workflowData : { templates: [] },
|
|
1067
1137
|
triggers: raw.triggers
|
|
1068
1138
|
} : raw;
|
|
1069
|
-
|
|
1139
|
+
const parsed = WorkflowFullSchema.parse(flat);
|
|
1140
|
+
if (parsed.workflowData?.templates) {
|
|
1141
|
+
parsed.workflowData.templates = parsed.workflowData.templates.map(normalizeRemoveFromWorkflowAction);
|
|
1142
|
+
}
|
|
1143
|
+
return parsed;
|
|
1070
1144
|
}
|
|
1071
1145
|
/**
|
|
1072
1146
|
* Create a new empty workflow
|
|
@@ -1227,7 +1301,7 @@ ${errorBody}`
|
|
|
1227
1301
|
*/
|
|
1228
1302
|
buildActionChain(actions) {
|
|
1229
1303
|
validateActionChain(actions);
|
|
1230
|
-
const linked = actions.map((action, i) => {
|
|
1304
|
+
const linked = actions.map(normalizeRemoveFromWorkflowAction).map((action, i) => {
|
|
1231
1305
|
const copy = { ...action };
|
|
1232
1306
|
if (!copy.id) {
|
|
1233
1307
|
copy.id = crypto.randomUUID();
|
|
@@ -4300,21 +4374,28 @@ function registerWorkflowBuilderTools(server2, client) {
|
|
|
4300
4374
|
);
|
|
4301
4375
|
server2.tool(
|
|
4302
4376
|
"build_goal_event",
|
|
4303
|
-
"Build a correctly-shaped GHL workflow goal-event node. Goal events sit inline in the action chain \u2014 when the goal condition fires during workflow execution, the configured action runs (default: exit the workflow). The previous action's `next` should point to the goal node's id; the goal node itself does not have a `next`.
|
|
4304
|
-
{
|
|
4305
|
-
goal_condition: import_zod31.z.
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4377
|
+
"Build a correctly-shaped GHL workflow goal-event node. Goal events sit inline in the action chain \u2014 when the goal condition fires during workflow execution, the configured action runs (default: exit the workflow). The previous action's `next` should point to the goal node's id; the goal node itself does not have a `next`. All 10 goal_condition values are catalogued (from GHL's workflow-builder JS bundle, extracted 2026-05-18): email_event, link_click, add_contact_tag, remove_contact_tag, appointment_status, payment_received, form_submission, document_status, invoice_paid, review_request_clicked. Each one has a different `extras` shape (see the `goal_condition` field's description for details).",
|
|
4378
|
+
{
|
|
4379
|
+
goal_condition: import_zod31.z.enum([
|
|
4380
|
+
"email_event",
|
|
4381
|
+
"link_click",
|
|
4382
|
+
"add_contact_tag",
|
|
4383
|
+
"remove_contact_tag",
|
|
4384
|
+
"appointment_status",
|
|
4385
|
+
"payment_received",
|
|
4386
|
+
"form_submission",
|
|
4387
|
+
"document_status",
|
|
4388
|
+
"invoice_paid",
|
|
4389
|
+
"review_request_clicked"
|
|
4390
|
+
]).describe("The goal-condition identifier. Extras shape per condition: email_event \u2192 {stepIds:[]}; link_click \u2192 {linkIds:[]}; appointment_status \u2192 {calendarId}; payment_received \u2192 {globalProductIds:[]}; form_submission \u2192 {formIds:[]}; document_status \u2192 {templateId}; invoice_paid \u2192 {invoiceStepId}; review_request_clicked \u2192 {reviewTypes:['sms'|'email'], reviewLinkId}; add_contact_tag/remove_contact_tag \u2192 {tags:[]} (uncaptured but inferred)."),
|
|
4391
|
+
extras: import_zod31.z.record(import_zod31.z.unknown()).optional().describe("Goal-condition-specific config. See goal_condition description for the expected shape per value. Pass {} or omit for goal_conditions without extras."),
|
|
4392
|
+
action: import_zod31.z.enum(["exit", "continue", "wait"]).default("exit").describe("What happens when the goal fires (per GHL's GoalAction enum). 'exit' terminates the workflow path (verified). 'continue' lets it proceed to a downstream node. 'wait' pauses on the goal."),
|
|
4309
4393
|
name: import_zod31.z.string().default("Goal").describe("Display name in the GHL UI."),
|
|
4310
4394
|
op: import_zod31.z.enum(["or", "and"]).default("or").describe("Top-level boolean operator across segments. Default 'or'."),
|
|
4311
4395
|
inner_op: import_zod31.z.enum(["or", "and"]).default("or").describe("Boolean operator across conditions within a single segment. Default 'or'.")
|
|
4312
4396
|
},
|
|
4313
|
-
async ({ goal_condition, extras, action,
|
|
4397
|
+
async ({ goal_condition, extras, action, name, op, inner_op }) => {
|
|
4314
4398
|
try {
|
|
4315
|
-
if (action === "goto" && !target_node_id) {
|
|
4316
|
-
throw new Error("action='goto' requires target_node_id to identify which workflow action to jump to.");
|
|
4317
|
-
}
|
|
4318
4399
|
const nodeId = crypto.randomUUID();
|
|
4319
4400
|
const conditionId = crypto.randomUUID();
|
|
4320
4401
|
const attributes = {
|
|
@@ -4330,9 +4411,6 @@ function registerWorkflowBuilderTools(server2, client) {
|
|
|
4330
4411
|
type: "workflow_goal",
|
|
4331
4412
|
action
|
|
4332
4413
|
};
|
|
4333
|
-
if (action === "goto" && target_node_id) {
|
|
4334
|
-
attributes.targetNodeId = target_node_id;
|
|
4335
|
-
}
|
|
4336
4414
|
const goalNode = {
|
|
4337
4415
|
id: nodeId,
|
|
4338
4416
|
name,
|
|
@@ -4397,6 +4475,8 @@ function registerFunnelBuilderTools(server2, builderClient) {
|
|
|
4397
4475
|
}
|
|
4398
4476
|
async function funnelRequest(method, path6, body) {
|
|
4399
4477
|
const headers = await client.buildHeaders();
|
|
4478
|
+
headers.Origin = "https://app.gohighlevel.com";
|
|
4479
|
+
headers.Referer = "https://app.gohighlevel.com/";
|
|
4400
4480
|
const url = `https://backend.leadconnectorhq.com/funnels${path6}`;
|
|
4401
4481
|
const options = { method, headers };
|
|
4402
4482
|
if (body && (method === "POST" || method === "PUT")) {
|
|
@@ -4502,21 +4582,92 @@ ${text2}`);
|
|
|
4502
4582
|
);
|
|
4503
4583
|
server2.tool(
|
|
4504
4584
|
"update_funnel",
|
|
4505
|
-
"Update a funnel's name,
|
|
4585
|
+
"Update a funnel's settings: name, path/slug, tracking codes, GDPR + payment + chat widget flags, etc. This is the 'save settings panel' endpoint \u2014 it sends the entire settings object, so the tool fetches current settings first, merges your overrides on top, then POSTs back. To rename a single step (page) inside a funnel, use update_funnel_step instead.",
|
|
4506
4586
|
{
|
|
4507
4587
|
funnelId: import_zod32.z.string().describe("The funnel ID to update."),
|
|
4508
|
-
name: import_zod32.z.string().optional().describe("New funnel name."),
|
|
4509
|
-
|
|
4588
|
+
name: import_zod32.z.string().optional().describe("New funnel display name."),
|
|
4589
|
+
path: import_zod32.z.string().optional().describe("URL slug for the funnel (e.g., '/my-funnel'). Mapped to funnelPath."),
|
|
4590
|
+
bodyTrackingCode: import_zod32.z.string().optional().describe("Custom tracking script injected before </body>."),
|
|
4591
|
+
headTrackingCode: import_zod32.z.string().optional().describe("Custom tracking script injected before </head>."),
|
|
4592
|
+
chatWidgetId: import_zod32.z.string().optional().describe("Chat widget to embed on every page in this funnel."),
|
|
4593
|
+
domainId: import_zod32.z.string().optional().describe("Custom domain ID for the funnel."),
|
|
4594
|
+
faviconUrl: import_zod32.z.string().optional().describe("Favicon URL for funnel pages."),
|
|
4595
|
+
paymentMode: import_zod32.z.boolean().optional().describe("Whether to require a payment mode for the funnel."),
|
|
4596
|
+
requireCreditCard: import_zod32.z.boolean().optional().describe("Whether to require a credit card on opt-in steps."),
|
|
4597
|
+
isGdprCompliant: import_zod32.z.boolean().optional().describe("Toggle GDPR compliance mode."),
|
|
4598
|
+
isOptimisePageLoad: import_zod32.z.boolean().optional().describe("Enable GHL's page-load optimization."),
|
|
4599
|
+
imageOptimization: import_zod32.z.boolean().optional().describe("Enable automatic image optimization."),
|
|
4600
|
+
allowPaymentModeOption: import_zod32.z.boolean().optional().describe("Allow buyers to choose payment mode on checkout."),
|
|
4601
|
+
storeCurrencyFormatting: import_zod32.z.boolean().optional().describe("Use store-wide currency formatting.")
|
|
4510
4602
|
},
|
|
4511
|
-
async (
|
|
4603
|
+
async (args) => {
|
|
4512
4604
|
try {
|
|
4513
|
-
const
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4605
|
+
const current = await funnelRequest("GET", `/funnel/list?locationId=${client.locationId}&limit=200`);
|
|
4606
|
+
const funnels = Array.isArray(current.funnels) ? current.funnels : [];
|
|
4607
|
+
const found = funnels.find((f) => f._id === args.funnelId || f.id === args.funnelId);
|
|
4608
|
+
if (!found) {
|
|
4609
|
+
throw new Error(`Funnel ${args.funnelId} not found in this location.`);
|
|
4610
|
+
}
|
|
4611
|
+
const overrides = {};
|
|
4612
|
+
if (args.name !== void 0) overrides.funnelName = args.name;
|
|
4613
|
+
if (args.path !== void 0) overrides.funnelPath = args.path;
|
|
4614
|
+
if (args.bodyTrackingCode !== void 0) overrides.bodyTrackingCode = args.bodyTrackingCode;
|
|
4615
|
+
if (args.headTrackingCode !== void 0) overrides.headTrackingCode = args.headTrackingCode;
|
|
4616
|
+
if (args.chatWidgetId !== void 0) overrides.chatWidgetId = args.chatWidgetId;
|
|
4617
|
+
if (args.domainId !== void 0) overrides.domainId = args.domainId;
|
|
4618
|
+
if (args.faviconUrl !== void 0) overrides.faviconUrl = args.faviconUrl;
|
|
4619
|
+
if (args.paymentMode !== void 0) overrides.paymentMode = args.paymentMode;
|
|
4620
|
+
if (args.requireCreditCard !== void 0) overrides.requireCreditCard = args.requireCreditCard;
|
|
4621
|
+
if (args.isGdprCompliant !== void 0) overrides.isGdprCompliant = args.isGdprCompliant;
|
|
4622
|
+
if (args.isOptimisePageLoad !== void 0) overrides.isOptimisePageLoad = args.isOptimisePageLoad;
|
|
4623
|
+
if (args.imageOptimization !== void 0) overrides.imageOptimization = args.imageOptimization;
|
|
4624
|
+
if (args.allowPaymentModeOption !== void 0) overrides.allowPaymentModeOption = args.allowPaymentModeOption;
|
|
4625
|
+
if (args.storeCurrencyFormatting !== void 0) overrides.storeCurrencyFormatting = args.storeCurrencyFormatting;
|
|
4626
|
+
const body = {
|
|
4627
|
+
locationId: client.locationId,
|
|
4628
|
+
funnelId: args.funnelId,
|
|
4629
|
+
funnelName: found.name ?? "",
|
|
4630
|
+
funnelPath: found.url ?? "/",
|
|
4631
|
+
allowPaymentModeOption: found.allowPaymentModeOption ?? true,
|
|
4632
|
+
bodyTrackingCode: found.bodyTrackingCode ?? "",
|
|
4633
|
+
chatWidgetId: found.chatWidgetId ?? "",
|
|
4634
|
+
domainId: found.domainId ?? "",
|
|
4635
|
+
faviconUrl: found.faviconUrl ?? "",
|
|
4636
|
+
headTrackingCode: found.headTrackingCode ?? "",
|
|
4637
|
+
imageOptimization: found.imageOptimization ?? true,
|
|
4638
|
+
isGdprCompliant: found.isGdprCompliant ?? false,
|
|
4639
|
+
isOptimisePageLoad: found.isOptimisePageLoad ?? true,
|
|
4640
|
+
paymentMode: found.paymentMode ?? true,
|
|
4641
|
+
requireCreditCard: found.requireCreditCard ?? true,
|
|
4642
|
+
stopAllSplitTestsAndReset: null,
|
|
4643
|
+
storeCurrencyFormatting: found.storeCurrencyFormatting ?? false,
|
|
4644
|
+
...overrides
|
|
4519
4645
|
};
|
|
4646
|
+
const result = await funnelRequest("POST", `/funnel/update-settings`, body);
|
|
4647
|
+
return jsonResponse(result);
|
|
4648
|
+
} catch (error) {
|
|
4649
|
+
return errorResponse(error);
|
|
4650
|
+
}
|
|
4651
|
+
}
|
|
4652
|
+
);
|
|
4653
|
+
server2.tool(
|
|
4654
|
+
"update_funnel_step",
|
|
4655
|
+
"Update a single step (page entry) inside a funnel \u2014 display name, URL slug, or attached domain. A step is GHL's container for one or more pages (multiple pages exist when split-testing). Use update_funnel for funnel-level settings instead.",
|
|
4656
|
+
{
|
|
4657
|
+
funnelId: import_zod32.z.string().describe("The funnel ID containing the step."),
|
|
4658
|
+
stepId: import_zod32.z.string().describe("The step ID to update (from get_funnel_pages / list_funnels_full)."),
|
|
4659
|
+
name: import_zod32.z.string().optional().describe("New step display name."),
|
|
4660
|
+
url: import_zod32.z.string().optional().describe("URL slug for the step (e.g., '/thank-you')."),
|
|
4661
|
+
domainName: import_zod32.z.string().optional().describe("Custom domain to attach to this step.")
|
|
4662
|
+
},
|
|
4663
|
+
async ({ funnelId, stepId, name, url, domainName }) => {
|
|
4664
|
+
try {
|
|
4665
|
+
const body = { stepId };
|
|
4666
|
+
if (name !== void 0) body.name = name;
|
|
4667
|
+
if (url !== void 0) body.url = url;
|
|
4668
|
+
if (domainName !== void 0) body.domainName = domainName;
|
|
4669
|
+
const result = await funnelRequest("PUT", `/funnel/step/${funnelId}`, body);
|
|
4670
|
+
return jsonResponse(result);
|
|
4520
4671
|
} catch (error) {
|
|
4521
4672
|
return errorResponse(error);
|
|
4522
4673
|
}
|
|
@@ -4524,17 +4675,19 @@ ${text2}`);
|
|
|
4524
4675
|
);
|
|
4525
4676
|
server2.tool(
|
|
4526
4677
|
"delete_funnel",
|
|
4527
|
-
"Permanently delete a funnel and all its pages. IRREVERSIBLE.",
|
|
4678
|
+
"Permanently delete a funnel and all its steps/pages. IRREVERSIBLE.",
|
|
4528
4679
|
{
|
|
4529
4680
|
funnelId: import_zod32.z.string().describe("The funnel ID to delete."),
|
|
4530
4681
|
confirm: import_zod32.z.literal("DELETE").describe("Must pass 'DELETE' to confirm this destructive action.")
|
|
4531
4682
|
},
|
|
4532
4683
|
async ({ funnelId }) => {
|
|
4533
4684
|
try {
|
|
4534
|
-
const result = await funnelRequest("
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4685
|
+
const result = await funnelRequest("POST", `/funnel/delete`, {
|
|
4686
|
+
funnelId,
|
|
4687
|
+
locationId: client.locationId,
|
|
4688
|
+
userId: client.getUserId()
|
|
4689
|
+
});
|
|
4690
|
+
return jsonResponse(result);
|
|
4538
4691
|
} catch (error) {
|
|
4539
4692
|
return errorResponse(error);
|
|
4540
4693
|
}
|
|
@@ -4542,23 +4695,30 @@ ${text2}`);
|
|
|
4542
4695
|
);
|
|
4543
4696
|
server2.tool(
|
|
4544
4697
|
"create_funnel_page",
|
|
4545
|
-
"Create a new page in a funnel.
|
|
4698
|
+
"Create a new step (page entry) in a funnel. The client generates a step UUID locally and sends it in the request; GHL auto-creates a blank page inside the step on the server side. The response includes the new step's id and the page's Firestore reference, which you can then update via update_page_content.",
|
|
4546
4699
|
{
|
|
4547
|
-
funnelId: import_zod32.z.string().describe("The funnel ID to add the
|
|
4548
|
-
name: import_zod32.z.string().describe("
|
|
4549
|
-
url: import_zod32.z.string().optional().describe("URL slug for the
|
|
4700
|
+
funnelId: import_zod32.z.string().describe("The funnel ID to add the step to."),
|
|
4701
|
+
name: import_zod32.z.string().describe("Step display name."),
|
|
4702
|
+
url: import_zod32.z.string().optional().describe("URL slug for the step. Defaults to '' (blank) like the GHL UI."),
|
|
4703
|
+
type: import_zod32.z.string().optional().describe("Step type. Defaults to 'optin_funnel_page'.")
|
|
4550
4704
|
},
|
|
4551
|
-
async ({ funnelId, name, url }) => {
|
|
4705
|
+
async ({ funnelId, name, url, type }) => {
|
|
4552
4706
|
try {
|
|
4553
|
-
const
|
|
4707
|
+
const stepId = crypto.randomUUID();
|
|
4708
|
+
const result = await funnelRequest("POST", `/funnel/create-step`, {
|
|
4554
4709
|
funnelId,
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4710
|
+
step: {
|
|
4711
|
+
id: stepId,
|
|
4712
|
+
name,
|
|
4713
|
+
url: url ?? "",
|
|
4714
|
+
pages: [],
|
|
4715
|
+
control_traffic: 100,
|
|
4716
|
+
split: false,
|
|
4717
|
+
type: type ?? "optin_funnel_page"
|
|
4718
|
+
}
|
|
4558
4719
|
});
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
};
|
|
4720
|
+
const merged = typeof result === "object" && result !== null ? { stepId, ...result } : { stepId, result };
|
|
4721
|
+
return jsonResponse(merged);
|
|
4562
4722
|
} catch (error) {
|
|
4563
4723
|
return errorResponse(error);
|
|
4564
4724
|
}
|
|
@@ -4566,20 +4726,22 @@ ${text2}`);
|
|
|
4566
4726
|
);
|
|
4567
4727
|
server2.tool(
|
|
4568
4728
|
"update_page_content",
|
|
4569
|
-
"Update a page's builder content \u2014 sections, elements,
|
|
4729
|
+
"Update a page's builder content \u2014 sections, elements, settings, pageStyles, trackingCode, popups, popupsList, fontsForPreview. Use get_page_content first to see the current structure, modify it, then pass the full 8-field envelope here. GHL's UI fires three POSTs to this endpoint per save (one collaborative-edit broadcast + two commits); for MCP use, one POST with write=true is enough.",
|
|
4570
4730
|
{
|
|
4571
4731
|
pageId: import_zod32.z.string().describe("The page ID to update."),
|
|
4572
|
-
content: import_zod32.z.record(import_zod32.z.unknown()).describe("The full page content JSON
|
|
4732
|
+
content: import_zod32.z.record(import_zod32.z.unknown()).describe("The full page content JSON. Expected fields: sections, settings, general, pageStyles, trackingCode, popups, popupsList, fontsForPreview."),
|
|
4733
|
+
isPublished: import_zod32.z.boolean().optional().describe("Whether the page should be marked published after the save. Defaults to false (draft).")
|
|
4573
4734
|
},
|
|
4574
|
-
async ({ pageId, content }) => {
|
|
4735
|
+
async ({ pageId, content, isPublished }) => {
|
|
4575
4736
|
try {
|
|
4576
|
-
const result = await funnelRequest("
|
|
4577
|
-
|
|
4578
|
-
|
|
4737
|
+
const result = await funnelRequest("POST", `/builder/prebuilt-section/sync/changes`, {
|
|
4738
|
+
locationId: client.locationId,
|
|
4739
|
+
pageId,
|
|
4740
|
+
pageData: content,
|
|
4741
|
+
write: true,
|
|
4742
|
+
isPublished: isPublished ?? false
|
|
4579
4743
|
});
|
|
4580
|
-
return
|
|
4581
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
4582
|
-
};
|
|
4744
|
+
return jsonResponse(result);
|
|
4583
4745
|
} catch (error) {
|
|
4584
4746
|
return errorResponse(error);
|
|
4585
4747
|
}
|
|
@@ -4587,17 +4749,16 @@ ${text2}`);
|
|
|
4587
4749
|
);
|
|
4588
4750
|
server2.tool(
|
|
4589
4751
|
"delete_funnel_page",
|
|
4590
|
-
"Permanently delete a
|
|
4752
|
+
"Permanently delete a step (and all its pages) from a funnel. IRREVERSIBLE. SIGNATURE CHANGED in v3.7.0: was pageId, now requires funnelId + stepId to match GHL's actual delete-step endpoint.",
|
|
4591
4753
|
{
|
|
4592
|
-
|
|
4754
|
+
funnelId: import_zod32.z.string().describe("The funnel ID containing the step."),
|
|
4755
|
+
stepId: import_zod32.z.string().describe("The step ID to delete (from get_funnel_pages / list_funnels_full)."),
|
|
4593
4756
|
confirm: import_zod32.z.literal("DELETE").describe("Must pass 'DELETE' to confirm this destructive action.")
|
|
4594
4757
|
},
|
|
4595
|
-
async ({
|
|
4758
|
+
async ({ funnelId, stepId }) => {
|
|
4596
4759
|
try {
|
|
4597
|
-
const result = await funnelRequest("
|
|
4598
|
-
return
|
|
4599
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
4600
|
-
};
|
|
4760
|
+
const result = await funnelRequest("POST", `/funnel/delete-step`, { funnelId, stepId });
|
|
4761
|
+
return jsonResponse(result);
|
|
4601
4762
|
} catch (error) {
|
|
4602
4763
|
return errorResponse(error);
|
|
4603
4764
|
}
|
|
@@ -6633,7 +6794,7 @@ async function validateFirebase(firebaseKey, refreshToken) {
|
|
|
6633
6794
|
function registerSetupTool(server2) {
|
|
6634
6795
|
server2.tool(
|
|
6635
6796
|
"setup_ghl_mcp",
|
|
6636
|
-
"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
|
|
6797
|
+
"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 178 tools (148 if you skip the optional Firebase fields; add Firebase later with enable_workflow_builder).",
|
|
6637
6798
|
{
|
|
6638
6799
|
email: import_zod42.z.string().email().describe("Email used at purchase."),
|
|
6639
6800
|
license_key: import_zod42.z.string().min(20).describe("License key from your purchase email."),
|
|
@@ -6688,7 +6849,7 @@ Note: Firebase credentials rejected (${fb.error}). Saved without Workflow Builde
|
|
|
6688
6849
|
ghl_firebase_api_key: workflowBuilderEnabled ? args.ghl_firebase_api_key?.trim() : void 0,
|
|
6689
6850
|
ghl_firebase_refresh_token: workflowBuilderEnabled ? args.ghl_firebase_refresh_token?.trim() : void 0
|
|
6690
6851
|
});
|
|
6691
|
-
const toolCount = workflowBuilderEnabled ? "
|
|
6852
|
+
const toolCount = workflowBuilderEnabled ? "178" : "148";
|
|
6692
6853
|
const wfLine = workflowBuilderEnabled ? "Workflow Builder: enabled." : "Workflow Builder: not configured (optional).";
|
|
6693
6854
|
const wfTip = workflowBuilderEnabled ? "" : "\nTo enable Workflow Builder later (8 extra tools): run enable_workflow_builder with your three Firebase values. No need to re-enter license/API key/location ID.";
|
|
6694
6855
|
return {
|
|
@@ -6716,7 +6877,7 @@ Note: Firebase credentials rejected (${fb.error}). Saved without Workflow Builde
|
|
|
6716
6877
|
function registerEnableWorkflowBuilderTool(server2) {
|
|
6717
6878
|
server2.tool(
|
|
6718
6879
|
"enable_workflow_builder",
|
|
6719
|
-
"Add Firebase credentials to an existing GHL Command install to unlock
|
|
6880
|
+
"Add Firebase credentials to an existing GHL Command install to unlock 30 additional tools across 6 modules: workflow builder (create/edit/clone/delete/publish/validate workflows, build_if_else_branch, build_goal_event, get_trigger_registry), funnel + page builder (10 tools), form builder (5 tools), pipeline builder (5 tools), and workflow cloning. Requires you've already run setup_ghl_mcp. Capture the three Firebase values from your GHL browser session \u2014 see elitedcs.com/ghl-mcp-firebase for step-by-step DevTools instructions. Tool count goes from 148 to 178 after the next Claude restart.",
|
|
6720
6881
|
{
|
|
6721
6882
|
ghl_user_id: import_zod42.z.string().min(10).describe("Firebase User ID (uid). DevTools \u2192 Application \u2192 IndexedDB \u2192 firebaseLocalStorageDb \u2192 firebaseLocalStorage \u2192 the value.uid field of the firebase:authUser row."),
|
|
6722
6883
|
ghl_firebase_api_key: import_zod42.z.string().min(10).describe("Firebase API Key starting with 'AIza'. The string between 'firebase:authUser:' and ':[DEFAULT]' in the row's Key column."),
|
|
@@ -6763,7 +6924,7 @@ DevTools steps: https://elitedcs.com/ghl-mcp-firebase`
|
|
|
6763
6924
|
"",
|
|
6764
6925
|
"Firebase credentials verified and saved.",
|
|
6765
6926
|
"",
|
|
6766
|
-
"**Restart Claude (quit fully and reopen) to load the
|
|
6927
|
+
"**Restart Claude (quit fully and reopen) to load the workflow builder + funnel builder + pipeline builder + form builder + workflow cloner tools (178 total).**",
|
|
6767
6928
|
"",
|
|
6768
6929
|
'After restart, try: "List my workflows in full detail" or "Validate workflow <id>".',
|
|
6769
6930
|
"",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elitedcs/ghl-mcp",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "GoHighLevel MCP Server for Claude.
|
|
3
|
+
"version": "3.8.0",
|
|
4
|
+
"description": "GoHighLevel MCP Server for Claude. 178 tools — full CRM, automation, marketing control, and the only programmatic GHL workflow builder.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"ghl-mcp": "dist/index.js"
|