@elitedcs/ghl-mcp 3.15.0 → 3.16.1
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 +27 -0
- package/README.md +1 -1
- package/dist/index.js +213 -9
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.16.1 — Docs: correct enable_workflow_builder tool counts
|
|
4
|
+
|
|
5
|
+
**No tool changes. Still 212 tools across 43 modules (163 without Firebase, 49 Firebase-gated).**
|
|
6
|
+
|
|
7
|
+
The `enable_workflow_builder` tool description and its success message had drifted out of date, still quoting the pre-v3.15 numbers ("30 additional tools across 6 modules", "163 to 203", "203 total"). Corrected to the current 49 Firebase-gated tools (163 → 212) and expanded the module list to match what's actually gated (smart lists, reputation, email campaigns, email templates, and memberships, plus the pre-deploy validator, were all missing).
|
|
8
|
+
|
|
9
|
+
## 3.16.0 — Membership/course creates, SMS templates, reviews list (Firebase-gated)
|
|
10
|
+
|
|
11
|
+
**212 tools across 43 modules (+6). Build courses and SMS templates from Claude; read the reviews that come back.**
|
|
12
|
+
|
|
13
|
+
Six new write/read tools, all reverse-engineered from DevTools captures of the live GHL UI against the MCP Testing sandbox and verified end-to-end (each returns 2xx with the exact request shape these tools send). All require Firebase auth — the public bearer key 401s on each — so the no-Firebase tool count stays 163.
|
|
14
|
+
|
|
15
|
+
### New tools (6)
|
|
16
|
+
|
|
17
|
+
- **`create_course`** — create a membership course (a "product") with title + description.
|
|
18
|
+
- **`create_membership_category`** — add a category/module inside a course (groups lessons; supports drip days).
|
|
19
|
+
- **`create_membership_lesson`** — add a lesson (a "post") inside a category, with HTML body and content type.
|
|
20
|
+
- **`create_membership_offer`** — create the access grant that enrolls contacts into one or more courses. Free by default; supports recurring/one-time pricing.
|
|
21
|
+
- **`create_sms_template`** — create an SMS/text template (a "snippet") for the composer and SMS workflow actions; merge fields supported. Also creates email snippets via `type: "email"`.
|
|
22
|
+
- **`list_reviews`** — list the reviews a location has received (Google, Facebook, etc.) with rating, author, text, and reply status. **Fixes the long-standing "No Location Found" error:** the reviews endpoint resolves location through nested `filterParams[locationId][0][value]`, not a flat `locationId`. Responding to a review is still pending (needs a live review to capture).
|
|
23
|
+
|
|
24
|
+
Course/category/lesson/offer hit `backend.leadconnectorhq.com/membership/locations/{loc}/*`; reviews hit `backend.leadconnectorhq.com/reputation/reviews`; SMS templates hit `services.leadconnectorhq.com/snippets/{loc}`. All with the workflow-builder Firebase token.
|
|
25
|
+
|
|
26
|
+
### Still pending
|
|
27
|
+
|
|
28
|
+
Email-campaign delete/send/schedule live in a cross-origin iframe (`email-home-prod.leadconnectorhq.com`) that can't be black-box captured and whose REST paths 404 on the public host — deferred until a capture from inside that iframe.
|
|
29
|
+
|
|
3
30
|
## 3.15.0 — Email-template delete, rename, archive (Firebase-gated)
|
|
4
31
|
|
|
5
32
|
**206 tools across 43 modules (+3). Manage email templates without leaving Claude.**
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# GHL Command — GoHighLevel MCP Server
|
|
2
2
|
|
|
3
|
-
**Full GoHighLevel API access for Claude.**
|
|
3
|
+
**Full GoHighLevel API access for Claude.** 212 tools across 43 modules — manage contacts, conversations, pipelines, calendars, funnels, workflows, invoices, custom objects, webhooks, and more. **Includes full workflow builder, funnel/page editor, form builder, pipeline builder, bulk operations, account export, and workflow cloning** — capabilities no other GHL tool offers. **Multi-tenant:** one install can run the workflow builder across multiple clients' GHL accounts.
|
|
4
4
|
|
|
5
5
|
**Distributed via npm as [`@elitedcs/ghl-mcp`](https://www.npmjs.com/package/@elitedcs/ghl-mcp).** Buyers install with one config block — no git, no Node.js setup, no terminal commands. Updates flow automatically (`npx @latest` re-resolves on every Claude restart).
|
|
6
6
|
|
package/dist/index.js
CHANGED
|
@@ -31,8 +31,8 @@ var require_package = __commonJS({
|
|
|
31
31
|
"package.json"(exports2, module2) {
|
|
32
32
|
module2.exports = {
|
|
33
33
|
name: "@elitedcs/ghl-mcp",
|
|
34
|
-
version: "3.
|
|
35
|
-
description: "GoHighLevel MCP Server for Claude.
|
|
34
|
+
version: "3.16.1",
|
|
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: {
|
|
38
38
|
"ghl-mcp": "dist/index.js"
|
|
@@ -3861,6 +3861,7 @@ function registerBlogTools(server2, client) {
|
|
|
3861
3861
|
// src/tools/emails.ts
|
|
3862
3862
|
var import_zod25 = require("zod");
|
|
3863
3863
|
var EMAIL_BUILDER_BASE = "https://backend.leadconnectorhq.com/emails/builder";
|
|
3864
|
+
var SNIPPETS_BASE = "https://services.leadconnectorhq.com/snippets";
|
|
3864
3865
|
var TEMPLATE_TYPES = ["html", "folder", "import", "builder", "blank", "ai_template", "vibe-editor"];
|
|
3865
3866
|
var EDITOR_TYPES = ["html", "builder"];
|
|
3866
3867
|
function registerEmailTools(server2, client) {
|
|
@@ -4024,6 +4025,44 @@ ${text2}`);
|
|
|
4024
4025
|
}
|
|
4025
4026
|
}
|
|
4026
4027
|
);
|
|
4028
|
+
server2.tool(
|
|
4029
|
+
"create_sms_template",
|
|
4030
|
+
"Create an SMS/text template (a 'snippet') for quick-insert into the conversations composer and SMS workflow actions. The body can include merge fields like {{contact.first_name}}. Set type to 'email' to create an HTML email snippet instead. Returns the created snippet including its id. Requires Firebase auth \u2014 the public bearer key returns 401 on this endpoint.",
|
|
4031
|
+
{
|
|
4032
|
+
name: import_zod25.z.string().describe("Template/snippet name (shown in the snippets list, not sent to contacts)."),
|
|
4033
|
+
body: import_zod25.z.string().describe("The message body. SMS: plain text with optional merge fields. Email snippet: HTML."),
|
|
4034
|
+
type: import_zod25.z.enum(["sms", "email"]).optional().describe("Snippet type. Defaults to 'sms' (text). Use 'email' for an HTML email snippet."),
|
|
4035
|
+
locationId: import_zod25.z.string().optional().describe("Location ID. Falls back to the active builder client's location.")
|
|
4036
|
+
},
|
|
4037
|
+
async ({ name, body, type, locationId: locationId2 }) => {
|
|
4038
|
+
try {
|
|
4039
|
+
const loc = locationId2 ?? client.locationId;
|
|
4040
|
+
const headers = await client.buildHeaders();
|
|
4041
|
+
const response = await fetch(`${SNIPPETS_BASE}/${loc}`, {
|
|
4042
|
+
method: "POST",
|
|
4043
|
+
headers,
|
|
4044
|
+
body: JSON.stringify({
|
|
4045
|
+
name,
|
|
4046
|
+
template: { body, attachments: [] },
|
|
4047
|
+
useForLiveChat: false,
|
|
4048
|
+
urlAttachments: [],
|
|
4049
|
+
type: type ?? "sms",
|
|
4050
|
+
isFolder: false,
|
|
4051
|
+
parentId: ""
|
|
4052
|
+
})
|
|
4053
|
+
});
|
|
4054
|
+
if (!response.ok) {
|
|
4055
|
+
const text2 = await response.text();
|
|
4056
|
+
throw new Error(`Snippets API Error ${response.status}: POST /snippets/${loc}
|
|
4057
|
+
${text2}`);
|
|
4058
|
+
}
|
|
4059
|
+
const text = await response.text();
|
|
4060
|
+
return jsonResponse(text ? JSON.parse(text) : { ok: true });
|
|
4061
|
+
} catch (error) {
|
|
4062
|
+
return errorResponse(error);
|
|
4063
|
+
}
|
|
4064
|
+
}
|
|
4065
|
+
);
|
|
4027
4066
|
}
|
|
4028
4067
|
|
|
4029
4068
|
// src/tools/trigger-links.ts
|
|
@@ -5731,7 +5770,7 @@ async function validateFirebase(firebaseKey, refreshToken) {
|
|
|
5731
5770
|
function registerSetupTool(server2) {
|
|
5732
5771
|
server2.tool(
|
|
5733
5772
|
"setup_ghl_mcp",
|
|
5734
|
-
"First-run setup for GHL Command MCP. Validates your license and GHL credentials, then writes them to a per-user credentials file. Restart Claude after this completes to load all
|
|
5773
|
+
"First-run setup for GHL Command MCP. Validates your license and GHL credentials, then writes them to a per-user credentials file. Restart Claude after this completes to load all 212 tools (163 if you skip the optional Firebase fields; add Firebase later with enable_workflow_builder).",
|
|
5735
5774
|
{
|
|
5736
5775
|
email: import_zod37.z.string().email().describe("Email used at purchase."),
|
|
5737
5776
|
license_key: import_zod37.z.string().min(20).describe("License key from your purchase email."),
|
|
@@ -5786,7 +5825,7 @@ Note: Firebase credentials rejected (${fb.error}). Saved without Workflow Builde
|
|
|
5786
5825
|
ghl_firebase_api_key: workflowBuilderEnabled ? args.ghl_firebase_api_key?.trim() : void 0,
|
|
5787
5826
|
ghl_firebase_refresh_token: workflowBuilderEnabled ? args.ghl_firebase_refresh_token?.trim() : void 0
|
|
5788
5827
|
});
|
|
5789
|
-
const toolCount = workflowBuilderEnabled ? "
|
|
5828
|
+
const toolCount = workflowBuilderEnabled ? "212" : "163";
|
|
5790
5829
|
const wfLine = workflowBuilderEnabled ? "Workflow Builder: enabled." : "Workflow Builder: not configured (optional).";
|
|
5791
5830
|
const wfTip = workflowBuilderEnabled ? "" : "\nTo enable Workflow Builder later (8 extra tools): run enable_workflow_builder with your three Firebase values. No need to re-enter license/API key/location ID.";
|
|
5792
5831
|
return {
|
|
@@ -5814,7 +5853,7 @@ Note: Firebase credentials rejected (${fb.error}). Saved without Workflow Builde
|
|
|
5814
5853
|
function registerEnableWorkflowBuilderTool(server2) {
|
|
5815
5854
|
server2.tool(
|
|
5816
5855
|
"enable_workflow_builder",
|
|
5817
|
-
"Add Firebase credentials to an existing GHL Command install to unlock
|
|
5856
|
+
"Add Firebase credentials to an existing GHL Command install to unlock 49 additional tools across the internal-API modules: workflow builder (create/edit/clone/delete/publish/validate workflows, build_if_else_branch, build_goal_event, get_trigger_registry), funnel + page builder, form builder, pipeline builder, workflow cloner, smart lists, reputation, email campaigns, email templates, and memberships, plus the pre-deploy validator. Requires you've already run setup_ghl_mcp. Capture the three Firebase values from your GHL browser session \u2014 see elitedcs.com/ghl-mcp-firebase for step-by-step DevTools instructions. Tool count goes from 163 to 212 after the next Claude restart.",
|
|
5818
5857
|
{
|
|
5819
5858
|
ghl_user_id: import_zod37.z.string().min(10).describe("Firebase User ID (uid). DevTools \u2192 Application \u2192 IndexedDB \u2192 firebaseLocalStorageDb \u2192 firebaseLocalStorage \u2192 the value.uid field of the firebase:authUser row."),
|
|
5820
5859
|
ghl_firebase_api_key: import_zod37.z.string().min(10).describe("Firebase API Key starting with 'AIza'. The string between 'firebase:authUser:' and ':[DEFAULT]' in the row's Key column."),
|
|
@@ -5861,7 +5900,7 @@ DevTools steps: https://elitedcs.com/ghl-mcp-firebase`
|
|
|
5861
5900
|
"",
|
|
5862
5901
|
"Firebase credentials verified and saved.",
|
|
5863
5902
|
"",
|
|
5864
|
-
"**Restart Claude (quit fully and reopen) to load the workflow builder + funnel builder + pipeline builder + form builder + workflow cloner tools (
|
|
5903
|
+
"**Restart Claude (quit fully and reopen) to load the workflow builder + funnel builder + pipeline builder + form builder + workflow cloner tools (212 total).**",
|
|
5865
5904
|
"",
|
|
5866
5905
|
'After restart, try: "List my workflows in full detail" or "Validate workflow <id>".',
|
|
5867
5906
|
"",
|
|
@@ -6911,6 +6950,43 @@ ${text2}`);
|
|
|
6911
6950
|
}
|
|
6912
6951
|
}
|
|
6913
6952
|
);
|
|
6953
|
+
server2.tool(
|
|
6954
|
+
"list_reviews",
|
|
6955
|
+
"List the reviews a location has received (Google, Facebook, etc.) with rating, author, text, reply status, and source. Supports paging and an optional rating filter. NOTE: location is resolved through nested filter params internally \u2014 a flat locationId is what caused the long-standing 'No Location Found' error, now fixed. Responding to a review is not yet available via API. Requires Firebase auth.",
|
|
6956
|
+
{
|
|
6957
|
+
locationId: import_zod43.z.string().optional().describe("Location ID. Falls back to the active builder client's location."),
|
|
6958
|
+
pageNumber: import_zod43.z.number().optional().describe("1-based page number. Defaults to 1."),
|
|
6959
|
+
pageSize: import_zod43.z.number().optional().describe("Results per page. Defaults to 10."),
|
|
6960
|
+
rating: import_zod43.z.number().optional().describe("Optional: only return reviews with this star rating (1-5)."),
|
|
6961
|
+
includeDeleted: import_zod43.z.boolean().optional().describe("Include deleted reviews. Defaults to false.")
|
|
6962
|
+
},
|
|
6963
|
+
async ({ locationId: locationId2, pageNumber, pageSize, rating, includeDeleted }) => {
|
|
6964
|
+
try {
|
|
6965
|
+
const loc = locationId2 ?? client.locationId;
|
|
6966
|
+
const q = [
|
|
6967
|
+
`filterParams[locationId][0][value]=${encodeURIComponent(loc)}`,
|
|
6968
|
+
`filterParams[locationId][0][condition]=eq`,
|
|
6969
|
+
`filterParams[deleted][0][value]=${includeDeleted ? "true" : "false"}`,
|
|
6970
|
+
`filterParams[deleted][0][condition]=eq`
|
|
6971
|
+
];
|
|
6972
|
+
if (rating !== void 0) {
|
|
6973
|
+
q.push(`filterParams[rating][0][value]=${rating}`);
|
|
6974
|
+
q.push(`filterParams[rating][0][condition]=eq`);
|
|
6975
|
+
}
|
|
6976
|
+
q.push(`sortParams[dateAdded]=-1`);
|
|
6977
|
+
q.push(`pageNumber=${pageNumber ?? 1}`);
|
|
6978
|
+
q.push(`pageSize=${pageSize ?? 10}`);
|
|
6979
|
+
const query = q.map((p) => {
|
|
6980
|
+
const i = p.indexOf("=");
|
|
6981
|
+
return `${encodeURIComponent(p.slice(0, i))}=${p.slice(i + 1)}`;
|
|
6982
|
+
}).join("&");
|
|
6983
|
+
const result = await reputationRequest("GET", `/reviews?${query}`);
|
|
6984
|
+
return jsonResponse(result);
|
|
6985
|
+
} catch (error) {
|
|
6986
|
+
return errorResponse(error);
|
|
6987
|
+
}
|
|
6988
|
+
}
|
|
6989
|
+
);
|
|
6914
6990
|
}
|
|
6915
6991
|
|
|
6916
6992
|
// src/tools/email-campaigns.ts
|
|
@@ -6974,12 +7050,16 @@ var MEMBERSHIP_BASE = "https://backend.leadconnectorhq.com/membership";
|
|
|
6974
7050
|
function registerMembershipTools(server2, builderClient) {
|
|
6975
7051
|
const client = builderClient;
|
|
6976
7052
|
if (!client) return;
|
|
6977
|
-
async function membershipRequest(path6) {
|
|
7053
|
+
async function membershipRequest(path6, method = "GET", body) {
|
|
6978
7054
|
const headers = await client.buildHeaders();
|
|
6979
|
-
const response = await fetch(`${MEMBERSHIP_BASE}${path6}`, {
|
|
7055
|
+
const response = await fetch(`${MEMBERSHIP_BASE}${path6}`, {
|
|
7056
|
+
method,
|
|
7057
|
+
headers,
|
|
7058
|
+
body: body ? JSON.stringify(body) : void 0
|
|
7059
|
+
});
|
|
6980
7060
|
if (!response.ok) {
|
|
6981
7061
|
const text2 = await response.text();
|
|
6982
|
-
throw new Error(`Membership API Error ${response.status}:
|
|
7062
|
+
throw new Error(`Membership API Error ${response.status}: ${method} ${path6}
|
|
6983
7063
|
${text2}`);
|
|
6984
7064
|
}
|
|
6985
7065
|
const text = await response.text();
|
|
@@ -7036,6 +7116,130 @@ ${text2}`);
|
|
|
7036
7116
|
}
|
|
7037
7117
|
}
|
|
7038
7118
|
);
|
|
7119
|
+
server2.tool(
|
|
7120
|
+
"create_course",
|
|
7121
|
+
"Create a membership course (a 'product') in a location. Creates the course shell with a title and description; add categories (create_membership_category) and lessons (create_membership_lesson) into it, and an offer (create_membership_offer) to grant access. Returns the new product, including its id. Requires Firebase auth.",
|
|
7122
|
+
{
|
|
7123
|
+
title: import_zod45.z.string().describe("Course title."),
|
|
7124
|
+
description: import_zod45.z.string().optional().describe("Course description. Defaults to empty."),
|
|
7125
|
+
locationId: import_zod45.z.string().optional().describe("Location ID. Falls back to the active builder client's location.")
|
|
7126
|
+
},
|
|
7127
|
+
async ({ title, description, locationId: locationId2 }) => {
|
|
7128
|
+
try {
|
|
7129
|
+
const loc = locationId2 ?? client.locationId;
|
|
7130
|
+
const result = await membershipRequest(`/locations/${loc}/products`, "POST", {
|
|
7131
|
+
title,
|
|
7132
|
+
description: description ?? ""
|
|
7133
|
+
});
|
|
7134
|
+
return jsonResponse(result);
|
|
7135
|
+
} catch (error) {
|
|
7136
|
+
return errorResponse(error);
|
|
7137
|
+
}
|
|
7138
|
+
}
|
|
7139
|
+
);
|
|
7140
|
+
server2.tool(
|
|
7141
|
+
"create_membership_category",
|
|
7142
|
+
"Create a category (module/section) inside a membership course. Categories group lessons. Needs the productId of the course (from create_course or list_membership_offers). Returns the new category, including its id (use it as categoryId when creating lessons). Requires Firebase auth.",
|
|
7143
|
+
{
|
|
7144
|
+
title: import_zod45.z.string().describe("Category title (e.g. 'Module 1')."),
|
|
7145
|
+
productId: import_zod45.z.string().describe("The course/product id this category belongs to."),
|
|
7146
|
+
description: import_zod45.z.string().optional().describe("Category description. Defaults to empty."),
|
|
7147
|
+
visibility: import_zod45.z.enum(["published", "draft"]).optional().describe("'published' (default) or 'draft'."),
|
|
7148
|
+
sequenceNo: import_zod45.z.number().optional().describe("Display order within the course. Defaults to 0."),
|
|
7149
|
+
dripDays: import_zod45.z.number().optional().describe("Days after enrollment before this category unlocks. Defaults to 0 (no drip)."),
|
|
7150
|
+
locationId: import_zod45.z.string().optional().describe("Location ID. Falls back to the active builder client's location.")
|
|
7151
|
+
},
|
|
7152
|
+
async ({ title, productId, description, visibility, sequenceNo, dripDays, locationId: locationId2 }) => {
|
|
7153
|
+
try {
|
|
7154
|
+
const loc = locationId2 ?? client.locationId;
|
|
7155
|
+
const result = await membershipRequest(`/locations/${loc}/categories`, "POST", {
|
|
7156
|
+
title,
|
|
7157
|
+
productId,
|
|
7158
|
+
visibility: visibility ?? "published",
|
|
7159
|
+
sequenceNo: sequenceNo ?? 0,
|
|
7160
|
+
dripDays: dripDays ?? 0,
|
|
7161
|
+
description: description ?? "",
|
|
7162
|
+
parentCategory: null,
|
|
7163
|
+
posterImage: "",
|
|
7164
|
+
lockedBy: null,
|
|
7165
|
+
lockedByCategory: null,
|
|
7166
|
+
commentPermission: null,
|
|
7167
|
+
metadata: null
|
|
7168
|
+
});
|
|
7169
|
+
return jsonResponse(result);
|
|
7170
|
+
} catch (error) {
|
|
7171
|
+
return errorResponse(error);
|
|
7172
|
+
}
|
|
7173
|
+
}
|
|
7174
|
+
);
|
|
7175
|
+
server2.tool(
|
|
7176
|
+
"create_membership_lesson",
|
|
7177
|
+
"Create a lesson (a 'post') inside a membership course category. Needs both the categoryId (from create_membership_category) and the productId of the course. Description is the lesson body as HTML. Returns the new lesson, including its id. Requires Firebase auth.",
|
|
7178
|
+
{
|
|
7179
|
+
title: import_zod45.z.string().describe("Lesson title."),
|
|
7180
|
+
categoryId: import_zod45.z.string().describe("The category id this lesson belongs to (from create_membership_category)."),
|
|
7181
|
+
productId: import_zod45.z.string().describe("The course/product id this lesson belongs to."),
|
|
7182
|
+
description: import_zod45.z.string().optional().describe("Lesson body as HTML. Defaults to empty."),
|
|
7183
|
+
contentType: import_zod45.z.enum(["video", "audio", "text", "pdf", "assignment"]).optional().describe("Lesson content type. Defaults to 'video'."),
|
|
7184
|
+
visibility: import_zod45.z.enum(["published", "draft"]).optional().describe("'published' (default) or 'draft'."),
|
|
7185
|
+
sequenceNo: import_zod45.z.number().optional().describe("Display order within the category. Defaults to 0."),
|
|
7186
|
+
locationId: import_zod45.z.string().optional().describe("Location ID. Falls back to the active builder client's location.")
|
|
7187
|
+
},
|
|
7188
|
+
async ({ title, categoryId, productId, description, contentType, visibility, sequenceNo, locationId: locationId2 }) => {
|
|
7189
|
+
try {
|
|
7190
|
+
const loc = locationId2 ?? client.locationId;
|
|
7191
|
+
const result = await membershipRequest(`/locations/${loc}/posts`, "POST", {
|
|
7192
|
+
title,
|
|
7193
|
+
description: description ?? "",
|
|
7194
|
+
categoryId,
|
|
7195
|
+
productId,
|
|
7196
|
+
visibility: visibility ?? "published",
|
|
7197
|
+
sequenceNo: sequenceNo ?? 0,
|
|
7198
|
+
posterImage: null,
|
|
7199
|
+
commentStatus: "visible",
|
|
7200
|
+
contentType: contentType ?? "video",
|
|
7201
|
+
commentPermission: "enabled",
|
|
7202
|
+
lockedByPost: null,
|
|
7203
|
+
lockedByCategory: null,
|
|
7204
|
+
certificateTemplateId: null,
|
|
7205
|
+
metaData: null,
|
|
7206
|
+
contentId: null
|
|
7207
|
+
});
|
|
7208
|
+
return jsonResponse(result);
|
|
7209
|
+
} catch (error) {
|
|
7210
|
+
return errorResponse(error);
|
|
7211
|
+
}
|
|
7212
|
+
}
|
|
7213
|
+
);
|
|
7214
|
+
server2.tool(
|
|
7215
|
+
"create_membership_offer",
|
|
7216
|
+
"Create a membership offer \u2014 the access grant that enrolls contacts into one or more courses/products. Link it to course product ids. Defaults to a free offer; for paid, set type to 'recurring' or 'one_time' with an amount. Returns the new offer, including its id (referenced by the offer_access_granted trigger). Requires Firebase auth.",
|
|
7217
|
+
{
|
|
7218
|
+
title: import_zod45.z.string().describe("Offer title (shown at checkout / in the offer list)."),
|
|
7219
|
+
productIds: import_zod45.z.array(import_zod45.z.string()).describe("Course/product ids this offer grants access to (from create_course or list_membership_offers)."),
|
|
7220
|
+
type: import_zod45.z.enum(["free", "recurring", "one_time"]).optional().describe("Offer type. Defaults to 'free'."),
|
|
7221
|
+
amount: import_zod45.z.number().optional().describe("Price for paid offers. Defaults to 0 (free)."),
|
|
7222
|
+
currency: import_zod45.z.string().optional().describe("Currency code for paid offers. Defaults to 'USD'."),
|
|
7223
|
+
locationId: import_zod45.z.string().optional().describe("Location ID. Falls back to the active builder client's location.")
|
|
7224
|
+
},
|
|
7225
|
+
async ({ title, productIds, type, amount, currency, locationId: locationId2 }) => {
|
|
7226
|
+
try {
|
|
7227
|
+
const loc = locationId2 ?? client.locationId;
|
|
7228
|
+
const result = await membershipRequest(`/locations/${loc}/offers`, "POST", {
|
|
7229
|
+
title,
|
|
7230
|
+
type: type ?? "free",
|
|
7231
|
+
isLivePaymentMode: true,
|
|
7232
|
+
locationId: loc,
|
|
7233
|
+
productIds,
|
|
7234
|
+
amount: amount ?? 0,
|
|
7235
|
+
currency: currency ?? "USD"
|
|
7236
|
+
});
|
|
7237
|
+
return jsonResponse(result);
|
|
7238
|
+
} catch (error) {
|
|
7239
|
+
return errorResponse(error);
|
|
7240
|
+
}
|
|
7241
|
+
}
|
|
7242
|
+
);
|
|
7039
7243
|
}
|
|
7040
7244
|
|
|
7041
7245
|
// src/tools/template-deployer.ts
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elitedcs/ghl-mcp",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "GoHighLevel MCP Server for Claude.
|
|
3
|
+
"version": "3.16.1",
|
|
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": {
|
|
7
7
|
"ghl-mcp": "dist/index.js"
|