@charisol/plexo-mcp 1.0.0 → 1.0.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/README.md CHANGED
@@ -9,6 +9,7 @@ Connect **Claude Desktop**, **Claude Web**, **ChatGPT**, **Cursor**, **Windsurf*
9
9
  ## Capabilities & Tools
10
10
 
11
11
  - 🚀 **`publish_landing_page`**: Creates, compiles, and publishes a landing page (JSON schema + HTML) to a subdomain or custom domain in 1 step.
12
+ - ✉️ **`create_email_template`**: Creates and saves a responsive email template (same JSON schema as landing pages, no domain).
12
13
  - 📄 **`list_landing_pages`**: Retrieves saved landing page designs and active domain URLs.
13
14
  - ✉️ **`list_email_templates`**: Retrieves saved email templates.
14
15
  - 📊 **`get_analytics`**: Fetches total page views, unique visitor counts, and daily timelines.
@@ -34,7 +34,7 @@ class PlexoClient {
34
34
  const res = await fetch(`${this.baseUrl}/api/v1/publish`, {
35
35
  method: "POST",
36
36
  headers: this.getHeaders(),
37
- body: JSON.stringify(params),
37
+ body: JSON.stringify({ ...params, kind: "LANDING_PAGE" }),
38
38
  });
39
39
  const data = (await res.json());
40
40
  if (!res.ok) {
@@ -42,6 +42,21 @@ class PlexoClient {
42
42
  }
43
43
  return data;
44
44
  }
45
+ async createEmailTemplate(params) {
46
+ this.checkAuth();
47
+ // Same /api/v1/publish endpoint as publishLandingPage — kind: "EMAIL" skips the
48
+ // domain-publishing step server-side and just saves the template.
49
+ const res = await fetch(`${this.baseUrl}/api/v1/publish`, {
50
+ method: "POST",
51
+ headers: this.getHeaders(),
52
+ body: JSON.stringify({ ...params, kind: "EMAIL" }),
53
+ });
54
+ const data = (await res.json());
55
+ if (!res.ok) {
56
+ throw new Error(data?.error || `Email template creation failed with status ${res.status}`);
57
+ }
58
+ return data;
59
+ }
45
60
  async getUserProfile() {
46
61
  this.checkAuth();
47
62
  const res = await fetch(`${this.baseUrl}/api/v1/profile`, {
package/dist/index.js CHANGED
@@ -19,7 +19,63 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
19
19
  tools: [
20
20
  {
21
21
  name: "publish_landing_page",
22
- description: "Creates, compiles, and publishes a landing page to Plexo in one atomic step. Returns the published live URL and editable visual builder URL.",
22
+ description: `Creates, compiles, and publishes a landing page to Plexo in one atomic step. Returns the published live URL and editable visual builder URL.
23
+
24
+ IMPORTANT INSTRUCTION FOR AI CLIENTS:
25
+ The designJson argument MUST be a fully hydrated layout tree containing body style and rows array. There is no shorthand format —
26
+ do NOT send rows shaped like { "type": "products", "content": { "items": [...] } }. That will be REJECTED with a validation error.
27
+ Every row MUST already contain a 'columns' array with percentage widths ('100%', '50%', '33.33%'), and each column MUST contain an
28
+ 'elements' array with fully-styled component objects ('heading', 'paragraph', 'button', 'card', 'image', 'menu', 'social', 'divider',
29
+ 'spacer', 'form_container'). For any repeated-item section (products, features, testimonials, pricing tiers, etc.) YOU must expand
30
+ each item into its own column with real elements — one column per item — rather than passing a list for the server to interpret.
31
+
32
+ EXAMPLE VALID designJson PAYLOAD (hero row, plus a 3-item product grid row):
33
+ {
34
+ "body": {
35
+ "style": { "backgroundColor": "#08090f", "color": "#f0f2ff", "fontFamily": "Inter, sans-serif", "htmlTitle": "Bulum SaaS Platform" },
36
+ "rows": [
37
+ {
38
+ "id": "row-hero",
39
+ "style": { "paddingTop": "80px", "paddingBottom": "80px" },
40
+ "columns": [
41
+ {
42
+ "id": "col-hero",
43
+ "width": "100%",
44
+ "elements": [
45
+ { "type": "heading", "style": { "fontSize": "48px", "fontWeight": "800", "textAlign": "center", "color": "#ffffff" }, "attributes": { "text": "Build & Scale Faster" } },
46
+ { "type": "paragraph", "style": { "fontSize": "18px", "color": "#94a3b8", "textAlign": "center" }, "attributes": { "text": "The ultimate platform for modern digital teams." } },
47
+ { "type": "button", "style": { "textAlign": "center", "backgroundColor": "#8b5cf6", "color": "#ffffff", "borderRadius": "12px", "paddingTop": "14px", "paddingBottom": "14px", "paddingLeft": "28px", "paddingRight": "28px" }, "attributes": { "text": "Start Free Trial", "href": "#signup" } }
48
+ ]
49
+ }
50
+ ]
51
+ },
52
+ {
53
+ "id": "row-products",
54
+ "style": { "paddingTop": "60px", "paddingBottom": "60px" },
55
+ "columns": [
56
+ { "id": "col-product-1", "width": "33.33%", "elements": [
57
+ { "type": "image", "style": { "width": "100%", "borderRadius": "12px" }, "attributes": { "src": "https://...", "alt": "Urban Runner" } },
58
+ { "type": "heading", "style": { "fontSize": "20px", "marginTop": "12px" }, "attributes": { "text": "Urban Runner" } },
59
+ { "type": "paragraph", "style": { "fontSize": "14px", "color": "#94a3b8" }, "attributes": { "text": "Lightweight sneakers for daily adventures" } },
60
+ { "type": "paragraph", "style": { "fontSize": "16px", "fontWeight": "700", "color": "#8b5cf6" }, "attributes": { "text": "$89" } }
61
+ ] },
62
+ { "id": "col-product-2", "width": "33.33%", "elements": [
63
+ { "type": "image", "style": { "width": "100%", "borderRadius": "12px" }, "attributes": { "src": "https://...", "alt": "Classic Court" } },
64
+ { "type": "heading", "style": { "fontSize": "20px", "marginTop": "12px" }, "attributes": { "text": "Classic Court" } },
65
+ { "type": "paragraph", "style": { "fontSize": "14px", "color": "#94a3b8" }, "attributes": { "text": "Timeless style with modern comfort" } },
66
+ { "type": "paragraph", "style": { "fontSize": "16px", "fontWeight": "700", "color": "#8b5cf6" }, "attributes": { "text": "$79" } }
67
+ ] },
68
+ { "id": "col-product-3", "width": "33.33%", "elements": [
69
+ { "type": "image", "style": { "width": "100%", "borderRadius": "12px" }, "attributes": { "src": "https://...", "alt": "Street Flex" } },
70
+ { "type": "heading", "style": { "fontSize": "20px", "marginTop": "12px" }, "attributes": { "text": "Street Flex" } },
71
+ { "type": "paragraph", "style": { "fontSize": "14px", "color": "#94a3b8" }, "attributes": { "text": "Flexible performance footwear" } },
72
+ { "type": "paragraph", "style": { "fontSize": "16px", "fontWeight": "700", "color": "#8b5cf6" }, "attributes": { "text": "$99" } }
73
+ ] }
74
+ ]
75
+ }
76
+ ]
77
+ }
78
+ }`,
23
79
  inputSchema: {
24
80
  type: "object",
25
81
  properties: {
@@ -29,11 +85,70 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
29
85
  },
30
86
  designJson: {
31
87
  type: "object",
32
- description: "Plexo layout schema containing body style and rows array",
88
+ description: "Plexo layout schema object containing body style and a fully hydrated rows array with columns and elements. See the tool description for the exact required shape and a worked example.",
89
+ required: ["body"],
90
+ properties: {
91
+ body: {
92
+ type: "object",
93
+ required: ["style", "rows"],
94
+ properties: {
95
+ style: {
96
+ type: "object",
97
+ description: "Global CSS style and page metadata.",
98
+ required: ["backgroundColor", "color", "fontFamily", "htmlTitle"],
99
+ properties: {
100
+ backgroundColor: { type: "string", description: "Background color of the page in hex format (e.g. '#08090f' for dark mode, '#ffffff' for light mode)." },
101
+ color: { type: "string", description: "Default text color of the page in hex format (e.g. '#f0f2ff' for dark mode, '#1e293b' for light mode)." },
102
+ fontFamily: { type: "string", description: "Font family of the page text (e.g. 'Inter, sans-serif')." },
103
+ htmlTitle: { type: "string", description: "The HTML title of the page (matches the brand name or page title, e.g. 'Bulum SaaS Platform')." },
104
+ },
105
+ },
106
+ rows: {
107
+ type: "array",
108
+ description: "Array of row objects. Every row MUST already have a 'columns' array — there is no shorthand row type; rows without 'columns' are rejected.",
109
+ items: {
110
+ type: "object",
111
+ required: ["id", "style", "columns"],
112
+ properties: {
113
+ id: { type: "string" },
114
+ style: { type: "object" },
115
+ columns: {
116
+ type: "array",
117
+ description: "Required. One entry per column — for a repeated-item section (products, features, testimonials), put one item per column here, not a nested list.",
118
+ items: {
119
+ type: "object",
120
+ required: ["id", "width", "elements"],
121
+ properties: {
122
+ id: { type: "string" },
123
+ width: { type: "string", description: "Percentage width (e.g. '100%', '50%', '33.33%')." },
124
+ elements: {
125
+ type: "array",
126
+ items: {
127
+ type: "object",
128
+ required: ["id", "type", "style", "attributes"],
129
+ properties: {
130
+ type: {
131
+ type: "string",
132
+ enum: ["heading", "paragraph", "button", "card", "image", "menu", "social", "divider", "spacer", "form_container", "table", "timer", "video"],
133
+ },
134
+ style: { type: "object" },
135
+ attributes: { type: "object", description: "Component attributes (text, href, src, title, description, links, fields)." },
136
+ },
137
+ },
138
+ },
139
+ },
140
+ },
141
+ },
142
+ },
143
+ },
144
+ },
145
+ },
146
+ },
147
+ },
33
148
  },
34
149
  compiledHtml: {
35
150
  type: "string",
36
- description: "Optional pre-compiled HTML string. If omitted, Plexo compiles designJson automatically.",
151
+ description: "Ignored. HTML is always compiled server-side from the validated designJson (and sanitized) so the published page can never drift from what's editable in the Plexo dashboard.",
37
152
  },
38
153
  domain: {
39
154
  type: "string",
@@ -48,6 +163,30 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
48
163
  required: ["designJson"],
49
164
  },
50
165
  },
166
+ {
167
+ name: "create_email_template",
168
+ description: `Creates and saves a responsive HTML email template for newsletters or promotional campaigns.
169
+
170
+ Uses the SAME fully-hydrated layout schema as publish_landing_page — designJson MUST be { "body": { "style": {...}, "rows": [{ "id", "style", "columns": [{ "id", "width", "elements": [{ "id", "type", "style", "attributes" }] }] }] } }. There is no shorthand row format; rows without a 'columns' array are rejected. See publish_landing_page's description for a full worked example. Email templates are saved but never published to a domain.`,
171
+ inputSchema: {
172
+ type: "object",
173
+ properties: {
174
+ name: {
175
+ type: "string",
176
+ description: "Subject line or template title (e.g. 'Weekly Newsletter #42')",
177
+ },
178
+ designJson: {
179
+ type: "object",
180
+ description: "Plexo layout schema object (same shape as publish_landing_page's designJson) containing body style and a fully hydrated rows array with columns and elements.",
181
+ },
182
+ compiledHtml: {
183
+ type: "string",
184
+ description: "Ignored. HTML is always compiled server-side from the validated designJson (and sanitized).",
185
+ },
186
+ },
187
+ required: ["designJson"],
188
+ },
189
+ },
51
190
  {
52
191
  name: "list_landing_pages",
53
192
  description: "Lists all saved landing page templates and published domain URLs in the user's Plexo account.",
@@ -122,6 +261,17 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
122
261
  ],
123
262
  };
124
263
  }
264
+ case "create_email_template": {
265
+ const result = await client.createEmailTemplate(args);
266
+ return {
267
+ content: [
268
+ {
269
+ type: "text",
270
+ text: JSON.stringify(result, null, 2),
271
+ },
272
+ ],
273
+ };
274
+ }
125
275
  case "list_landing_pages": {
126
276
  const data = await client.listTemplates();
127
277
  const landingPages = (data.templates || []).filter((t) => t.kind === "LANDING_PAGE");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@charisol/plexo-mcp",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Model Context Protocol (MCP) Server for Plexo - Landing page generation, email templates, publishing, and analytics.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -46,7 +46,7 @@ export class PlexoClient {
46
46
  const res = await fetch(`${this.baseUrl}/api/v1/publish`, {
47
47
  method: "POST",
48
48
  headers: this.getHeaders(),
49
- body: JSON.stringify(params),
49
+ body: JSON.stringify({ ...params, kind: "LANDING_PAGE" }),
50
50
  });
51
51
 
52
52
  const data = (await res.json()) as any;
@@ -57,6 +57,28 @@ export class PlexoClient {
57
57
  return data;
58
58
  }
59
59
 
60
+ async createEmailTemplate(params: {
61
+ name?: string;
62
+ designJson: Record<string, any>;
63
+ compiledHtml?: string;
64
+ }): Promise<any> {
65
+ this.checkAuth();
66
+ // Same /api/v1/publish endpoint as publishLandingPage — kind: "EMAIL" skips the
67
+ // domain-publishing step server-side and just saves the template.
68
+ const res = await fetch(`${this.baseUrl}/api/v1/publish`, {
69
+ method: "POST",
70
+ headers: this.getHeaders(),
71
+ body: JSON.stringify({ ...params, kind: "EMAIL" }),
72
+ });
73
+
74
+ const data = (await res.json()) as any;
75
+ if (!res.ok) {
76
+ throw new Error(data?.error || `Email template creation failed with status ${res.status}`);
77
+ }
78
+
79
+ return data;
80
+ }
81
+
60
82
  async getUserProfile(): Promise<any> {
61
83
  this.checkAuth();
62
84
  const res = await fetch(`${this.baseUrl}/api/v1/profile`, {
package/src/index.ts CHANGED
@@ -26,8 +26,63 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
26
26
  tools: [
27
27
  {
28
28
  name: "publish_landing_page",
29
- description:
30
- "Creates, compiles, and publishes a landing page to Plexo in one atomic step. Returns the published live URL and editable visual builder URL.",
29
+ description: `Creates, compiles, and publishes a landing page to Plexo in one atomic step. Returns the published live URL and editable visual builder URL.
30
+
31
+ IMPORTANT INSTRUCTION FOR AI CLIENTS:
32
+ The designJson argument MUST be a fully hydrated layout tree containing body style and rows array. There is no shorthand format —
33
+ do NOT send rows shaped like { "type": "products", "content": { "items": [...] } }. That will be REJECTED with a validation error.
34
+ Every row MUST already contain a 'columns' array with percentage widths ('100%', '50%', '33.33%'), and each column MUST contain an
35
+ 'elements' array with fully-styled component objects ('heading', 'paragraph', 'button', 'card', 'image', 'menu', 'social', 'divider',
36
+ 'spacer', 'form_container'). For any repeated-item section (products, features, testimonials, pricing tiers, etc.) YOU must expand
37
+ each item into its own column with real elements — one column per item — rather than passing a list for the server to interpret.
38
+
39
+ EXAMPLE VALID designJson PAYLOAD (hero row, plus a 3-item product grid row):
40
+ {
41
+ "body": {
42
+ "style": { "backgroundColor": "#08090f", "color": "#f0f2ff", "fontFamily": "Inter, sans-serif", "htmlTitle": "Bulum SaaS Platform" },
43
+ "rows": [
44
+ {
45
+ "id": "row-hero",
46
+ "style": { "paddingTop": "80px", "paddingBottom": "80px" },
47
+ "columns": [
48
+ {
49
+ "id": "col-hero",
50
+ "width": "100%",
51
+ "elements": [
52
+ { "type": "heading", "style": { "fontSize": "48px", "fontWeight": "800", "textAlign": "center", "color": "#ffffff" }, "attributes": { "text": "Build & Scale Faster" } },
53
+ { "type": "paragraph", "style": { "fontSize": "18px", "color": "#94a3b8", "textAlign": "center" }, "attributes": { "text": "The ultimate platform for modern digital teams." } },
54
+ { "type": "button", "style": { "textAlign": "center", "backgroundColor": "#8b5cf6", "color": "#ffffff", "borderRadius": "12px", "paddingTop": "14px", "paddingBottom": "14px", "paddingLeft": "28px", "paddingRight": "28px" }, "attributes": { "text": "Start Free Trial", "href": "#signup" } }
55
+ ]
56
+ }
57
+ ]
58
+ },
59
+ {
60
+ "id": "row-products",
61
+ "style": { "paddingTop": "60px", "paddingBottom": "60px" },
62
+ "columns": [
63
+ { "id": "col-product-1", "width": "33.33%", "elements": [
64
+ { "type": "image", "style": { "width": "100%", "borderRadius": "12px" }, "attributes": { "src": "https://...", "alt": "Urban Runner" } },
65
+ { "type": "heading", "style": { "fontSize": "20px", "marginTop": "12px" }, "attributes": { "text": "Urban Runner" } },
66
+ { "type": "paragraph", "style": { "fontSize": "14px", "color": "#94a3b8" }, "attributes": { "text": "Lightweight sneakers for daily adventures" } },
67
+ { "type": "paragraph", "style": { "fontSize": "16px", "fontWeight": "700", "color": "#8b5cf6" }, "attributes": { "text": "$89" } }
68
+ ] },
69
+ { "id": "col-product-2", "width": "33.33%", "elements": [
70
+ { "type": "image", "style": { "width": "100%", "borderRadius": "12px" }, "attributes": { "src": "https://...", "alt": "Classic Court" } },
71
+ { "type": "heading", "style": { "fontSize": "20px", "marginTop": "12px" }, "attributes": { "text": "Classic Court" } },
72
+ { "type": "paragraph", "style": { "fontSize": "14px", "color": "#94a3b8" }, "attributes": { "text": "Timeless style with modern comfort" } },
73
+ { "type": "paragraph", "style": { "fontSize": "16px", "fontWeight": "700", "color": "#8b5cf6" }, "attributes": { "text": "$79" } }
74
+ ] },
75
+ { "id": "col-product-3", "width": "33.33%", "elements": [
76
+ { "type": "image", "style": { "width": "100%", "borderRadius": "12px" }, "attributes": { "src": "https://...", "alt": "Street Flex" } },
77
+ { "type": "heading", "style": { "fontSize": "20px", "marginTop": "12px" }, "attributes": { "text": "Street Flex" } },
78
+ { "type": "paragraph", "style": { "fontSize": "14px", "color": "#94a3b8" }, "attributes": { "text": "Flexible performance footwear" } },
79
+ { "type": "paragraph", "style": { "fontSize": "16px", "fontWeight": "700", "color": "#8b5cf6" }, "attributes": { "text": "$99" } }
80
+ ] }
81
+ ]
82
+ }
83
+ ]
84
+ }
85
+ }`,
31
86
  inputSchema: {
32
87
  type: "object",
33
88
  properties: {
@@ -37,11 +92,70 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
37
92
  },
38
93
  designJson: {
39
94
  type: "object",
40
- description: "Plexo layout schema containing body style and rows array",
95
+ description: "Plexo layout schema object containing body style and a fully hydrated rows array with columns and elements. See the tool description for the exact required shape and a worked example.",
96
+ required: ["body"],
97
+ properties: {
98
+ body: {
99
+ type: "object",
100
+ required: ["style", "rows"],
101
+ properties: {
102
+ style: {
103
+ type: "object",
104
+ description: "Global CSS style and page metadata.",
105
+ required: ["backgroundColor", "color", "fontFamily", "htmlTitle"],
106
+ properties: {
107
+ backgroundColor: { type: "string", description: "Background color of the page in hex format (e.g. '#08090f' for dark mode, '#ffffff' for light mode)." },
108
+ color: { type: "string", description: "Default text color of the page in hex format (e.g. '#f0f2ff' for dark mode, '#1e293b' for light mode)." },
109
+ fontFamily: { type: "string", description: "Font family of the page text (e.g. 'Inter, sans-serif')." },
110
+ htmlTitle: { type: "string", description: "The HTML title of the page (matches the brand name or page title, e.g. 'Bulum SaaS Platform')." },
111
+ },
112
+ },
113
+ rows: {
114
+ type: "array",
115
+ description: "Array of row objects. Every row MUST already have a 'columns' array — there is no shorthand row type; rows without 'columns' are rejected.",
116
+ items: {
117
+ type: "object",
118
+ required: ["id", "style", "columns"],
119
+ properties: {
120
+ id: { type: "string" },
121
+ style: { type: "object" },
122
+ columns: {
123
+ type: "array",
124
+ description: "Required. One entry per column — for a repeated-item section (products, features, testimonials), put one item per column here, not a nested list.",
125
+ items: {
126
+ type: "object",
127
+ required: ["id", "width", "elements"],
128
+ properties: {
129
+ id: { type: "string" },
130
+ width: { type: "string", description: "Percentage width (e.g. '100%', '50%', '33.33%')." },
131
+ elements: {
132
+ type: "array",
133
+ items: {
134
+ type: "object",
135
+ required: ["id", "type", "style", "attributes"],
136
+ properties: {
137
+ type: {
138
+ type: "string",
139
+ enum: ["heading", "paragraph", "button", "card", "image", "menu", "social", "divider", "spacer", "form_container", "table", "timer", "video"],
140
+ },
141
+ style: { type: "object" },
142
+ attributes: { type: "object", description: "Component attributes (text, href, src, title, description, links, fields)." },
143
+ },
144
+ },
145
+ },
146
+ },
147
+ },
148
+ },
149
+ },
150
+ },
151
+ },
152
+ },
153
+ },
154
+ },
41
155
  },
42
156
  compiledHtml: {
43
157
  type: "string",
44
- description: "Optional pre-compiled HTML string. If omitted, Plexo compiles designJson automatically.",
158
+ description: "Ignored. HTML is always compiled server-side from the validated designJson (and sanitized) so the published page can never drift from what's editable in the Plexo dashboard.",
45
159
  },
46
160
  domain: {
47
161
  type: "string",
@@ -56,6 +170,30 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
56
170
  required: ["designJson"],
57
171
  },
58
172
  },
173
+ {
174
+ name: "create_email_template",
175
+ description: `Creates and saves a responsive HTML email template for newsletters or promotional campaigns.
176
+
177
+ Uses the SAME fully-hydrated layout schema as publish_landing_page — designJson MUST be { "body": { "style": {...}, "rows": [{ "id", "style", "columns": [{ "id", "width", "elements": [{ "id", "type", "style", "attributes" }] }] }] } }. There is no shorthand row format; rows without a 'columns' array are rejected. See publish_landing_page's description for a full worked example. Email templates are saved but never published to a domain.`,
178
+ inputSchema: {
179
+ type: "object",
180
+ properties: {
181
+ name: {
182
+ type: "string",
183
+ description: "Subject line or template title (e.g. 'Weekly Newsletter #42')",
184
+ },
185
+ designJson: {
186
+ type: "object",
187
+ description: "Plexo layout schema object (same shape as publish_landing_page's designJson) containing body style and a fully hydrated rows array with columns and elements.",
188
+ },
189
+ compiledHtml: {
190
+ type: "string",
191
+ description: "Ignored. HTML is always compiled server-side from the validated designJson (and sanitized).",
192
+ },
193
+ },
194
+ required: ["designJson"],
195
+ },
196
+ },
59
197
  {
60
198
  name: "list_landing_pages",
61
199
  description: "Lists all saved landing page templates and published domain URLs in the user's Plexo account.",
@@ -133,6 +271,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
133
271
  };
134
272
  }
135
273
 
274
+ case "create_email_template": {
275
+ const result = await client.createEmailTemplate(args as any);
276
+ return {
277
+ content: [
278
+ {
279
+ type: "text",
280
+ text: JSON.stringify(result, null, 2),
281
+ },
282
+ ],
283
+ };
284
+ }
285
+
136
286
  case "list_landing_pages": {
137
287
  const data = await client.listTemplates();
138
288
  const landingPages = (data.templates || []).filter(