@elitedcs/ghl-mcp 3.68.0 → 3.70.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elitedcs/ghl-mcp",
3
- "version": "3.68.0",
3
+ "version": "3.70.0",
4
4
  "mcpName": "io.github.drjerryrelth/ghl-command",
5
5
  "description": "GoHighLevel MCP Server for Claude. 242 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.",
6
6
  "main": "dist/index.js",
@@ -18,7 +18,12 @@
18
18
  "README.md",
19
19
  "CHANGELOG.md",
20
20
  "skills",
21
- "guide"
21
+ "guide",
22
+ "skills/blueprint/references/build-plan-schema.md",
23
+ "skills/blueprint/presets/generic-client.preset.json",
24
+ "skills/blueprint/presets/med-spa.preset.json",
25
+ "skills/blueprint/presets/clinic-launch-a2p.preset.json",
26
+ "skills/blueprint/examples/sample-build-plan.json"
22
27
  ],
23
28
  "scripts": {
24
29
  "build": "esbuild src/index.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/index.js --packages=external && esbuild src/capture-helper.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/capture-helper.js --packages=external",
@@ -63,17 +68,17 @@
63
68
  },
64
69
  "dependencies": {
65
70
  "@modelcontextprotocol/sdk": "^1.29.0",
66
- "dotenv": "^16.5.0",
71
+ "dotenv": "^17.4.2",
67
72
  "json5": "^2.2.3",
68
73
  "playwright-core": "^1.61.1",
69
- "zod": "^3.24.4"
74
+ "zod": "^4.4.3"
70
75
  },
71
76
  "devDependencies": {
72
77
  "@clack/prompts": "^1.1.0",
73
- "@types/node": "^22.15.3",
78
+ "@types/node": "^26.2.0",
74
79
  "esbuild": "^0.28.1",
75
80
  "open": "^11.0.0",
76
- "typescript": "^5.8.3",
81
+ "typescript": "^7.0.2",
77
82
  "vitest": "^4.1.6"
78
83
  }
79
84
  }
@@ -132,6 +132,7 @@ For each external funnel, run the lane in `references/external-funnel.md` after
132
132
  - Honest capability boundaries. Always show the steps only the operator can do. It makes the rest believable.
133
133
  - Operator voice. No em-dashes, no hype, no emoji-spam. Client-ready.
134
134
  - Do not clone or redistribute Agency OS / Business OS. Detect, integrate, credit.
135
+ - **Re-runs reuse the saved plan.** `apply_build_plan` `mode:"execute"` saves the approved plan for that sub-account on the operator's machine. To re-run (after a halt, or to finish what a first pass skipped), call `apply_build_plan` with `useSavedPlan:true` and NO `plan` — never re-author a plan for an account that already has one: a differently named plan is refused, because never-clobber binds what matches by name and CREATES everything else (a second pipeline beside the first). Only when the operator has approved a genuinely new plan for that account, pass the new plan with `replaceSavedPlan:true`.
135
136
  - The plan never executes itself. Stop at approval. After approval, GHL-native staging runs only via `apply_build_plan` (confirm the account first); the external funnel lane (STEP 10) runs only on an informed yes through the capability gate.
136
137
  - **External funnels are customer-managed, zero product involvement in their accounts.** The product generates, scaffolds, hands over verified wiring, and verifies — it never deploys for the user, never asks for or stores their token, never touches their host/GHL account beyond what the operator's own session does. The user owns hosting, the secret, uptime, and DNS.
137
138
  - **External forms send verified GHL custom-field IDs, never name-guessed keys** (the silent-drop class). A funnel is not "done" until `verify_funnel` passes on the real branded production URL plus a burner booking — never on a thank-you page.
@@ -63,7 +63,7 @@ Each question maps 1:1 to a Brief field (schema §4) via its `key`. The mapping
63
63
 
64
64
  | # | Label | `key` | Type | Required | Options / help |
65
65
  |---|---|---|---|---|---|
66
- | E1 | Is your business email sending set up? | `email_ready` | radio (yes/no) | no | Yes if you have a sending domain / mailbox connected in GHL. |
66
+ | E1 | Is your sending domain set up? | `email_ready` | radio (yes/no) | no | Yes if you have a sending domain / mailbox connected in GHL. (Label carries no "email" on purpose: browsers autofill saved addresses into it otherwise.) |
67
67
  | E2 | Do you want to send text messages (SMS)? | `sms_desired` | radio (yes/no) | no | Yes flags the A2P registration step you'll need to complete. |
68
68
  | E3 | A2P / SMS registration status | `a2p_status` | dropdown | no | Options: `Not started`, `In progress`, `Approved`, `Not needed`. |
69
69
  | E4 | Payment processing | `payment_processor` | dropdown | no | Options: `Stripe connected`, `Stripe not connected`, `Other`, `None`. *(Flags the Stripe handoff if you sell on a page.)* |
@@ -106,7 +106,7 @@
106
106
  "selectedUser": "USER_ID"
107
107
  }
108
108
  },
