@elitedcs/ghl-mcp 3.34.7 → 3.34.8

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,35 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.34.8 — create_opportunity + get_funnel_pages no longer 422 on omitted required params
4
+
5
+ Two real defects found during a full end-to-end build test on a live sub-account
6
+ (every advertised object created, read back, and deleted). Both are cases where GHL
7
+ requires a parameter the tool treated as optional, so the call 422'd unless the
8
+ caller happened to pass it.
9
+
10
+ - **`create_opportunity` now defaults `status` to `"open"`.** GHL's
11
+ `POST /opportunities/` rejects a create with no status (`422 "status should not
12
+ be empty"`). The tool exposed `status` as optional and omitted it from the body,
13
+ so a bare create always failed. It now sends `status: "open"` when the caller
14
+ doesn't specify one. Logic extracted to `buildCreateOpportunityBody` with tests.
15
+ - **`get_funnel_pages` now defaults `limit`/`offset`.** GHL's `GET /funnels/page`
16
+ requires both (`422 "limit should not be empty" / "offset should not be empty"`)
17
+ and caps `limit` at 20. The tool only sent them when provided, so listing a
18
+ funnel's pages failed by default. It now sends `limit: 20, offset: 0` when
19
+ omitted. (`get_funnels` / `GET /funnels/funnel/list` does not require them and is
20
+ unchanged.) Logic extracted to `buildFunnelPagesParams` with tests.
21
+
22
+ Verified working in the same test pass (no change needed): create_funnel,
23
+ create_funnel_page, create_form, create_calendar (incl. team-member assignment),
24
+ create_custom_field, create_location_tag, create_contact, and the full workflow
25
+ lifecycle (create → update actions → validate → publish). Suite 280 pass / 1 skip.
26
+
27
+ Known follow-up (not in this release): exposing calendar availability / `openHours`.
28
+ Investigation showed round-robin "OptimizeForAvailability" calendars derive
29
+ availability from the assigned user's working hours, not a calendar `openHours`
30
+ field (every live round-robin calendar inspected had `openHours: {}`), so this needs
31
+ a design + live write-verification pass before shipping rather than a guessed shape.
32
+
3
33
  ## 3.34.7 — Audit now sees UUID pipeline-stage ids (dead-stage silent failure)
4
34
 
5
35
  - **`audit_workflows` / `validate_workflow` now catch a dead pipeline STAGE
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.7",
34
+ version: "3.34.8",
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",
@@ -2540,6 +2540,20 @@ function registerConversationTools(server2, client) {
2540
2540
  var import_zod8 = require("zod");
2541
2541
  var statusEnum = import_zod8.z.enum(["open", "won", "lost", "abandoned"]).describe("Opportunity status");
2542
2542
  var statusEnumWithAll = import_zod8.z.enum(["open", "won", "lost", "abandoned", "all"]).describe("Opportunity status filter (use 'all' to include every status)");
2543
+ function buildCreateOpportunityBody(args, locationId2) {
2544
+ const body = {
2545
+ locationId: locationId2,
2546
+ pipelineId: args.pipelineId,
2547
+ pipelineStageId: args.pipelineStageId,
2548
+ contactId: args.contactId,
2549
+ name: args.name,
2550
+ status: args.status ?? "open"
2551
+ };
2552
+ if (args.monetaryValue !== void 0) body.monetaryValue = args.monetaryValue;
2553
+ if (args.assignedTo !== void 0) body.assignedTo = args.assignedTo;
2554
+ if (args.source !== void 0) body.source = args.source;
2555
+ return body;
2556
+ }
2543
2557
  function registerOpportunityTools(server2, client) {
2544
2558
  safeTool(
2545
2559
  server2,
@@ -2612,25 +2626,14 @@ function registerOpportunityTools(server2, client) {
2612
2626
  pipelineStageId: import_zod8.z.string().describe("Pipeline stage ID (required)"),
2613
2627
  contactId: import_zod8.z.string().describe("Contact ID (required)"),
2614
2628
  name: import_zod8.z.string().describe("Opportunity name (required)"),
2615
- status: statusEnum.optional().describe("Opportunity status"),
2629
+ status: statusEnum.optional().describe("Opportunity status. Defaults to 'open' (GHL requires a non-empty status on create)."),
2616
2630
  monetaryValue: import_zod8.z.number().optional().describe("Monetary value of the opportunity"),
2617
2631
  assignedTo: import_zod8.z.string().optional().describe("User ID to assign the opportunity to"),
2618
2632
  source: import_zod8.z.string().optional().describe("Lead source")
2619
2633
  },
2620
2634
  async (args) => {
2621
2635
  const locationId2 = client.resolveLocationId(args.locationId);
2622
- const body = {
2623
- locationId: locationId2,
2624
- pipelineId: args.pipelineId,
2625
- pipelineStageId: args.pipelineStageId,
2626
- contactId: args.contactId,
2627
- name: args.name
2628
- };
2629
- if (args.status !== void 0) body.status = args.status;
2630
- if (args.monetaryValue !== void 0)
2631
- body.monetaryValue = args.monetaryValue;
2632
- if (args.assignedTo !== void 0) body.assignedTo = args.assignedTo;
2633
- if (args.source !== void 0) body.source = args.source;
2636
+ const body = buildCreateOpportunityBody(args, locationId2);
2634
2637
  return await client.post("/opportunities/", { body });
2635
2638
  }
2636
2639
  );
@@ -3289,6 +3292,14 @@ function registerWorkflowTools(server2, client) {
3289
3292
 
3290
3293
  // src/tools/funnels.ts
3291
3294
  var import_zod12 = require("zod");
3295
+ function buildFunnelPagesParams(args) {
3296
+ return {
3297
+ locationId: args.locationId,
3298
+ funnelId: args.funnelId,
3299
+ limit: args.limit ?? 20,
3300
+ offset: args.offset ?? 0
3301
+ };
3302
+ }
3292
3303
  function registerFunnelTools(server2, client) {
3293
3304
  safeTool(
3294
3305
  server2,
@@ -3314,17 +3325,12 @@ function registerFunnelTools(server2, client) {
3314
3325
  {
3315
3326
  locationId: import_zod12.z.string().optional().describe("GHL Location ID (optional if GHL_LOCATION_ID is set)"),
3316
3327
  funnelId: import_zod12.z.string().describe("The funnel ID"),
3317
- limit: import_zod12.z.number().optional().describe("Max number of pages to return"),
3318
- offset: import_zod12.z.number().optional().describe("Offset for pagination")
3328
+ limit: import_zod12.z.number().optional().describe("Max number of pages to return (1-20). Defaults to 20 (GHL requires it and caps at 20)."),
3329
+ offset: import_zod12.z.number().optional().describe("Offset for pagination. Defaults to 0 (GHL requires it).")
3319
3330
  },
3320
3331
  async ({ locationId: locationId2, funnelId, limit, offset }) => {
3321
3332
  const resolvedLocationId = client.resolveLocationId(locationId2);
3322
- const params = {
3323
- locationId: resolvedLocationId,
3324
- funnelId
3325
- };
3326
- if (limit !== void 0) params.limit = limit;
3327
- if (offset !== void 0) params.offset = offset;
3333
+ const params = buildFunnelPagesParams({ locationId: resolvedLocationId, funnelId, limit, offset });
3328
3334
  return client.get("/funnels/page", { params });
3329
3335
  }
3330
3336
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elitedcs/ghl-mcp",
3
- "version": "3.34.7",
3
+ "version": "3.34.8",
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",