@cmo-so/mcp 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cmo-mcp.mjs +58 -5
- package/package.json +1 -1
package/dist/cmo-mcp.mjs
CHANGED
|
@@ -7199,7 +7199,7 @@ var require_dist = __commonJS({
|
|
|
7199
7199
|
// package.json
|
|
7200
7200
|
var package_default = {
|
|
7201
7201
|
name: "@cmo-so/cli",
|
|
7202
|
-
version: "0.
|
|
7202
|
+
version: "0.6.0",
|
|
7203
7203
|
description: "CMO.so on the command line: your websites, ideas, blog posts, LinkedIn queue and results, plus a local MCP server for Claude Desktop, Cursor and other MCP clients.",
|
|
7204
7204
|
type: "module",
|
|
7205
7205
|
license: "MIT",
|
|
@@ -7989,6 +7989,10 @@ function domainApi(api2, domain) {
|
|
|
7989
7989
|
/** A post on one video channel (YouTube by default, or TikTok) from a ready video, waiting in Review; Maggie
|
|
7990
7990
|
* writes the details (YouTube) or the caption (TikTok) unless write is false. */
|
|
7991
7991
|
postFromVideo: (videoId, opts = {}) => post(`${base}/social/video/${videoId}/post`, opts),
|
|
7992
|
+
/** Make a LinkedIn, Facebook or Instagram post a video post: it goes out as this video (its picture is dropped). */
|
|
7993
|
+
attachVideo: (id, videoId) => post(`${base}/social/${id}/video`, { video_id: videoId }),
|
|
7994
|
+
/** Take the video off a post: it's a text post again. */
|
|
7995
|
+
detachVideo: (id) => api2.request(`${base}/social/${id}/video`, { method: "DELETE" }),
|
|
7992
7996
|
youtubeSettings: () => api2.request(`${base}/social/youtube/settings`),
|
|
7993
7997
|
setYouTubeSettings: (s) => put(`${base}/social/youtube/settings`, s),
|
|
7994
7998
|
/** A YouTube post's title, tags, visibility, made-for-kids or altered-content answer. */
|
|
@@ -8237,7 +8241,7 @@ var list = (xs, n = 5) => {
|
|
|
8237
8241
|
var ids = (a) => (Array.isArray(a.ids) && a.ids.length ? a.ids : a.id != null ? [a.id] : []).map(Number);
|
|
8238
8242
|
var keys = (a) => Object.keys(a ?? {}).filter((k) => a[k] !== void 0);
|
|
8239
8243
|
var videoChannels = (a) => (Array.isArray(a.channels) && a.channels.length ? a.channels : ["youtube"]).map(
|
|
8240
|
-
(c) =>
|
|
8244
|
+
(c) => ({ tiktok: "TikTok", linkedin: "LinkedIn", facebook: "Facebook", instagram: "Instagram" })[String(c)] ?? "YouTube"
|
|
8241
8245
|
);
|
|
8242
8246
|
var confirmCopy = {
|
|
8243
8247
|
// --------------------------------------------------------- account / setup
|
|
@@ -8424,6 +8428,14 @@ var confirmCopy = {
|
|
|
8424
8428
|
en: () => "Make a link to connect your YouTube channel.",
|
|
8425
8429
|
"zh-Hant": () => "\u7522\u751F\u9023\u63A5\u4F60 YouTube \u983B\u9053\u7684\u9023\u7D50\u3002"
|
|
8426
8430
|
},
|
|
8431
|
+
social_video_attach: {
|
|
8432
|
+
en: (a) => `Make post #${a.id} a video post with ${a.url} (its picture is removed).`,
|
|
8433
|
+
"zh-Hant": (a) => `\u628A\u8CBC\u6587 #${a.id} \u6539\u6210\u5F71\u7247\u8CBC\u6587\uFF0C\u7528 ${a.url}\uFF08\u5716\u7247\u6703\u79FB\u9664\uFF09\u3002`
|
|
8434
|
+
},
|
|
8435
|
+
social_video_detach: {
|
|
8436
|
+
en: (a) => `Take the video off post #${a.id} (it's a text post again).`,
|
|
8437
|
+
"zh-Hant": (a) => `\u79FB\u9664\u8CBC\u6587 #${a.id} \u7684\u5F71\u7247\uFF08\u8B8A\u56DE\u6587\u5B57\u8CBC\u6587\uFF09\u3002`
|
|
8438
|
+
},
|
|
8427
8439
|
tiktok_connect_link: {
|
|
8428
8440
|
en: () => "Make a link to connect your TikTok account.",
|
|
8429
8441
|
"zh-Hant": () => "\u7522\u751F\u9023\u63A5\u4F60 TikTok \u5E33\u865F\u7684\u9023\u7D50\u3002"
|
|
@@ -10464,7 +10476,7 @@ var write5 = { resource: "autopilot", level: "write" };
|
|
|
10464
10476
|
var moves2 = ["up", "down", "top"];
|
|
10465
10477
|
var CHANNEL_KEYS = ["linkedin", "facebook", "instagram", "google_business"];
|
|
10466
10478
|
var ALL_CHANNEL_KEYS = [...CHANNEL_KEYS, "youtube", "tiktok"];
|
|
10467
|
-
var VIDEO_KEYS = ["youtube", "tiktok"];
|
|
10479
|
+
var VIDEO_KEYS = ["linkedin", "facebook", "instagram", "youtube", "tiktok"];
|
|
10468
10480
|
var TIKTOK_PRIVACY = ["PUBLIC_TO_EVERYONE", "MUTUAL_FOLLOW_FRIENDS", "FOLLOWER_OF_CREATOR", "SELF_ONLY"];
|
|
10469
10481
|
var channelsParam = {
|
|
10470
10482
|
type: "array",
|
|
@@ -10497,6 +10509,9 @@ var item = (i) => ({
|
|
|
10497
10509
|
youtube: i.youtube ?? null,
|
|
10498
10510
|
video: i.video ? { status: i.video.status, seconds: i.video.duration, shape: i.video.shape, error: i.video.error } : null
|
|
10499
10511
|
} : {},
|
|
10512
|
+
...i.video_asset_id && i.provider !== "youtube" && i.provider !== "tiktok" ? {
|
|
10513
|
+
video: i.video ? { status: i.video.status, seconds: i.video.duration, shape: i.video.shape, error: i.video.error } : { id: i.video_asset_id }
|
|
10514
|
+
} : {},
|
|
10500
10515
|
...i.provider === "tiktok" ? {
|
|
10501
10516
|
tiktok: i.tiktok ?? null,
|
|
10502
10517
|
video: i.video ? { status: i.video.status, seconds: i.video.duration, shape: i.video.shape, error: i.video.error } : null
|
|
@@ -11478,6 +11493,44 @@ var socialTools = [
|
|
|
11478
11493
|
return { url: out.url, expires_in_seconds: out.expires_in_seconds };
|
|
11479
11494
|
}
|
|
11480
11495
|
}),
|
|
11496
|
+
tool({
|
|
11497
|
+
name: "social_video_attach",
|
|
11498
|
+
description: "Make a LinkedIn, Facebook or Instagram post that hasn't gone out a video post: it goes out as this video (a DIRECT link to a video file, 5-30 seconds; never a platform page) with its text, and its picture is removed (a video post has no picture). Not for Google Business (posts can't carry video). Preview first.",
|
|
11499
|
+
parameters: {
|
|
11500
|
+
type: "object",
|
|
11501
|
+
properties: {
|
|
11502
|
+
id: { type: "integer", description: "The post (from social_list)" },
|
|
11503
|
+
url: { type: "string", description: "Direct https link to the video file" }
|
|
11504
|
+
},
|
|
11505
|
+
required: ["id", "url"]
|
|
11506
|
+
},
|
|
11507
|
+
group: "social",
|
|
11508
|
+
need: write5,
|
|
11509
|
+
risk: "W1",
|
|
11510
|
+
gates: ["VER"],
|
|
11511
|
+
run: async (ctx, a) => {
|
|
11512
|
+
const d = ws(ctx);
|
|
11513
|
+
let v = await d.videoFromLink(String(a.url));
|
|
11514
|
+
const until = Date.now() + 15e4;
|
|
11515
|
+
while ((v.status === "checking" || v.status === "uploading") && Date.now() < until) {
|
|
11516
|
+
await new Promise((r) => setTimeout(r, 3e3));
|
|
11517
|
+
v = await d.video(v.id);
|
|
11518
|
+
}
|
|
11519
|
+
if (v.status !== "ready")
|
|
11520
|
+
return { ok: false, video: { status: v.status, error: v.error, seconds: v.source_duration } };
|
|
11521
|
+
return { ok: true, post: item(await d.attachVideo(Number(a.id), v.id)) };
|
|
11522
|
+
}
|
|
11523
|
+
}),
|
|
11524
|
+
tool({
|
|
11525
|
+
name: "social_video_detach",
|
|
11526
|
+
description: "Take the video off a LinkedIn, Facebook or Instagram post that hasn't gone out: it's a text post again (a picture can be added after). Preview first.",
|
|
11527
|
+
parameters: { type: "object", properties: { id: { type: "integer" } }, required: ["id"] },
|
|
11528
|
+
group: "social",
|
|
11529
|
+
need: write5,
|
|
11530
|
+
risk: "W1",
|
|
11531
|
+
gates: ["VER"],
|
|
11532
|
+
run: async (ctx, a) => item(await ws(ctx).detachVideo(Number(a.id)))
|
|
11533
|
+
}),
|
|
11481
11534
|
tool({
|
|
11482
11535
|
name: "tiktok_connect_link",
|
|
11483
11536
|
description: "A link for the user to connect their TikTok account (or reconnect): they sign in to TikTok and allow Maggie to see their profile and post videos. Give them the link to open; never ask for a password. TikTok is in beta (testers only; until TikTok reviews our app, videos post as 'Only me' and the account must be private). TikTok posts are short videos (5-30 seconds) that the user approves one by one.",
|
|
@@ -11533,7 +11586,7 @@ var socialTools = [
|
|
|
11533
11586
|
}),
|
|
11534
11587
|
tool({
|
|
11535
11588
|
name: "social_video_add",
|
|
11536
|
-
description: "Make
|
|
11589
|
+
description: "Make video posts (channels: linkedin, facebook, instagram, youtube, tiktok; default youtube; one post each, never google_business: Google posts can't carry video) from a video: a DIRECT link to a video file (an .mp4 on their website, a public Dropbox link), never a YouTube / TikTok / Instagram page (we never download those; tell the user to upload the video in the app instead). The video must be 5-30 seconds: give start/end (seconds) to use a part of a longer one. vertical: make a wide video vertical (a Short) cropped at left, middle or right. Maggie writes YouTube's title, description and tags, TikTok's caption, or the LinkedIn / Facebook / Instagram text, from the video and the note (one AI generation per channel) unless write is false. Each post waits in Review: video posts are always approved by the user. YouTube asks whether it's made for kids; TikTok asks who can view it and the other TikTok settings (social_tiktok_set, as the user chooses). is_aigc: TikTok's AI-generated label, only when the user says the video was made with AI. Preview first.",
|
|
11537
11590
|
parameters: {
|
|
11538
11591
|
type: "object",
|
|
11539
11592
|
properties: {
|
|
@@ -11541,7 +11594,7 @@ var socialTools = [
|
|
|
11541
11594
|
channels: {
|
|
11542
11595
|
type: "array",
|
|
11543
11596
|
items: { type: "string", enum: [...VIDEO_KEYS] },
|
|
11544
|
-
description: "
|
|
11597
|
+
description: "Where the video goes (one post each); default youtube"
|
|
11545
11598
|
},
|
|
11546
11599
|
is_aigc: { type: "boolean", description: "TikTok: the video is AI-generated (the user said so)" },
|
|
11547
11600
|
note: { type: "string", description: "What the video is about, in the user's words" },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmo-so/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "CMO.so's MCP server for Claude Desktop, Cursor, VS Code and other MCP clients: manage your websites, blog posts, LinkedIn queue and results with Maggie.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|