@elitedcs/ghl-mcp 3.34.8 → 3.34.10

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/dist/index.js +173 -46
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,71 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.34.10 — `get_free_slots` accepts ISO dates; `update_form` name fallback for fresh forms
4
+
5
+ Two small fixes that close rough edges found while live-verifying v3.34.9 through
6
+ the MCP tools. Neither changes a proven capability; both have trivial workarounds.
7
+
8
+ - **`get_free_slots` now accepts ISO dates (its documented input) — not just epoch
9
+ milliseconds.** GHL's `GET /calendars/{id}/free-slots` requires `startDate` /
10
+ `endDate` as epoch **milliseconds** and 422s (`startDate must be a number…`) on an
11
+ ISO date, yet the tool's own schema documented `YYYY-MM-DD` and forwarded it
12
+ unconverted — so the documented input always failed. The tool now accepts a bare
13
+ `YYYY-MM-DD` (taken as start-of-day for `startDate`, end-of-day for `endDate`, in
14
+ the supplied `timezone`, default UTC), a full ISO datetime (`Date.parse`), or an
15
+ already-numeric epoch-millis value (passed through, back-compat) and converts to
16
+ the epoch ms GHL needs. Logic extracted to `buildFreeSlotsParams` / `toEpochMillis`
17
+ with tests (incl. the live Phoenix anchor `2026-06-15 → 1781506800000`).
18
+ - **`update_form` no longer throws on the natural `create_form` → `update_form`
19
+ sequence.** When `name` is omitted, `update_form` reads the current name to
20
+ preserve it. A form freshly created by `create_form` has no `name` in its builder
21
+ doc until its first save, so that read returned none and the call threw
22
+ (`Could not resolve current form name`). It now falls back to the public forms list
23
+ (which carries the name) and only errors — with actionable guidance to pass `name`
24
+ — if both sources come up empty. The form-builder tools now also receive the public
25
+ `GHLClient` for this lookup (it already had Firebase auth for the builder routes).
26
+ Helpers `pickFormName` / `findFormNameInList` extracted, with tests.
27
+
28
+ ## 3.34.9 — Calendar availability: create_calendar / update_calendar now set `openHours`
29
+
30
+ Closes the on-camera "assign availability hours" gap. `create_calendar` and
31
+ `update_calendar` previously exposed no availability parameter, so every calendar
32
+ was created with `openHours: {}` and a caller could not set business hours through
33
+ the MCP — the calendar only offered GHL's default window.
34
+
35
+ - **New `openHours` (and `availabilityType`) params on `create_calendar` and
36
+ `update_calendar`.** `openHours` is an array of `{daysOfTheWeek:[0-6], hours:
37
+ [{openHour,openMinute,closeHour,closeMinute}]}` (0=Sun … 6=Sat, 24-hour clock).
38
+ When `openHours` is supplied the builder also sends `availabilityType: 0`
39
+ (standard weekly hours) — the exact payload GHL honors — unless the caller
40
+ overrides it.
41
+ - **Multi-day blocks are auto-expanded to one block per day.** GHL's CREATE
42
+ endpoint 422s (`openHours.0.must be a valid day of week`) on a block listing more
43
+ than one weekday. Single-day-per-block is GHL's own canonical form (what it reads
44
+ back) and is accepted by both create and update. The builder accepts the natural
45
+ compact form (`daysOfTheWeek:[1,2,3,4,5]`) and expands it to per-day blocks. Logic
46
+ extracted to `buildCreateCalendarBody` / `buildUpdateCalendarBody` /
47
+ `expandOpenHours`, with tests.
48
+
49
+ **Corrects the 3.34.8 note.** The earlier guess — that round-robin availability
50
+ comes only from the user's working hours and not a calendar `openHours` field — was
51
+ wrong. Pinned live on a real sub-account, the full model is:
52
+
53
+ - `openHours` **does** drive availability. Setting it changes `/free-slots`
54
+ immediately (a Wed-only 13:00–15:00 window collapsed slots to Wednesdays
55
+ 13:00–14:30; a Mon–Fri 9–6 window produced exactly 09:00–17:30 each weekday).
56
+ - On **event / simple** calendars `openHours` is the sole source — every configured
57
+ day/time becomes bookable (a Sat 10–1 window booked Saturdays).
58
+ - On **round_robin** "OptimizeForAvailability" calendars the bookable slots are the
59
+ **intersection** of `openHours` and each assigned user's working hours, so a day
60
+ only opens if a team member is also available then (the same Sat 10–1 window
61
+ produced zero slots when the lone user had no Saturday availability). To open a day
62
+ on round_robin, set the user's availability too (UI-gated), or use an event-type
63
+ calendar where `openHours` alone controls. The tool descriptions state this.
64
+
65
+ Write-verified live: created calendars with hours through the builders, read the
66
+ hours back, and confirmed `/free-slots` returned exactly the configured days/times;
67
+ all throwaways deleted. Suite 289 pass / 1 skip.
68
+
3
69
  ## 3.34.8 — create_opportunity + get_funnel_pages no longer 422 on omitted required params
