@buzzposter/mcp 0.3.5 → 0.3.7
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/index.js +540 -120
- package/dist/tools.d.ts +22 -1
- package/dist/tools.js +534 -120
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -118,6 +118,79 @@ var BuzzPosterClient = class {
|
|
|
118
118
|
async uploadFromUrl(data) {
|
|
119
119
|
return this.request("POST", "/api/v1/media/upload-from-url", data);
|
|
120
120
|
}
|
|
121
|
+
async uploadFile(filePath, filename) {
|
|
122
|
+
const fs4 = await import("fs");
|
|
123
|
+
const pathMod = await import("path");
|
|
124
|
+
const buffer = fs4.readFileSync(filePath);
|
|
125
|
+
const name = filename || pathMod.basename(filePath);
|
|
126
|
+
const ext = pathMod.extname(name).toLowerCase();
|
|
127
|
+
const mimeMap = {
|
|
128
|
+
".jpg": "image/jpeg",
|
|
129
|
+
".jpeg": "image/jpeg",
|
|
130
|
+
".png": "image/png",
|
|
131
|
+
".gif": "image/gif",
|
|
132
|
+
".webp": "image/webp",
|
|
133
|
+
".svg": "image/svg+xml",
|
|
134
|
+
".mp4": "video/mp4",
|
|
135
|
+
".mov": "video/quicktime",
|
|
136
|
+
".webm": "video/webm"
|
|
137
|
+
};
|
|
138
|
+
const mime = mimeMap[ext] || "application/octet-stream";
|
|
139
|
+
const formData = new FormData();
|
|
140
|
+
formData.append("file", new Blob([buffer], { type: mime }), name);
|
|
141
|
+
const url = new URL(`${this.baseUrl}/api/v1/media/upload`);
|
|
142
|
+
const headers = {
|
|
143
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
144
|
+
};
|
|
145
|
+
if (this.organizationId) {
|
|
146
|
+
headers["X-Organization-Id"] = this.organizationId;
|
|
147
|
+
}
|
|
148
|
+
const res = await fetch(url, { method: "POST", headers, body: formData });
|
|
149
|
+
if (!res.ok) {
|
|
150
|
+
const errorBody = await res.json().catch(() => ({ message: res.statusText }));
|
|
151
|
+
let message = `API error (${res.status})`;
|
|
152
|
+
if (errorBody && typeof errorBody === "object") {
|
|
153
|
+
const b = errorBody;
|
|
154
|
+
if (typeof b.message === "string" && b.message) message = b.message;
|
|
155
|
+
else if (typeof b.error === "string" && b.error) message = b.error;
|
|
156
|
+
}
|
|
157
|
+
throw new Error(`BuzzPoster API error (${res.status}): ${message}`);
|
|
158
|
+
}
|
|
159
|
+
const text = await res.text();
|
|
160
|
+
return text ? JSON.parse(text) : void 0;
|
|
161
|
+
}
|
|
162
|
+
async uploadBase64(data, filename, contentType) {
|
|
163
|
+
const buffer = Buffer.from(data, "base64");
|
|
164
|
+
const mime = contentType || "application/octet-stream";
|
|
165
|
+
const formData = new FormData();
|
|
166
|
+
formData.append("file", new Blob([buffer], { type: mime }), filename);
|
|
167
|
+
const url = new URL(`${this.baseUrl}/api/v1/media/upload`);
|
|
168
|
+
const headers = {
|
|
169
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
170
|
+
};
|
|
171
|
+
if (this.organizationId) {
|
|
172
|
+
headers["X-Organization-Id"] = this.organizationId;
|
|
173
|
+
}
|
|
174
|
+
const res = await fetch(url, { method: "POST", headers, body: formData });
|
|
175
|
+
if (!res.ok) {
|
|
176
|
+
const errorBody = await res.json().catch(() => ({ message: res.statusText }));
|
|
177
|
+
let message = `API error (${res.status})`;
|
|
178
|
+
if (errorBody && typeof errorBody === "object") {
|
|
179
|
+
const b = errorBody;
|
|
180
|
+
if (typeof b.message === "string" && b.message) message = b.message;
|
|
181
|
+
else if (typeof b.error === "string" && b.error) message = b.error;
|
|
182
|
+
}
|
|
183
|
+
throw new Error(`BuzzPoster API error (${res.status}): ${message}`);
|
|
184
|
+
}
|
|
185
|
+
const text = await res.text();
|
|
186
|
+
return text ? JSON.parse(text) : void 0;
|
|
187
|
+
}
|
|
188
|
+
async presignUpload(filename, contentType) {
|
|
189
|
+
return this.request("POST", "/api/v1/media/presign", { filename, content_type: contentType });
|
|
190
|
+
}
|
|
191
|
+
async confirmUpload(key, filename, contentType) {
|
|
192
|
+
return this.request("POST", "/api/v1/media/confirm-upload", { key, filename, content_type: contentType });
|
|
193
|
+
}
|
|
121
194
|
async listMedia() {
|
|
122
195
|
return this.request("GET", "/api/v1/media");
|
|
123
196
|
}
|
|
@@ -1258,14 +1331,17 @@ function registerMediaTools(server2, client2) {
|
|
|
1258
1331
|
"manage_media",
|
|
1259
1332
|
{
|
|
1260
1333
|
title: "Manage Media",
|
|
1261
|
-
description: "Browse assets gallery, upload from URL, list files, or delete media.",
|
|
1334
|
+
description: "Browse assets gallery, upload from URL, local file, or base64 data, list files, or delete media.",
|
|
1262
1335
|
inputSchema: {
|
|
1263
|
-
action: z3.enum(["get_assets", "upload", "list", "delete"]),
|
|
1336
|
+
action: z3.enum(["get_assets", "upload", "upload_file", "upload_base64", "presign", "confirm_upload", "list", "delete"]),
|
|
1264
1337
|
limit: z3.number().optional().describe("Max assets to return (get_assets, default 10, max 20)"),
|
|
1265
1338
|
url: z3.string().optional().describe("Public URL to upload (upload)"),
|
|
1266
|
-
|
|
1339
|
+
file_path: z3.string().optional().describe("Local file path to upload (upload_file)"),
|
|
1340
|
+
data: z3.string().optional().describe("Base64-encoded file contents (upload_base64)"),
|
|
1341
|
+
content_type: z3.string().optional().describe("MIME type e.g. image/png (upload_base64, presign, confirm_upload)"),
|
|
1342
|
+
filename: z3.string().optional().describe("Filename (upload, upload_file, upload_base64, presign, confirm_upload)"),
|
|
1267
1343
|
folder: z3.string().optional().describe("Storage folder path (upload)"),
|
|
1268
|
-
key: z3.string().optional().describe("Media file key/path (delete)"),
|
|
1344
|
+
key: z3.string().optional().describe("Media file key/path (delete, confirm_upload)"),
|
|
1269
1345
|
confirmed: z3.boolean().default(false).describe("Confirm deletion (delete)")
|
|
1270
1346
|
},
|
|
1271
1347
|
annotations: {
|
|
@@ -1342,6 +1418,92 @@ function registerMediaTools(server2, client2) {
|
|
|
1342
1418
|
content: [{ type: "text", text: lines.join("\n") }]
|
|
1343
1419
|
};
|
|
1344
1420
|
}
|
|
1421
|
+
if (args.action === "upload_file") {
|
|
1422
|
+
if (!args.file_path) {
|
|
1423
|
+
return { content: [{ type: "text", text: "file_path is required for upload_file." }], isError: true };
|
|
1424
|
+
}
|
|
1425
|
+
if (!fs2.existsSync(args.file_path)) {
|
|
1426
|
+
return { content: [{ type: "text", text: `File not found: ${args.file_path}` }], isError: true };
|
|
1427
|
+
}
|
|
1428
|
+
const result = await client2.uploadFile(args.file_path, args.filename);
|
|
1429
|
+
const lines = [];
|
|
1430
|
+
lines.push("## Upload Complete");
|
|
1431
|
+
lines.push("");
|
|
1432
|
+
lines.push(`**URL:** ${result.url ?? "unknown"}`);
|
|
1433
|
+
lines.push(`**Filename:** ${result.filename ?? "unknown"}`);
|
|
1434
|
+
lines.push(`**Size:** ${formatSize(result.size)}`);
|
|
1435
|
+
lines.push(`**Type:** ${result.mimeType ?? "unknown"}`);
|
|
1436
|
+
return {
|
|
1437
|
+
content: [{ type: "text", text: lines.join("\n") }]
|
|
1438
|
+
};
|
|
1439
|
+
}
|
|
1440
|
+
if (args.action === "upload_base64") {
|
|
1441
|
+
if (!args.data) {
|
|
1442
|
+
return { content: [{ type: "text", text: "data (base64 string) is required for upload_base64." }], isError: true };
|
|
1443
|
+
}
|
|
1444
|
+
if (!args.filename) {
|
|
1445
|
+
return { content: [{ type: "text", text: "filename is required for upload_base64." }], isError: true };
|
|
1446
|
+
}
|
|
1447
|
+
const result = await client2.uploadBase64(args.data, args.filename, args.content_type);
|
|
1448
|
+
const lines = [];
|
|
1449
|
+
lines.push("## Upload Complete");
|
|
1450
|
+
lines.push("");
|
|
1451
|
+
lines.push(`**URL:** ${result.url ?? "unknown"}`);
|
|
1452
|
+
lines.push(`**Filename:** ${result.filename ?? "unknown"}`);
|
|
1453
|
+
lines.push(`**Size:** ${formatSize(result.size)}`);
|
|
1454
|
+
lines.push(`**Type:** ${result.mimeType ?? "unknown"}`);
|
|
1455
|
+
return {
|
|
1456
|
+
content: [{ type: "text", text: lines.join("\n") }]
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
if (args.action === "presign") {
|
|
1460
|
+
if (!args.filename) {
|
|
1461
|
+
return { content: [{ type: "text", text: "filename is required for presign." }], isError: true };
|
|
1462
|
+
}
|
|
1463
|
+
if (!args.content_type) {
|
|
1464
|
+
return { content: [{ type: "text", text: "content_type is required for presign (e.g. image/png)." }], isError: true };
|
|
1465
|
+
}
|
|
1466
|
+
const result = await client2.presignUpload(args.filename, args.content_type);
|
|
1467
|
+
const lines = [];
|
|
1468
|
+
lines.push("## Presigned Upload URL");
|
|
1469
|
+
lines.push("");
|
|
1470
|
+
lines.push(`**Upload URL:** ${result.upload_url}`);
|
|
1471
|
+
lines.push(`**CDN URL:** ${result.cdn_url}`);
|
|
1472
|
+
lines.push(`**Key:** ${result.key}`);
|
|
1473
|
+
lines.push(`**Expires:** ${result.expires_at}`);
|
|
1474
|
+
lines.push("");
|
|
1475
|
+
lines.push("**Step 1:** Upload the file:");
|
|
1476
|
+
lines.push("```");
|
|
1477
|
+
lines.push(`curl -X PUT -H "Content-Type: ${args.content_type}" --data-binary @${args.filename} "${result.upload_url}"`);
|
|
1478
|
+
lines.push("```");
|
|
1479
|
+
lines.push("");
|
|
1480
|
+
lines.push(`**Step 2:** Register the upload by calling this tool with action=confirm_upload, key="${result.key}", filename="${args.filename}", content_type="${args.content_type}"`);
|
|
1481
|
+
return {
|
|
1482
|
+
content: [{ type: "text", text: lines.join("\n") }]
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
if (args.action === "confirm_upload") {
|
|
1486
|
+
if (!args.key) {
|
|
1487
|
+
return { content: [{ type: "text", text: "key is required for confirm_upload." }], isError: true };
|
|
1488
|
+
}
|
|
1489
|
+
if (!args.filename) {
|
|
1490
|
+
return { content: [{ type: "text", text: "filename is required for confirm_upload." }], isError: true };
|
|
1491
|
+
}
|
|
1492
|
+
if (!args.content_type) {
|
|
1493
|
+
return { content: [{ type: "text", text: "content_type is required for confirm_upload." }], isError: true };
|
|
1494
|
+
}
|
|
1495
|
+
const result = await client2.confirmUpload(args.key, args.filename, args.content_type);
|
|
1496
|
+
const lines = [];
|
|
1497
|
+
lines.push("## Upload Confirmed");
|
|
1498
|
+
lines.push("");
|
|
1499
|
+
lines.push(`**URL:** ${result.url}`);
|
|
1500
|
+
lines.push(`**Filename:** ${result.filename}`);
|
|
1501
|
+
lines.push(`**Size:** ${formatSize(result.size)}`);
|
|
1502
|
+
lines.push(`**Type:** ${result.mimeType}`);
|
|
1503
|
+
return {
|
|
1504
|
+
content: [{ type: "text", text: lines.join("\n") }]
|
|
1505
|
+
};
|
|
1506
|
+
}
|
|
1345
1507
|
if (args.action === "list") {
|
|
1346
1508
|
const result = await client2.listMedia();
|
|
1347
1509
|
const items = result?.media ?? [];
|
|
@@ -1384,16 +1546,267 @@ This will permanently delete this media file. Call this tool again with confirme
|
|
|
1384
1546
|
);
|
|
1385
1547
|
}
|
|
1386
1548
|
|
|
1387
|
-
// src/tools/
|
|
1549
|
+
// src/tools/newsletter.ts
|
|
1388
1550
|
import { z as z4 } from "zod";
|
|
1551
|
+
function registerNewsletterTools(server2, client2, options = {}) {
|
|
1552
|
+
server2.tool(
|
|
1553
|
+
"manage_newsletters",
|
|
1554
|
+
"Create, update, send, schedule, or list newsletters.\n\nIMPORTANT \u2014 Template-based creation:\n1. Call get_context with include_newsletter_template=true to get the user's template with section IDs\n2. Call create with template_id + sections array (NOT raw content HTML)\n3. The server assembles styled HTML from the template design + your section content\n\nOnly use raw content HTML if the user has no templates or explicitly asks for custom HTML.",
|
|
1555
|
+
{
|
|
1556
|
+
action: z4.enum(["create", "update", "send", "schedule", "list"]),
|
|
1557
|
+
broadcast_id: z4.string().optional().describe("Newsletter ID (update/send/schedule)"),
|
|
1558
|
+
subject: z4.string().optional().describe("Subject line (create/update, also search keyword for list)"),
|
|
1559
|
+
content: z4.string().optional().describe("Raw HTML content (create/update). Only use when no template is available or user explicitly requests custom HTML. When a template exists, use sections instead."),
|
|
1560
|
+
sections: z4.array(z4.object({
|
|
1561
|
+
section_id: z4.string().describe("Section ID from the template's section config"),
|
|
1562
|
+
heading: z4.string().optional(),
|
|
1563
|
+
body: z4.string().optional().describe("Section body (basic HTML OK: p, strong, em, a, ul/li)"),
|
|
1564
|
+
image_url: z4.string().optional(),
|
|
1565
|
+
image_alt: z4.string().optional(),
|
|
1566
|
+
cta_text: z4.string().optional(),
|
|
1567
|
+
cta_url: z4.string().optional(),
|
|
1568
|
+
quote: z4.string().optional(),
|
|
1569
|
+
quote_attribution: z4.string().optional()
|
|
1570
|
+
})).optional().describe("Structured section content matching the template's section IDs. PREFERRED over raw content \u2014 preserves the user's template design and style."),
|
|
1571
|
+
preview_text: z4.string().optional().describe("Preview text (create/update)"),
|
|
1572
|
+
template_id: z4.string().optional().describe("BuzzPoster template ID (from newsletter_templates). Used with sections to auto-generate HTML."),
|
|
1573
|
+
esp_template_id: z4.string().optional().describe("ESP-native template ID (Kit: email_template_id, Beehiiv: post_template_id). Distinct from template_id which references BuzzPoster templates."),
|
|
1574
|
+
scheduled_for: z4.string().optional().describe("ISO datetime (schedule)"),
|
|
1575
|
+
page: z4.string().optional().describe("Page number (list)"),
|
|
1576
|
+
status: z4.string().optional().describe("Filter status (list)"),
|
|
1577
|
+
from_date: z4.string().optional().describe("ISO date from (list)"),
|
|
1578
|
+
to_date: z4.string().optional().describe("ISO date to (list)"),
|
|
1579
|
+
confirmed: z4.boolean().default(false).describe("Confirm action (send/schedule)")
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
title: "Manage Newsletters",
|
|
1583
|
+
readOnlyHint: false,
|
|
1584
|
+
destructiveHint: true,
|
|
1585
|
+
idempotentHint: false,
|
|
1586
|
+
openWorldHint: true
|
|
1587
|
+
},
|
|
1588
|
+
async (args) => {
|
|
1589
|
+
if (args.action === "create") {
|
|
1590
|
+
if (!args.subject) {
|
|
1591
|
+
return { content: [{ type: "text", text: "subject is required for create." }], isError: true };
|
|
1592
|
+
}
|
|
1593
|
+
if (!args.content && !args.sections) {
|
|
1594
|
+
return { content: [{ type: "text", text: "content or sections is required for create." }], isError: true };
|
|
1595
|
+
}
|
|
1596
|
+
const payload = {
|
|
1597
|
+
subject: args.subject,
|
|
1598
|
+
previewText: args.preview_text
|
|
1599
|
+
};
|
|
1600
|
+
if (args.content) payload.content = args.content;
|
|
1601
|
+
if (args.sections) payload.sections = args.sections;
|
|
1602
|
+
if (args.template_id) payload.templateId = args.template_id;
|
|
1603
|
+
if (args.esp_template_id) payload.espTemplateId = args.esp_template_id;
|
|
1604
|
+
const result = await client2.createBroadcast(payload);
|
|
1605
|
+
const r = result;
|
|
1606
|
+
const response = {
|
|
1607
|
+
id: r.id,
|
|
1608
|
+
subject: args.subject,
|
|
1609
|
+
content: args.content ?? r.renderedHtml ?? void 0,
|
|
1610
|
+
previewText: args.preview_text,
|
|
1611
|
+
previewUrl: r.previewUrl,
|
|
1612
|
+
editUrl: r.editUrl,
|
|
1613
|
+
status: "draft"
|
|
1614
|
+
};
|
|
1615
|
+
return {
|
|
1616
|
+
content: [
|
|
1617
|
+
{ type: "text", text: JSON.stringify(response) }
|
|
1618
|
+
]
|
|
1619
|
+
};
|
|
1620
|
+
}
|
|
1621
|
+
if (args.action === "update") {
|
|
1622
|
+
if (!args.broadcast_id) {
|
|
1623
|
+
return { content: [{ type: "text", text: "broadcast_id is required for update." }], isError: true };
|
|
1624
|
+
}
|
|
1625
|
+
const data = {};
|
|
1626
|
+
if (args.subject) data.subject = args.subject;
|
|
1627
|
+
if (args.content) data.content = args.content;
|
|
1628
|
+
if (args.preview_text) data.previewText = args.preview_text;
|
|
1629
|
+
const result = await client2.updateBroadcast(args.broadcast_id, data);
|
|
1630
|
+
const r = result;
|
|
1631
|
+
const response = {
|
|
1632
|
+
id: args.broadcast_id,
|
|
1633
|
+
subject: args.subject ?? r.subject,
|
|
1634
|
+
content: args.content ?? r.renderedHtml ?? void 0,
|
|
1635
|
+
previewText: args.preview_text,
|
|
1636
|
+
previewUrl: r.previewUrl,
|
|
1637
|
+
editUrl: r.editUrl,
|
|
1638
|
+
status: r.status ?? "draft"
|
|
1639
|
+
};
|
|
1640
|
+
return {
|
|
1641
|
+
content: [
|
|
1642
|
+
{ type: "text", text: JSON.stringify(response) }
|
|
1643
|
+
]
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
if (args.action === "send") {
|
|
1647
|
+
if (!options.allowDirectSend) {
|
|
1648
|
+
return {
|
|
1649
|
+
content: [{
|
|
1650
|
+
type: "text",
|
|
1651
|
+
text: "Direct send is disabled. Enable it in your BuzzPoster dashboard settings under Publishing Rules."
|
|
1652
|
+
}],
|
|
1653
|
+
isError: true
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1656
|
+
if (!args.broadcast_id) {
|
|
1657
|
+
return { content: [{ type: "text", text: "broadcast_id is required for send." }], isError: true };
|
|
1658
|
+
}
|
|
1659
|
+
if (args.confirmed !== true) {
|
|
1660
|
+
let subscriberCount = "unknown";
|
|
1661
|
+
let rulesText = "";
|
|
1662
|
+
try {
|
|
1663
|
+
const subData = await client2.listSubscribers({ perPage: "1" });
|
|
1664
|
+
subscriberCount = String(subData?.totalCount ?? subData?.total ?? subData?.subscribers?.length ?? "unknown");
|
|
1665
|
+
} catch {
|
|
1666
|
+
}
|
|
1667
|
+
try {
|
|
1668
|
+
const rules = await client2.getPublishingRules();
|
|
1669
|
+
rulesText = `
|
|
1670
|
+
### Safety Checks
|
|
1671
|
+
`;
|
|
1672
|
+
rulesText += `- Double confirmation required: ${rules.requireDoubleConfirmNewsletter ? "**yes**" : "no"}
|
|
1673
|
+
`;
|
|
1674
|
+
rulesText += `- Immediate send allowed: ${rules.allowImmediateSend ? "yes" : "**no**"}
|
|
1675
|
+
`;
|
|
1676
|
+
if (rules.requiredDisclaimer) {
|
|
1677
|
+
rulesText += `- Required disclaimer: "${rules.requiredDisclaimer}"
|
|
1678
|
+
`;
|
|
1679
|
+
}
|
|
1680
|
+
} catch {
|
|
1681
|
+
}
|
|
1682
|
+
let espText = "";
|
|
1683
|
+
try {
|
|
1684
|
+
const account = await client2.getAccount();
|
|
1685
|
+
espText = account?.espProvider ? `**ESP:** ${account.espProvider}
|
|
1686
|
+
` : "";
|
|
1687
|
+
} catch {
|
|
1688
|
+
}
|
|
1689
|
+
const preview = `## Send Newsletter Confirmation
|
|
1690
|
+
|
|
1691
|
+
**Broadcast ID:** ${args.broadcast_id}
|
|
1692
|
+
**Subscribers:** ~${subscriberCount} recipients
|
|
1693
|
+
` + espText + rulesText + `
|
|
1694
|
+
**This action cannot be undone.** Once sent, the email goes to every subscriber.
|
|
1695
|
+
|
|
1696
|
+
Call this tool again with confirmed=true to send.`;
|
|
1697
|
+
return { content: [{ type: "text", text: preview }] };
|
|
1698
|
+
}
|
|
1699
|
+
await client2.sendBroadcast(args.broadcast_id);
|
|
1700
|
+
return {
|
|
1701
|
+
content: [{ type: "text", text: "Newsletter sent successfully." }]
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
if (args.action === "schedule") {
|
|
1705
|
+
if (!args.broadcast_id) {
|
|
1706
|
+
return { content: [{ type: "text", text: "broadcast_id is required for schedule." }], isError: true };
|
|
1707
|
+
}
|
|
1708
|
+
if (!args.scheduled_for) {
|
|
1709
|
+
return { content: [{ type: "text", text: "scheduled_for is required for schedule." }], isError: true };
|
|
1710
|
+
}
|
|
1711
|
+
if (args.confirmed !== true) {
|
|
1712
|
+
let subscriberCount = "unknown";
|
|
1713
|
+
let rulesText = "";
|
|
1714
|
+
try {
|
|
1715
|
+
const subData = await client2.listSubscribers({ perPage: "1" });
|
|
1716
|
+
subscriberCount = String(
|
|
1717
|
+
subData?.totalCount ?? subData?.total ?? subData?.subscribers?.length ?? "unknown"
|
|
1718
|
+
);
|
|
1719
|
+
} catch {
|
|
1720
|
+
}
|
|
1721
|
+
try {
|
|
1722
|
+
const rules = await client2.getPublishingRules();
|
|
1723
|
+
rulesText = `
|
|
1724
|
+
### Safety Checks
|
|
1725
|
+
`;
|
|
1726
|
+
rulesText += `- Double confirmation required: ${rules.requireDoubleConfirmNewsletter ? "**yes**" : "no"}
|
|
1727
|
+
`;
|
|
1728
|
+
rulesText += `- Immediate send allowed: ${rules.allowImmediateSend ? "yes" : "**no**"}
|
|
1729
|
+
`;
|
|
1730
|
+
if (rules.requiredDisclaimer) {
|
|
1731
|
+
rulesText += `- Required disclaimer: "${rules.requiredDisclaimer}"
|
|
1732
|
+
`;
|
|
1733
|
+
}
|
|
1734
|
+
} catch {
|
|
1735
|
+
}
|
|
1736
|
+
let espText = "";
|
|
1737
|
+
try {
|
|
1738
|
+
const account = await client2.getAccount();
|
|
1739
|
+
espText = account?.espProvider ? `**ESP:** ${account.espProvider}
|
|
1740
|
+
` : "";
|
|
1741
|
+
} catch {
|
|
1742
|
+
}
|
|
1743
|
+
const preview = `## Schedule Newsletter Confirmation
|
|
1744
|
+
|
|
1745
|
+
**Broadcast ID:** ${args.broadcast_id}
|
|
1746
|
+
**Scheduled for:** ${args.scheduled_for}
|
|
1747
|
+
**Subscribers:** ~${subscriberCount} recipients
|
|
1748
|
+
` + espText + rulesText + `
|
|
1749
|
+
Scheduling can typically be cancelled or rescheduled later, but please verify the time is correct.
|
|
1750
|
+
|
|
1751
|
+
Call this tool again with confirmed=true to schedule.`;
|
|
1752
|
+
return { content: [{ type: "text", text: preview }] };
|
|
1753
|
+
}
|
|
1754
|
+
await client2.scheduleBroadcast(args.broadcast_id, {
|
|
1755
|
+
scheduledFor: args.scheduled_for
|
|
1756
|
+
});
|
|
1757
|
+
return {
|
|
1758
|
+
content: [{
|
|
1759
|
+
type: "text",
|
|
1760
|
+
text: `Newsletter scheduled successfully for ${args.scheduled_for}.`
|
|
1761
|
+
}]
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1764
|
+
if (args.action === "list") {
|
|
1765
|
+
const params = {};
|
|
1766
|
+
if (args.page) params.page = args.page;
|
|
1767
|
+
if (args.status) params.status = args.status;
|
|
1768
|
+
if (args.from_date) params.fromDate = args.from_date;
|
|
1769
|
+
if (args.to_date) params.toDate = args.to_date;
|
|
1770
|
+
if (args.subject) params.subject = args.subject;
|
|
1771
|
+
const result = await client2.listBroadcasts(params);
|
|
1772
|
+
const broadcasts = result?.broadcasts ?? [];
|
|
1773
|
+
if (broadcasts.length === 0) {
|
|
1774
|
+
return {
|
|
1775
|
+
content: [{ type: "text", text: "No newsletters found matching your filters." }]
|
|
1776
|
+
};
|
|
1777
|
+
}
|
|
1778
|
+
let text = `## Newsletters (${broadcasts.length}`;
|
|
1779
|
+
if (result?.totalCount != null) text += ` of ${result.totalCount}`;
|
|
1780
|
+
text += ")\n\n";
|
|
1781
|
+
for (const b of broadcasts) {
|
|
1782
|
+
const status = (b.status ?? "unknown").toUpperCase();
|
|
1783
|
+
const date = b.sentAt ? new Date(b.sentAt).toLocaleString() : b.createdAt ? new Date(b.createdAt).toLocaleString() : "";
|
|
1784
|
+
text += `- **[${status}]** "${b.subject ?? "(no subject)"}"
|
|
1785
|
+
`;
|
|
1786
|
+
text += ` ID: ${b.id}`;
|
|
1787
|
+
if (date) text += ` | ${b.sentAt ? "Sent" : "Created"}: ${date}`;
|
|
1788
|
+
text += "\n";
|
|
1789
|
+
}
|
|
1790
|
+
return { content: [{ type: "text", text }] };
|
|
1791
|
+
}
|
|
1792
|
+
return {
|
|
1793
|
+
content: [{ type: "text", text: `Unknown action: ${args.action}` }],
|
|
1794
|
+
isError: true
|
|
1795
|
+
};
|
|
1796
|
+
}
|
|
1797
|
+
);
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
// src/tools/rss.ts
|
|
1801
|
+
import { z as z5 } from "zod";
|
|
1389
1802
|
function registerRssTools(server2, client2) {
|
|
1390
1803
|
server2.tool(
|
|
1391
1804
|
"rss",
|
|
1392
1805
|
"Fetch RSS/Atom feed entries or extract full article content from a URL. Returns og_image when available.",
|
|
1393
1806
|
{
|
|
1394
|
-
action:
|
|
1395
|
-
url:
|
|
1396
|
-
limit:
|
|
1807
|
+
action: z5.enum(["fetch_feed", "fetch_article"]),
|
|
1808
|
+
url: z5.string().describe("Feed or article URL"),
|
|
1809
|
+
limit: z5.number().optional().describe("Max feed entries (fetch_feed, default 100)")
|
|
1397
1810
|
},
|
|
1398
1811
|
{
|
|
1399
1812
|
title: "RSS Tools",
|
|
@@ -1463,13 +1876,13 @@ function registerRssTools(server2, client2) {
|
|
|
1463
1876
|
}
|
|
1464
1877
|
|
|
1465
1878
|
// src/tools/account.ts
|
|
1466
|
-
import { z as
|
|
1879
|
+
import { z as z6 } from "zod";
|
|
1467
1880
|
function registerAccountTools(server2, client2) {
|
|
1468
1881
|
server2.tool(
|
|
1469
1882
|
"manage_account",
|
|
1470
1883
|
"Get account details/connections or check health status of connected social accounts.",
|
|
1471
1884
|
{
|
|
1472
|
-
action:
|
|
1885
|
+
action: z6.enum(["get_details", "check_health"])
|
|
1473
1886
|
},
|
|
1474
1887
|
{
|
|
1475
1888
|
title: "Manage Account",
|
|
@@ -1568,21 +1981,21 @@ ${lines.join("\n")}`;
|
|
|
1568
1981
|
}
|
|
1569
1982
|
|
|
1570
1983
|
// src/tools/brand-voice.ts
|
|
1571
|
-
import { z as
|
|
1984
|
+
import { z as z7 } from "zod";
|
|
1572
1985
|
function registerBrandVoiceTools(server2, client2) {
|
|
1573
1986
|
server2.tool(
|
|
1574
1987
|
"manage_brand_voice",
|
|
1575
1988
|
"Get, create, or update the brand voice profile. Call with action 'get' before creating content.",
|
|
1576
1989
|
{
|
|
1577
|
-
action:
|
|
1578
|
-
name:
|
|
1579
|
-
description:
|
|
1580
|
-
dos:
|
|
1581
|
-
donts:
|
|
1582
|
-
platform_rules:
|
|
1583
|
-
platform_examples:
|
|
1584
|
-
example_posts:
|
|
1585
|
-
confirmed:
|
|
1990
|
+
action: z7.enum(["get", "create", "update"]),
|
|
1991
|
+
name: z7.string().max(80).optional().describe("Voice name (create required, update optional)"),
|
|
1992
|
+
description: z7.string().max(2e3).optional().describe("Voice description (create/update)"),
|
|
1993
|
+
dos: z7.array(z7.string().max(200)).max(15).optional().describe("Writing rules to follow (create/update)"),
|
|
1994
|
+
donts: z7.array(z7.string().max(200)).max(15).optional().describe("Things to avoid (create/update)"),
|
|
1995
|
+
platform_rules: z7.record(z7.string().max(300)).optional().describe("Per-platform guidelines (create/update)"),
|
|
1996
|
+
platform_examples: z7.record(z7.array(z7.string().max(500)).max(3)).optional().describe("Per-platform examples (create/update)"),
|
|
1997
|
+
example_posts: z7.array(z7.string().max(500)).max(5).optional().describe("Example posts (create/update)"),
|
|
1998
|
+
confirmed: z7.boolean().default(false).describe("Confirm write (create/update)")
|
|
1586
1999
|
},
|
|
1587
2000
|
{
|
|
1588
2001
|
title: "Manage Brand Voice",
|
|
@@ -1754,7 +2167,7 @@ function registerBrandVoiceTools(server2, client2) {
|
|
|
1754
2167
|
}
|
|
1755
2168
|
|
|
1756
2169
|
// src/tools/audience.ts
|
|
1757
|
-
import { z as
|
|
2170
|
+
import { z as z8 } from "zod";
|
|
1758
2171
|
function formatAudience(audience) {
|
|
1759
2172
|
const lines = [];
|
|
1760
2173
|
lines.push(`## ${audience.name}${audience.isDefault ? " (default)" : ""}`);
|
|
@@ -1801,17 +2214,17 @@ function registerAudienceTools(server2, client2) {
|
|
|
1801
2214
|
"manage_audiences",
|
|
1802
2215
|
"List, get, create, update, or delete audience profiles.",
|
|
1803
2216
|
{
|
|
1804
|
-
action:
|
|
1805
|
-
name:
|
|
1806
|
-
description:
|
|
1807
|
-
demographics:
|
|
1808
|
-
pain_points:
|
|
1809
|
-
motivations:
|
|
1810
|
-
preferred_platforms:
|
|
1811
|
-
tone_notes:
|
|
1812
|
-
content_preferences:
|
|
1813
|
-
is_default:
|
|
1814
|
-
confirmed:
|
|
2217
|
+
action: z8.enum(["list", "get", "create", "update", "delete"]),
|
|
2218
|
+
name: z8.string().max(100).optional().describe("Audience name (get/create/update/delete)"),
|
|
2219
|
+
description: z8.string().max(500).optional().describe("Description (create/update)"),
|
|
2220
|
+
demographics: z8.string().max(500).optional().describe("Demographics (create/update)"),
|
|
2221
|
+
pain_points: z8.array(z8.string().max(200)).max(10).optional().describe("Pain points, full list (create/update)"),
|
|
2222
|
+
motivations: z8.array(z8.string().max(200)).max(10).optional().describe("Motivations, full list (create/update)"),
|
|
2223
|
+
preferred_platforms: z8.array(z8.string()).max(6).optional().describe("Active platforms, full list (create/update)"),
|
|
2224
|
+
tone_notes: z8.string().max(500).optional().describe("Tone guidance (create/update)"),
|
|
2225
|
+
content_preferences: z8.string().max(500).optional().describe("Content preferences (create/update)"),
|
|
2226
|
+
is_default: z8.boolean().optional().describe("Set as default (create/update)"),
|
|
2227
|
+
confirmed: z8.boolean().default(false).describe("Confirm write (create/update/delete)")
|
|
1815
2228
|
},
|
|
1816
2229
|
{
|
|
1817
2230
|
title: "Manage Audiences",
|
|
@@ -2006,7 +2419,7 @@ Call again with confirmed=true to delete.` }]
|
|
|
2006
2419
|
}
|
|
2007
2420
|
|
|
2008
2421
|
// src/tools/calendar.ts
|
|
2009
|
-
import { z as
|
|
2422
|
+
import { z as z9 } from "zod";
|
|
2010
2423
|
import { registerAppTool as registerAppTool3 } from "@modelcontextprotocol/ext-apps/server";
|
|
2011
2424
|
var BASE_CHAR_LIMITS2 = {
|
|
2012
2425
|
twitter: 280,
|
|
@@ -2027,15 +2440,15 @@ function registerCalendarTools(server2, client2) {
|
|
|
2027
2440
|
title: "Manage Content Calendar",
|
|
2028
2441
|
description: "View content calendar, add posts to queue, or view queue schedule.",
|
|
2029
2442
|
inputSchema: {
|
|
2030
|
-
action:
|
|
2031
|
-
from:
|
|
2032
|
-
to:
|
|
2033
|
-
status:
|
|
2034
|
-
type:
|
|
2035
|
-
content:
|
|
2036
|
-
platforms:
|
|
2037
|
-
media_urls:
|
|
2038
|
-
confirmed:
|
|
2443
|
+
action: z9.enum(["get_calendar", "schedule_to_queue", "get_queue"]),
|
|
2444
|
+
from: z9.string().optional().describe("ISO date from (get_calendar)"),
|
|
2445
|
+
to: z9.string().optional().describe("ISO date to (get_calendar)"),
|
|
2446
|
+
status: z9.string().optional().describe("Filter status (get_calendar)"),
|
|
2447
|
+
type: z9.string().optional().describe("Filter type: social_post or newsletter (get_calendar)"),
|
|
2448
|
+
content: z9.string().optional().describe("Post text (schedule_to_queue)"),
|
|
2449
|
+
platforms: z9.array(z9.string()).optional().describe("Target platforms (schedule_to_queue)"),
|
|
2450
|
+
media_urls: z9.array(z9.string()).optional().describe("Media URLs (schedule_to_queue)"),
|
|
2451
|
+
confirmed: z9.boolean().default(false).describe("Confirm scheduling (schedule_to_queue)")
|
|
2039
2452
|
},
|
|
2040
2453
|
annotations: {
|
|
2041
2454
|
readOnlyHint: false,
|
|
@@ -2262,7 +2675,7 @@ Next slot: ${slotDate2.toLocaleString()} (${dayNames[slotDate2.getDay()]})
|
|
|
2262
2675
|
}
|
|
2263
2676
|
|
|
2264
2677
|
// src/tools/sources.ts
|
|
2265
|
-
import { z as
|
|
2678
|
+
import { z as z10 } from "zod";
|
|
2266
2679
|
var TYPE_LABELS = {
|
|
2267
2680
|
feed: "RSS Feed",
|
|
2268
2681
|
website: "Website",
|
|
@@ -2288,17 +2701,17 @@ function registerSourceTools(server2, client2) {
|
|
|
2288
2701
|
"manage_sources",
|
|
2289
2702
|
"List, add, update, or remove content sources (RSS feeds, websites, channels). Max 10 sources.",
|
|
2290
2703
|
{
|
|
2291
|
-
action:
|
|
2292
|
-
source_id:
|
|
2293
|
-
name:
|
|
2294
|
-
url:
|
|
2295
|
-
type:
|
|
2296
|
-
category:
|
|
2297
|
-
tags:
|
|
2298
|
-
notes:
|
|
2299
|
-
searchQuery:
|
|
2300
|
-
isActive:
|
|
2301
|
-
confirmed:
|
|
2704
|
+
action: z10.enum(["list", "add", "update", "remove"]),
|
|
2705
|
+
source_id: z10.number().optional().describe("Source ID (update/remove)"),
|
|
2706
|
+
name: z10.string().optional().describe("Display name (add/update)"),
|
|
2707
|
+
url: z10.string().optional().describe("Source URL (add/update)"),
|
|
2708
|
+
type: z10.enum(SOURCE_TYPES).optional().describe("Source type (add/update)"),
|
|
2709
|
+
category: z10.string().optional().describe("Category for organization (add/update)"),
|
|
2710
|
+
tags: z10.array(z10.string()).optional().describe("Tags for filtering (add/update)"),
|
|
2711
|
+
notes: z10.string().optional().describe("Notes about the source (add/update)"),
|
|
2712
|
+
searchQuery: z10.string().optional().describe("Search keyword for 'search' type (add/update)"),
|
|
2713
|
+
isActive: z10.boolean().optional().describe("Active status (update)"),
|
|
2714
|
+
confirmed: z10.boolean().default(false).describe("Confirm removal (remove)")
|
|
2302
2715
|
},
|
|
2303
2716
|
{
|
|
2304
2717
|
title: "Manage Content Sources",
|
|
@@ -2404,7 +2817,7 @@ This will permanently remove this content source. Call again with confirmed=true
|
|
|
2404
2817
|
}
|
|
2405
2818
|
|
|
2406
2819
|
// src/tools/wordpress.ts
|
|
2407
|
-
import { z as
|
|
2820
|
+
import { z as z11 } from "zod";
|
|
2408
2821
|
import { registerAppTool as registerAppTool4 } from "@modelcontextprotocol/ext-apps/server";
|
|
2409
2822
|
function mapWpStatus(wpStatus) {
|
|
2410
2823
|
switch (wpStatus) {
|
|
@@ -2453,26 +2866,26 @@ function registerWordPressTools(server2, client2) {
|
|
|
2453
2866
|
title: "Manage WordPress",
|
|
2454
2867
|
description: "CRUD WordPress posts/pages, upload media, list categories/tags.",
|
|
2455
2868
|
inputSchema: {
|
|
2456
|
-
action:
|
|
2457
|
-
post_id:
|
|
2458
|
-
title:
|
|
2459
|
-
content:
|
|
2460
|
-
wp_status:
|
|
2461
|
-
categories:
|
|
2462
|
-
tags:
|
|
2463
|
-
featured_media:
|
|
2464
|
-
excerpt:
|
|
2465
|
-
date:
|
|
2466
|
-
slug:
|
|
2467
|
-
per_page:
|
|
2468
|
-
page:
|
|
2469
|
-
search:
|
|
2470
|
-
filter_categories:
|
|
2471
|
-
filter_tags:
|
|
2472
|
-
force:
|
|
2473
|
-
url:
|
|
2474
|
-
filename:
|
|
2475
|
-
confirmed:
|
|
2869
|
+
action: z11.enum(["create_post", "update_post", "publish_post", "list_posts", "get_post", "create_page", "delete_post", "upload_media", "list_categories", "list_tags"]),
|
|
2870
|
+
post_id: z11.number().optional().describe("WordPress post/page ID (update/publish/get/delete)"),
|
|
2871
|
+
title: z11.string().optional().describe("Title (create_post/create_page/update)"),
|
|
2872
|
+
content: z11.string().optional().describe("HTML content (create_post/create_page/update)"),
|
|
2873
|
+
wp_status: z11.enum(["draft", "publish", "pending", "private", "future"]).optional().describe("Post status (create_post/create_page/update, default draft)"),
|
|
2874
|
+
categories: z11.array(z11.number()).optional().describe("Category IDs (create_post/update)"),
|
|
2875
|
+
tags: z11.array(z11.number()).optional().describe("Tag IDs (create_post/update)"),
|
|
2876
|
+
featured_media: z11.number().optional().describe("Featured image ID (create_post/create_page/update)"),
|
|
2877
|
+
excerpt: z11.string().optional().describe("Excerpt (create_post/create_page/update)"),
|
|
2878
|
+
date: z11.string().optional().describe("ISO 8601 date (create_post/update, required for 'future')"),
|
|
2879
|
+
slug: z11.string().optional().describe("URL slug (create_post/create_page/update)"),
|
|
2880
|
+
per_page: z11.string().optional().describe("Results per page (list_posts)"),
|
|
2881
|
+
page: z11.string().optional().describe("Page number (list_posts)"),
|
|
2882
|
+
search: z11.string().optional().describe("Search keyword (list_posts)"),
|
|
2883
|
+
filter_categories: z11.string().optional().describe("Filter by category IDs, comma-separated (list_posts)"),
|
|
2884
|
+
filter_tags: z11.string().optional().describe("Filter by tag IDs, comma-separated (list_posts)"),
|
|
2885
|
+
force: z11.boolean().default(false).describe("Permanent delete instead of trash (delete_post)"),
|
|
2886
|
+
url: z11.string().optional().describe("Public image URL (upload_media)"),
|
|
2887
|
+
filename: z11.string().optional().describe("Filename for upload (upload_media)"),
|
|
2888
|
+
confirmed: z11.boolean().default(false).describe("Confirm action (create non-draft/publish/delete)")
|
|
2476
2889
|
},
|
|
2477
2890
|
annotations: {
|
|
2478
2891
|
readOnlyHint: false,
|
|
@@ -2856,7 +3269,7 @@ ${args.force ? "WARNING: This will permanently delete the post and cannot be und
|
|
|
2856
3269
|
}
|
|
2857
3270
|
|
|
2858
3271
|
// src/tools/ghost.ts
|
|
2859
|
-
import { z as
|
|
3272
|
+
import { z as z12 } from "zod";
|
|
2860
3273
|
import { registerAppTool as registerAppTool5 } from "@modelcontextprotocol/ext-apps/server";
|
|
2861
3274
|
function mapGhostStatus(ghostStatus) {
|
|
2862
3275
|
switch (ghostStatus) {
|
|
@@ -2895,22 +3308,22 @@ function registerGhostTools(server2, client2) {
|
|
|
2895
3308
|
title: "Manage Ghost",
|
|
2896
3309
|
description: "CRUD Ghost posts, send newsletters, list members/newsletters.",
|
|
2897
3310
|
inputSchema: {
|
|
2898
|
-
action:
|
|
2899
|
-
post_id:
|
|
2900
|
-
title:
|
|
2901
|
-
html:
|
|
2902
|
-
status:
|
|
2903
|
-
tags:
|
|
2904
|
-
featured:
|
|
2905
|
-
custom_excerpt:
|
|
2906
|
-
feature_image:
|
|
2907
|
-
updated_at:
|
|
2908
|
-
newsletter_id:
|
|
2909
|
-
email_only:
|
|
2910
|
-
limit:
|
|
2911
|
-
page:
|
|
2912
|
-
filter:
|
|
2913
|
-
confirmed:
|
|
3311
|
+
action: z12.enum(["create", "update", "publish", "list", "get", "send_newsletter", "list_members", "list_newsletters"]),
|
|
3312
|
+
post_id: z12.string().optional().describe("Ghost post ID (update/publish/get/send_newsletter)"),
|
|
3313
|
+
title: z12.string().optional().describe("Post title (create/update)"),
|
|
3314
|
+
html: z12.string().optional().describe("HTML content (create/update)"),
|
|
3315
|
+
status: z12.enum(["draft", "published", "scheduled"]).optional().describe("Post status (create/update, default draft)"),
|
|
3316
|
+
tags: z12.array(z12.string()).optional().describe("Tag names (create/update)"),
|
|
3317
|
+
featured: z12.boolean().optional().describe("Featured flag (create/update)"),
|
|
3318
|
+
custom_excerpt: z12.string().optional().describe("Custom excerpt (create/update)"),
|
|
3319
|
+
feature_image: z12.string().optional().describe("Feature image URL (create/update)"),
|
|
3320
|
+
updated_at: z12.string().optional().describe("Collision detection timestamp (update/publish/send_newsletter)"),
|
|
3321
|
+
newsletter_id: z12.string().optional().describe("Newsletter ID (send_newsletter)"),
|
|
3322
|
+
email_only: z12.boolean().default(false).describe("Email only, no publish (send_newsletter)"),
|
|
3323
|
+
limit: z12.string().optional().describe("Results per page (list/list_members)"),
|
|
3324
|
+
page: z12.string().optional().describe("Page number (list/list_members)"),
|
|
3325
|
+
filter: z12.string().optional().describe("NQL filter (list_members)"),
|
|
3326
|
+
confirmed: z12.boolean().default(false).describe("Confirm action (create non-draft/publish/send_newsletter)")
|
|
2914
3327
|
},
|
|
2915
3328
|
annotations: {
|
|
2916
3329
|
readOnlyHint: false,
|
|
@@ -3284,7 +3697,7 @@ Call this tool again with confirmed=true to send.`;
|
|
|
3284
3697
|
}
|
|
3285
3698
|
|
|
3286
3699
|
// src/tools/image-templates.ts
|
|
3287
|
-
import { z as
|
|
3700
|
+
import { z as z13 } from "zod";
|
|
3288
3701
|
import {
|
|
3289
3702
|
registerAppResource as registerAppResource3,
|
|
3290
3703
|
registerAppTool as registerAppTool6,
|
|
@@ -3323,13 +3736,13 @@ function registerImageTemplateTools(server2, client2) {
|
|
|
3323
3736
|
title: "Manage Images",
|
|
3324
3737
|
description: "Generate branded images, list templates, or list formats/dimensions.",
|
|
3325
3738
|
inputSchema: {
|
|
3326
|
-
action:
|
|
3327
|
-
template_id:
|
|
3328
|
-
article_image_url:
|
|
3329
|
-
headline:
|
|
3330
|
-
summary:
|
|
3331
|
-
formats:
|
|
3332
|
-
platforms:
|
|
3739
|
+
action: z13.enum(["generate", "list_templates", "list_formats"]),
|
|
3740
|
+
template_id: z13.string().optional().describe("Image template ID, omit for default (generate)"),
|
|
3741
|
+
article_image_url: z13.string().optional().describe("Background image URL (generate)"),
|
|
3742
|
+
headline: z13.string().optional().describe("Headline text overlay (generate)"),
|
|
3743
|
+
summary: z13.string().optional().describe("Summary text below headline (generate)"),
|
|
3744
|
+
formats: z13.array(z13.string()).optional().describe("Output formats: square, portrait, landscape, wide, story (generate)"),
|
|
3745
|
+
platforms: z13.array(z13.string()).optional().describe("Platform shortcuts: instagram, facebook, linkedin, twitter (generate)")
|
|
3333
3746
|
},
|
|
3334
3747
|
annotations: {
|
|
3335
3748
|
readOnlyHint: false,
|
|
@@ -3469,21 +3882,21 @@ function registerImageTemplateTools(server2, client2) {
|
|
|
3469
3882
|
}
|
|
3470
3883
|
|
|
3471
3884
|
// src/tools/publishing-rules.ts
|
|
3472
|
-
import { z as
|
|
3885
|
+
import { z as z14 } from "zod";
|
|
3473
3886
|
function registerPublishingRulesTools(server2, client2) {
|
|
3474
3887
|
server2.tool(
|
|
3475
3888
|
"manage_publishing_rules",
|
|
3476
3889
|
"Get or update publishing safety rules (immediate publish, blocked words, daily limits, default actions, Twitter Premium).",
|
|
3477
3890
|
{
|
|
3478
|
-
action:
|
|
3479
|
-
allow_immediate_publish:
|
|
3480
|
-
allow_immediate_send:
|
|
3481
|
-
social_default_action:
|
|
3482
|
-
newsletter_default_action:
|
|
3483
|
-
max_posts_per_day:
|
|
3484
|
-
blocked_words:
|
|
3485
|
-
twitter_premium:
|
|
3486
|
-
confirmed:
|
|
3891
|
+
action: z14.enum(["get", "update"]),
|
|
3892
|
+
allow_immediate_publish: z14.boolean().optional().describe("Allow immediate social publish (update)"),
|
|
3893
|
+
allow_immediate_send: z14.boolean().optional().describe("Allow immediate newsletter send (update)"),
|
|
3894
|
+
social_default_action: z14.enum(["draft", "schedule", "publish"]).optional().describe("Default social action (update)"),
|
|
3895
|
+
newsletter_default_action: z14.enum(["draft", "schedule", "send"]).optional().describe("Default newsletter action (update)"),
|
|
3896
|
+
max_posts_per_day: z14.number().int().min(1).max(100).nullable().optional().describe("Max posts/day, null=unlimited (update)"),
|
|
3897
|
+
blocked_words: z14.array(z14.string().max(100)).max(200).nullable().optional().describe("Blocked words list (update)"),
|
|
3898
|
+
twitter_premium: z14.boolean().optional().describe("Enable 25K char Twitter limit (update)"),
|
|
3899
|
+
confirmed: z14.boolean().default(false).describe("Confirm update (update)")
|
|
3487
3900
|
},
|
|
3488
3901
|
{
|
|
3489
3902
|
title: "Manage Publishing Rules",
|
|
@@ -3565,15 +3978,15 @@ function registerPublishingRulesTools(server2, client2) {
|
|
|
3565
3978
|
}
|
|
3566
3979
|
|
|
3567
3980
|
// src/tools/context.ts
|
|
3568
|
-
import { z as
|
|
3981
|
+
import { z as z15 } from "zod";
|
|
3569
3982
|
function registerContextTools(server2, client2) {
|
|
3570
3983
|
server2.tool(
|
|
3571
3984
|
"get_context",
|
|
3572
3985
|
"Get brand voice, audience, and knowledge in one call for content creation.",
|
|
3573
3986
|
{
|
|
3574
|
-
platform:
|
|
3575
|
-
topic:
|
|
3576
|
-
include_newsletter_stats:
|
|
3987
|
+
platform: z15.string().optional().describe("Filter voice rules for platform"),
|
|
3988
|
+
topic: z15.string().optional().describe("Filter knowledge items by topic/tag"),
|
|
3989
|
+
include_newsletter_stats: z15.boolean().optional().describe("Include recent analytics")
|
|
3577
3990
|
},
|
|
3578
3991
|
{
|
|
3579
3992
|
title: "Get Context",
|
|
@@ -3647,13 +4060,13 @@ function registerContextTools(server2, client2) {
|
|
|
3647
4060
|
}
|
|
3648
4061
|
|
|
3649
4062
|
// src/tools/team.ts
|
|
3650
|
-
import { z as
|
|
4063
|
+
import { z as z16 } from "zod";
|
|
3651
4064
|
function registerTeamTools(server2, client2) {
|
|
3652
4065
|
server2.tool(
|
|
3653
4066
|
"manage_team",
|
|
3654
4067
|
"Manage team members, invitations, and organizations. List members, invite or remove members, manage invitations, and list organizations.",
|
|
3655
4068
|
{
|
|
3656
|
-
action:
|
|
4069
|
+
action: z16.enum([
|
|
3657
4070
|
"list_members",
|
|
3658
4071
|
"invite_member",
|
|
3659
4072
|
"remove_member",
|
|
@@ -3661,10 +4074,10 @@ function registerTeamTools(server2, client2) {
|
|
|
3661
4074
|
"revoke_invitation",
|
|
3662
4075
|
"list_organizations"
|
|
3663
4076
|
]),
|
|
3664
|
-
email:
|
|
3665
|
-
role:
|
|
3666
|
-
member_id:
|
|
3667
|
-
invitation_id:
|
|
4077
|
+
email: z16.string().optional().describe("Email address (invite_member)"),
|
|
4078
|
+
role: z16.string().optional().describe("Role for the member (invite_member), e.g. 'admin', 'member'"),
|
|
4079
|
+
member_id: z16.string().optional().describe("Member ID (remove_member)"),
|
|
4080
|
+
invitation_id: z16.string().optional().describe("Invitation ID (revoke_invitation)")
|
|
3668
4081
|
},
|
|
3669
4082
|
{
|
|
3670
4083
|
title: "Manage Team",
|
|
@@ -3805,10 +4218,17 @@ var server = new McpServer(
|
|
|
3805
4218
|
},
|
|
3806
4219
|
{}
|
|
3807
4220
|
);
|
|
4221
|
+
var allowDirectSend = false;
|
|
4222
|
+
try {
|
|
4223
|
+
const account = await client.getAccount();
|
|
4224
|
+
allowDirectSend = account?.allowDirectSend === true;
|
|
4225
|
+
} catch {
|
|
4226
|
+
}
|
|
3808
4227
|
registerPostPreviewResource(server);
|
|
3809
4228
|
registerPostTools(server, client);
|
|
3810
4229
|
registerInsightsTools(server, client);
|
|
3811
4230
|
registerMediaTools(server, client);
|
|
4231
|
+
registerNewsletterTools(server, client, { allowDirectSend });
|
|
3812
4232
|
registerRssTools(server, client);
|
|
3813
4233
|
registerAccountTools(server, client);
|
|
3814
4234
|
registerBrandVoiceTools(server, client);
|