@buzzposter/mcp 0.1.4 → 0.1.5
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 +96 -21
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -101,12 +101,28 @@ var BuzzPosterClient = class {
|
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
103
|
// Media
|
|
104
|
-
async
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
async uploadMediaMultipart(filename, buffer, mimeType) {
|
|
105
|
+
const formData = new FormData();
|
|
106
|
+
formData.append("file", new Blob([buffer], { type: mimeType }), filename);
|
|
107
|
+
const url = new URL(`${this.baseUrl}/api/v1/media/upload`);
|
|
108
|
+
const res = await fetch(url, {
|
|
109
|
+
method: "POST",
|
|
110
|
+
headers: { Authorization: `Bearer ${this.apiKey}` },
|
|
111
|
+
body: formData
|
|
109
112
|
});
|
|
113
|
+
if (!res.ok) {
|
|
114
|
+
const errorBody = await res.json().catch(() => ({ message: res.statusText }));
|
|
115
|
+
const message = typeof errorBody === "object" && errorBody !== null && "message" in errorBody ? String(errorBody.message) : `API error (${res.status})`;
|
|
116
|
+
throw new Error(`BuzzPoster API error (${res.status}): ${message}`);
|
|
117
|
+
}
|
|
118
|
+
const text = await res.text();
|
|
119
|
+
return text ? JSON.parse(text) : void 0;
|
|
120
|
+
}
|
|
121
|
+
async uploadFromUrl(data) {
|
|
122
|
+
return this.request("POST", "/api/v1/media/upload-from-url", data);
|
|
123
|
+
}
|
|
124
|
+
async getUploadUrl(data) {
|
|
125
|
+
return this.request("POST", "/api/v1/media/presign", data);
|
|
110
126
|
}
|
|
111
127
|
async listMedia() {
|
|
112
128
|
return this.request("GET", "/api/v1/media");
|
|
@@ -540,7 +556,7 @@ Retrying will only attempt the failed platforms. Call this tool again with confi
|
|
|
540
556
|
function registerAccountTools(server2, client2) {
|
|
541
557
|
server2.tool(
|
|
542
558
|
"list_accounts",
|
|
543
|
-
"List all connected social media
|
|
559
|
+
"List all connected accounts \u2014 both social media platforms (Twitter, Instagram, etc.) and email service provider / ESP (Kit, Beehiiv, Mailchimp). Use this whenever the user asks about their accounts, connections, or integrations.",
|
|
544
560
|
{},
|
|
545
561
|
{
|
|
546
562
|
title: "List Connected Accounts",
|
|
@@ -551,8 +567,44 @@ function registerAccountTools(server2, client2) {
|
|
|
551
567
|
},
|
|
552
568
|
async () => {
|
|
553
569
|
const result = await client2.listAccounts();
|
|
570
|
+
const accounts = result.accounts ?? [];
|
|
571
|
+
const esp = result.esp;
|
|
572
|
+
if (accounts.length === 0 && !esp) {
|
|
573
|
+
return {
|
|
574
|
+
content: [{
|
|
575
|
+
type: "text",
|
|
576
|
+
text: "## Connected Accounts\n\nNo accounts connected. Connect social media accounts and/or an email service provider via the dashboard."
|
|
577
|
+
}]
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
let text = "## Connected Accounts\n\n";
|
|
581
|
+
text += "### Social Media\n";
|
|
582
|
+
if (accounts.length > 0) {
|
|
583
|
+
for (const a of accounts) {
|
|
584
|
+
const icon = a.isActive ? "\u2705" : "\u274C";
|
|
585
|
+
const platform = a.platform.charAt(0).toUpperCase() + a.platform.slice(1);
|
|
586
|
+
const name = a.username || a.displayName || a.platform;
|
|
587
|
+
text += `${icon} **${platform}** \u2014 @${name}
|
|
588
|
+
`;
|
|
589
|
+
}
|
|
590
|
+
} else {
|
|
591
|
+
text += "No social accounts connected.\n";
|
|
592
|
+
}
|
|
593
|
+
text += "\n### Email Service Provider (ESP)\n";
|
|
594
|
+
if (esp && esp.connected) {
|
|
595
|
+
const provider = esp.provider.charAt(0).toUpperCase() + esp.provider.slice(1);
|
|
596
|
+
text += `\u2705 **${provider}** \u2014 Connected`;
|
|
597
|
+
if (esp.publicationId) text += ` (Publication: ${esp.publicationId})`;
|
|
598
|
+
text += "\n";
|
|
599
|
+
} else if (esp) {
|
|
600
|
+
const provider = esp.provider.charAt(0).toUpperCase() + esp.provider.slice(1);
|
|
601
|
+
text += `\u26A0\uFE0F **${provider}** \u2014 Provider set but API key missing
|
|
602
|
+
`;
|
|
603
|
+
} else {
|
|
604
|
+
text += "No ESP configured.\n";
|
|
605
|
+
}
|
|
554
606
|
return {
|
|
555
|
-
content: [{ type: "text", text
|
|
607
|
+
content: [{ type: "text", text }]
|
|
556
608
|
};
|
|
557
609
|
}
|
|
558
610
|
);
|
|
@@ -844,8 +896,7 @@ function registerMediaTools(server2, client2) {
|
|
|
844
896
|
openWorldHint: false
|
|
845
897
|
},
|
|
846
898
|
async (args) => {
|
|
847
|
-
const buffer = await readFile(args.file_path);
|
|
848
|
-
const base64 = buffer.toString("base64");
|
|
899
|
+
const buffer = Buffer.from(await readFile(args.file_path));
|
|
849
900
|
const filename = args.file_path.split("/").pop() ?? "upload";
|
|
850
901
|
const ext = filename.split(".").pop()?.toLowerCase() ?? "";
|
|
851
902
|
const mimeMap = {
|
|
@@ -861,33 +912,57 @@ function registerMediaTools(server2, client2) {
|
|
|
861
912
|
pdf: "application/pdf"
|
|
862
913
|
};
|
|
863
914
|
const mimeType = mimeMap[ext] ?? "application/octet-stream";
|
|
864
|
-
const result = await client2.
|
|
915
|
+
const result = await client2.uploadMediaMultipart(filename, buffer, mimeType);
|
|
865
916
|
return {
|
|
866
917
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
867
918
|
};
|
|
868
919
|
}
|
|
869
920
|
);
|
|
870
921
|
server2.tool(
|
|
871
|
-
"
|
|
872
|
-
"Upload media from
|
|
922
|
+
"upload_from_url",
|
|
923
|
+
"Upload media from a public URL. The server fetches the image/video and uploads it to storage. Returns a CDN URL that can be used in posts. Supports JPEG, PNG, GIF, WebP, MP4, MOV, WebM up to 25MB.",
|
|
873
924
|
{
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
925
|
+
url: z4.string().url().describe("Public URL of the image or video to upload"),
|
|
926
|
+
filename: z4.string().optional().describe("Optional filename override (including extension)"),
|
|
927
|
+
folder: z4.string().optional().describe("Optional folder path within the customer's storage")
|
|
877
928
|
},
|
|
878
929
|
{
|
|
879
|
-
title: "Upload Media
|
|
930
|
+
title: "Upload Media from URL",
|
|
880
931
|
readOnlyHint: false,
|
|
881
932
|
destructiveHint: false,
|
|
882
933
|
idempotentHint: false,
|
|
883
934
|
openWorldHint: false
|
|
884
935
|
},
|
|
885
936
|
async (args) => {
|
|
886
|
-
const result = await client2.
|
|
887
|
-
args.
|
|
888
|
-
args.
|
|
889
|
-
args.
|
|
890
|
-
);
|
|
937
|
+
const result = await client2.uploadFromUrl({
|
|
938
|
+
url: args.url,
|
|
939
|
+
filename: args.filename,
|
|
940
|
+
folder: args.folder
|
|
941
|
+
});
|
|
942
|
+
return {
|
|
943
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
);
|
|
947
|
+
server2.tool(
|
|
948
|
+
"get_upload_url",
|
|
949
|
+
"Get a pre-signed URL for direct client upload to storage. The URL is valid for 5 minutes. After uploading to the URL, the file will be available at the returned CDN URL.",
|
|
950
|
+
{
|
|
951
|
+
filename: z4.string().describe("The filename including extension (e.g. photo.jpg)"),
|
|
952
|
+
content_type: z4.string().describe("MIME type of the file (e.g. image/jpeg, video/mp4)")
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
title: "Get Upload URL",
|
|
956
|
+
readOnlyHint: true,
|
|
957
|
+
destructiveHint: false,
|
|
958
|
+
idempotentHint: false,
|
|
959
|
+
openWorldHint: false
|
|
960
|
+
},
|
|
961
|
+
async (args) => {
|
|
962
|
+
const result = await client2.getUploadUrl({
|
|
963
|
+
filename: args.filename,
|
|
964
|
+
content_type: args.content_type
|
|
965
|
+
});
|
|
891
966
|
return {
|
|
892
967
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
893
968
|
};
|