@elitedcs/ghl-mcp 3.41.0 → 3.42.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/dist/index.js +181 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ var require_package = __commonJS({
|
|
|
31
31
|
"package.json"(exports2, module2) {
|
|
32
32
|
module2.exports = {
|
|
33
33
|
name: "@elitedcs/ghl-mcp",
|
|
34
|
-
version: "3.
|
|
34
|
+
version: "3.42.0",
|
|
35
35
|
mcpName: "io.github.drjerryrelth/ghl-command",
|
|
36
36
|
description: "GoHighLevel MCP Server for Claude. 218 tools \u2014 full CRM, automation, marketing control, account-wide workflow audit, and the only programmatic GHL workflow builder, now multi-tenant across client accounts.",
|
|
37
37
|
main: "dist/index.js",
|
|
@@ -11089,7 +11089,9 @@ function buildRefIndex(plan) {
|
|
|
11089
11089
|
sms: /* @__PURE__ */ new Map(),
|
|
11090
11090
|
workflowName: /* @__PURE__ */ new Map(),
|
|
11091
11091
|
pipelineName: /* @__PURE__ */ new Map(),
|
|
11092
|
-
stageName: /* @__PURE__ */ new Map()
|
|
11092
|
+
stageName: /* @__PURE__ */ new Map(),
|
|
11093
|
+
formName: /* @__PURE__ */ new Map(),
|
|
11094
|
+
calendarName: /* @__PURE__ */ new Map()
|
|
11093
11095
|
};
|
|
11094
11096
|
for (const t of plan.tags ?? []) idx.tagName.set(t.ref, t.name);
|
|
11095
11097
|
for (const f of plan.customFields ?? []) {
|
|
@@ -11103,6 +11105,8 @@ function buildRefIndex(plan) {
|
|
|
11103
11105
|
idx.pipelineName.set(p.ref, p.name);
|
|
11104
11106
|
for (const st of p.stages) idx.stageName.set(st.ref, st.name);
|
|
11105
11107
|
}
|
|
11108
|
+
for (const fm of plan.forms ?? []) idx.formName.set(fm.ref, fm.name);
|
|
11109
|
+
for (const c of plan.calendars ?? []) idx.calendarName.set(c.ref, c.name);
|
|
11106
11110
|
return idx;
|
|
11107
11111
|
}
|
|
11108
11112
|
function htmlWrap(text) {
|
|
@@ -11284,13 +11288,31 @@ function expandAction(action, idx, idMap) {
|
|
|
11284
11288
|
}
|
|
11285
11289
|
case "create_opportunity":
|
|
11286
11290
|
case "update_opportunity": {
|
|
11291
|
+
const pipelineId = resolveId(action.pipelineRef, idMap);
|
|
11292
|
+
const stageId = resolveId(action.stageRef, idMap);
|
|
11293
|
+
const pendingRefs = [];
|
|
11294
|
+
if (isPending(pipelineId)) pendingRefs.push(action.pipelineRef);
|
|
11295
|
+
if (isPending(stageId)) pendingRefs.push(action.stageRef);
|
|
11287
11296
|
const pName = idx.pipelineName.get(action.pipelineRef) ?? action.pipelineRef;
|
|
11288
11297
|
const sName = idx.stageName.get(action.stageRef) ?? action.stageRef;
|
|
11289
|
-
const verb = action.type === "create_opportunity" ? "Create" : "Move";
|
|
11298
|
+
const verb = action.type === "create_opportunity" ? "Create opportunity" : "Move opportunity";
|
|
11290
11299
|
return {
|
|
11291
|
-
kind: "
|
|
11292
|
-
|
|
11293
|
-
|
|
11300
|
+
kind: "expanded",
|
|
11301
|
+
pendingRefs,
|
|
11302
|
+
native: {
|
|
11303
|
+
type: "internal_update_opportunity",
|
|
11304
|
+
name: `${verb}: ${pName} / ${sName}`,
|
|
11305
|
+
// NODE-level discriminator (the normalizer also forces this; included so
|
|
11306
|
+
// the expanded action is correct even outside the save path).
|
|
11307
|
+
workflowsActionType: "INTERNAL",
|
|
11308
|
+
attributes: {
|
|
11309
|
+
type: "internal_update_opportunity",
|
|
11310
|
+
__customInputFields__: [
|
|
11311
|
+
{ filterField: "pipelineId", value: pipelineId, valueFieldType: "select", dataType: "SINGLE_OPTIONS" },
|
|
11312
|
+
{ filterField: "pipelineStageId", value: stageId, valueFieldType: "select", dataType: "SINGLE_OPTIONS" }
|
|
11313
|
+
]
|
|
11314
|
+
}
|
|
11315
|
+
}
|
|
11294
11316
|
};
|
|
11295
11317
|
}
|
|
11296
11318
|
case "goal_event": {
|
|
@@ -11316,6 +11338,42 @@ function expandAction(action, idx, idMap) {
|
|
|
11316
11338
|
}
|
|
11317
11339
|
}
|
|
11318
11340
|
var MAX_ACTIONS_PER_WORKFLOW = 40;
|
|
11341
|
+
function triggerPlainEnglish(trigger, idx) {
|
|
11342
|
+
const formName = trigger.formRef ? idx.formName.get(trigger.formRef) ?? trigger.formRef : "?";
|
|
11343
|
+
const stageName = trigger.stageRef ? idx.stageName.get(trigger.stageRef) ?? trigger.stageRef : "?";
|
|
11344
|
+
const calName = trigger.calendarRef ? idx.calendarName.get(trigger.calendarRef) ?? trigger.calendarRef : "?";
|
|
11345
|
+
switch (trigger.type) {
|
|
11346
|
+
case "form_submission":
|
|
11347
|
+
case "form_submitted":
|
|
11348
|
+
return `when form "${formName}" is submitted`;
|
|
11349
|
+
case "pipeline_stage_updated":
|
|
11350
|
+
return `when an opportunity reaches stage "${stageName}"`;
|
|
11351
|
+
case "appointment":
|
|
11352
|
+
return `on an appointment event${trigger.calendarRef ? ` for calendar "${calName}"` : ""}`;
|
|
11353
|
+
case "customer_reply":
|
|
11354
|
+
return "when a contact replies";
|
|
11355
|
+
default:
|
|
11356
|
+
return `trigger type "${trigger.type}"`;
|
|
11357
|
+
}
|
|
11358
|
+
}
|
|
11359
|
+
function expandTrigger(trigger, idx) {
|
|
11360
|
+
if (trigger.type === "contact_tag") {
|
|
11361
|
+
if (!trigger.tagRef) return { kind: "manual", reason: "Set this workflow's contact-tag trigger in the GHL UI (the plan trigger has no tag)." };
|
|
11362
|
+
const tagName = idx.tagName.get(trigger.tagRef) ?? trigger.tagRef;
|
|
11363
|
+
return {
|
|
11364
|
+
kind: "native",
|
|
11365
|
+
trigger: {
|
|
11366
|
+
name: "Contact Tag",
|
|
11367
|
+
type: "contact_tag",
|
|
11368
|
+
conditions: [{ operator: "index-of-true", field: "tagsAdded", value: tagName, title: "Tag Added", type: "select", id: "tag-added" }]
|
|
11369
|
+
}
|
|
11370
|
+
};
|
|
11371
|
+
}
|
|
11372
|
+
return {
|
|
11373
|
+
kind: "manual",
|
|
11374
|
+
reason: `Set this workflow's trigger in the GHL UI: ${triggerPlainEnglish(trigger, idx)}, then publish. (Blueprint builds the workflow + all its steps as DRAFT; only this trigger type isn't auto-built yet.)`
|
|
11375
|
+
};
|
|
11376
|
+
}
|
|
11319
11377
|
function expandWorkflow(workflow, idx, idMap, gatedBy) {
|
|
11320
11378
|
const nativeActions = [];
|
|
11321
11379
|
const manual = [];
|
|
@@ -11333,6 +11391,13 @@ function expandWorkflow(workflow, idx, idMap, gatedBy) {
|
|
|
11333
11391
|
}
|
|
11334
11392
|
});
|
|
11335
11393
|
const splitInto = Math.max(1, Math.ceil(nativeActions.length / MAX_ACTIONS_PER_WORKFLOW));
|
|
11394
|
+
let nativeTrigger;
|
|
11395
|
+
let triggerManual;
|
|
11396
|
+
if (workflow.trigger) {
|
|
11397
|
+
const t = expandTrigger(workflow.trigger, idx);
|
|
11398
|
+
if (t.kind === "native") nativeTrigger = t.trigger;
|
|
11399
|
+
else triggerManual = t.reason;
|
|
11400
|
+
}
|
|
11336
11401
|
return {
|
|
11337
11402
|
ref: workflow.ref,
|
|
11338
11403
|
name: workflow.name,
|
|
@@ -11341,7 +11406,9 @@ function expandWorkflow(workflow, idx, idMap, gatedBy) {
|
|
|
11341
11406
|
needsContent,
|
|
11342
11407
|
pendingRefs: [...pendingRefs],
|
|
11343
11408
|
splitInto,
|
|
11344
|
-
gatedBy
|
|
11409
|
+
gatedBy,
|
|
11410
|
+
nativeTrigger,
|
|
11411
|
+
triggerManual
|
|
11345
11412
|
};
|
|
11346
11413
|
}
|
|
11347
11414
|
function scanSection(section2, planObjects, existing) {
|
|
@@ -11494,6 +11561,10 @@ function renderReport(plan, result, ctx) {
|
|
|
11494
11561
|
L.push(` \u2022 [funnel] Design + populate the pages of funnel "${fn.name}" (Blueprint builds the funnel + steps; page content/design is manual).`);
|
|
11495
11562
|
}
|
|
11496
11563
|
for (const w of result.workflows) {
|
|
11564
|
+
if (w.triggerManual) {
|
|
11565
|
+
any = true;
|
|
11566
|
+
L.push(` \u2022 [${w.name}] ${w.triggerManual}`);
|
|
11567
|
+
}
|
|
11497
11568
|
for (const m of w.manual) {
|
|
11498
11569
|
any = true;
|
|
11499
11570
|
L.push(` \u2022 [${w.name}] ${m.reason}`);
|
|
@@ -11805,6 +11876,73 @@ async function executeBackbone(plan, deps, opts = {}) {
|
|
|
11805
11876
|
}
|
|
11806
11877
|
manual.push({ ref: fn.ref, type: "funnel-page-content", name: fn.name, reason: funnelContentReason(fn) });
|
|
11807
11878
|
}
|
|
11879
|
+
const wfIndex = buildRefIndex(plan);
|
|
11880
|
+
const wfIdMap = new Map(Object.entries(idMap));
|
|
11881
|
+
for (const wf of plan.workflows ?? []) {
|
|
11882
|
+
let workflows;
|
|
11883
|
+
try {
|
|
11884
|
+
workflows = await deps.listWorkflows();
|
|
11885
|
+
} catch (e) {
|
|
11886
|
+
return halt(wf.ref, "workflow", `could not read existing workflows: ${msg(e)}`);
|
|
11887
|
+
}
|
|
11888
|
+
const matches = workflows.filter((w) => norm2(w.name) === norm2(wf.name));
|
|
11889
|
+
if (matches.length > 1) {
|
|
11890
|
+
return halt(wf.ref, "workflow", `${matches.length} existing workflows are named "${wf.name}" \u2014 ambiguous, cannot safely bind ${wf.ref}. Resolve the duplicate in GHL, then re-run.`);
|
|
11891
|
+
}
|
|
11892
|
+
const expansion = expandWorkflow(wf, wfIndex, wfIdMap, []);
|
|
11893
|
+
if (expansion.pendingRefs.length) {
|
|
11894
|
+
return halt(wf.ref, "workflow", `workflow "${wf.name}" references objects that weren't built/resolved: ${expansion.pendingRefs.join(", ")}. Cannot build it.`);
|
|
11895
|
+
}
|
|
11896
|
+
if (matches.length === 1) {
|
|
11897
|
+
const exId = matches[0].id;
|
|
11898
|
+
if (expansion.nativeActions.length > 0) {
|
|
11899
|
+
let existingCount = -1;
|
|
11900
|
+
try {
|
|
11901
|
+
existingCount = await deps.getWorkflowActionCount(exId);
|
|
11902
|
+
} catch {
|
|
11903
|
+
existingCount = -1;
|
|
11904
|
+
}
|
|
11905
|
+
if (existingCount === 0) {
|
|
11906
|
+
return halt(wf.ref, "workflow", `a workflow named "${wf.name}" already exists but has NO actions \u2014 likely an empty orphan from a failed prior run (or a name collision). Delete it in GHL, then re-run. (Blueprint never modifies an existing workflow.)`);
|
|
11907
|
+
}
|
|
11908
|
+
}
|
|
11909
|
+
idMap[wf.ref] = exId;
|
|
11910
|
+
built.push({ ref: wf.ref, type: "workflow", name: wf.name, status: "existing", realId: exId });
|
|
11911
|
+
continue;
|
|
11912
|
+
}
|
|
11913
|
+
let wfId;
|
|
11914
|
+
try {
|
|
11915
|
+
wfId = await deps.createWorkflow(wf.name);
|
|
11916
|
+
} catch (e) {
|
|
11917
|
+
return halt(wf.ref, "workflow", `create failed: ${msg(e)}`);
|
|
11918
|
+
}
|
|
11919
|
+
if (!wfId) return halt(wf.ref, "workflow", "workflow create returned no id");
|
|
11920
|
+
const triggers = expansion.nativeTrigger ? [expansion.nativeTrigger] : [];
|
|
11921
|
+
try {
|
|
11922
|
+
await deps.saveWorkflow(wfId, { actions: expansion.nativeActions, triggers, stopOnResponse: wf.stopOnResponse });
|
|
11923
|
+
if (expansion.nativeActions.length > 0) {
|
|
11924
|
+
const count = await deps.getWorkflowActionCount(wfId);
|
|
11925
|
+
if (count === 0) throw new Error("saved but no actions persisted (read-after-write)");
|
|
11926
|
+
}
|
|
11927
|
+
} catch (e) {
|
|
11928
|
+
let rolledBack = false;
|
|
11929
|
+
try {
|
|
11930
|
+
await deps.deleteWorkflow(wfId);
|
|
11931
|
+
rolledBack = true;
|
|
11932
|
+
} catch {
|
|
11933
|
+
}
|
|
11934
|
+
return halt(
|
|
11935
|
+
wf.ref,
|
|
11936
|
+
"workflow",
|
|
11937
|
+
rolledBack ? `actions/trigger save failed; the partial workflow was rolled back (deleted): ${msg(e)}` : `actions/trigger save failed AND the rollback delete also failed \u2014 manually delete the orphan workflow (id ${wfId}) in GHL before re-running: ${msg(e)}`
|
|
11938
|
+
);
|
|
11939
|
+
}
|
|
11940
|
+
idMap[wf.ref] = wfId;
|
|
11941
|
+
built.push({ ref: wf.ref, type: "workflow", name: wf.name, status: "created", realId: wfId });
|
|
11942
|
+
if (expansion.triggerManual) manual.push({ ref: wf.ref, type: "workflow-trigger", name: wf.name, reason: `[${wf.name}] ${expansion.triggerManual}` });
|
|
11943
|
+
for (const nc of expansion.needsContent) manual.push({ ref: wf.ref, type: "workflow-action", name: wf.name, reason: `[${wf.name}] ${nc.reason}` });
|
|
11944
|
+
for (const m of expansion.manual) manual.push({ ref: wf.ref, type: "workflow-action", name: wf.name, reason: `[${wf.name}] ${m.reason}` });
|
|
11945
|
+
}
|
|
11808
11946
|
return { ok: true, idMap, built, manual, deferred: deferredSections(plan) };
|
|
11809
11947
|
}
|
|
11810
11948
|
async function buildSimple(objects, type, list, create, nameOf, pollForNew, idMap, built) {
|
|
@@ -11839,10 +11977,8 @@ async function buildSimple(objects, type, list, create, nameOf, pollForNew, idMa
|
|
|
11839
11977
|
}
|
|
11840
11978
|
return null;
|
|
11841
11979
|
}
|
|
11842
|
-
function deferredSections(
|
|
11843
|
-
|
|
11844
|
-
if (plan.workflows?.length) out.push({ section: "workflows", count: plan.workflows.length });
|
|
11845
|
-
return out;
|
|
11980
|
+
function deferredSections(_plan) {
|
|
11981
|
+
return [];
|
|
11846
11982
|
}
|
|
11847
11983
|
function msg(e) {
|
|
11848
11984
|
return e instanceof Error ? e.message : String(e);
|
|
@@ -12192,6 +12328,35 @@ ${text2.slice(0, 300)}`);
|
|
|
12192
12328
|
},
|
|
12193
12329
|
deleteFunnel: async (funnelId) => {
|
|
12194
12330
|
await funnelApi("POST", `/funnel/delete`, { funnelId, locationId: locationId2, userId: builderClient.getUserId() });
|
|
12331
|
+
},
|
|
12332
|
+
// ── Workflows ───────────────────────────────────────────────────────────
|
|
12333
|
+
// NOTE: unlike /forms/ and /funnels/, the GHL /workflows/ list endpoint does
|
|
12334
|
+
// NOT paginate — it 422s on `limit`/`skip` ("property X should not exist") and
|
|
12335
|
+
// returns ALL workflows in one call (live-verified 2026-06-16). So a single
|
|
12336
|
+
// call IS the full never-clobber scan here; no pagination is possible or needed.
|
|
12337
|
+
listWorkflows: async () => pickObjects(await client.get("/workflows/", { params: { locationId: locationId2 } }), ["workflows"]),
|
|
12338
|
+
createWorkflow: async (name) => {
|
|
12339
|
+
const wf = await builderClient.createWorkflow(name);
|
|
12340
|
+
const id = wf && typeof wf === "object" ? wf : {};
|
|
12341
|
+
const wfId = typeof id.id === "string" ? id.id : typeof id._id === "string" ? id._id : void 0;
|
|
12342
|
+
if (!wfId) throw new Error(`create_workflow returned no id: ${JSON.stringify(wf).slice(0, 200)}`);
|
|
12343
|
+
return wfId;
|
|
12344
|
+
},
|
|
12345
|
+
saveWorkflow: async (workflowId, opts) => {
|
|
12346
|
+
await builderClient.updateWorkflow(workflowId, {
|
|
12347
|
+
actions: opts.actions,
|
|
12348
|
+
triggers: opts.triggers,
|
|
12349
|
+
status: "draft",
|
|
12350
|
+
stopOnResponse: opts.stopOnResponse
|
|
12351
|
+
});
|
|
12352
|
+
},
|
|
12353
|
+
getWorkflowActionCount: async (workflowId) => {
|
|
12354
|
+
const full = await builderClient.getWorkflow(workflowId);
|
|
12355
|
+
const templates = full && typeof full === "object" ? full.workflowData : void 0;
|
|
12356
|
+
return Array.isArray(templates?.templates) ? templates.templates.length : 0;
|
|
12357
|
+
},
|
|
12358
|
+
deleteWorkflow: async (workflowId) => {
|
|
12359
|
+
await builderClient.deleteWorkflow(workflowId);
|
|
12195
12360
|
}
|
|
12196
12361
|
};
|
|
12197
12362
|
}
|
|
@@ -12250,7 +12415,7 @@ function registerIntakeToBuildTools(server2, client, builderClient) {
|
|
|
12250
12415
|
);
|
|
12251
12416
|
server2.tool(
|
|
12252
12417
|
"apply_build_plan",
|
|
12253
|
-
`Take an APPROVED Blueprint \xA75 build plan + the CURRENT confirmed sub-account and build it. mode:"dry_run" (default) writes NOTHING \u2014 it resolves refs, expands each workflow's logical actions to native GHL JSON, runs the NEVER-CLOBBER existing-asset scan, and returns a two-part report. Run it FIRST. mode:"execute" performs LIVE writes for the CRM backbone (pipelines+stages, custom fields, tags, custom values), calendars, AND forms: never clobbers (same-named objects are bound to their existing id, never modified), verifies each create by read-back before resolving its ref, halts on the first failure returning the partial idMap, and is idempotent (re-run = no-op). Staff-requiring calendars (round_robin etc.) auto-build only when you are the sole account user (auto-assigns you as the team member); with 0 or 2+ users they're surfaced as a manual step, not auto-staffed to a guess. Forms build with their standard + custom fields (custom fieldRefs resolve to the real fields created earlier in the run). Funnels build structurally (funnel + named steps
|
|
12418
|
+
`Take an APPROVED Blueprint \xA75 build plan + the CURRENT confirmed sub-account and build it. mode:"dry_run" (default) writes NOTHING \u2014 it resolves refs, expands each workflow's logical actions to native GHL JSON, runs the NEVER-CLOBBER existing-asset scan, and returns a two-part report. Run it FIRST. mode:"execute" performs LIVE writes for the CRM backbone (pipelines+stages, custom fields, tags, custom values), calendars, AND forms: never clobbers (same-named objects are bound to their existing id, never modified), verifies each create by read-back before resolving its ref, halts on the first failure returning the partial idMap, and is idempotent (re-run = no-op). Staff-requiring calendars (round_robin etc.) auto-build only when you are the sole account user (auto-assigns you as the team member); with 0 or 2+ users they're surfaced as a manual step, not auto-staffed to a guess. Forms build with their standard + custom fields (custom fieldRefs resolve to the real fields created earlier in the run). Funnels build structurally (funnel + named steps; page content/HTML is a manual step \u2014 plans carry outlines). Workflows build as DRAFT with all their logical actions expanded to native GHL JSON (incl. opportunity create/move steps, re-enabled v3.41.0) and chained; a contact_tag trigger is built automatically, other trigger types are surfaced as a manual step; the operator reviews + publishes. Always confirms the active location and validates the plan before any write.`,
|
|
12254
12419
|
{
|
|
12255
12420
|
plan: import_zod53.z.record(import_zod53.z.unknown()).describe("The approved \xA75 Build Plan object."),
|
|
12256
12421
|
mode: import_zod53.z.enum(["dry_run", "execute"]).optional().describe("dry_run (default) = resolve/expand/scan/report, no writes. execute = live writes (not yet enabled)."),
|
|
@@ -12343,7 +12508,7 @@ function registerIntakeToBuildTools(server2, client, builderClient) {
|
|
|
12343
12508
|
manual: exec.manual,
|
|
12344
12509
|
idMap: exec.idMap,
|
|
12345
12510
|
deferred: exec.deferred,
|
|
12346
|
-
deferredNote: "execute builds the CRM backbone (pipelines, custom fields, tags, custom values), calendars, forms,
|
|
12511
|
+
deferredNote: "execute builds the WHOLE plan live: CRM backbone (pipelines, custom fields, tags, custom values), calendars, forms, funnels (funnel + named steps), and workflows (DRAFT, with all steps incl. opportunity create/move). Remaining manual steps are surfaced per item: staff-requiring calendars in multi-user accounts, funnel page content/design, workflow triggers other than contact_tag (set by hand), and publishing the DRAFT workflows.",
|
|
12347
12512
|
nextManualSteps: [...execManualLines, ...manualLines, ...handoffLines],
|
|
12348
12513
|
summary: exec.ok ? `Built ${exec.built.filter((b) => b.status === "created").length} new object(s), bound ${exec.built.filter((b) => b.status === "existing").length} existing.${exec.manual.length ? ` ${exec.manual.length} item(s) need a manual step (see nextManualSteps).` : ""}${exec.deferred.length ? " Deferred: " + exec.deferred.map((d) => `${d.count} ${d.section}`).join(", ") + " (manual)." : ""}` : `HALTED at ${exec.halted?.atRef} (${exec.halted?.reason}). ${exec.built.length} object(s) were created before the halt \u2014 see idMap to resume or clean up. NEVER-CLOBBER means a re-run will bind those, not duplicate them.`
|
|
12349
12514
|
});
|
|
@@ -12375,6 +12540,8 @@ function registerIntakeToBuildTools(server2, client, builderClient) {
|
|
|
12375
12540
|
autoActions: w.nativeActions.length,
|
|
12376
12541
|
manualSteps: w.manual,
|
|
12377
12542
|
needsContent: w.needsContent,
|
|
12543
|
+
triggerManual: w.triggerManual,
|
|
12544
|
+
triggerAutoBuilt: !!w.nativeTrigger,
|
|
12378
12545
|
pendingRefs: w.pendingRefs,
|
|
12379
12546
|
splitInto: w.splitInto,
|
|
12380
12547
|
gatedBy: w.gatedBy,
|
|
@@ -12383,7 +12550,7 @@ function registerIntakeToBuildTools(server2, client, builderClient) {
|
|
|
12383
12550
|
calendarsManual: result.calendarsManual,
|
|
12384
12551
|
handoffs: result.handoffs,
|
|
12385
12552
|
report,
|
|
12386
|
-
next: 'Review the report. When it looks right, re-run with mode:"execute" to build live:
|
|
12553
|
+
next: 'Review the report. When it looks right, re-run with mode:"execute" to build it all live: CRM backbone (pipelines, fields, tags, custom values), calendars, forms, funnels (funnel + named steps), and workflows (DRAFT, with all steps incl. opportunity moves). Manual next steps: funnel page content/design, contact-tag-triggers build automatically but other trigger types are set by hand, then publish the workflows.'
|
|
12387
12554
|
});
|
|
12388
12555
|
} catch (error) {
|
|
12389
12556
|
return errorResponse(error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elitedcs/ghl-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.42.0",
|
|
4
4
|
"mcpName": "io.github.drjerryrelth/ghl-command",
|
|
5
5
|
"description": "GoHighLevel MCP Server for Claude. 218 tools — full CRM, automation, marketing control, account-wide workflow audit, and the only programmatic GHL workflow builder, now multi-tenant across client accounts.",
|
|
6
6
|
"main": "dist/index.js",
|