@elitedcs/ghl-mcp 3.83.3 → 3.83.4

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 CHANGED
@@ -2,6 +2,32 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 3.83.4 — one door for every write, so "protected" cannot quietly stop meaning protected
6
+
7
+ 3.83.3 fixed the holes. This closes the shape that kept making them.
8
+
9
+ Marking a client account protected is checked in one place for the public API. But
10
+ this product also writes to GoHighLevel through its own builder connection, and
11
+ eleven tool modules had each grown their own copy of that request — their own
12
+ headers, their own timeout, their own fetch. Every copy was a separate door into
13
+ your account, and a check added to one of them told you nothing about the other
14
+ ten. That is why the last release had to find fourteen of them.
15
+
16
+ They now share one door. It builds the headers, applies the thirty-second timeout
17
+ and runs the protected-account check once, for all of them. A tool written next
18
+ year gets the check without its author having to remember, and a test refuses any
19
+ new code that tries to go around it.
20
+
21
+ Nothing about what the tools do has changed. The same requests go to the same
22
+ places with the same bodies and the same headers, including the two different
23
+ builder origins GoHighLevel requires for page saves and for everything else. If
24
+ you cannot tell the difference from the outside, that is the intended result.
25
+
26
+ Also in this release: `update_form` now tells you what a field needs in order to
27
+ RENDER rather than only how to send one. A custom question needs the real custom
28
+ field's id, key and data type from your account; a field written without them is
29
+ stored and shows as raw data instead of a rendered field.
30
+
5
31
  ## 3.83.3 — an account you marked protected is now actually protected
6
32
 
7
33
  **Marking a client account protected did not stop fourteen write paths from writing to it.**
package/README.md CHANGED
@@ -897,7 +897,7 @@ Built by **[Elite DCs, LLC](https://elitedcs.com)** — a digital marketing and
897
897
 
898
898
  **Tech stack:** TypeScript, Node.js, esbuild, MCP SDK, Zod, GHL API v2, Firebase Auth
899
899
 
900
- **Version:** 3.83.3
900
+ **Version:** 3.83.4
901
901
 
902
902
  ---
903
903
 
package/dist/index.js CHANGED
@@ -1922,6 +1922,25 @@ function validateActionChain(actions, existingIds) {
1922
1922
  }
1923
1923
  }
1924
1924
  }
1925
+ async function builderRequest(client, method, url, opts = {}) {
1926
+ assertWriteAllowed(method, url, { body: opts.body, defaultLocationId: client.locationId });
1927
+ const headers = { ...await client.buildHeaders(), ...opts.headers ?? {} };
1928
+ const init = { method, headers };
1929
+ if (opts.body !== void 0) init.body = JSON.stringify(opts.body);
1930
+ const controller = new AbortController();
1931
+ const timeout = setTimeout(() => controller.abort(), 3e4);
1932
+ init.signal = controller.signal;
1933
+ try {
1934
+ return await fetch(url, init);
1935
+ } catch (error) {
1936
+ if (error instanceof Error && error.name === "AbortError") {
1937
+ throw new Error(`Request timeout (30s): ${method} ${url}`);
1938
+ }
1939
+ throw error;
1940
+ } finally {
1941
+ clearTimeout(timeout);
1942
+ }
1943
+ }
1925
1944
  var fs4, path4, dotenv, import_zod4, BACKEND_BASE, FIREBASE_TOKEN_URL, MAX_RETRIES2, BASE_DELAY_MS2, FirebaseTokenSchema, WorkflowActionSchema, WorkflowFullSchema, CreateWorkflowResponseSchema, ParkedContactsError, UUID_V4, WorkflowBuilderClient;