109
- "notes": "Nested 'notification' object REQUIRED. selectedUser MUST be a real user ID GHL now REJECTS an empty string (live-verified 2026-08-06; the old 'empty = all users' behavior is gone). Use get_users to find IDs. EMAIL CHANNEL (verified live 2026-07-20, PWDJ workflow e91f28da): attributes.type is 'email' (NOT 'notification'), nested key is 'email' (NOT 'notification'), body field is 'html' (NOT 'body'), selectedUser is an ARRAY of user IDs, include attachments:[] and isCloned:false. A 'send_email' discriminator inside a 'notification' object saves but silently never sends.",
109
+ "notes": "Nested 'notification' object REQUIRED. selectedUser MUST be a real user ID \u2014 GHL now REJECTS an empty string (live-verified 2026-08-06; the old 'empty = all users' behavior is gone). Use get_users to find IDs. EMAIL CHANNEL (verified live 2026-07-20, PWDJ workflow e91f28da): attributes.type is 'email' (NOT 'notification'), nested key is 'email' (NOT 'notification'), body field is 'html' (NOT 'body'), selectedUser is an ARRAY of user IDs, include attachments:[] and isCloned:false. A 'send_email' discriminator inside a 'notification' object saves but silently never sends.",
110
110
  "emailChannelExample": {
111
111
  "type": "email",
112
112
  "email": {
@@ -166,6 +166,27 @@
166
166
  },
167
167
  "notes": "Requires BOTH workflowId (string) AND workflow_id (ARRAY with same ID). Also needs type: 'remove_from_workflow' inside attributes. Derived from GHL UI."
168
168
  },
169
+ "internal_create_opportunity": {
170
+ "example": {
171
+ "type": "internal_create_opportunity",
172
+ "workflowsActionType": "INTERNAL",
173
+ "attributes": {
174
+ "type": "internal_create_opportunity",
175
+ "pipelineId": "PIPELINE_ID",
176
+ "__customInputFields__": [
177
+ {
178
+ "__customInputs__": {},
179
+ "dataType": "SINGLE_OPTIONS",
180
+ "filterField": "pipelineStageId",
181
+ "value": "STAGE_ID",
182
+ "valueFieldType": "select"
183
+ }
184
+ ],
185
+ "__customInputs__": {}
186
+ }
187
+ },
188
+ "notes": "CREATES a card (GHL's newer separate 'Create Opportunity' action). This minimal shape is live-proven to create at runtime (2026-07-24): pipelineId at the ATTRIBUTES level (not inside __customInputFields__), __customInputFields__ carrying pipelineStageId, workflowsActionType:'INTERNAL' at the NODE level. UI-built nodes also carry name/status/monetaryValue entries and work \u2014 copy a working node field-for-field rather than inventing entries. Without a name entry the card is named from the contact (observed live 2026-07-24). Use THIS for 'create an opportunity for the new lead'."
189
+ },
169
190
  "internal_update_opportunity": {
170
191
  "example": {
171
192
  "__customInputFields__": [
@@ -185,7 +206,7 @@
185
206
  "workflowsActionType": "INTERNAL",
186
207
  "type": "internal_update_opportunity"
187
208
  },
188
- "notes": "CREATABLE from scratch (re-enabled v3.41.0). The discriminator workflowsActionType:'INTERNAL' MUST sit at the NODE level, never nested in attributes \u2014 a nested copy makes GHL reject the node as 'action has a corrupted type' and silently fail the whole save. update_workflow_actions normalizes this for you (hoists workflowsActionType to the node level, scaffolds allowBackward + __customInputs__, gives each __customInputFields__ entry an __customInputs__). The shape below (workflowsActionType at the node level alongside type/name/attributes) is correct for both creating and round-tripping. Use pipeline and stage IDs (not names) \u2014 get_pipelines / list_pipelines_full to find them FIRST. CRITICAL: if the pipelineId or pipelineStageId don't exist in the target sub-account, GHL silently fails this action AND can kill subsequent actions. A synthesized node needs BOTH a pipelineId and a pipelineStageId entry; a node round-tripped via get_workflow_full keeps its id and passes through unchanged."
209
+ "notes": "GHL's combined 'Create/Update Opportunity'. With only pipelineId + pipelineStageId it CANNOT create a card \u2014 it moves one the contact already has; a contact with no opportunity (a new lead) gets nothing and the workflow continues as if it worked (customer report 2026-08-26). It creates only when __customInputFields__ also carry Opportunity name (GHL's doc: Name, Source, Status mandatory to create). GoHighLevel is phasing this combined action out for new workflows, so prefer internal_create_opportunity to create; use this node after find_opportunity, after a create step in the same workflow, or on an opportunity trigger. CREATABLE from scratch (re-enabled v3.41.0). The discriminator workflowsActionType:'INTERNAL' MUST sit at the NODE level, never nested in attributes \u2014 a nested copy makes GHL reject the node as 'action has a corrupted type' and silently fail the whole save. update_workflow_actions normalizes this for you (hoists workflowsActionType to the node level, scaffolds allowBackward + __customInputs__, gives each __customInputFields__ entry an __customInputs__). The shape below (workflowsActionType at the node level alongside type/name/attributes) is correct for both creating and round-tripping. Use pipeline and stage IDs (not names) \u2014 get_pipelines / list_pipelines_full to find them FIRST. CRITICAL: if the pipelineId or pipelineStageId don't exist in the target sub-account, GHL silently fails this action AND can kill subsequent actions. A synthesized node needs BOTH a pipelineId and a pipelineStageId entry; a node round-tripped via get_workflow_full keeps its id and passes through unchanged."
189
210
  },
190
211
  "_if_else_branching": {
191
212
  "notes": "if_else is a node type discriminator only. Do not send a single flat if_else action.",