@elitedcs/ghl-mcp 3.17.1 → 3.18.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,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.18.0 — Social Planner: location-scoped endpoints, scheduled posts, typed media
4
+
5
+ **No new tools (still 212 across 43 modules) — fixes plus a capability add to the existing Social Planner tools.**
6
+
7
+ - Every Social Planner call (`get_social_posts`, `get_social_post`, `delete_social_post`, `get_social_media_accounts`, `create_social_post`) now hits the correct location-scoped v2 path (`/social-media-posting/{locationId}/...`). The bare paths were returning errors.
8
+ - `create_social_post` now supports **scheduled posts**: pass `scheduledAt` (sent as `scheduleDate`) with `status: "scheduled"`. `status` is a typed enum: `in_review`, `scheduled`, `draft`, `published`.
9
+ - Media items are typed — each URL is sent as `{ url, type }` with the MIME type inferred. Scheduled posts reject untyped media (and Instagram requires at least one media item).
10
+
3
11
  ## 3.17.1 — Onboarding messaging fixes + public feedback tracker
4
12
 
5
13
  **No tool changes — still 212 across 43 modules.** Bug-driven fixes from a buyer support ticket (Ryan Thomas, 2026-05-25), plus a public place to file feedback.
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.17.1",
34
+ version: "3.18.0",
35
35
  description: "GoHighLevel MCP Server for Claude. 212 tools \u2014 full CRM, automation, marketing control, and the only programmatic GHL workflow builder, now multi-tenant across client accounts.",
36
36
  main: "dist/index.js",