4
70
 
5
71
  Two real defects found during a full end-to-end build test on a live sub-account
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.8",
34
+ version: "3.34.10",
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",
@@ -2727,6 +2727,113 @@ var CalendarTeamMemberSchema = import_zod9.z.object({
2727
2727
  selected: import_zod9.z.boolean().describe("Whether this user is currently active on the calendar (true to enable)."),
2728
2728
  locationConfigurations: import_zod9.z.array(TeamMemberLocationConfigSchema).min(1).describe("At least one meeting-location config. Typical shape: [{kind:'custom', position:0, location:''}].")
2729
2729
  }).strict();
2730
+ var OpenHoursWindowSchema = import_zod9.z.object({
2731
+ openHour: import_zod9.z.number().int().min(0).max(23).describe("Opening hour on a 24-hour clock (0-23)."),
2732
+ openMinute: import_zod9.z.number().int().min(0).max(59).describe("Opening minute (0-59)."),
2733
+ closeHour: import_zod9.z.number().int().min(0).max(23).describe("Closing hour on a 24-hour clock (0-23)."),
2734
+ closeMinute: import_zod9.z.number().int().min(0).max(59).describe("Closing minute (0-59).")
2735
+ }).strict();
2736
+ var OpenHoursBlockSchema = import_zod9.z.object({
2737
+ daysOfTheWeek: import_zod9.z.array(import_zod9.z.number().int().min(0).max(6)).min(1).describe("Weekdays this block applies to. 0=Sunday, 1=Monday, \u2026 6=Saturday."),
2738
+ hours: import_zod9.z.array(OpenHoursWindowSchema).min(1).describe("One or more open time windows that apply to these days.")
2739
+ }).strict();
2740
+ function expandOpenHours(blocks) {
2741
+ const out = [];
2742
+ for (const block of blocks) {
2743
+ for (const day of block.daysOfTheWeek) {
2744
+ out.push({ daysOfTheWeek: [day], hours: block.hours });
2745
+ }
2746
+ }
2747
+ return out;
2748
+ }
2749
+ function applyCalendarFields(body, args) {
2750
+ if (args.description !== void 0) body.description = args.description;
2751
+ if (args.slug !== void 0) body.slug = args.slug;
2752
+ if (args.widgetSlug !== void 0) body.widgetSlug = args.widgetSlug;
2753
+ if (args.calendarType !== void 0) body.calendarType = args.calendarType;
2754
+ if (args.teamMembers !== void 0) body.teamMembers = args.teamMembers;
2755
+ if (args.eventTitle !== void 0) body.eventTitle = args.eventTitle;
2756
+ if (args.eventColor !== void 0) body.eventColor = args.eventColor;
2757
+ if (args.slotDuration !== void 0) body.slotDuration = args.slotDuration;
2758
+ if (args.slotBuffer !== void 0) body.slotBuffer = args.slotBuffer;
2759
+ if (args.slotInterval !== void 0) body.slotInterval = args.slotInterval;
2760
+ if (args.appointmentPerSlot !== void 0) body.appointmentPerSlot = args.appointmentPerSlot;
2761
+ if (args.openHours !== void 0) {
2762
+ body.openHours = expandOpenHours(args.openHours);
2763
+ body.availabilityType = args.availabilityType ?? 0;
2764
+ } else if (args.availabilityType !== void 0) {
2765
+ body.availabilityType = args.availabilityType;
2766
+ }
2767
+ }
2768
+ function buildCreateCalendarBody(args, resolvedLocationId) {
2769
+ const body = {
2770
+ locationId: resolvedLocationId,
2771
+ name: args.name
2772
+ };
2773
+ applyCalendarFields(body, args);
2774
+ return body;
2775
+ }
2776
+ function buildUpdateCalendarBody(args) {
2777
+ const body = {};
2778
+ if (args.name !== void 0) body.name = args.name;
2779
+ applyCalendarFields(body, args);
2780
+ return body;
2781
+ }
2782
+ function tzOffsetMillis(utcMillis, timeZone) {
2783
+ const dtf = new Intl.DateTimeFormat("en-US", {
2784
+ timeZone,
2785
+ hourCycle: "h23",
2786
+ year: "numeric",
2787
+ month: "2-digit",
2788
+ day: "2-digit",
2789
+ hour: "2-digit",
2790
+ minute: "2-digit",
2791
+ second: "2-digit"
2792
+ });
2793
+ const parts = dtf.formatToParts(new Date(utcMillis));
2794
+ const get = (type) => Number(parts.find((p) => p.type === type)?.value);
2795
+ const asUTC = Date.UTC(get("year"), get("month") - 1, get("day"), get("hour"), get("minute"), get("second"));
2796
+ return asUTC - utcMillis;
2797
+ }
2798
+ function zonedStartOfDayMillis(year, month, day, timeZone) {
2799
+ const utcGuess = Date.UTC(year, month - 1, day, 0, 0, 0, 0);
2800
+ if (!timeZone) return utcGuess;
2801
+ return utcGuess - tzOffsetMillis(utcGuess, timeZone);
2802
+ }
2803
+ function zonedDayBoundaryMillis(year, month, day, endOfDay, timeZone) {
2804
+ if (endOfDay) return zonedStartOfDayMillis(year, month, day + 1, timeZone) - 1;
2805
+ return zonedStartOfDayMillis(year, month, day, timeZone);
2806
+ }
2807
+ function toEpochMillis(value, opts = {}) {
2808
+ const trimmed = value.trim();
2809
+ if (/^\d+$/.test(trimmed)) {
2810
+ if (trimmed.length === 13) return trimmed;
2811
+ throw new Error(`Ambiguous numeric date "${value}" for free-slots \u2014 pass epoch MILLISECONDS (13 digits), a YYYY-MM-DD date, or a full ISO datetime.`);
2812
+ }
2813
+ const dateOnly = /^(\d{4})-(\d{2})-(\d{2})$/.exec(trimmed);
2814
+ if (dateOnly) {
2815
+ const millis = zonedDayBoundaryMillis(
2816
+ Number(dateOnly[1]),
2817
+ Number(dateOnly[2]),
2818
+ Number(dateOnly[3]),
2819
+ Boolean(opts.endOfDay),
2820
+ opts.timeZone
2821
+ );
2822
+ return String(millis);
2823
+ }
2824
+ const parsed = Date.parse(trimmed);
2825
+ if (!Number.isNaN(parsed)) return String(parsed);
2826
+ throw new Error(`Invalid date "${value}" for free-slots \u2014 use YYYY-MM-DD, a full ISO datetime, or epoch milliseconds.`);
2827
+ }
2828
+ function buildFreeSlotsParams(args) {
2829
+ const params = {
2830
+ startDate: toEpochMillis(args.startDate, { timeZone: args.timezone }),
2831
+ endDate: toEpochMillis(args.endDate, { endOfDay: true, timeZone: args.timezone })
2832
+ };
2833
+ if (args.timezone !== void 0) params.timezone = args.timezone;
2834
+ if (args.userId !== void 0) params.userId = args.userId;
2835
+ return params;
2836
+ }
2730
2837
  function registerCalendarTools(server2, client) {
2731
2838
  safeTool(
2732
2839
  server2,
@@ -2771,25 +2878,15 @@ function registerCalendarTools(server2, client) {
2771
2878
  slotDuration: import_zod9.z.number().optional().describe("Slot duration in minutes"),
2772
2879
  slotBuffer: import_zod9.z.number().optional().describe("Buffer time between slots in minutes"),
2773
2880
  slotInterval: import_zod9.z.number().optional().describe("Slot interval in minutes"),
2774
- appointmentPerSlot: import_zod9.z.number().optional().describe("Max appointments per slot")
2881
+ appointmentPerSlot: import_zod9.z.number().optional().describe("Max appointments per slot"),
2882
+ openHours: import_zod9.z.array(OpenHoursBlockSchema).optional().describe(
2883
+ "Weekly business hours that make slots bookable (the 'assign availability hours' step). Each entry maps weekdays (0=Sun \u2026 6=Sat) to one or more open windows on a 24-hour clock; multi-day entries are auto-expanded to GHL's required one-block-per-day form. Example Mon-Fri 9-6 + Sat 10-1: [{daysOfTheWeek:[1,2,3,4,5],hours:[{openHour:9,openMinute:0,closeHour:18,closeMinute:0}]},{daysOfTheWeek:[6],hours:[{openHour:10,openMinute:0,closeHour:13,closeMinute:0}]}]. Behavior (verified live): on event/simple calendars these hours are the sole source of availability. On round_robin calendars the bookable slots are the INTERSECTION of these hours and each assigned user's working hours, so a day only opens if a team member is also available then (e.g. a Saturday window needs a user with Saturday availability). Omit to use GHL's defaults."
2884
+ ),
2885
+ availabilityType: import_zod9.z.number().int().optional().describe("Availability mode. 0 = standard weekly hours (from openHours); auto-set when you pass openHours. Leave unset otherwise.")
2775
2886
  },
2776
- async ({ locationId: locationId2, name, description, slug, widgetSlug, calendarType, teamMembers, eventTitle, eventColor, slotDuration, slotBuffer, slotInterval, appointmentPerSlot }) => {
2777
- const resolvedLocationId = client.resolveLocationId(locationId2);
2778
- const body = {
2779
- locationId: resolvedLocationId,
2780
- name
2781
- };
2782
- if (description !== void 0) body.description = description;
2783
- if (slug !== void 0) body.slug = slug;
2784
- if (widgetSlug !== void 0) body.widgetSlug = widgetSlug;
2785
- if (calendarType !== void 0) body.calendarType = calendarType;
2786
- if (teamMembers !== void 0) body.teamMembers = teamMembers;
2787
- if (eventTitle !== void 0) body.eventTitle = eventTitle;
2788
- if (eventColor !== void 0) body.eventColor = eventColor;
2789
- if (slotDuration !== void 0) body.slotDuration = slotDuration;
2790
- if (slotBuffer !== void 0) body.slotBuffer = slotBuffer;
2791
- if (slotInterval !== void 0) body.slotInterval = slotInterval;
2792
- if (appointmentPerSlot !== void 0) body.appointmentPerSlot = appointmentPerSlot;
2887
+ async (args) => {
2888
+ const resolvedLocationId = client.resolveLocationId(args.locationId);
2889
+ const body = buildCreateCalendarBody(args, resolvedLocationId);
2793
2890
  return await client.post("/calendars/", { body });
2794
2891
  }
2795
2892
  );
@@ -2810,23 +2907,15 @@ function registerCalendarTools(server2, client) {
2810
2907
  slotDuration: import_zod9.z.number().optional().describe("Slot duration in minutes"),
2811
2908
  slotBuffer: import_zod9.z.number().optional().describe("Buffer time between slots in minutes"),
2812
2909
  slotInterval: import_zod9.z.number().optional().describe("Slot interval in minutes"),
2813
- appointmentPerSlot: import_zod9.z.number().optional().describe("Max appointments per slot")
2910
+ appointmentPerSlot: import_zod9.z.number().optional().describe("Max appointments per slot"),
2911
+ openHours: import_zod9.z.array(OpenHoursBlockSchema).optional().describe(
2912
+ "Weekly business hours that make slots bookable. Each entry maps weekdays (0=Sun \u2026 6=Sat) to one or more open windows on a 24-hour clock; multi-day entries are auto-expanded to GHL's required one-block-per-day form (e.g. [{daysOfTheWeek:[1,2,3,4,5],hours:[{openHour:9,openMinute:0,closeHour:18,closeMinute:0}]}] = Mon-Fri 9am-6pm). Replaces the calendar's existing hours. Behavior (verified live): event/simple calendars use these hours directly; round_robin calendars intersect them with each assigned user's working hours (a day only opens if a team member is available then)."
2913
+ ),
2914
+ availabilityType: import_zod9.z.number().int().optional().describe("Availability mode. 0 = standard weekly hours (from openHours); auto-set when you pass openHours. Leave unset otherwise.")
2814
2915
  },
2815
- async ({ calendarId, name, description, slug, widgetSlug, calendarType, teamMembers, eventTitle, eventColor, slotDuration, slotBuffer, slotInterval, appointmentPerSlot }) => {
2816
- const body = {};
2817
- if (name !== void 0) body.name = name;
2818
- if (description !== void 0) body.description = description;
2819
- if (slug !== void 0) body.slug = slug;
2820
- if (widgetSlug !== void 0) body.widgetSlug = widgetSlug;
2821
- if (calendarType !== void 0) body.calendarType = calendarType;
2822
- if (teamMembers !== void 0) body.teamMembers = teamMembers;
2823
- if (eventTitle !== void 0) body.eventTitle = eventTitle;
2824
- if (eventColor !== void 0) body.eventColor = eventColor;
2825
- if (slotDuration !== void 0) body.slotDuration = slotDuration;
2826
- if (slotBuffer !== void 0) body.slotBuffer = slotBuffer;
2827
- if (slotInterval !== void 0) body.slotInterval = slotInterval;
2828
- if (appointmentPerSlot !== void 0) body.appointmentPerSlot = appointmentPerSlot;
2829
- return await client.put(`/calendars/${calendarId}`, { body });
2916
+ async (args) => {
2917
+ const body = buildUpdateCalendarBody(args);
2918
+ return await client.put(`/calendars/${args.calendarId}`, { body });
2830
2919
  }
2831
2920
  );
2832
2921
  safeTool(
@@ -2847,15 +2936,13 @@ function registerCalendarTools(server2, client) {
2847
2936
  "Get available free slots for a calendar",
2848
2937
  {
2849
2938
  calendarId: import_zod9.z.string().describe("The calendar ID"),
2850
- startDate: import_zod9.z.string().describe("Start date in ISO format (YYYY-MM-DD)"),
2851
- endDate: import_zod9.z.string().describe("End date in ISO format (YYYY-MM-DD)"),
2939
+ startDate: import_zod9.z.string().describe("Start of the window. Accepts a date (YYYY-MM-DD), a full ISO datetime, or epoch milliseconds. A bare date is taken as start-of-day in `timezone` (UTC if unset). GHL's API needs epoch ms; the tool converts for you."),
2940
+ endDate: import_zod9.z.string().describe("End of the window. Accepts a date (YYYY-MM-DD), a full ISO datetime, or epoch milliseconds. A bare date is taken as end-of-day in `timezone` (UTC if unset)."),
2852
2941
  timezone: import_zod9.z.string().optional().describe("Timezone (e.g. America/New_York)"),
2853
2942
  userId: import_zod9.z.string().optional().describe("Filter by user ID")
2854
2943
  },
2855
2944
  async ({ calendarId, startDate, endDate, timezone, userId }) => {
2856
- const params = { startDate, endDate };
2857
- if (timezone !== void 0) params.timezone = timezone;
2858
- if (userId !== void 0) params.userId = userId;
2945
+ const params = buildFreeSlotsParams({ startDate, endDate, timezone, userId });
2859
2946
  return await client.get(`/calendars/${calendarId}/free-slots`, {
2860
2947
  params
2861
2948
  });
@@ -5973,13 +6060,34 @@ ${text2}`);
5973
6060
 
5974
6061
  // src/tools/form-builder.ts
5975
6062
  var import_zod35 = require("zod");
6063
+ function pickFormName(builderForm) {
6064
+ if (builderForm && typeof builderForm === "object" && "form" in builderForm) {
6065
+ const name = builderForm.form?.name;
6066
+ if (typeof name === "string" && name.length > 0) return name;
6067
+ }
6068
+ return void 0;
6069
+ }
6070
+ function findFormNameInList(list, formId) {
6071
+ const forms = list?.forms;
6072
+ if (Array.isArray(forms)) {
6073
+ for (const f of forms) {
6074
+ if (f && typeof f === "object") {
6075
+ const entry = f;
6076
+ if ((entry.id === formId || entry._id === formId) && typeof entry.name === "string" && entry.name.length > 0) {
6077
+ return entry.name;
6078
+ }
6079
+ }
6080
+ }
6081
+ }
6082
+ return void 0;
6083
+ }
5976
6084
  function buildUpdateFormPath(formId, locationId2) {
5977
6085
  return `/${formId}?locationId=${locationId2}`;
5978
6086
  }
5979
6087
  function buildUpdateFormBody(name, formData) {
5980
6088
  return { name, formData };
5981
6089
  }
5982
- function registerFormBuilderTools(server2, builderClient) {
6090
+ function registerFormBuilderTools(server2, builderClient, publicClient) {
5983
6091
  const client = builderClient;
5984
6092
  if (!client) return;
5985
6093
  async function formRequest(method, path7, body) {
@@ -6033,11 +6141,28 @@ ${text2}`);
6033
6141
  let resolvedName = name;
6034
6142
  if (resolvedName === void 0) {
6035
6143
  const current = await formRequest("GET", `/${formId}?locationId=${client.locationId}`);
6036
- const currentName = typeof current === "object" && current !== null && "form" in current ? current.form?.name : void 0;
6037
- if (typeof currentName !== "string") {
6038
- throw new Error(`Could not resolve current form name for ${formId} (GET /forms/${formId} returned no string name).`);
6144
+ resolvedName = pickFormName(current);
6145
+ if (resolvedName === void 0 && publicClient) {
6146
+ try {
6147
+ const pageSize = 100;
6148
+ const maxForms = 5e3;
6149
+ for (let skip = 0; skip < maxForms; skip += pageSize) {
6150
+ const list = await publicClient.get("/forms/", {
6151
+ params: { locationId: client.locationId, limit: pageSize, skip }
6152
+ });
6153
+ resolvedName = findFormNameInList(list, formId);
6154
+ if (resolvedName !== void 0) break;
6155
+ const forms = list?.forms;
6156
+ if (!Array.isArray(forms) || forms.length < pageSize) break;
6157
+ }
6158
+ } catch {
6159
+ }
6160
+ }
6161
+ if (resolvedName === void 0) {
6162
+ throw new Error(
6163
+ `Could not resolve the current name for form ${formId}. Pass the \`name\` argument explicitly \u2014 a form created via create_form has no builder-doc name until its first save.`
6164
+ );
6039
6165
  }
6040
- resolvedName = currentName;
6041
6166
  }
6042
6167
  const result = await formRequest(
6043
6168
  "POST",
@@ -9511,7 +9636,6 @@ var publicApiTools = [
9511
9636
  var internalApiTools = [
9512
9637
  [registerWorkflowBuilderTools, "workflow-builder"],
9513
9638
  [registerFunnelBuilderTools, "funnel-builder"],
9514
- [registerFormBuilderTools, "form-builder"],
9515
9639
  [registerPipelineBuilderTools, "pipeline-builder"],
9516
9640
  [registerWorkflowClonerTools, "workflow-cloner"],
9517
9641
  [registerSmartListTools, "smart-lists"],
@@ -9524,9 +9648,11 @@ var VALIDATORS_MODULE = "validators";
9524
9648
  var DIAGNOSTICS_MODULE = "diagnostics";
9525
9649
  var LOCATION_SWITCHER_MODULE = "location-switcher";
9526
9650
  var SNAPSHOTS_MODULE = "snapshots";
9651
+ var FORM_BUILDER_MODULE = "form-builder";
9527
9652
  var KNOWN_MODULES = /* @__PURE__ */ new Set([
9528
9653
  ...publicApiTools.map(([, label]) => label),
9529
9654
  ...internalApiTools.map(([, label]) => label),
9655
+ FORM_BUILDER_MODULE,
9530
9656
  VALIDATORS_MODULE,
9531
9657
  DIAGNOSTICS_MODULE,
9532
9658
  LOCATION_SWITCHER_MODULE,
@@ -9544,6 +9670,7 @@ function registerAllTools(server2, client, registry2, mcpVersion, env = process.
9544
9670
  for (const [register, moduleName] of internalApiTools) {
9545
9671
  register(wrap(moduleName), builderClient);
9546
9672
  }
9673
+ registerFormBuilderTools(wrap(FORM_BUILDER_MODULE), builderClient, client);
9547
9674
  registerValidatorTools(wrap(VALIDATORS_MODULE), client, builderClient);
9548
9675
  registerDiagnosticTools(
9549
9676
  wrap(DIAGNOSTICS_MODULE),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elitedcs/ghl-mcp",
3
- "version": "3.34.8",
3
+ "version": "3.34.10",
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",