1926
1945
  var init_workflow_builder_client = __esm({
1927
1946
  "src/workflow-builder-client.ts"() {
@@ -7435,14 +7454,8 @@ function registerEmailTools(server2, client) {
7435
7454
  function registerEmailBuilderInternalTools(server2, builderClient, publicClient) {
7436
7455
  if (!builderClient) return;
7437
7456
  const client = builderClient;
7438
- async function builderRequest(method, path39, body) {
7439
- const headers = await client.buildHeaders();
7440
- assertWriteAllowed(method, `${EMAIL_BUILDER_BASE}${path39}`, { defaultLocationId: client.locationId });
7441
- const response = await fetch(`${EMAIL_BUILDER_BASE}${path39}`, {
7442
- method,
7443
- headers,
7444
- body: body ? JSON.stringify(body) : void 0
7445
- });
7457
+ async function builderRequest2(method, path39, body) {
7458
+ const response = await builderRequest(client, method, `${EMAIL_BUILDER_BASE}${path39}`, body ? { body } : {});
7446
7459
  if (!response.ok) {
7447
7460
  const text2 = await response.text();
7448
7461
  throw new Error(`Email Builder API Error ${response.status}: ${method} /emails/builder${path39}
@@ -7464,7 +7477,7 @@ ${text2}`);
7464
7477
  const loc = locationId2 ?? client.locationId;
7465
7478
  return deleteEmailTemplateThroughDoors({
7466
7479
  publicDelete: () => publicClient.delete(publicEmailTemplateDeletePath(loc, templateId)),
7467
- internalDelete: () => builderRequest("DELETE", internalEmailTemplateDeletePath(templateId, loc))
7480
+ internalDelete: () => builderRequest2("DELETE", internalEmailTemplateDeletePath(templateId, loc))
7468
7481
  });
7469
7482
  }
7470
7483
  );
@@ -7479,7 +7492,7 @@ ${text2}`);
7479
7492
  },
7480
7493
  async ({ templateId, name, locationId: locationId2 }) => {
7481
7494
  const loc = locationId2 ?? client.locationId;
7482
- return builderRequest("PATCH", `/${templateId}`, { locationId: loc, name });
7495
+ return builderRequest2("PATCH", `/${templateId}`, { locationId: loc, name });
7483
7496
  }
7484
7497
  );
7485
7498
  safeTool(
@@ -7493,7 +7506,7 @@ ${text2}`);
7493
7506
  },
7494
7507
  async ({ templateId, archived, locationId: locationId2 }) => {
7495
7508
  const loc = locationId2 ?? client.locationId;
7496
- return builderRequest("PATCH", `/${templateId}`, { locationId: loc, archived: archived ?? true });
7509
+ return builderRequest2("PATCH", `/${templateId}`, { locationId: loc, archived: archived ?? true });
7497
7510
  }
7498
7511
  );
7499
7512
  safeTool(
@@ -7508,11 +7521,8 @@ ${text2}`);
7508
7521
  },
7509
7522
  async ({ name, body, type, locationId: locationId2 }) => {
7510
7523
  const loc = locationId2 ?? client.locationId;
7511
- const headers = await client.buildHeaders();
7512
- const response = await fetch(`${SNIPPETS_BASE}/${loc}`, {
7513
- method: "POST",
7514
- headers,
7515
- body: JSON.stringify(buildSnippetPayload({ name, body, type }))
7524
+ const response = await builderRequest(client, "POST", `${SNIPPETS_BASE}/${loc}`, {
7525
+ body: buildSnippetPayload({ name, body, type })
7516
7526
  });
7517
7527
  if (!response.ok) {
7518
7528
  const text2 = await response.text();
@@ -7542,8 +7552,8 @@ var init_emails = __esm({
7542
7552
  init_account_read_retry();
7543
7553
  init_account_reads();
7544
7554
  import_zod28 = require("zod");
7555
+ init_workflow_builder_client();
7545
7556
  init_tool_helpers();
7546
- init_account_rules();
7547
7557
  EMAIL_BUILDER_BASE = "https://backend.leadconnectorhq.com/emails/builder";
7548
7558
  SNIPPETS_BASE = "https://services.leadconnectorhq.com/snippets";
7549
7559
  TEMPLATE_TYPES = ["html", "folder", "import", "builder", "blank", "ai_template", "vibe-editor"];
@@ -11238,15 +11248,17 @@ function registerFunnelBuilderTools(server2, builderClient) {
11238
11248
  return client.request("DELETE", path39);
11239
11249
  }
11240
11250
  async function funnelRequest(method, path39, body) {
11241
- const headers = await client.buildHeaders();
11242
- headers.Origin = "https://app.gohighlevel.com";
11243
- headers.Referer = "https://app.gohighlevel.com/";
11244
11251
  const url = `https://backend.leadconnectorhq.com/funnels${path39}`;
11245
- const options = { method, headers };
11246
- if (body && (method === "POST" || method === "PUT")) {
11247
- options.body = JSON.stringify(body);
11248
- }
11249
- const response = await fetch(url, options);
11252
+ const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
11253
+ const response = await builderRequest(client, method, url, {
11254
+ ...sendsBody ? { body } : {},
11255
+ headers: {
11256
+ // Internal-API calls require the app origin (autosave needs the
11257
+ // page-builder one instead; see the autosave call).
11258
+ Origin: "https://app.gohighlevel.com",
11259
+ Referer: "https://app.gohighlevel.com/"
11260
+ }
11261
+ });
11250
11262
  if (!response.ok) {
11251
11263
  const text2 = await response.text();
11252
11264
  throw new Error(`Funnel API Error ${response.status}: ${method} ${path39}
@@ -11508,12 +11520,17 @@ ${text2}`);
11508
11520
  };
11509
11521
  }
11510
11522
  async function autosaveRequest(pageId, body) {
11511
- const headers = await client.buildHeaders();
11512
- headers.Origin = "https://page-builder.leadconnectorhq.com";
11513
- headers.Referer = "https://page-builder.leadconnectorhq.com/";
11514
11523
  const url = `https://backend.leadconnectorhq.com/funnels/builder/autosave/${pageId}`;
11515
- assertWriteAllowed("POST", url, { defaultLocationId: client.locationId });
11516
- const response = await fetch(url, { method: "POST", headers, body: JSON.stringify(body) });
11524
+ const response = await builderRequest(client, "POST", url, {
11525
+ body,
11526
+ headers: {
11527
+ // The autosave endpoint's IAM check requires the builder origin (verified
11528
+ // live — app.gohighlevel.com was not tested and page-builder is what the
11529
+ // real builder sends).
11530
+ Origin: "https://page-builder.leadconnectorhq.com",
11531
+ Referer: "https://page-builder.leadconnectorhq.com/"
11532
+ }
11533
+ });
11517
11534
  if (!response.ok) {
11518
11535
  throw new Error(`Funnel API Error ${response.status}: POST /builder/autosave/${pageId}
11519
11536
  ${await response.text()}`);
@@ -11619,9 +11636,9 @@ var init_funnel_builder = __esm({
11619
11636
  "src/tools/funnel-builder.ts"() {
11620
11637
  "use strict";
11621
11638
  import_zod41 = require("zod");
11639
+ init_workflow_builder_client();
11622
11640
  init_tool_helpers();
11623
11641
  init_page_reads();
11624
- init_account_rules();
11625
11642
  }
11626
11643
  });
11627
11644
 
@@ -16477,10 +16494,15 @@ function registerPageStudioTools(server2, builderClient) {
16477
16494
  return { map: out, truncated };
16478
16495
  }
16479
16496
  async function funnelRequest(method, path39, body) {
16480
- const headers = await client.buildHeaders();
16481
- headers.Origin = "https://app.gohighlevel.com";
16482
- headers.Referer = "https://app.gohighlevel.com/";
16483
- const response = await fetch(`https://backend.leadconnectorhq.com/funnels${path39}`, { method, headers, ...body && { body: JSON.stringify(body) } });
16497
+ const response = await builderRequest(client, method, `https://backend.leadconnectorhq.com/funnels${path39}`, {
16498
+ ...body ? { body } : {},
16499
+ headers: {
16500
+ // Internal-API calls require the app origin (autosave needs the
16501
+ // page-builder one instead; see the autosave call).
16502
+ Origin: "https://app.gohighlevel.com",
16503
+ Referer: "https://app.gohighlevel.com/"
16504
+ }
16505
+ });
16484
16506
  if (!response.ok) throw new Error(`Funnel API Error ${response.status}: ${method} ${path39}
16485
16507
  ${await response.text()}`);
16486
16508
  const text = await response.text();
@@ -16497,15 +16519,13 @@ ${await response.text()}`);
16497
16519
  }
16498
16520
  }
16499
16521
  async function autosaveRequest(pageId, body) {
16500
- const headers = await client.buildHeaders();
16501
- headers.Origin = "https://page-builder.leadconnectorhq.com";
16502
- headers.Referer = "https://page-builder.leadconnectorhq.com/";
16503
16522
  const autosaveUrl = `https://backend.leadconnectorhq.com/funnels/builder/autosave/${pageId}`;
16504
- assertWriteAllowed("POST", autosaveUrl, { defaultLocationId: client.locationId });
16505
- const response = await fetch(autosaveUrl, {
16506
- method: "POST",
16507
- headers,
16508
- body: JSON.stringify(body)
16523
+ const response = await builderRequest(client, "POST", autosaveUrl, {
16524
+ body,
16525
+ headers: {
16526
+ Origin: "https://page-builder.leadconnectorhq.com",
16527
+ Referer: "https://page-builder.leadconnectorhq.com/"
16528
+ }
16509
16529
  });
16510
16530
  if (!response.ok) throw new Error(`Funnel API Error ${response.status}: POST /builder/autosave/${pageId}
16511
16531
  ${await response.text()}`);
@@ -16991,6 +17011,7 @@ var init_page_studio = __esm({
16991
17011
  "use strict";
16992
17012
  import_zod43 = require("zod");
16993
17013
  crypto4 = __toESM(require("node:crypto"));
17014
+ init_workflow_builder_client();
16994
17015
  init_ghl_templates();
16995
17016
  init_retheme();
16996
17017
  init_ghl_page();
@@ -16999,7 +17020,6 @@ var init_page_studio = __esm({
16999
17020
  init_tool_helpers();
17000
17021
  init_compose();
17001
17022
  init_website();
17002
- init_account_rules();
17003
17023
  valueCardSchema = import_zod43.z.object({
17004
17024
  title: import_zod43.z.string().describe("Card title (short, uppercase reads best)."),
17005
17025
  bodyHtml: import_zod43.z.string().describe("Card body as HTML (<p>\u2026</p>). May use {{location.*}} merge fields."),
@@ -17088,14 +17108,9 @@ function cleanFormDataForSave(formData) {
17088
17108
  return isJsonObject(cleaned) ? cleaned : formData;
17089
17109
  }
17090
17110
  async function formApiRequest(client, method, path39, body) {
17091
- const headers = await client.buildHeaders();
17092
17111
  const url = `https://backend.leadconnectorhq.com/forms${path39}`;
17093
- assertWriteAllowed(method, url, { defaultLocationId: client.locationId });
17094
- const options = { method, headers };
17095
- if (body && (method === "POST" || method === "PUT")) {
17096
- options.body = JSON.stringify(body);
17097
- }
17098
- const response = await fetch(url, options);
17112
+ const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
17113
+ const response = await builderRequest(client, method, url, sendsBody ? { body } : {});
17099
17114
  if (!response.ok) {
17100
17115
  const text2 = await response.text();
17101
17116
  throw new Error(`Form API Error ${response.status}: ${method} ${path39}
@@ -17162,10 +17177,10 @@ function registerFormBuilderTools(server2, builderClient, publicClient) {
17162
17177
  );
17163
17178
  server2.tool(
17164
17179
  "update_form",
17165
- "Update a form's structure \u2014 fields, labels, conditional logic, auto-responder, email notifications, styling. Use get_form_full first to read the current form, modify the formData object, then pass it here. If name is omitted, the current name is preserved (one extra GET).",
17180
+ "Update a form's structure \u2014 fields, labels, conditional logic, auto-responder, email notifications, styling. Use get_form_full first to read the current form, modify the formData object, then pass it here. If name is omitted, the current name is preserved (one extra GET). IMPORTANT \u2014 a NEW field will not render in GoHighLevel's form editor unless it carries the binding GHL needs: a custom-question field must include the real custom field's `id`, `fieldKey` and `dataType` from THIS account (read them with get_custom_fields first; do not invent them), and a standard field (first_name, last_name, email, phone) needs `standard: true` with its `tag`. A field written without that binding is stored but shows as raw data instead of a rendered field. These shapes were reverse-engineered from live UI-built forms; copy an existing field from get_form_full rather than composing one from memory.",
17166
17181
  {
17167
17182
  formId: import_zod44.z.string().describe("The form ID to update."),
17168
- formData: import_zod44.z.record(import_zod44.z.string(), import_zod44.z.unknown()).describe("The updated formData object containing form fields, settings, autoResponder config, etc."),
17183
+ formData: import_zod44.z.record(import_zod44.z.string(), import_zod44.z.unknown()).describe("The updated formData object containing form fields, settings, autoResponder config, etc. Fields live at formData.form.fields; each one needs the binding described above or the editor cannot render it."),
17169
17184
  name: import_zod44.z.string().optional().describe("Updated form name. If omitted, the current name is preserved.")
17170
17185
  },
17171
17186
  async ({ formId, formData, name }) => {
@@ -17292,8 +17307,8 @@ var init_form_builder = __esm({
17292
17307
  "src/tools/form-builder.ts"() {
17293
17308
  "use strict";
17294
17309
  import_zod44 = require("zod");
17310
+ init_workflow_builder_client();
17295
17311
  init_tool_helpers();
17296
- init_account_rules();
17297
17312
  }
17298
17313
  });
17299
17314
 
@@ -17686,14 +17701,9 @@ function registerPipelineBuilderTools(server2, builderClient) {
17686
17701
  if (!builderClient) return;
17687
17702
  const client = builderClient;
17688
17703
  async function pipelineRequest(method, path39, body) {
17689
- const headers = await client.buildHeaders();
17690
17704
  const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${path39}`;
17691
- assertWriteAllowed(method, url, { defaultLocationId: client.locationId });
17692
- const options = { method, headers };
17693
- if (body && (method === "POST" || method === "PUT" || method === "PATCH")) {
17694
- options.body = JSON.stringify(body);
17695
- }
17696
- const response = await fetch(url, options);
17705
+ const sendsBody = body !== void 0 && (method === "POST" || method === "PUT" || method === "PATCH");
17706
+ const response = await builderRequest(client, method, url, sendsBody ? { body } : {});
17697
17707
  if (!response.ok) {
17698
17708
  const text2 = await response.text();
17699
17709
  throw new Error(`Pipeline API Error ${response.status}: ${method} ${path39}
@@ -17871,7 +17881,7 @@ var init_pipeline_builder = __esm({
17871
17881
  "src/tools/pipeline-builder.ts"() {
17872
17882
  "use strict";
17873
17883
  import_zod46 = require("zod");
17874
- init_account_rules();
17884
+ init_workflow_builder_client();
17875
17885
  }
17876
17886
  });
17877
17887
 
@@ -28581,7 +28591,7 @@ var require_package = __commonJS({
28581
28591
  "package.json"(exports2, module2) {
28582
28592
  module2.exports = {
28583
28593
  name: "@elitedcs/ghl-mcp",
28584
- version: "3.83.3",
28594
+ version: "3.83.4",
28585
28595
  mcpName: "io.github.drjerryrelth/ghl-command",
28586
28596
  description: "GoHighLevel MCP Server for Claude. 250 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.",
28587
28597
  main: "dist/index.js",
@@ -39216,14 +39226,9 @@ function registerSmartListTools(server2, builderClient) {
39216
39226
  if (!builderClient) return;
39217
39227
  const client = builderClient;
39218
39228
  async function smartListRequest(method, path39, body) {
39219
- const headers = await client.buildHeaders();
39220
39229
  const url = `${SMARTLIST_BASE}${path39}`;
39221
- assertWriteAllowed(method, url, { defaultLocationId: client.locationId });
39222
- const options = { method, headers };
39223
- if (body && (method === "POST" || method === "PUT")) {
39224
- options.body = JSON.stringify(body);
39225
- }
39226
- const response = await fetch(url, options);
39230
+ const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
39231
+ const response = await builderRequest(client, method, url, sendsBody ? { body } : {});
39227
39232
  if (!response.ok) {
39228
39233
  const text2 = await response.text();
39229
39234
  throw new Error(`Smart Lists API Error ${response.status}: ${method} ${path39}
@@ -39288,8 +39293,7 @@ ${await res.text()}`);
39288
39293
  ];
39289
39294
  const body = buildContactSmartListBody({ listName: name, locationId: loc, filters });
39290
39295
  const headers = await client.buildHeaders();
39291
- assertWriteAllowed("POST", CONTACT_SMARTLIST_BASE, { defaultLocationId: client.locationId });
39292
- const res = await fetch(CONTACT_SMARTLIST_BASE, { method: "POST", headers, body: JSON.stringify(body) });
39296
+ const res = await builderRequest(client, "POST", CONTACT_SMARTLIST_BASE, { body });
39293
39297
  if (!res.ok) throw new Error(`Smart Lists API Error ${res.status}: POST /contacts/smartlist
39294
39298
  ${await res.text()}`);
39295
39299
  return jsonResponse(JSON.parse(await res.text() || "{}"));
@@ -39326,12 +39330,7 @@ ${await res.text()}`);
39326
39330
  async ({ listId }) => {
39327
39331
  try {
39328
39332
  const headers = await client.buildHeaders();
39329
- assertWriteAllowed("POST", CONTACT_SMARTLIST_DELETE, { defaultLocationId: client.locationId });
39330
- const res = await fetch(CONTACT_SMARTLIST_DELETE, {
39331
- method: "POST",
39332
- headers,
39333
- body: JSON.stringify({ smartlist_id: listId })
39334
- });
39333
+ const res = await builderRequest(client, "POST", CONTACT_SMARTLIST_DELETE, { body: { smartlist_id: listId } });
39335
39334
  if (!res.ok) throw new Error(`Smart Lists API Error ${res.status}: POST /smartlist/delete
39336
39335
  ${await res.text()}`);
39337
39336
  return jsonResponse(JSON.parse(await res.text() || "{}"));
@@ -39439,8 +39438,8 @@ var init_smart_lists = __esm({
39439
39438
  "src/tools/smart-lists.ts"() {
39440
39439
  "use strict";
39441
39440
  import_zod57 = require("zod");
39441
+ init_workflow_builder_client();
39442
39442
  init_tool_helpers();
39443
- init_account_rules();
39444
39443
  SMARTLIST_BASE = "https://backend.leadconnectorhq.com/lists/dynamic";
39445
39444
  OBJECT_KEYS = ["contacts", "opportunity"];
39446
39445
  CONTACT_SMARTLIST_BASE = "https://services.leadconnectorhq.com/contacts/smartlist";
@@ -39462,9 +39461,7 @@ function registerReputationTools(server2, builderClient) {
39462
39461
  if (!builderClient) return;
39463
39462
  const client = builderClient;
39464
39463
  async function reputationRequest(method, path39) {
39465
- assertWriteAllowed(method, `${REPUTATION_BASE}${path39}`, { defaultLocationId: client.locationId });
39466
- const headers = await client.buildHeaders();
39467
- const response = await fetch(`${REPUTATION_BASE}${path39}`, { method, headers });
39464
+ const response = await builderRequest(client, method, `${REPUTATION_BASE}${path39}`);
39468
39465
  if (!response.ok) {
39469
39466
  const text2 = await response.text();
39470
39467
  throw new Error(`Reputation API Error ${response.status}: ${method} ${path39}
@@ -39540,8 +39537,8 @@ var init_reputation = __esm({
39540
39537
  "src/tools/reputation.ts"() {
39541
39538
  "use strict";
39542
39539
  import_zod58 = require("zod");
39540
+ init_workflow_builder_client();
39543
39541
  init_tool_helpers();
39544
- init_account_rules();
39545
39542
  REPUTATION_BASE = "https://backend.leadconnectorhq.com/reputation";
39546
39543
  }
39547
39544
  });
@@ -39575,13 +39572,7 @@ function registerEmailCampaignTools(server2, builderClient) {
39575
39572
  if (isPlainText !== void 0) body.isPlainText = isPlainText;
39576
39573
  if (enableResendToUnopened !== void 0) body.enableResendToUnopened = enableResendToUnopened;
39577
39574
  if (hasUtmTracking !== void 0) body.hasUtmTracking = hasUtmTracking;
39578
- const headers = await client.buildHeaders();
39579
- assertWriteAllowed("POST", `${SVC_BASE}/emails/schedule`, { defaultLocationId: client.locationId });
39580
- const response = await fetch(`${SVC_BASE}/emails/schedule`, {
39581
- method: "POST",
39582
- headers,
39583
- body: JSON.stringify(body)
39584
- });
39575
+ const response = await builderRequest(client, "POST", `${SVC_BASE}/emails/schedule`, { body });
39585
39576
  if (!response.ok) {
39586
39577
  const text2 = await response.text();
39587
39578
  throw new Error(`Email Campaign API Error ${response.status}: POST /emails/schedule
@@ -39601,8 +39592,8 @@ var init_email_campaigns = __esm({
39601
39592
  "src/tools/email-campaigns.ts"() {
39602
39593
  "use strict";
39603
39594
  import_zod59 = require("zod");
39595
+ init_workflow_builder_client();
39604
39596
  init_tool_helpers();
39605
- init_account_rules();
39606
39597
  SVC_BASE = "https://services.leadconnectorhq.com";
39607
39598
  }
39608
39599
  });
@@ -39612,13 +39603,7 @@ function registerMembershipTools(server2, builderClient) {
39612
39603
  if (!builderClient) return;
39613
39604
  const client = builderClient;
39614
39605
  async function membershipRequest(path39, method = "GET", body) {
39615
- assertWriteAllowed(method, `${MEMBERSHIP_BASE2}${path39}`, { defaultLocationId: client.locationId });
39616
- const headers = await client.buildHeaders();
39617
- const response = await fetch(`${MEMBERSHIP_BASE2}${path39}`, {
39618
- method,
39619
- headers,
39620
- body: body ? JSON.stringify(body) : void 0
39621
- });
39606
+ const response = await builderRequest(client, method, `${MEMBERSHIP_BASE2}${path39}`, body ? { body } : {});
39622
39607
  if (!response.ok) {
39623
39608
  const text2 = await response.text();
39624
39609
  throw new Error(`Membership API Error ${response.status}: ${method} ${path39}
@@ -39799,8 +39784,8 @@ var init_memberships = __esm({
39799
39784
  "src/tools/memberships.ts"() {
39800
39785
  "use strict";
39801
39786
  import_zod60 = require("zod");
39787
+ init_workflow_builder_client();
39802
39788
  init_tool_helpers();
39803
- init_account_rules();
39804
39789
  MEMBERSHIP_BASE2 = "https://backend.leadconnectorhq.com/membership";
39805
39790
  }
39806
39791
  });
@@ -40148,12 +40133,8 @@ Pipelines: ${template.pipelines.length} to create`);
40148
40133
  }
40149
40134
  } else {
40150
40135
  try {
40151
- const headers = await builderClient.buildHeaders();
40152
- assertWriteAllowed("POST", "https://backend.leadconnectorhq.com/opportunities/pipelines", { defaultLocationId: locId });
40153
- const res = await fetch("https://backend.leadconnectorhq.com/opportunities/pipelines", {
40154
- method: "POST",
40155
- headers,
40156
- body: JSON.stringify({
40136
+ const res = await builderRequest(builderClient, "POST", "https://backend.leadconnectorhq.com/opportunities/pipelines", {
40137
+ body: {
40157
40138
  name: resolved2.name,
40158
40139
  stages: (resolved2.stages || []).map((s) => ({
40159
40140
  ...s,
@@ -40163,7 +40144,7 @@ Pipelines: ${template.pipelines.length} to create`);
40163
40144
  locationId: locId,
40164
40145
  showInFunnel: true,
40165
40146
  showInPieChart: true
40166
- })
40147
+ }
40167
40148
  });
40168
40149
  if (res.ok) {
40169
40150
  counts.pipelines.created++;
@@ -40324,7 +40305,7 @@ var init_template_deployer = __esm({
40324
40305
  init_tool_helpers();
40325
40306
  fs28 = __toESM(require("fs"));
40326
40307
  path27 = __toESM(require("path"));
40327
- init_account_rules();
40308
+ init_workflow_builder_client();
40328
40309
  TemplateSchema = import_zod61.z.object({
40329
40310
  templateName: import_zod61.z.string(),
40330
40311
  templateVersion: import_zod61.z.string().optional(),
@@ -50986,9 +50967,7 @@ function pickCalendarPins(workflow) {
50986
50967
  }
50987
50968
  function makeFirebaseRequest(builderClient) {
50988
50969
  return async (url, method, body) => {
50989
- assertWriteAllowed(method, url, { defaultLocationId: builderClient.locationId });
50990
- const headers = await builderClient.buildHeaders();
50991
- const response = await fetch(url, { method, headers, body: body ? JSON.stringify(body) : void 0 });
50970
+ const response = await builderRequest(builderClient, method, url, body ? { body } : {});
50992
50971
  if (!response.ok) {
50993
50972
  const text2 = await response.text();
50994
50973
  throw new Error(`API ${response.status}: ${method} ${url.replace(/^https:\/\/[^/]+/, "")}
@@ -51000,11 +50979,9 @@ ${text2}`);
51000
50979
  }
51001
50980
  function makePipelineApi(builderClient) {
51002
50981
  return async (method, path39, body) => {
51003
- const headers = await builderClient.buildHeaders();
51004
50982
  const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${path39}`;
51005
- const options = { method, headers };
51006
- if (body && (method === "POST" || method === "PUT")) options.body = JSON.stringify(body);
51007
- const response = await fetch(url, options);
50983
+ const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
50984
+ const response = await builderRequest(builderClient, method, url, sendsBody ? { body } : {});
51008
50985
  if (!response.ok) {
51009
50986
  const text2 = await response.text();
51010
50987
  throw new Error(`Pipeline API ${response.status}: ${method} ${path39}
@@ -51021,13 +50998,17 @@ ${text2}`);
51021
50998
  }
51022
50999
  function makeFunnelApi(builderClient) {
51023
51000
  return async (method, path39, body) => {
51024
- const headers = await builderClient.buildHeaders();
51025
- headers.Origin = "https://app.gohighlevel.com";
51026
- headers.Referer = "https://app.gohighlevel.com/";
51027
51001
  const url = `https://backend.leadconnectorhq.com/funnels${path39}`;
51028
- const options = { method, headers };
51029
- if (body && (method === "POST" || method === "PUT")) options.body = JSON.stringify(body);
51030
- const response = await fetch(url, options);
51002
+ const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
51003
+ const response = await builderRequest(builderClient, method, url, {
51004
+ ...sendsBody ? { body } : {},
51005
+ headers: {
51006
+ // Origin/Referer REQUIRED on internal-API funnel writes (else 401
51007
+ // "Error calling IAM service") — verified in funnel-builder.ts.
51008
+ Origin: "https://app.gohighlevel.com",
51009
+ Referer: "https://app.gohighlevel.com/"
51010
+ }
51011
+ });
51031
51012
  if (!response.ok) {
51032
51013
  const text2 = await response.text();
51033
51014
  throw new Error(`Funnel API ${response.status}: ${method} ${path39}
@@ -52138,6 +52119,7 @@ var init_intake_to_build = __esm({
52138
52119
  init_build_contract();
52139
52120
  init_build_obligations();
52140
52121
  import_zod80 = require("zod");
52122
+ init_workflow_builder_client();
52141
52123
  init_tool_helpers();
52142
52124
  init_form_builder();
52143
52125
  init_calendars();
@@ -52160,7 +52142,6 @@ var init_intake_to_build = __esm({
52160
52142
  init_plan_from_preset();
52161
52143
  init_executor();
52162
52144
  init_execute();
52163
- init_account_rules();
52164
52145
  customFieldItemSchema = import_zod80.z.object({
52165
52146
  id: import_zod80.z.string(),
52166
52147
  name: import_zod80.z.string(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elitedcs/ghl-mcp",
3
- "version": "3.83.3",
3
+ "version": "3.83.4",
4
4
  "mcpName": "io.github.drjerryrelth/ghl-command",
5
5
  "description": "GoHighLevel MCP Server for Claude. 250 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",