@elitedcs/ghl-mcp 3.3.0 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/README.md +5 -4
- package/dist/index.js +305 -22
- package/package.json +3 -2
- package/templates/trigger-schemas.json +37854 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.3.1 — validate_workflow + catalogue in npm package
|
|
4
|
+
|
|
5
|
+
**174 tools across 37 modules. Bundle: 266.2 KB.**
|
|
6
|
+
|
|
7
|
+
Two small wins:
|
|
8
|
+
|
|
9
|
+
### `validate_workflow` tool (NEW)
|
|
10
|
+
Pre-flight ID validation for a deployed workflow. Scans every trigger and action for references to pipelines, pipeline stages, custom fields, users, and other workflows. Verifies each ID exists in the current location. Returns a structured report with `references_scanned`, `issues_count`, and a `findings[]` list naming exactly which action / trigger / field path holds an invalid reference.
|
|
11
|
+
|
|
12
|
+
This catches the silent-failure bug documented in CLAUDE.md: *"Invalid IDs silently kill all subsequent actions in a workflow."* GHL doesn't surface the error anywhere — actions just stop firing. Run `validate_workflow <workflowId>` after editing, or whenever a workflow stops behaving as expected.
|
|
13
|
+
|
|
14
|
+
Coverage in this release:
|
|
15
|
+
- Pipeline IDs (in `internal_update_opportunity` actions + trigger conditions)
|
|
16
|
+
- Pipeline Stage IDs (cross-checked against their parent pipeline's stage list)
|
|
17
|
+
- Custom Field IDs (in `update_contact_field` actions)
|
|
18
|
+
- User IDs (in `internal_notification.selectedUser`, `task_notification.assignedTo`, trigger conditions)
|
|
19
|
+
- Workflow IDs (in `remove_from_workflow` actions + trigger `add_to_workflow` actions)
|
|
20
|
+
|
|
21
|
+
Forms, calendars, and surveys are referenced in trigger conditions for specific trigger types (form_submission, customer_appointment, survey_submission) — those checks are deferred to a later release.
|
|
22
|
+
|
|
23
|
+
### `templates/trigger-schemas.json` now ships in the npm package
|
|
24
|
+
The 1.1 MB trigger catalogue (57 native + 434 marketplace trigger entries) was previously left out of the published package — buyers running `npx -y @elitedcs/ghl-mcp@latest` didn't receive it. Added to `package.json` `files[]` so installs always include it.
|
|
25
|
+
|
|
26
|
+
### Files changed
|
|
27
|
+
- `src/tools/validators.ts` — NEW: registerValidatorTools + validate_workflow.
|
|
28
|
+
- `src/tools/index.ts` — wired validators into the registry.
|
|
29
|
+
- `package.json` — added trigger-schemas.json to `files[]`; bumped version; tool count 173 → 174; description updated.
|
|
30
|
+
- README, CLAUDE.md, CHANGELOG — synced.
|
|
31
|
+
|
|
3
32
|
## 3.3.0 — 100% native trigger coverage
|
|
4
33
|
|
|
5
34
|
**173 tools across 36 modules. Bundle: 255.4 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.** 174 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 8 workflow builder tools use GHL'''s internal API and require Firebase credentials. Without them, the other 166 tools work fine — you just won'''t have workflow 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,7 +167,7 @@ Re-run setup_ghl_mcp with workflow builder:
|
|
|
167
167
|
|
|
168
168
|
---
|
|
169
169
|
|
|
170
|
-
## Tools (
|
|
170
|
+
## Tools (174)
|
|
171
171
|
|
|
172
172
|
### CRM & Contacts (15 tools)
|
|
173
173
|
|
|
@@ -332,7 +332,7 @@ Re-run setup_ghl_mcp with workflow builder:
|
|
|
332
332
|
| `get_subscriptions` | List active subscriptions |
|
|
333
333
|
| `get_transactions` | View transaction history |
|
|
334
334
|
|
|
335
|
-
### Workflow Builder (
|
|
335
|
+
### Workflow Builder (8 tools) — Internal API
|
|
336
336
|
|
|
337
337
|
> **This is the flagship feature.** GHL's public API has **zero** workflow write endpoints. These tools use GHL's internal backend API — the same API their own UI calls — reverse-engineered to give Claude full workflow CRUD. No other GHL integration, Zapier connector, or third-party tool can create or edit workflows programmatically. Requires additional Firebase auth setup (see "Enable Workflow Builder" in Quick Start above).
|
|
338
338
|
|
|
@@ -345,6 +345,7 @@ Re-run setup_ghl_mcp with workflow builder:
|
|
|
345
345
|
| `delete_workflow_full` | Permanently delete a workflow |
|
|
346
346
|
| `publish_workflow` | Publish a draft workflow to make it active |
|
|
347
347
|
| `get_trigger_registry` | Discover GHL's marketplace trigger apps (Zoom, WooCommerce, Shopify, etc.) and their available trigger templates |
|
|
348
|
+
| `validate_workflow` | Pre-flight validation: scans every action and trigger for references to pipelines, stages, custom fields, users, and other workflows; verifies each ID exists. Catches the silent-failure bug where invalid IDs make GHL skip subsequent actions |
|
|
348
349
|
|
|
349
350
|
**What you can build:** Complete automation sequences — lead nurture drip campaigns, appointment reminder sequences, onboarding flows, re-engagement workflows, internal notification chains. Tell Claude what you want and it builds the workflow action by action.
|
|
350
351
|
|
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.3.
|
|
35
|
-
description: "GoHighLevel MCP Server for Claude.
|
|
34
|
+
version: "3.3.1",
|
|
35
|
+
description: "GoHighLevel MCP Server for Claude. 174 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"
|
|
@@ -41,6 +41,7 @@ var require_package = __commonJS({
|
|
|
41
41
|
"dist/index.js",
|
|
42
42
|
"templates/action-schemas.json",
|
|
43
43
|
"templates/clinic-medspa.json",
|
|
44
|
+
"templates/trigger-schemas.json",
|
|
44
45
|
"README.md",
|
|
45
46
|
"CHANGELOG.md"
|
|
46
47
|
],
|
|
@@ -5930,6 +5931,287 @@ ${errors.join("\n")}` : "\nNo errors!",
|
|
|
5930
5931
|
);
|
|
5931
5932
|
}
|
|
5932
5933
|
|
|
5934
|
+
// src/tools/validators.ts
|
|
5935
|
+
var import_zod40 = require("zod");
|
|
5936
|
+
function extractFromTrigger(trigger, refs) {
|
|
5937
|
+
const triggerName = String(trigger.name ?? trigger.type ?? "unnamed trigger");
|
|
5938
|
+
const where = `trigger "${triggerName}"`;
|
|
5939
|
+
const conditions = Array.isArray(trigger.conditions) ? trigger.conditions : [];
|
|
5940
|
+
for (let i = 0; i < conditions.length; i++) {
|
|
5941
|
+
const c = conditions[i];
|
|
5942
|
+
const field = typeof c.field === "string" ? c.field : null;
|
|
5943
|
+
const value = c.value;
|
|
5944
|
+
if (!field || value === void 0 || value === null) continue;
|
|
5945
|
+
const valueAsArray = Array.isArray(value) ? value : [value];
|
|
5946
|
+
for (const v of valueAsArray) {
|
|
5947
|
+
if (typeof v !== "string") continue;
|
|
5948
|
+
const childWhere = `${where} \u2192 conditions[${i}] (field=${field})`;
|
|
5949
|
+
switch (field) {
|
|
5950
|
+
case "opportunity.pipelineId":
|
|
5951
|
+
refs.push({ kind: "pipeline", id: v, where: childWhere });
|
|
5952
|
+
break;
|
|
5953
|
+
case "opportunity.pipelineStageId":
|
|
5954
|
+
refs.push({ kind: "stage", id: v, where: childWhere });
|
|
5955
|
+
break;
|
|
5956
|
+
case "opportunity.assignedTo":
|
|
5957
|
+
case "contact.assignedTo":
|
|
5958
|
+
refs.push({ kind: "user", id: v, where: childWhere });
|
|
5959
|
+
break;
|
|
5960
|
+
case "workflow.id":
|
|
5961
|
+
refs.push({ kind: "workflow", id: v, where: childWhere });
|
|
5962
|
+
break;
|
|
5963
|
+
}
|
|
5964
|
+
}
|
|
5965
|
+
}
|
|
5966
|
+
const triggerActions = Array.isArray(trigger.actions) ? trigger.actions : [];
|
|
5967
|
+
for (let i = 0; i < triggerActions.length; i++) {
|
|
5968
|
+
const a = triggerActions[i];
|
|
5969
|
+
if (a.type === "add_to_workflow" && typeof a.workflow_id === "string") {
|
|
5970
|
+
refs.push({
|
|
5971
|
+
kind: "workflow",
|
|
5972
|
+
id: a.workflow_id,
|
|
5973
|
+
where: `${where} \u2192 actions[${i}] (add_to_workflow)`
|
|
5974
|
+
});
|
|
5975
|
+
}
|
|
5976
|
+
}
|
|
5977
|
+
}
|
|
5978
|
+
function extractFromAction(action, refs) {
|
|
5979
|
+
const type = typeof action.type === "string" ? action.type : "unknown";
|
|
5980
|
+
const name = typeof action.name === "string" ? action.name : "unnamed action";
|
|
5981
|
+
const where = `action "${name}" (${type})`;
|
|
5982
|
+
const attr = action.attributes ?? {};
|
|
5983
|
+
switch (type) {
|
|
5984
|
+
case "update_contact_field": {
|
|
5985
|
+
const fields = Array.isArray(attr.fields) ? attr.fields : [];
|
|
5986
|
+
for (let i = 0; i < fields.length; i++) {
|
|
5987
|
+
const f = fields[i];
|
|
5988
|
+
if (typeof f.field === "string") {
|
|
5989
|
+
refs.push({
|
|
5990
|
+
kind: "custom_field",
|
|
5991
|
+
id: f.field,
|
|
5992
|
+
where: `${where} \u2192 fields[${i}]`
|
|
5993
|
+
});
|
|
5994
|
+
}
|
|
5995
|
+
}
|
|
5996
|
+
break;
|
|
5997
|
+
}
|
|
5998
|
+
case "internal_notification": {
|
|
5999
|
+
const notif = attr.notification ?? {};
|
|
6000
|
+
if (typeof notif.selectedUser === "string" && notif.selectedUser.trim() !== "") {
|
|
6001
|
+
refs.push({
|
|
6002
|
+
kind: "user",
|
|
6003
|
+
id: notif.selectedUser,
|
|
6004
|
+
where: `${where} \u2192 notification.selectedUser`
|
|
6005
|
+
});
|
|
6006
|
+
}
|
|
6007
|
+
break;
|
|
6008
|
+
}
|
|
6009
|
+
case "task_notification": {
|
|
6010
|
+
if (typeof attr.assignedTo === "string" && attr.assignedTo.trim() !== "") {
|
|
6011
|
+
refs.push({
|
|
6012
|
+
kind: "user",
|
|
6013
|
+
id: attr.assignedTo,
|
|
6014
|
+
where: `${where} \u2192 assignedTo`
|
|
6015
|
+
});
|
|
6016
|
+
}
|
|
6017
|
+
break;
|
|
6018
|
+
}
|
|
6019
|
+
case "remove_from_workflow": {
|
|
6020
|
+
if (typeof attr.workflowId === "string") {
|
|
6021
|
+
refs.push({
|
|
6022
|
+
kind: "workflow",
|
|
6023
|
+
id: attr.workflowId,
|
|
6024
|
+
where: `${where} \u2192 workflowId`
|
|
6025
|
+
});
|
|
6026
|
+
}
|
|
6027
|
+
const workflowIdArr = Array.isArray(attr.workflow_id) ? attr.workflow_id : [];
|
|
6028
|
+
for (let i = 0; i < workflowIdArr.length; i++) {
|
|
6029
|
+
const v = workflowIdArr[i];
|
|
6030
|
+
if (typeof v === "string") {
|
|
6031
|
+
refs.push({
|
|
6032
|
+
kind: "workflow",
|
|
6033
|
+
id: v,
|
|
6034
|
+
where: `${where} \u2192 workflow_id[${i}]`
|
|
6035
|
+
});
|
|
6036
|
+
}
|
|
6037
|
+
}
|
|
6038
|
+
break;
|
|
6039
|
+
}
|
|
6040
|
+
case "internal_update_opportunity": {
|
|
6041
|
+
const customInputs = Array.isArray(attr.__customInputFields__) ? attr.__customInputFields__ : [];
|
|
6042
|
+
for (let i = 0; i < customInputs.length; i++) {
|
|
6043
|
+
const c = customInputs[i];
|
|
6044
|
+
if (typeof c.value !== "string") continue;
|
|
6045
|
+
if (c.filterField === "pipelineId") {
|
|
6046
|
+
refs.push({ kind: "pipeline", id: c.value, where: `${where} \u2192 __customInputFields__[${i}].pipelineId` });
|
|
6047
|
+
} else if (c.filterField === "pipelineStageId") {
|
|
6048
|
+
refs.push({ kind: "stage", id: c.value, where: `${where} \u2192 __customInputFields__[${i}].pipelineStageId` });
|
|
6049
|
+
}
|
|
6050
|
+
}
|
|
6051
|
+
break;
|
|
6052
|
+
}
|
|
6053
|
+
}
|
|
6054
|
+
}
|
|
6055
|
+
function registerValidatorTools(server2, client, builderClient) {
|
|
6056
|
+
if (!builderClient) return;
|
|
6057
|
+
server2.tool(
|
|
6058
|
+
"validate_workflow",
|
|
6059
|
+
"Pre-flight ID validation for a deployed GHL workflow. Scans every trigger and action for references to pipelines, pipeline stages, custom fields, users, and other workflows; verifies each ID exists in the current location. Use this BEFORE publish_workflow when a workflow has been edited, or whenever a published workflow stops behaving as expected. Catches the silent-failure bug where invalid IDs make GHL skip all subsequent actions without warning. Returns a structured report of valid + missing references.",
|
|
6060
|
+
{
|
|
6061
|
+
workflowId: import_zod40.z.string().describe("The workflow ID to validate.")
|
|
6062
|
+
},
|
|
6063
|
+
async ({ workflowId }) => {
|
|
6064
|
+
try {
|
|
6065
|
+
const workflow = await builderClient.getWorkflow(workflowId);
|
|
6066
|
+
if (!workflow) return errorResponse(new Error(`Workflow ${workflowId} not found`));
|
|
6067
|
+
const refs = [];
|
|
6068
|
+
const triggers = Array.isArray(workflow.triggers) ? workflow.triggers : [];
|
|
6069
|
+
for (const t of triggers) {
|
|
6070
|
+
extractFromTrigger(t, refs);
|
|
6071
|
+
}
|
|
6072
|
+
const actions = workflow.workflowData?.templates ?? [];
|
|
6073
|
+
for (const a of actions) {
|
|
6074
|
+
extractFromAction(a, refs);
|
|
6075
|
+
}
|
|
6076
|
+
if (refs.length === 0) {
|
|
6077
|
+
const empty = {
|
|
6078
|
+
workflowId,
|
|
6079
|
+
workflowName: workflow.name,
|
|
6080
|
+
status: "ok",
|
|
6081
|
+
references_scanned: 0,
|
|
6082
|
+
issues_count: 0,
|
|
6083
|
+
findings: []
|
|
6084
|
+
};
|
|
6085
|
+
return jsonResponse(empty);
|
|
6086
|
+
}
|
|
6087
|
+
const refCategories = new Set(refs.map((r) => r.kind));
|
|
6088
|
+
const locationId2 = client.defaultLocationId;
|
|
6089
|
+
const fetches = {};
|
|
6090
|
+
if (refCategories.has("pipeline") || refCategories.has("stage")) {
|
|
6091
|
+
fetches.pipelines = client.get("/opportunities/pipelines", { params: { locationId: locationId2 } });
|
|
6092
|
+
}
|
|
6093
|
+
if (refCategories.has("custom_field")) {
|
|
6094
|
+
fetches.customFields = client.get(`/locations/${locationId2}/customFields`);
|
|
6095
|
+
}
|
|
6096
|
+
if (refCategories.has("user")) {
|
|
6097
|
+
fetches.users = client.get("/users/", { params: { locationId: locationId2 } });
|
|
6098
|
+
}
|
|
6099
|
+
if (refCategories.has("workflow")) {
|
|
6100
|
+
fetches.workflows = builderClient.listWorkflowsFull();
|
|
6101
|
+
}
|
|
6102
|
+
const results = await Promise.allSettled(Object.values(fetches));
|
|
6103
|
+
const keys = Object.keys(fetches);
|
|
6104
|
+
const data = {};
|
|
6105
|
+
for (let i = 0; i < keys.length; i++) {
|
|
6106
|
+
const r = results[i];
|
|
6107
|
+
data[keys[i]] = r.status === "fulfilled" ? r.value : null;
|
|
6108
|
+
}
|
|
6109
|
+
const validPipelineIds = /* @__PURE__ */ new Set();
|
|
6110
|
+
const validStageIds = /* @__PURE__ */ new Set();
|
|
6111
|
+
const stageToPipeline = /* @__PURE__ */ new Map();
|
|
6112
|
+
if (data.pipelines) {
|
|
6113
|
+
try {
|
|
6114
|
+
const parsed = PipelinesResponseSchema.parse(data.pipelines);
|
|
6115
|
+
for (const p of parsed.pipelines) {
|
|
6116
|
+
validPipelineIds.add(p.id);
|
|
6117
|
+
for (const s of p.stages) {
|
|
6118
|
+
validStageIds.add(s.id);
|
|
6119
|
+
stageToPipeline.set(s.id, p.id);
|
|
6120
|
+
}
|
|
6121
|
+
}
|
|
6122
|
+
} catch {
|
|
6123
|
+
}
|
|
6124
|
+
}
|
|
6125
|
+
const validCustomFieldIds = /* @__PURE__ */ new Set();
|
|
6126
|
+
if (data.customFields && typeof data.customFields === "object") {
|
|
6127
|
+
const cf = data.customFields;
|
|
6128
|
+
const arr = Array.isArray(cf.customFields) ? cf.customFields : Array.isArray(cf) ? cf : [];
|
|
6129
|
+
for (const f of arr) {
|
|
6130
|
+
if (typeof f === "object" && f !== null && typeof f.id === "string") {
|
|
6131
|
+
validCustomFieldIds.add(f.id);
|
|
6132
|
+
}
|
|
6133
|
+
}
|
|
6134
|
+
}
|
|
6135
|
+
const validUserIds = /* @__PURE__ */ new Set();
|
|
6136
|
+
if (data.users && typeof data.users === "object") {
|
|
6137
|
+
const u = data.users;
|
|
6138
|
+
const arr = Array.isArray(u.users) ? u.users : Array.isArray(u) ? u : [];
|
|
6139
|
+
for (const user of arr) {
|
|
6140
|
+
if (typeof user === "object" && user !== null && typeof user.id === "string") {
|
|
6141
|
+
validUserIds.add(user.id);
|
|
6142
|
+
}
|
|
6143
|
+
}
|
|
6144
|
+
}
|
|
6145
|
+
const validWorkflowIds = /* @__PURE__ */ new Set();
|
|
6146
|
+
if (data.workflows && typeof data.workflows === "object") {
|
|
6147
|
+
const w = data.workflows;
|
|
6148
|
+
const arr = Array.isArray(w.rows) ? w.rows : Array.isArray(w.workflows) ? w.workflows : Array.isArray(w) ? w : [];
|
|
6149
|
+
for (const wf of arr) {
|
|
6150
|
+
if (typeof wf === "object" && wf !== null) {
|
|
6151
|
+
const o = wf;
|
|
6152
|
+
const id = typeof o._id === "string" ? o._id : typeof o.id === "string" ? o.id : null;
|
|
6153
|
+
if (id) validWorkflowIds.add(id);
|
|
6154
|
+
}
|
|
6155
|
+
}
|
|
6156
|
+
}
|
|
6157
|
+
const findings = [];
|
|
6158
|
+
for (const ref of refs) {
|
|
6159
|
+
let valid = false;
|
|
6160
|
+
let extraMsg = "";
|
|
6161
|
+
switch (ref.kind) {
|
|
6162
|
+
case "pipeline":
|
|
6163
|
+
valid = validPipelineIds.has(ref.id);
|
|
6164
|
+
break;
|
|
6165
|
+
case "stage":
|
|
6166
|
+
valid = validStageIds.has(ref.id);
|
|
6167
|
+
break;
|
|
6168
|
+
case "custom_field":
|
|
6169
|
+
valid = validCustomFieldIds.has(ref.id);
|
|
6170
|
+
break;
|
|
6171
|
+
case "user":
|
|
6172
|
+
valid = validUserIds.has(ref.id);
|
|
6173
|
+
break;
|
|
6174
|
+
case "workflow":
|
|
6175
|
+
valid = validWorkflowIds.has(ref.id);
|
|
6176
|
+
if (valid && ref.id === workflowId) {
|
|
6177
|
+
extraMsg = " (self-reference)";
|
|
6178
|
+
}
|
|
6179
|
+
break;
|
|
6180
|
+
}
|
|
6181
|
+
if (!valid) {
|
|
6182
|
+
findings.push({
|
|
6183
|
+
severity: "error",
|
|
6184
|
+
category: ref.kind,
|
|
6185
|
+
id: ref.id,
|
|
6186
|
+
where: ref.where,
|
|
6187
|
+
message: `${ref.kind} id "${ref.id}" does not exist in this location \u2014 GHL will silently skip this action and all subsequent actions when the workflow runs.`
|
|
6188
|
+
});
|
|
6189
|
+
} else if (extraMsg) {
|
|
6190
|
+
findings.push({
|
|
6191
|
+
severity: "warning",
|
|
6192
|
+
category: ref.kind,
|
|
6193
|
+
id: ref.id,
|
|
6194
|
+
where: ref.where,
|
|
6195
|
+
message: `${ref.kind} id "${ref.id}" is valid${extraMsg}.`
|
|
6196
|
+
});
|
|
6197
|
+
}
|
|
6198
|
+
}
|
|
6199
|
+
const report = {
|
|
6200
|
+
workflowId,
|
|
6201
|
+
workflowName: workflow.name,
|
|
6202
|
+
status: findings.some((f) => f.severity === "error") ? "issues_found" : "ok",
|
|
6203
|
+
references_scanned: refs.length,
|
|
6204
|
+
issues_count: findings.filter((f) => f.severity === "error").length,
|
|
6205
|
+
findings
|
|
6206
|
+
};
|
|
6207
|
+
return jsonResponse(report);
|
|
6208
|
+
} catch (error) {
|
|
6209
|
+
return errorResponse(error);
|
|
6210
|
+
}
|
|
6211
|
+
}
|
|
6212
|
+
);
|
|
6213
|
+
}
|
|
6214
|
+
|
|
5933
6215
|
// src/tools/index.ts
|
|
5934
6216
|
var publicApiTools = [
|
|
5935
6217
|
[registerContactTools, "contacts"],
|
|
@@ -5972,6 +6254,7 @@ function registerAllTools(server2, client, registry2, mcpVersion) {
|
|
|
5972
6254
|
registerFormBuilderTools(server2, builderClient);
|
|
5973
6255
|
registerPipelineBuilderTools(server2, builderClient);
|
|
5974
6256
|
registerWorkflowClonerTools(server2, builderClient);
|
|
6257
|
+
registerValidatorTools(server2, client, builderClient);
|
|
5975
6258
|
registerLocationSwitcherTools(server2, client, builderClient, registry2, mcpVersion);
|
|
5976
6259
|
}
|
|
5977
6260
|
|
|
@@ -5979,18 +6262,18 @@ function registerAllTools(server2, client, registry2, mcpVersion) {
|
|
|
5979
6262
|
var fs4 = __toESM(require("fs"));
|
|
5980
6263
|
var path4 = __toESM(require("path"));
|
|
5981
6264
|
var os = __toESM(require("os"));
|
|
5982
|
-
var
|
|
6265
|
+
var import_zod41 = require("zod");
|
|
5983
6266
|
var APP_NAME = "elitedcs-ghl-mcp";
|
|
5984
|
-
var CredentialsSchema =
|
|
5985
|
-
license_key:
|
|
5986
|
-
email:
|
|
5987
|
-
verified_at:
|
|
5988
|
-
ghl_api_key:
|
|
5989
|
-
ghl_location_id:
|
|
5990
|
-
ghl_company_id:
|
|
5991
|
-
ghl_user_id:
|
|
5992
|
-
ghl_firebase_api_key:
|
|
5993
|
-
ghl_firebase_refresh_token:
|
|
6267
|
+
var CredentialsSchema = import_zod41.z.object({
|
|
6268
|
+
license_key: import_zod41.z.string().min(1),
|
|
6269
|
+
email: import_zod41.z.string().email(),
|
|
6270
|
+
verified_at: import_zod41.z.string().min(1),
|
|
6271
|
+
ghl_api_key: import_zod41.z.string().min(1),
|
|
6272
|
+
ghl_location_id: import_zod41.z.string().min(1),
|
|
6273
|
+
ghl_company_id: import_zod41.z.string().optional(),
|
|
6274
|
+
ghl_user_id: import_zod41.z.string().optional(),
|
|
6275
|
+
ghl_firebase_api_key: import_zod41.z.string().optional(),
|
|
6276
|
+
ghl_firebase_refresh_token: import_zod41.z.string().optional()
|
|
5994
6277
|
});
|
|
5995
6278
|
function appDataDir() {
|
|
5996
6279
|
const home = os.homedir();
|
|
@@ -6040,7 +6323,7 @@ function writeCredentials(creds) {
|
|
|
6040
6323
|
// src/setup-tool.ts
|
|
6041
6324
|
var os2 = __toESM(require("os"));
|
|
6042
6325
|
var crypto3 = __toESM(require("crypto"));
|
|
6043
|
-
var
|
|
6326
|
+
var import_zod42 = require("zod");
|
|
6044
6327
|
var LICENSE_API = "https://elitedcs.com/api/validate-license";
|
|
6045
6328
|
var GHL_API = "https://services.leadconnectorhq.com";
|
|
6046
6329
|
var FIREBASE_TOKEN_API = "https://securetoken.googleapis.com/v1/token";
|
|
@@ -6111,14 +6394,14 @@ function registerSetupTool(server2) {
|
|
|
6111
6394
|
"setup_ghl_mcp",
|
|
6112
6395
|
"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 171 tools.",
|
|
6113
6396
|
{
|
|
6114
|
-
email:
|
|
6115
|
-
license_key:
|
|
6116
|
-
ghl_api_key:
|
|
6117
|
-
ghl_location_id:
|
|
6118
|
-
ghl_company_id:
|
|
6119
|
-
ghl_user_id:
|
|
6120
|
-
ghl_firebase_api_key:
|
|
6121
|
-
ghl_firebase_refresh_token:
|
|
6397
|
+
email: import_zod42.z.string().email().describe("Email used at purchase."),
|
|
6398
|
+
license_key: import_zod42.z.string().min(20).describe("License key from your purchase email."),
|
|
6399
|
+
ghl_api_key: import_zod42.z.string().min(10).describe("GHL Private Integration key (starts with 'pit-'). Created INSIDE the sub-account at Settings > Integrations > Private Integrations."),
|
|
6400
|
+
ghl_location_id: import_zod42.z.string().min(10).describe("GHL Location ID (sub-account ID). Found in your GHL URL: /location/THIS_PART/dashboard."),
|
|
6401
|
+
ghl_company_id: import_zod42.z.string().optional().describe("(Agency only) Company ID for multi-location access."),
|
|
6402
|
+
ghl_user_id: import_zod42.z.string().optional().describe("(Workflow Builder, optional) Firebase User ID. See README for browser capture instructions."),
|
|
6403
|
+
ghl_firebase_api_key: import_zod42.z.string().optional().describe("(Workflow Builder, optional) Firebase API Key starting with 'AIza'."),
|
|
6404
|
+
ghl_firebase_refresh_token: import_zod42.z.string().optional().describe("(Workflow Builder, optional) Firebase refresh token starting with 'AMf-'.")
|
|
6122
6405
|
},
|
|
6123
6406
|
async (args) => {
|
|
6124
6407
|
const lic = await validateLicense(args.email, args.license_key);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elitedcs/ghl-mcp",
|
|
3
|
-
"version": "3.3.
|
|
4
|
-
"description": "GoHighLevel MCP Server for Claude.
|
|
3
|
+
"version": "3.3.1",
|
|
4
|
+
"description": "GoHighLevel MCP Server for Claude. 174 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"
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"dist/index.js",
|
|
11
11
|
"templates/action-schemas.json",
|
|
12
12
|
"templates/clinic-medspa.json",
|
|
13
|
+
"templates/trigger-schemas.json",
|
|
13
14
|
"README.md",
|
|
14
15
|
"CHANGELOG.md"
|
|
15
16
|
],
|