@charisol/plexo-mcp 1.0.3 → 1.0.4
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/dist/client/plexoClient.js +16 -0
- package/dist/index.js +97 -1
- package/package.json +1 -1
- package/src/client/plexoClient.ts +20 -0
- package/src/index.ts +98 -1
|
@@ -99,6 +99,22 @@ class PlexoClient {
|
|
|
99
99
|
}
|
|
100
100
|
return data;
|
|
101
101
|
}
|
|
102
|
+
async getStrataTokens(projectId) {
|
|
103
|
+
this.checkAuth();
|
|
104
|
+
const url = new URL(`${this.baseUrl}/api/v1/strata/tokens`);
|
|
105
|
+
if (projectId) {
|
|
106
|
+
url.searchParams.set("projectId", projectId);
|
|
107
|
+
}
|
|
108
|
+
const res = await fetch(url.toString(), {
|
|
109
|
+
method: "GET",
|
|
110
|
+
headers: this.getHeaders(),
|
|
111
|
+
});
|
|
112
|
+
const data = (await res.json());
|
|
113
|
+
if (!res.ok) {
|
|
114
|
+
throw new Error(data?.error || `Failed to fetch Strata tokens (Status ${res.status})`);
|
|
115
|
+
}
|
|
116
|
+
return data;
|
|
117
|
+
}
|
|
102
118
|
async listTemplates() {
|
|
103
119
|
this.checkAuth();
|
|
104
120
|
const res = await fetch(`${this.baseUrl}/api/templates`, {
|
package/dist/index.js
CHANGED
|
@@ -167,7 +167,7 @@ EXAMPLE VALID designJson PAYLOAD (hero row, plus a 3-item product grid row):
|
|
|
167
167
|
name: "create_email_template",
|
|
168
168
|
description: `Creates and saves a responsive HTML email template for newsletters or promotional campaigns.
|
|
169
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.`,
|
|
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. Text content for heading/paragraph/text/button elements MUST be under attributes.text (NOT attributes.content) — a "content" key is silently ignored by the editor and renders as empty/placeholder text. See publish_landing_page's description for a full worked example. Email templates are saved but never published to a domain.`,
|
|
171
171
|
inputSchema: {
|
|
172
172
|
type: "object",
|
|
173
173
|
properties: {
|
|
@@ -178,6 +178,74 @@ Uses the SAME fully-hydrated layout schema as publish_landing_page — designJso
|
|
|
178
178
|
designJson: {
|
|
179
179
|
type: "object",
|
|
180
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
|
+
required: ["body"],
|
|
182
|
+
properties: {
|
|
183
|
+
body: {
|
|
184
|
+
type: "object",
|
|
185
|
+
required: ["style", "rows"],
|
|
186
|
+
properties: {
|
|
187
|
+
style: {
|
|
188
|
+
type: "object",
|
|
189
|
+
description: "Global CSS style and page metadata.",
|
|
190
|
+
required: ["backgroundColor", "color", "fontFamily", "htmlTitle"],
|
|
191
|
+
properties: {
|
|
192
|
+
backgroundColor: { type: "string", description: "Background color of the email in hex format (e.g. '#F4F2F8')." },
|
|
193
|
+
color: { type: "string", description: "Default text color of the email in hex format." },
|
|
194
|
+
fontFamily: { type: "string", description: "Font family of the email text (e.g. 'Arial, Helvetica, sans-serif')." },
|
|
195
|
+
htmlTitle: { type: "string", description: "The HTML title of the email (matches the subject/brand name)." },
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
rows: {
|
|
199
|
+
type: "array",
|
|
200
|
+
description: "Array of row objects. Every row MUST already have a 'columns' array — there is no shorthand row type; rows without 'columns' are rejected.",
|
|
201
|
+
items: {
|
|
202
|
+
type: "object",
|
|
203
|
+
required: ["id", "style", "columns"],
|
|
204
|
+
properties: {
|
|
205
|
+
id: { type: "string" },
|
|
206
|
+
style: { type: "object" },
|
|
207
|
+
columns: {
|
|
208
|
+
type: "array",
|
|
209
|
+
description: "Required. One entry per column.",
|
|
210
|
+
items: {
|
|
211
|
+
type: "object",
|
|
212
|
+
required: ["id", "width", "elements"],
|
|
213
|
+
properties: {
|
|
214
|
+
id: { type: "string" },
|
|
215
|
+
width: { type: "string", description: "Percentage width (e.g. '100%', '50%', '33.33%')." },
|
|
216
|
+
elements: {
|
|
217
|
+
type: "array",
|
|
218
|
+
items: {
|
|
219
|
+
type: "object",
|
|
220
|
+
required: ["id", "type", "style", "attributes"],
|
|
221
|
+
properties: {
|
|
222
|
+
type: {
|
|
223
|
+
type: "string",
|
|
224
|
+
enum: ["heading", "paragraph", "text", "button", "card", "image", "menu", "social", "divider", "spacer", "form_container", "input", "textarea", "select", "carousel", "html", "icon", "table", "timer", "video"],
|
|
225
|
+
},
|
|
226
|
+
style: { type: "object" },
|
|
227
|
+
attributes: {
|
|
228
|
+
type: "object",
|
|
229
|
+
description: "Component attributes. IMPORTANT: text content for 'heading'/'paragraph'/'text'/'button' elements goes under the key 'text' (NOT 'content'). Images use 'src'/'alt'. Buttons/links use 'href'.",
|
|
230
|
+
properties: {
|
|
231
|
+
text: { type: "string", description: "Visible text for heading/paragraph/text/button elements." },
|
|
232
|
+
href: { type: "string", description: "Link URL for button/card elements." },
|
|
233
|
+
src: { type: "string", description: "Image URL for image elements." },
|
|
234
|
+
alt: { type: "string", description: "Alt text for image elements." },
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
},
|
|
181
249
|
},
|
|
182
250
|
compiledHtml: {
|
|
183
251
|
type: "string",
|
|
@@ -187,6 +255,23 @@ Uses the SAME fully-hydrated layout schema as publish_landing_page — designJso
|
|
|
187
255
|
required: ["designJson"],
|
|
188
256
|
},
|
|
189
257
|
},
|
|
258
|
+
{
|
|
259
|
+
name: "get_strata_tokens",
|
|
260
|
+
description: `Checks whether the account has a Strata design-system project connected and, if so, fetches its design tokens (colors, typography, spacing, etc).
|
|
261
|
+
|
|
262
|
+
Call this BEFORE publish_landing_page or create_email_template whenever the user wants their brand/Strata colors and styles used. Call with no arguments first to check the currently connected project. If the result has "connected": false, ask the user for their Strata project id (found in their Strata project's snapshot/share URL) and call this tool again with that projectId — it connects the account to that project (remembered for future calls) and fetches its tokens in the same call.
|
|
263
|
+
|
|
264
|
+
Map the returned tokens into designJson style fields: color-type tokens into backgroundColor/color/borderColor, spacing-type tokens into padding/margin values, and any font-related tokens into fontFamily/fontSize. Prefer tokens whose "name" hints at their role (e.g. a name containing "primary", "background", "text", "accent").`,
|
|
265
|
+
inputSchema: {
|
|
266
|
+
type: "object",
|
|
267
|
+
properties: {
|
|
268
|
+
projectId: {
|
|
269
|
+
type: "string",
|
|
270
|
+
description: "Optional. The user's Strata project id to connect (or switch to). Omit to check/use the previously connected project, if any.",
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
},
|
|
190
275
|
{
|
|
191
276
|
name: "update_template",
|
|
192
277
|
description: `Edits an existing landing page or email template in place, under the same template ID. Recompiles and re-saves the HTML from the new designJson — the editable URL stays the same, and for a published landing page the live URL and domain are unchanged too (this does not publish/unpublish or change the domain; call publish_landing_page again with a domain for that).
|
|
@@ -300,6 +385,17 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
300
385
|
],
|
|
301
386
|
};
|
|
302
387
|
}
|
|
388
|
+
case "get_strata_tokens": {
|
|
389
|
+
const result = await client.getStrataTokens(args?.projectId);
|
|
390
|
+
return {
|
|
391
|
+
content: [
|
|
392
|
+
{
|
|
393
|
+
type: "text",
|
|
394
|
+
text: JSON.stringify(result, null, 2),
|
|
395
|
+
},
|
|
396
|
+
],
|
|
397
|
+
};
|
|
398
|
+
}
|
|
303
399
|
case "update_template": {
|
|
304
400
|
const result = await client.updateTemplate(args);
|
|
305
401
|
return {
|
package/package.json
CHANGED
|
@@ -136,6 +136,26 @@ export class PlexoClient {
|
|
|
136
136
|
return data;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
async getStrataTokens(projectId?: string): Promise<any> {
|
|
140
|
+
this.checkAuth();
|
|
141
|
+
const url = new URL(`${this.baseUrl}/api/v1/strata/tokens`);
|
|
142
|
+
if (projectId) {
|
|
143
|
+
url.searchParams.set("projectId", projectId);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const res = await fetch(url.toString(), {
|
|
147
|
+
method: "GET",
|
|
148
|
+
headers: this.getHeaders(),
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const data = (await res.json()) as any;
|
|
152
|
+
if (!res.ok) {
|
|
153
|
+
throw new Error(data?.error || `Failed to fetch Strata tokens (Status ${res.status})`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return data;
|
|
157
|
+
}
|
|
158
|
+
|
|
139
159
|
async listTemplates(): Promise<any> {
|
|
140
160
|
this.checkAuth();
|
|
141
161
|
const res = await fetch(`${this.baseUrl}/api/templates`, {
|
package/src/index.ts
CHANGED
|
@@ -174,7 +174,7 @@ EXAMPLE VALID designJson PAYLOAD (hero row, plus a 3-item product grid row):
|
|
|
174
174
|
name: "create_email_template",
|
|
175
175
|
description: `Creates and saves a responsive HTML email template for newsletters or promotional campaigns.
|
|
176
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.`,
|
|
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. Text content for heading/paragraph/text/button elements MUST be under attributes.text (NOT attributes.content) — a "content" key is silently ignored by the editor and renders as empty/placeholder text. See publish_landing_page's description for a full worked example. Email templates are saved but never published to a domain.`,
|
|
178
178
|
inputSchema: {
|
|
179
179
|
type: "object",
|
|
180
180
|
properties: {
|
|
@@ -185,6 +185,74 @@ Uses the SAME fully-hydrated layout schema as publish_landing_page — designJso
|
|
|
185
185
|
designJson: {
|
|
186
186
|
type: "object",
|
|
187
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
|
+
required: ["body"],
|
|
189
|
+
properties: {
|
|
190
|
+
body: {
|
|
191
|
+
type: "object",
|
|
192
|
+
required: ["style", "rows"],
|
|
193
|
+
properties: {
|
|
194
|
+
style: {
|
|
195
|
+
type: "object",
|
|
196
|
+
description: "Global CSS style and page metadata.",
|
|
197
|
+
required: ["backgroundColor", "color", "fontFamily", "htmlTitle"],
|
|
198
|
+
properties: {
|
|
199
|
+
backgroundColor: { type: "string", description: "Background color of the email in hex format (e.g. '#F4F2F8')." },
|
|
200
|
+
color: { type: "string", description: "Default text color of the email in hex format." },
|
|
201
|
+
fontFamily: { type: "string", description: "Font family of the email text (e.g. 'Arial, Helvetica, sans-serif')." },
|
|
202
|
+
htmlTitle: { type: "string", description: "The HTML title of the email (matches the subject/brand name)." },
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
rows: {
|
|
206
|
+
type: "array",
|
|
207
|
+
description: "Array of row objects. Every row MUST already have a 'columns' array — there is no shorthand row type; rows without 'columns' are rejected.",
|
|
208
|
+
items: {
|
|
209
|
+
type: "object",
|
|
210
|
+
required: ["id", "style", "columns"],
|
|
211
|
+
properties: {
|
|
212
|
+
id: { type: "string" },
|
|
213
|
+
style: { type: "object" },
|
|
214
|
+
columns: {
|
|
215
|
+
type: "array",
|
|
216
|
+
description: "Required. One entry per column.",
|
|
217
|
+
items: {
|
|
218
|
+
type: "object",
|
|
219
|
+
required: ["id", "width", "elements"],
|
|
220
|
+
properties: {
|
|
221
|
+
id: { type: "string" },
|
|
222
|
+
width: { type: "string", description: "Percentage width (e.g. '100%', '50%', '33.33%')." },
|
|
223
|
+
elements: {
|
|
224
|
+
type: "array",
|
|
225
|
+
items: {
|
|
226
|
+
type: "object",
|
|
227
|
+
required: ["id", "type", "style", "attributes"],
|
|
228
|
+
properties: {
|
|
229
|
+
type: {
|
|
230
|
+
type: "string",
|
|
231
|
+
enum: ["heading", "paragraph", "text", "button", "card", "image", "menu", "social", "divider", "spacer", "form_container", "input", "textarea", "select", "carousel", "html", "icon", "table", "timer", "video"],
|
|
232
|
+
},
|
|
233
|
+
style: { type: "object" },
|
|
234
|
+
attributes: {
|
|
235
|
+
type: "object",
|
|
236
|
+
description: "Component attributes. IMPORTANT: text content for 'heading'/'paragraph'/'text'/'button' elements goes under the key 'text' (NOT 'content'). Images use 'src'/'alt'. Buttons/links use 'href'.",
|
|
237
|
+
properties: {
|
|
238
|
+
text: { type: "string", description: "Visible text for heading/paragraph/text/button elements." },
|
|
239
|
+
href: { type: "string", description: "Link URL for button/card elements." },
|
|
240
|
+
src: { type: "string", description: "Image URL for image elements." },
|
|
241
|
+
alt: { type: "string", description: "Alt text for image elements." },
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
},
|
|
188
256
|
},
|
|
189
257
|
compiledHtml: {
|
|
190
258
|
type: "string",
|
|
@@ -194,6 +262,23 @@ Uses the SAME fully-hydrated layout schema as publish_landing_page — designJso
|
|
|
194
262
|
required: ["designJson"],
|
|
195
263
|
},
|
|
196
264
|
},
|
|
265
|
+
{
|
|
266
|
+
name: "get_strata_tokens",
|
|
267
|
+
description: `Checks whether the account has a Strata design-system project connected and, if so, fetches its design tokens (colors, typography, spacing, etc).
|
|
268
|
+
|
|
269
|
+
Call this BEFORE publish_landing_page or create_email_template whenever the user wants their brand/Strata colors and styles used. Call with no arguments first to check the currently connected project. If the result has "connected": false, ask the user for their Strata project id (found in their Strata project's snapshot/share URL) and call this tool again with that projectId — it connects the account to that project (remembered for future calls) and fetches its tokens in the same call.
|
|
270
|
+
|
|
271
|
+
Map the returned tokens into designJson style fields: color-type tokens into backgroundColor/color/borderColor, spacing-type tokens into padding/margin values, and any font-related tokens into fontFamily/fontSize. Prefer tokens whose "name" hints at their role (e.g. a name containing "primary", "background", "text", "accent").`,
|
|
272
|
+
inputSchema: {
|
|
273
|
+
type: "object",
|
|
274
|
+
properties: {
|
|
275
|
+
projectId: {
|
|
276
|
+
type: "string",
|
|
277
|
+
description: "Optional. The user's Strata project id to connect (or switch to). Omit to check/use the previously connected project, if any.",
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
},
|
|
197
282
|
{
|
|
198
283
|
name: "update_template",
|
|
199
284
|
description: `Edits an existing landing page or email template in place, under the same template ID. Recompiles and re-saves the HTML from the new designJson — the editable URL stays the same, and for a published landing page the live URL and domain are unchanged too (this does not publish/unpublish or change the domain; call publish_landing_page again with a domain for that).
|
|
@@ -311,6 +396,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
311
396
|
};
|
|
312
397
|
}
|
|
313
398
|
|
|
399
|
+
case "get_strata_tokens": {
|
|
400
|
+
const result = await client.getStrataTokens((args as any)?.projectId);
|
|
401
|
+
return {
|
|
402
|
+
content: [
|
|
403
|
+
{
|
|
404
|
+
type: "text",
|
|
405
|
+
text: JSON.stringify(result, null, 2),
|
|
406
|
+
},
|
|
407
|
+
],
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
314
411
|
case "update_template": {
|
|
315
412
|
const result = await client.updateTemplate(args as any);
|
|
316
413
|
return {
|