@elitedcs/ghl-mcp 3.11.0 → 3.12.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,78 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.12.0 — Email campaigns: create-draft + list fix (gap-closure round 5)
4
+
5
+ **198 tools across 42 modules. Bundle: ~316 KB.**
6
+
7
+ ### Bug fix: `get_email_campaigns` was broken
8
+
9
+ The existing tool hit `/emails/` which returns 404 — it had been returning errors for buyers. Repointed to `/emails/schedule` (the real email-broadcast list endpoint). Now returns campaigns with id, name, status (draft/scheduled/sent), templateId, and send config. Added an optional `limit` param. (For the older automation-campaign-builder feature, `get_campaigns` is the separate tool.)
10
+
11
+ ### New tool: `create_email_campaign` (Firebase-gated)
12
+
13
+ Create an email campaign/broadcast DRAFT from an existing email template. Required: `templateId` (make one with `create_email_template`). Optional: name, subject, fromName, fromEmail, isPlainText, enableResendToUnopened, hasUtmTracking.
14
+
15
+ ### The IAM wall + the workaround
16
+
17
+ `POST /emails/schedule` with a bearer (Private Integration) token returns `"This route is not yet supported by the IAM Service"` — a hard GHL wall. **Firebase auth gets past it** (same internal-API path as workflow-builder). So create_email_campaign is Firebase-gated.
18
+
19
+ ### Honest scope: draft-only
20
+
21
+ The campaign is created as `status: "draft"`. What's NOT available via any discoverable endpoint (probed bearer + Firebase, every path variant):
22
+ - **send / schedule-to-send** — finish in the GHL UI (Marketing → Emails)
23
+ - **delete** — drafts are removed via the GHL UI
24
+ - **update** a draft
25
+ - **get single** campaign
26
+
27
+ These live in the Marketing app and would need a DevTools capture against a live account. The create tool's response includes a `_note` field stating the draft-only limitation so the LLM relays it to the buyer. Despite the limits, this gets a campaign ~90% built programmatically (template, subject, sender, tracking all set) — the buyer just clicks send.
28
+
29
+ ### Tool count impact
30
+
31
+ - Total: 197 → 198 (+1 new; get_email_campaigns is a fix, not a new tool)
32
+ - Modules: 41 → 42 (new email-campaigns module)
33
+ - create_email_campaign is Firebase-gated; get_email_campaigns works on public API
34
+
35
+ ### Files changed
36
+
37
+ - `src/tools/emails.ts` — fixed get_email_campaigns endpoint (/emails/ → /emails/schedule)
38
+ - `src/tools/email-campaigns.ts` — NEW: create_email_campaign (Firebase)
39
+ - `src/tools/index.ts` — registered email-campaigns module
40
+ - `src/setup-tool.ts` — count 197 → 198
41
+
42
+ ## 3.11.1 — Reputation: review-link list (partial gap-closure round 4)
43
+
44
+ **197 tools across 41 modules. Bundle: ~315 KB.**
45
+
46
+ Partial close on the reputation gap. One verified tool shipped; the bigger reviews surface needs a DevTools capture against a live account.
47
+
48
+ ### New tool (Firebase-gated)
49
+
50
+ - **`get_review_link_list`** — lists the review-link destinations (Google, Facebook, etc.) configured for a location. Each entry has a label + the public review URL. Useful for building review-request workflows: the workflow goal condition `review_request_clicked` (shipped in v3.8.0) references these review-link ids.
51
+
52
+ Endpoint: `GET backend.leadconnectorhq.com/reputation/integrations/review-link-list?locationId=X` via Firebase auth. Verified 2026-05-22.
53
+
54
+ ### What's NOT shipped + why
55
+
56
+ The core reputation surface — listing the reviews that come BACK from Google/Facebook, responding to them, review-request campaigns — sits behind `/reputation/reviews`. That endpoint returns `401 "Unauthorized Access: undefined - No Location Found"` regardless of:
57
+ - bearer (PIT) vs Firebase auth
58
+ - which location header/param is sent (`location-id`, `locationid`, `location`, query param, path segment)
59
+
60
+ The `undefined` in the error means the endpoint reads a location field from the request that comes back empty — the GHL reputation UI sends something specific that black-box probing can't reproduce. **This needs a DevTools capture** of the exact request the reputation UI makes, against a live account that has connected review platforms (MCP Testing has none, so there'd be nothing to verify against anyway).
61
+
62
+ Documented as capture-pending in the tool's own description so the LLM gives buyers an honest answer.
63
+
64
+ ### Tool count impact
65
+
66
+ - Total: 196 → 197 (+1)
67
+ - Firebase-gated (the new tool uses internal-API auth)
68
+ - Modules: 40 → 41 (new reputation module)
69
+
70
+ ### Files changed
71
+
72
+ - `src/tools/reputation.ts` — NEW
73
+ - `src/tools/index.ts` — registered `registerReputationTools`
74
+ - `src/setup-tool.ts` — Firebase-mode count 196 → 197
75
+
3
76
  ## 3.11.0 — Smart Lists CRUD (gap-closure round 3)