37
37
  bin: {
@@ -3606,18 +3606,22 @@ function registerSocialPlannerTools(server2, client) {
3606
3606
  fromDate: import_zod21.z.string().optional().describe("Start date filter (ISO string)"),
3607
3607
  toDate: import_zod21.z.string().optional().describe("End date filter (ISO string)"),
3608
3608
  includeUsers: import_zod21.z.boolean().optional().describe("Whether to include user details"),
3609
- status: import_zod21.z.enum(["in_review", "scheduled", "published", "failed", "in_progress"]).optional().describe("Post status filter")
3609
+ status: import_zod21.z.enum(["in_review", "scheduled", "published", "failed", "in_progress"]).optional().describe("Post status filter"),
3610
+ skip: import_zod21.z.number().optional().describe("Pagination offset"),
3611
+ limit: import_zod21.z.number().optional().describe("Page size")
3610
3612
  },
3611
- async ({ locationId: locationId2, type, accounts, fromDate, toDate, includeUsers, status }) => {
3613
+ async ({ locationId: locationId2, type, accounts, fromDate, toDate, includeUsers, status, skip, limit }) => {
3612
3614
  const resolvedLocationId = client.resolveLocationId(locationId2);
3613
- const params = { locationId: resolvedLocationId };
3614
- if (type !== void 0) params.type = type;
3615
- if (accounts !== void 0) params.accounts = accounts;
3616
- if (fromDate !== void 0) params.fromDate = fromDate;
3617
- if (toDate !== void 0) params.toDate = toDate;
3618
- if (includeUsers !== void 0) params.includeUsers = includeUsers;
3619
- if (status !== void 0) params.status = status;
3620
- return client.get("/social-media-posting/", { params });
3615
+ const body = {};
3616
+ if (type !== void 0) body.type = type;
3617
+ if (accounts !== void 0) body.accounts = accounts;
3618
+ if (fromDate !== void 0) body.fromDate = fromDate;
3619
+ if (toDate !== void 0) body.toDate = toDate;
3620
+ if (includeUsers !== void 0) body.includeUsers = includeUsers;
3621
+ if (status !== void 0) body.status = status;
3622
+ body.skip = skip ?? 0;
3623
+ body.limit = limit ?? 20;
3624
+ return client.post(`/social-media-posting/${resolvedLocationId}/posts/list`, { body });
3621
3625
  }
3622
3626
  );
3623
3627
  safeTool(
@@ -3625,10 +3629,12 @@ function registerSocialPlannerTools(server2, client) {
3625
3629
  "get_social_post",
3626
3630
  "Get a single social media post by ID",
3627
3631
  {
3628
- postId: import_zod21.z.string().describe("The social media post ID")
3632
+ postId: import_zod21.z.string().describe("The social media post ID"),
3633
+ locationId: import_zod21.z.string().optional().describe("GHL Location ID (optional if GHL_LOCATION_ID is set)")
3629
3634
  },
3630
- async ({ postId }) => {
3631
- return client.get(`/social-media-posting/${postId}`);
3635
+ async ({ postId, locationId: locationId2 }) => {
3636
+ const resolvedLocationId = client.resolveLocationId(locationId2);
3637
+ return client.get(`/social-media-posting/${resolvedLocationId}/posts/${postId}`);
3632
3638
  }
3633
3639
  );
3634
3640
  safeTool(
@@ -3636,13 +3642,16 @@ function registerSocialPlannerTools(server2, client) {
3636
3642
  "delete_social_post",
3637
3643
  "Delete a social media post",
3638
3644
  {
3639
- postId: import_zod21.z.string().describe("The social media post ID to delete")
3645
+ postId: import_zod21.z.string().describe("The social media post ID to delete"),
3646
+ locationId: import_zod21.z.string().optional().describe("GHL Location ID (optional if GHL_LOCATION_ID is set)")
3640
3647
  },
3641
- async ({ postId }) => {
3642
- return client.delete(`/social-media-posting/${postId}`);
3648
+ async ({ postId, locationId: locationId2 }) => {
3649
+ const resolvedLocationId = client.resolveLocationId(locationId2);
3650
+ return client.delete(`/social-media-posting/${resolvedLocationId}/posts/${postId}`);
3643
3651
  }
3644
3652
  );
3645
- server2.tool(
3653
+ safeTool(
3654
+ server2,
3646
3655
  "get_social_media_accounts",
3647
3656
  "Get connected social media accounts for a location",
3648
3657
  {
@@ -3650,21 +3659,7 @@ function registerSocialPlannerTools(server2, client) {
3650
3659
  },
3651
3660
  async ({ locationId: locationId2 }) => {
3652
3661
  const resolvedLocationId = client.resolveLocationId(locationId2);
3653
- try {
3654
- const result = await client.get(
3655
- `/social-media-posting/oauth/${resolvedLocationId}/accounts`
3656
- );
3657
- return jsonResponse(result);
3658
- } catch {
3659
- try {
3660
- const result = await client.get(
3661
- `/social-media-posting/oauth/facebook/accounts/${resolvedLocationId}`
3662
- );
3663
- return jsonResponse(result);
3664
- } catch (fallbackError) {
3665
- return errorResponse(fallbackError);
3666
- }
3667
- }
3662
+ return client.get(`/social-media-posting/${resolvedLocationId}/accounts`);
3668
3663
  }
3669
3664
  );
3670
3665
  safeTool(
@@ -3674,9 +3669,11 @@ function registerSocialPlannerTools(server2, client) {
3674
3669
  {
3675
3670
  locationId: import_zod21.z.string().optional().describe("GHL Location ID (optional if GHL_LOCATION_ID is set)"),
3676
3671
  accountIds: import_zod21.z.array(import_zod21.z.string()).describe("Array of social account IDs to post to"),
3672
+ userId: import_zod21.z.string().optional().describe("GHL user ID that authors the post (required by the API; falls back to GHL_USER_ID env)"),
3677
3673
  summary: import_zod21.z.string().optional().describe("The post text/caption"),
3678
3674
  media: import_zod21.z.array(import_zod21.z.string()).optional().describe("Array of media URLs to attach"),
3679
- status: import_zod21.z.enum(["in_review", "scheduled", "draft"]).optional().describe("Post status"),
3675
+ type: import_zod21.z.enum(["post", "story", "reel"]).optional().describe("Post type (default post)"),
3676
+ status: import_zod21.z.enum(["in_review", "scheduled", "draft", "published"]).optional().describe("Post status"),
3680
3677
  scheduledAt: import_zod21.z.string().optional().describe("Scheduled publish time (ISO string)"),
3681
3678
  tags: import_zod21.z.array(import_zod21.z.string()).optional().describe("Tags for the post"),
3682
3679
  ogData: import_zod21.z.object({
@@ -3685,16 +3682,41 @@ function registerSocialPlannerTools(server2, client) {
3685
3682
  image: import_zod21.z.string().optional()
3686
3683
  }).optional().describe("Open Graph data for link previews")
3687
3684
  },
3688
- async ({ locationId: locationId2, accountIds, summary, media, status, scheduledAt, tags, ogData }) => {
3685
+ async ({ locationId: locationId2, accountIds, userId, summary, media, type, status, scheduledAt, tags, ogData }) => {
3689
3686
  const resolvedLocationId = client.resolveLocationId(locationId2);
3690
- const body = { locationId: resolvedLocationId, accountIds };
3687
+ const resolvedUserId = userId ?? process.env.GHL_USER_ID;
3688
+ if (!resolvedUserId) {
3689
+ throw new Error(
3690
+ "create_social_post requires a userId (the post author). Pass userId or set GHL_USER_ID."
3691
+ );
3692
+ }
3693
+ const body = {
3694
+ accountIds,
3695
+ userId: resolvedUserId,
3696
+ type: type ?? "post"
3697
+ };
3691
3698
  if (summary !== void 0) body.summary = summary;
3692
- if (media !== void 0) body.media = media;
3699
+ if (media !== void 0) {
3700
+ const mimeFor = (url) => {
3701
+ const ext = url.split("?")[0].split(".").pop()?.toLowerCase() ?? "";
3702
+ const map = {
3703
+ png: "image/png",
3704
+ jpg: "image/jpeg",
3705
+ jpeg: "image/jpeg",
3706
+ gif: "image/gif",
3707
+ webp: "image/webp",
3708
+ mp4: "video/mp4",
3709
+ mov: "video/quicktime"
3710
+ };
3711
+ return map[ext] ?? "image/png";
3712
+ };
3713
+ body.media = media.map((url) => ({ url, type: mimeFor(url) }));
3714
+ }
3693
3715
  if (status !== void 0) body.status = status;
3694
- if (scheduledAt !== void 0) body.scheduledAt = scheduledAt;
3716
+ if (scheduledAt !== void 0) body.scheduleDate = scheduledAt;
3695
3717
  if (tags !== void 0) body.tags = tags;
3696
3718
  if (ogData !== void 0) body.ogData = ogData;
3697
- return client.post("/social-media-posting/", { body });
3719
+ return client.post(`/social-media-posting/${resolvedLocationId}/posts`, { body });
3698
3720
  }
3699
3721
  );
3700
3722
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elitedcs/ghl-mcp",
3
- "version": "3.17.1",
3
+ "version": "3.18.0",
4
4
  "description": "GoHighLevel MCP Server for Claude. 212 tools — full CRM, automation, marketing control, and the only programmatic GHL workflow builder, now multi-tenant across client accounts.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {