@elitedcs/ghl-mcp 3.62.0 → 3.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.63.0 — the guide library grows from 3 guides to 20
4
+
5
+ - **`get_user_guide` now opens a 20-guide library.** Seventeen guides were
6
+ written and proven live but had never shipped, so anyone running
7
+ `get user guide` was still getting the three-guide edition. The bundled
8
+ offline guide goes from 43KB to 111KB: 20 open guides, 10 still marked
9
+ "Available in the app" until their prompts are proven. Every prompt marked
10
+ "Proven live" was run against a real GoHighLevel account before it shipped.
11
+ - Same library renders to ghlcommand.com/skills, so the in-product guide and
12
+ the website always match.
13
+ - **Fix: reading appointments returned nothing.** `get_calendar_events` sent
14
+ ISO timestamps, but GHL's `/calendars/events` needs epoch milliseconds and
15
+ answers a wrong-format request with `200` and an empty array instead of an
16
+ error — so a calendar holding real confirmed bookings read back as "nothing
17
+ booked". Now converts via the timezone-aware helper free-slots already used,
18
+ plus an optional `timezone` parameter so a bare `YYYY-MM-DD` window resolves
19
+ in the sub-account's timezone (end date inclusive). Live-proven both
20
+ directions.
21
+
22
+ ## 3.62.1 — update_pipeline works again (Bug 8)
23
+
24
+ - **Fix: `update_pipeline` no longer 422s.** GHL's pipeline PUT rejects unknown
25
+ body properties, and the request body was seeded with `locationId` — so every
26
+ update died with "property locationId should not exist" before the stages were
27
+ read. locationId now rides as a query parameter (the same pattern
28
+ `delete_pipeline` already used). Live-proven on the sandbox with the case that
29
+ matters: existing stage IDs survive the update (rename + reorder + append in
30
+ one call), so open opportunities are never orphaned. New regression proof:
31
+ `scripts/pipeline-update-proof.mjs`.
32
+ - Trigger reference: `custom_date_reminder` real UI-generated shape captured
33
+ (conditions + custom_date_reminder_config; before-days variant — after-days
34
+ still unverified).
35
+ - Action reference: the workflow Email action has NO "to" field — it always
36
+ mails the enrolled contact; third parties are copied via `cc` (merge fields
37
+ supported). Documented so nobody builds a "send to a third party" node that
38
+ silently mails the contact.
39
+
40
+
3
41
  ## 3.62.0 — The user guide ships inside the product
4
42
 
5
43
  - **New tool `get_user_guide`** (free tier included): opens the full GHL Command