4
77
 
5
78
  **196 tools across 40 modules. Bundle: 315.1 KB.**
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # GHL Command — GoHighLevel MCP Server
2
2
 
3
- **Full GoHighLevel API access for Claude.** 196 tools across 40 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.
3
+ **Full GoHighLevel API access for Claude.** 198 tools across 42 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.
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.11.0",
35
- description: "GoHighLevel MCP Server for Claude. 196 tools \u2014 full CRM, automation, marketing control, and the only programmatic GHL workflow builder.",
34
+ version: "3.12.0",
35
+ description: "GoHighLevel MCP Server for Claude. 198 tools \u2014 full CRM, automation, marketing control, and the only programmatic GHL workflow builder.",
36
36
  main: "dist/index.js",
37
37
  bin: {
38
38
  "ghl-mcp": "dist/index.js"
@@ -3583,15 +3583,16 @@ function registerEmailTools(server2, client) {
3583
3583
  safeTool(
3584
3584
  server2,
3585
3585
  "get_email_campaigns",
3586
- "List email campaigns for a location.",
3586
+ "List email campaigns / broadcasts (scheduled email sends) for a location. Returns each campaign's id, name, status (draft / scheduled / sent), templateId, send config, and stats. FIXED in v3.12.0: previously hit /emails/ (404); now correctly uses /emails/schedule. For automation campaigns (the older campaign-builder feature), use get_campaigns instead.",
3587
3587
  {
3588
- locationId: import_zod24.z.string().optional().describe("GHL Location ID (optional if GHL_LOCATION_ID is set)")
3588
+ locationId: import_zod24.z.string().optional().describe("GHL Location ID (optional if GHL_LOCATION_ID is set)."),
3589
+ limit: import_zod24.z.number().optional().describe("Max campaigns to return.")
3589
3590
  },
3590
- async ({ locationId: locationId2 }) => {
3591
+ async ({ locationId: locationId2, limit }) => {
3591
3592
  const resolvedLocationId = client.resolveLocationId(locationId2);
3592
- return client.get("/emails/", {
3593
- params: { locationId: resolvedLocationId }
3594
- });
3593
+ const params = { locationId: resolvedLocationId };
3594
+ if (limit !== void 0) params.limit = limit;
3595
+ return client.get("/emails/schedule", { params });
3595
3596
  }
3596
3597
  );
3597
3598
  safeTool(
@@ -6153,42 +6154,133 @@ ${text2}`);
6153
6154
  );
6154
6155
  }
6155
6156
 
6156
- // src/tools/template-deployer.ts
6157
+ // src/tools/reputation.ts
6157
6158
  var import_zod41 = require("zod");
6159
+ var REPUTATION_BASE = "https://backend.leadconnectorhq.com/reputation";
6160
+ function registerReputationTools(server2, builderClient) {
6161
+ const client = builderClient;
6162
+ if (!client) return;
6163
+ async function reputationRequest(method, path6) {
6164
+ const headers = await client.buildHeaders();
6165
+ const response = await fetch(`${REPUTATION_BASE}${path6}`, { method, headers });
6166
+ if (!response.ok) {
6167
+ const text2 = await response.text();
6168
+ throw new Error(`Reputation API Error ${response.status}: ${method} ${path6}
6169
+ ${text2}`);
6170
+ }
6171
+ const text = await response.text();
6172
+ if (!text) return {};
6173
+ return JSON.parse(text);
6174
+ }
6175
+ server2.tool(
6176
+ "get_review_link_list",
6177
+ "List the review-link destinations configured for a location \u2014 the platforms (Google, Facebook, etc.) where review requests send contacts. Each entry has a label and the public review URL. Useful for: building review-request workflows (the workflow goal condition `review_request_clicked` references these review-link ids), and auditing which review platforms a sub-account has connected. NOTE: listing the actual reviews that come BACK (and responding to them) is not yet available \u2014 that endpoint needs a DevTools capture against a live account with connected review platforms.",
6178
+ {
6179
+ locationId: import_zod41.z.string().optional().describe("Location ID. Falls back to the active builder client's location.")
6180
+ },
6181
+ async ({ locationId: locationId2 }) => {
6182
+ try {
6183
+ const loc = locationId2 ?? client.locationId;
6184
+ const result = await reputationRequest("GET", `/integrations/review-link-list?locationId=${loc}`);
6185
+ return jsonResponse(result);
6186
+ } catch (error) {
6187
+ return errorResponse(error);
6188
+ }
6189
+ }
6190
+ );
6191
+ }
6192
+
6193
+ // src/tools/email-campaigns.ts
6194
+ var import_zod42 = require("zod");
6195
+ var SVC_BASE = "https://services.leadconnectorhq.com";
6196
+ function registerEmailCampaignTools(server2, builderClient) {
6197
+ const client = builderClient;
6198
+ if (!client) return;
6199
+ server2.tool(
6200
+ "create_email_campaign",
6201
+ "Create an email campaign / broadcast DRAFT from an existing email template. Requires a templateId (create one first with create_email_template). The campaign is created as a draft \u2014 to actually SEND or schedule it, finish in the GHL UI: the send/schedule endpoint isn't available through the API yet. There's also no API delete for campaigns, so drafts created here are removed via the GHL UI. Despite those limits, this gets the campaign 90% built \u2014 template, subject, sender, name all set programmatically.",
6202
+ {
6203
+ templateId: import_zod42.z.string().describe("ID of an email template (from create_email_template or list_email_templates) to use as the campaign body."),
6204
+ name: import_zod42.z.string().optional().describe("Internal campaign name (shown in the campaigns list, not to recipients). Defaults to a GHL-generated name."),
6205
+ subject: import_zod42.z.string().optional().describe("Email subject line recipients see."),
6206
+ fromName: import_zod42.z.string().optional().describe("Sender display name."),
6207
+ fromEmail: import_zod42.z.string().optional().describe("Sender email address. Must be a verified sending address in the location."),
6208
+ isPlainText: import_zod42.z.boolean().optional().describe("Send as plain text instead of HTML. Defaults to false."),
6209
+ enableResendToUnopened: import_zod42.z.boolean().optional().describe("Auto-resend to contacts who didn't open. Defaults to false."),
6210
+ hasUtmTracking: import_zod42.z.boolean().optional().describe("Append UTM tracking params to links. Defaults to false."),
6211
+ locationId: import_zod42.z.string().optional().describe("Location ID. Falls back to the active builder client's location.")
6212
+ },
6213
+ async ({ templateId, name, subject, fromName, fromEmail, isPlainText, enableResendToUnopened, hasUtmTracking, locationId: locationId2 }) => {
6214
+ try {
6215
+ const loc = locationId2 ?? client.locationId;
6216
+ const body = { locationId: loc, templateId };
6217
+ if (name !== void 0) body.name = name;
6218
+ if (subject !== void 0) body.subject = subject;
6219
+ if (fromName !== void 0) body.fromName = fromName;
6220
+ if (fromEmail !== void 0) body.fromEmail = fromEmail;
6221
+ if (isPlainText !== void 0) body.isPlainText = isPlainText;
6222
+ if (enableResendToUnopened !== void 0) body.enableResendToUnopened = enableResendToUnopened;
6223
+ if (hasUtmTracking !== void 0) body.hasUtmTracking = hasUtmTracking;
6224
+ const headers = await client.buildHeaders();
6225
+ const response = await fetch(`${SVC_BASE}/emails/schedule`, {
6226
+ method: "POST",
6227
+ headers,
6228
+ body: JSON.stringify(body)
6229
+ });
6230
+ if (!response.ok) {
6231
+ const text2 = await response.text();
6232
+ throw new Error(`Email Campaign API Error ${response.status}: POST /emails/schedule
6233
+ ${text2}`);
6234
+ }
6235
+ const text = await response.text();
6236
+ const result = text ? JSON.parse(text) : {};
6237
+ return jsonResponse({
6238
+ ...result,
6239
+ _note: "Campaign created as a DRAFT. To send or schedule it, open it in the GHL UI (Marketing \u2192 Emails) \u2014 the send endpoint isn't available via API. To delete a draft, use the GHL UI."
6240
+ });
6241
+ } catch (error) {
6242
+ return errorResponse(error);
6243
+ }
6244
+ }
6245
+ );
6246
+ }
6247
+
6248
+ // src/tools/template-deployer.ts
6249
+ var import_zod43 = require("zod");
6158
6250
  var fs3 = __toESM(require("fs"));
6159
6251
  var path3 = __toESM(require("path"));
6160
6252
  function delay3(ms) {
6161
6253
  return new Promise((resolve5) => setTimeout(resolve5, ms));
6162
6254
  }
6163
- var TemplateSchema = import_zod41.z.object({
6164
- templateName: import_zod41.z.string(),
6165
- templateVersion: import_zod41.z.string().optional(),
6166
- description: import_zod41.z.string().optional().default(""),
6167
- questionnaire: import_zod41.z.array(import_zod41.z.object({
6168
- id: import_zod41.z.string(),
6169
- question: import_zod41.z.string(),
6170
- type: import_zod41.z.string(),
6171
- required: import_zod41.z.boolean().optional(),
6172
- placeholder: import_zod41.z.string().optional()
6255
+ var TemplateSchema = import_zod43.z.object({
6256
+ templateName: import_zod43.z.string(),
6257
+ templateVersion: import_zod43.z.string().optional(),
6258
+ description: import_zod43.z.string().optional().default(""),
6259
+ questionnaire: import_zod43.z.array(import_zod43.z.object({
6260
+ id: import_zod43.z.string(),
6261
+ question: import_zod43.z.string(),
6262
+ type: import_zod43.z.string(),
6263
+ required: import_zod43.z.boolean().optional(),
6264
+ placeholder: import_zod43.z.string().optional()
6173
6265
  })).optional().default([]),
6174
- location: import_zod41.z.record(import_zod41.z.unknown()).optional(),
6175
- tags: import_zod41.z.array(import_zod41.z.string()).optional(),
6176
- customFields: import_zod41.z.array(import_zod41.z.object({
6177
- name: import_zod41.z.string(),
6178
- dataType: import_zod41.z.string()
6266
+ location: import_zod43.z.record(import_zod43.z.unknown()).optional(),
6267
+ tags: import_zod43.z.array(import_zod43.z.string()).optional(),
6268
+ customFields: import_zod43.z.array(import_zod43.z.object({
6269
+ name: import_zod43.z.string(),
6270
+ dataType: import_zod43.z.string()
6179
6271
  })).optional(),
6180
- pipelines: import_zod41.z.array(import_zod41.z.object({
6181
- name: import_zod41.z.string(),
6182
- stages: import_zod41.z.array(import_zod41.z.object({ position: import_zod41.z.number(), name: import_zod41.z.string() }))
6272
+ pipelines: import_zod43.z.array(import_zod43.z.object({
6273
+ name: import_zod43.z.string(),
6274
+ stages: import_zod43.z.array(import_zod43.z.object({ position: import_zod43.z.number(), name: import_zod43.z.string() }))
6183
6275
  })).optional(),
6184
- workflows: import_zod41.z.array(import_zod41.z.object({
6185
- name: import_zod41.z.string(),
6186
- condition: import_zod41.z.string().optional(),
6187
- actions: import_zod41.z.array(import_zod41.z.record(import_zod41.z.unknown())).optional().default([])
6276
+ workflows: import_zod43.z.array(import_zod43.z.object({
6277
+ name: import_zod43.z.string(),
6278
+ condition: import_zod43.z.string().optional(),
6279
+ actions: import_zod43.z.array(import_zod43.z.record(import_zod43.z.unknown())).optional().default([])
6188
6280
  })).optional(),
6189
- calendars: import_zod41.z.array(import_zod41.z.object({
6190
- name: import_zod41.z.string(),
6191
- description: import_zod41.z.string().optional()
6281
+ calendars: import_zod43.z.array(import_zod43.z.object({
6282
+ name: import_zod43.z.string(),
6283
+ description: import_zod43.z.string().optional()
6192
6284
  })).optional()
6193
6285
  });
6194
6286
  function registerTemplateDeployerTools(server2, client) {
@@ -6259,7 +6351,7 @@ function registerTemplateDeployerTools(server2, client) {
6259
6351
  "get_template_questionnaire",
6260
6352
  "Get the questionnaire for a specific template. Returns all the questions that need to be answered before deploying. Present these to the user one at a time in a conversational style.",
6261
6353
  {
6262
- templateFile: import_zod41.z.string().describe("Path to the template JSON file (from list_templates).")
6354
+ templateFile: import_zod43.z.string().describe("Path to the template JSON file (from list_templates).")
6263
6355
  },
6264
6356
  async ({ templateFile }) => {
6265
6357
  try {
@@ -6292,10 +6384,10 @@ function registerTemplateDeployerTools(server2, client) {
6292
6384
  "deploy_template",
6293
6385
  "Deploy a template to set up a GHL sub-account. Creates tags, custom fields, pipelines with stages, calendars, workflows, and forms based on the template and the user's questionnaire answers. This is the main setup automation tool.",
6294
6386
  {
6295
- templateFile: import_zod41.z.string().describe("Path to the template JSON file."),
6296
- answers: import_zod41.z.record(import_zod41.z.unknown()).describe("Questionnaire answers keyed by question ID (e.g. {business_name: 'My Clinic', business_phone: '+15551234567', ...})."),
6297
- locationId: import_zod41.z.string().optional().describe("Location ID to deploy to. Uses default if not specified."),
6298
- dryRun: import_zod41.z.boolean().optional().describe("If true, shows what would be created without actually creating anything. Defaults to false.")
6387
+ templateFile: import_zod43.z.string().describe("Path to the template JSON file."),
6388
+ answers: import_zod43.z.record(import_zod43.z.unknown()).describe("Questionnaire answers keyed by question ID (e.g. {business_name: 'My Clinic', business_phone: '+15551234567', ...})."),
6389
+ locationId: import_zod43.z.string().optional().describe("Location ID to deploy to. Uses default if not specified."),
6390
+ dryRun: import_zod43.z.boolean().optional().describe("If true, shows what would be created without actually creating anything. Defaults to false.")
6299
6391
  },
6300
6392
  async ({ templateFile, answers, locationId: locationId2, dryRun }) => {
6301
6393
  try {
@@ -6541,7 +6633,7 @@ ${errors.join("\n")}` : "\nNo errors!",
6541
6633
  }
6542
6634
 
6543
6635
  // src/tools/validators.ts
6544
- var import_zod42 = require("zod");
6636
+ var import_zod44 = require("zod");
6545
6637
  function extractFromTrigger(trigger, refs) {
6546
6638
  const triggerName = String(trigger.name ?? trigger.type ?? "unnamed trigger");
6547
6639
  const where = `trigger "${triggerName}"`;
@@ -6676,7 +6768,7 @@ function registerValidatorTools(server2, client, builderClient) {
6676
6768
  "validate_workflow",
6677
6769
  "Pre-flight ID validation for a deployed GHL workflow. Scans every trigger and action for references to pipelines, pipeline stages, custom fields, users, workflows, forms, calendars, and surveys; verifies each ID exists in the current location. Use this BEFORE publish_workflow when a workflow has been edited, or whenever a published workflow stops behaving as expected. Catches the silent-failure bug where invalid IDs make GHL skip all subsequent actions without warning. Returns a structured report of valid + missing references.",
6678
6770
  {
6679
- workflowId: import_zod42.z.string().describe("The workflow ID to validate.")
6771
+ workflowId: import_zod44.z.string().describe("The workflow ID to validate.")
6680
6772
  },
6681
6773
  async ({ workflowId }) => {
6682
6774
  try {
@@ -7045,6 +7137,8 @@ function registerAllTools(server2, client, registry2, mcpVersion) {
7045
7137
  registerPipelineBuilderTools(server2, builderClient);
7046
7138
  registerWorkflowClonerTools(server2, builderClient);
7047
7139
  registerSmartListTools(server2, builderClient);
7140
+ registerReputationTools(server2, builderClient);
7141
+ registerEmailCampaignTools(server2, builderClient);
7048
7142
  registerValidatorTools(server2, client, builderClient);
7049
7143
  registerDiagnosticTools(server2, mcpVersion ?? "unknown", client, builderClient, registry2 ?? null);
7050
7144
  registerLocationSwitcherTools(server2, client, builderClient, registry2, mcpVersion);
@@ -7054,18 +7148,18 @@ function registerAllTools(server2, client, registry2, mcpVersion) {
7054
7148
  var fs4 = __toESM(require("fs"));
7055
7149
  var path4 = __toESM(require("path"));
7056
7150
  var os = __toESM(require("os"));
7057
- var import_zod43 = require("zod");
7151
+ var import_zod45 = require("zod");
7058
7152
  var APP_NAME = "elitedcs-ghl-mcp";
7059
- var CredentialsSchema = import_zod43.z.object({
7060
- license_key: import_zod43.z.string().min(1),
7061
- email: import_zod43.z.string().email(),
7062
- verified_at: import_zod43.z.string().min(1),
7063
- ghl_api_key: import_zod43.z.string().min(1),
7064
- ghl_location_id: import_zod43.z.string().min(1),
7065
- ghl_company_id: import_zod43.z.string().optional(),
7066
- ghl_user_id: import_zod43.z.string().optional(),
7067
- ghl_firebase_api_key: import_zod43.z.string().optional(),
7068
- ghl_firebase_refresh_token: import_zod43.z.string().optional()
7153
+ var CredentialsSchema = import_zod45.z.object({
7154
+ license_key: import_zod45.z.string().min(1),
7155
+ email: import_zod45.z.string().email(),
7156
+ verified_at: import_zod45.z.string().min(1),
7157
+ ghl_api_key: import_zod45.z.string().min(1),
7158
+ ghl_location_id: import_zod45.z.string().min(1),
7159
+ ghl_company_id: import_zod45.z.string().optional(),
7160
+ ghl_user_id: import_zod45.z.string().optional(),
7161
+ ghl_firebase_api_key: import_zod45.z.string().optional(),
7162
+ ghl_firebase_refresh_token: import_zod45.z.string().optional()
7069
7163
  });
7070
7164
  function appDataDir() {
7071
7165
  const home = os.homedir();
@@ -7115,7 +7209,7 @@ function writeCredentials(creds) {
7115
7209
  // src/setup-tool.ts
7116
7210
  var os2 = __toESM(require("os"));
7117
7211
  var crypto3 = __toESM(require("crypto"));
7118
- var import_zod44 = require("zod");
7212
+ var import_zod46 = require("zod");
7119
7213
  var LICENSE_API = "https://elitedcs.com/api/validate-license";
7120
7214
  var GHL_API = "https://services.leadconnectorhq.com";
7121
7215
  var FIREBASE_TOKEN_API = "https://securetoken.googleapis.com/v1/token";
@@ -7184,16 +7278,16 @@ async function validateFirebase(firebaseKey, refreshToken) {
7184
7278
  function registerSetupTool(server2) {
7185
7279
  server2.tool(
7186
7280
  "setup_ghl_mcp",
7187
- "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 196 tools (161 if you skip the optional Firebase fields; add Firebase later with enable_workflow_builder).",
7281
+ "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 198 tools (161 if you skip the optional Firebase fields; add Firebase later with enable_workflow_builder).",
7188
7282
  {
7189
- email: import_zod44.z.string().email().describe("Email used at purchase."),
7190
- license_key: import_zod44.z.string().min(20).describe("License key from your purchase email."),
7191
- ghl_api_key: import_zod44.z.string().min(10).describe("GHL Private Integration key (starts with 'pit-'). Created INSIDE the sub-account at Settings > Integrations > Private Integrations."),
7192
- ghl_location_id: import_zod44.z.string().min(10).describe("GHL Location ID (sub-account ID). Found in your GHL URL: /location/THIS_PART/dashboard."),
7193
- ghl_company_id: import_zod44.z.string().optional().describe("(Agency only) Company ID for multi-location access."),
7194
- ghl_user_id: import_zod44.z.string().optional().describe("(Workflow Builder, optional) Firebase User ID. See README for browser capture instructions."),
7195
- ghl_firebase_api_key: import_zod44.z.string().optional().describe("(Workflow Builder, optional) Firebase API Key starting with 'AIza'."),
7196
- ghl_firebase_refresh_token: import_zod44.z.string().optional().describe("(Workflow Builder, optional) Firebase refresh token starting with 'AMf-'.")
7283
+ email: import_zod46.z.string().email().describe("Email used at purchase."),
7284
+ license_key: import_zod46.z.string().min(20).describe("License key from your purchase email."),
7285
+ ghl_api_key: import_zod46.z.string().min(10).describe("GHL Private Integration key (starts with 'pit-'). Created INSIDE the sub-account at Settings > Integrations > Private Integrations."),
7286
+ ghl_location_id: import_zod46.z.string().min(10).describe("GHL Location ID (sub-account ID). Found in your GHL URL: /location/THIS_PART/dashboard."),
7287
+ ghl_company_id: import_zod46.z.string().optional().describe("(Agency only) Company ID for multi-location access."),
7288
+ ghl_user_id: import_zod46.z.string().optional().describe("(Workflow Builder, optional) Firebase User ID. See README for browser capture instructions."),
7289
+ ghl_firebase_api_key: import_zod46.z.string().optional().describe("(Workflow Builder, optional) Firebase API Key starting with 'AIza'."),
7290
+ ghl_firebase_refresh_token: import_zod46.z.string().optional().describe("(Workflow Builder, optional) Firebase refresh token starting with 'AMf-'.")
7197
7291
  },
7198
7292
  async (args) => {
7199
7293
  const lic = await validateLicense(args.email, args.license_key);
@@ -7239,7 +7333,7 @@ Note: Firebase credentials rejected (${fb.error}). Saved without Workflow Builde
7239
7333
  ghl_firebase_api_key: workflowBuilderEnabled ? args.ghl_firebase_api_key?.trim() : void 0,
7240
7334
  ghl_firebase_refresh_token: workflowBuilderEnabled ? args.ghl_firebase_refresh_token?.trim() : void 0
7241
7335
  });
7242
- const toolCount = workflowBuilderEnabled ? "196" : "161";
7336
+ const toolCount = workflowBuilderEnabled ? "198" : "161";
7243
7337
  const wfLine = workflowBuilderEnabled ? "Workflow Builder: enabled." : "Workflow Builder: not configured (optional).";
7244
7338
  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.";
7245
7339
  return {
@@ -7267,11 +7361,11 @@ Note: Firebase credentials rejected (${fb.error}). Saved without Workflow Builde
7267
7361
  function registerEnableWorkflowBuilderTool(server2) {
7268
7362
  server2.tool(
7269
7363
  "enable_workflow_builder",
7270
- "Add Firebase credentials to an existing GHL Command install to unlock 30 additional tools across 6 modules: workflow builder (create/edit/clone/delete/publish/validate workflows, build_if_else_branch, build_goal_event, get_trigger_registry), funnel + page builder (10 tools), form builder (5 tools), pipeline builder (5 tools), and workflow cloning. 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 161 to 196 after the next Claude restart.",
7364
+ "Add Firebase credentials to an existing GHL Command install to unlock 30 additional tools across 6 modules: workflow builder (create/edit/clone/delete/publish/validate workflows, build_if_else_branch, build_goal_event, get_trigger_registry), funnel + page builder (10 tools), form builder (5 tools), pipeline builder (5 tools), and workflow cloning. 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 161 to 198 after the next Claude restart.",
7271
7365
  {
7272
- ghl_user_id: import_zod44.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."),
7273
- ghl_firebase_api_key: import_zod44.z.string().min(10).describe("Firebase API Key starting with 'AIza'. The string between 'firebase:authUser:' and ':[DEFAULT]' in the row's Key column."),
7274
- ghl_firebase_refresh_token: import_zod44.z.string().min(10).describe("Firebase refresh token. value.stsTokenManager.refreshToken in the firebase:authUser row.")
7366
+ ghl_user_id: import_zod46.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."),
7367
+ ghl_firebase_api_key: import_zod46.z.string().min(10).describe("Firebase API Key starting with 'AIza'. The string between 'firebase:authUser:' and ':[DEFAULT]' in the row's Key column."),
7368
+ ghl_firebase_refresh_token: import_zod46.z.string().min(10).describe("Firebase refresh token. value.stsTokenManager.refreshToken in the firebase:authUser row.")
7275
7369
  },
7276
7370
  async (args) => {
7277
7371
  const existing = readCredentials();
@@ -7314,7 +7408,7 @@ DevTools steps: https://elitedcs.com/ghl-mcp-firebase`
7314
7408
  "",
7315
7409
  "Firebase credentials verified and saved.",
7316
7410
  "",
7317
- "**Restart Claude (quit fully and reopen) to load the workflow builder + funnel builder + pipeline builder + form builder + workflow cloner tools (196 total).**",
7411
+ "**Restart Claude (quit fully and reopen) to load the workflow builder + funnel builder + pipeline builder + form builder + workflow cloner tools (198 total).**",
7318
7412
  "",
7319
7413
  'After restart, try: "List my workflows in full detail" or "Validate workflow <id>".',
7320
7414
  "",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elitedcs/ghl-mcp",
3
- "version": "3.11.0",
4
- "description": "GoHighLevel MCP Server for Claude. 196 tools — full CRM, automation, marketing control, and the only programmatic GHL workflow builder.",
3
+ "version": "3.12.0",
4
+ "description": "GoHighLevel MCP Server for Claude. 198 tools — full CRM, automation, marketing control, and the only programmatic GHL workflow builder.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "ghl-mcp": "dist/index.js"