package/dist/index.js CHANGED
@@ -2854,7 +2854,7 @@ var require_package = __commonJS({
2854
2854
  "package.json"(exports2, module2) {
2855
2855
  module2.exports = {
2856
2856
  name: "@elitedcs/ghl-mcp",
2857
- version: "3.62.0",
2857
+ version: "3.63.0",
2858
2858
  mcpName: "io.github.drjerryrelth/ghl-command",
2859
2859
  description: "GoHighLevel MCP Server for Claude. 235 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.",
2860
2860
  main: "dist/index.js",
@@ -7643,7 +7643,7 @@ function toEpochMillis(value, opts = {}) {
7643
7643
  const trimmed = value.trim();
7644
7644
  if (/^\d+$/.test(trimmed)) {
7645
7645
  if (trimmed.length === 13) return trimmed;
7646
- 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.`);
7646
+ throw new Error(`Ambiguous numeric date "${value}" \u2014 pass epoch MILLISECONDS (13 digits), a YYYY-MM-DD date, or a full ISO datetime.`);
7647
7647
  }
7648
7648
  const dateOnly = /^(\d{4})-(\d{2})-(\d{2})$/.exec(trimmed);
7649
7649
  if (dateOnly) {
@@ -7658,7 +7658,7 @@ function toEpochMillis(value, opts = {}) {
7658
7658
  }
7659
7659
  const parsed = Date.parse(trimmed);
7660
7660
  if (!Number.isNaN(parsed)) return String(parsed);
7661
- throw new Error(`Invalid date "${value}" for free-slots \u2014 use YYYY-MM-DD, a full ISO datetime, or epoch milliseconds.`);
7661
+ throw new Error(`Invalid date "${value}" \u2014 use YYYY-MM-DD, a full ISO datetime, or epoch milliseconds.`);
7662
7662
  }
7663
7663
  function buildFreeSlotsParams(args) {
7664
7664
  const params = {
@@ -7669,6 +7669,16 @@ function buildFreeSlotsParams(args) {
7669
7669
  if (args.userId !== void 0) params.userId = args.userId;
7670
7670
  return params;
7671
7671
  }
7672
+ function buildCalendarEventsParams(args) {
7673
+ const params = {
7674
+ locationId: args.locationId,
7675
+ startTime: toEpochMillis(args.startTime, { timeZone: args.timezone }),
7676
+ endTime: toEpochMillis(args.endTime, { endOfDay: true, timeZone: args.timezone })
7677
+ };
7678
+ if (args.calendarId !== void 0) params.calendarId = args.calendarId;
7679
+ if (args.userId !== void 0) params.userId = args.userId;
7680
+ return params;
7681
+ }
7672
7682
  function registerCalendarTools(server2, client) {
7673
7683
  safeTool(
7674
7684
  server2,
@@ -7789,20 +7799,25 @@ function registerCalendarTools(server2, client) {
7789
7799
  "List calendar events for a location within a time range",
7790
7800
  {
7791
7801
  locationId: import_zod12.z.string().optional().describe("Location ID (falls back to GHL_LOCATION_ID env var)"),
7792
- startTime: import_zod12.z.string().describe("Start time in ISO format"),
7793
- endTime: import_zod12.z.string().describe("End time in ISO format"),
7802
+ startTime: import_zod12.z.string().describe(
7803
+ "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 needs epoch ms here; the tool converts for you."
7804
+ ),
7805
+ endTime: import_zod12.z.string().describe(
7806
+ "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 that day, inclusive, in `timezone`."
7807
+ ),
7808
+ timezone: import_zod12.z.string().optional().describe("IANA timezone (e.g. America/Phoenix) used to resolve bare YYYY-MM-DD dates. Defaults to UTC."),
7794
7809
  calendarId: import_zod12.z.string().optional().describe("Filter by calendar ID"),
7795
7810
  userId: import_zod12.z.string().optional().describe("Filter by user ID")
7796
7811
  },
7797
- async ({ locationId: locationId2, startTime, endTime, calendarId, userId }) => {
7798
- const resolvedLocationId = client.resolveLocationId(locationId2);
7799
- const params = {
7800
- locationId: resolvedLocationId,
7812
+ async ({ locationId: locationId2, startTime, endTime, timezone, calendarId, userId }) => {
7813
+ const params = buildCalendarEventsParams({
7814
+ locationId: client.resolveLocationId(locationId2),
7801
7815
  startTime,
7802
- endTime
7803
- };
7804
- if (calendarId !== void 0) params.calendarId = calendarId;
7805
- if (userId !== void 0) params.userId = userId;
7816
+ endTime,
7817
+ timezone,
7818
+ calendarId,
7819
+ userId
7820
+ });
7806
7821
  return await client.get("/calendars/events", { params });
7807
7822
  }
7808
7823
  );
@@ -12486,7 +12501,7 @@ ${text2}`);
12486
12501
  },
12487
12502
  async ({ pipelineId }) => {
12488
12503
  try {
12489
- const result = await pipelineRequest("GET", `/${pipelineId}?locationId=${client.locationId}`);
12504
+ const result = await pipelineRequest("GET", `/${encodeURIComponent(pipelineId)}?locationId=${client.locationId}`);
12490
12505
  return {
12491
12506
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
12492
12507
  };
@@ -12556,12 +12571,12 @@ ${text2}`);
12556
12571
  },
12557
12572
  async ({ pipelineId, name, stages, showInFunnel, showInPieChart }) => {
12558
12573
  try {
12559
- const body = { locationId: client.locationId };
12574
+ const body = {};
12560
12575
  if (name !== void 0) body.name = name;
12561
12576
  if (stages !== void 0) body.stages = stages;
12562
12577
  if (showInFunnel !== void 0) body.showInFunnel = showInFunnel;
12563
12578
  if (showInPieChart !== void 0) body.showInPieChart = showInPieChart;
12564
- const result = await pipelineRequest("PUT", `/${pipelineId}`, body);
12579
+ const result = await pipelineRequest("PUT", `/${encodeURIComponent(pipelineId)}?locationId=${client.locationId}`, body);
12565
12580
  return {
12566
12581
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
12567
12582
  };
@@ -12580,7 +12595,7 @@ ${text2}`);
12580
12595
  },
12581
12596
  async ({ pipelineId }) => {
12582
12597
  try {
12583
- const result = await pipelineRequest("DELETE", `/${pipelineId}?locationId=${client.locationId}`);
12598
+ const result = await pipelineRequest("DELETE", `/${encodeURIComponent(pipelineId)}?locationId=${client.locationId}`);
12584
12599
  return {
12585
12600
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
12586
12601
  };