@cmo-so/mcp 0.10.0 → 0.11.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 +103 -15
- 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.11.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",
|
|
@@ -8149,8 +8149,17 @@ function domainApi(api2, domain) {
|
|
|
8149
8149
|
headers: { "Content-Type": "application/json" },
|
|
8150
8150
|
body: JSON.stringify(changes)
|
|
8151
8151
|
}),
|
|
8152
|
-
/** Make it (billed): send back the estimate the person agreed to.
|
|
8153
|
-
|
|
8152
|
+
/** Make it (billed): send back the estimate the person agreed to (estimate.pictures_usd for stage
|
|
8153
|
+
* "pictures": only the first frames, to look at before the paid clips). A script that doesn't fit its
|
|
8154
|
+
* timing is refused (409 script_check) unless goAhead. */
|
|
8155
|
+
makeAdVideo: (adId, estimateUsd, opts = {}) => post(`${base}/social/ad-videos/${adId}/make`, {
|
|
8156
|
+
confirm: true,
|
|
8157
|
+
estimate_usd: estimateUsd,
|
|
8158
|
+
...opts.stage ? { stage: opts.stage } : {},
|
|
8159
|
+
...opts.goAhead ? { go_ahead: true } : {}
|
|
8160
|
+
}),
|
|
8161
|
+
/** The person's own photo as a scene's first frame (base64, or photo_url: a picture already on CMO.so). */
|
|
8162
|
+
adVideoScenePicture: (adId, sceneId, photo) => post(`${base}/social/ad-videos/${adId}/scenes/${encodeURIComponent(sceneId)}/picture`, photo),
|
|
8154
8163
|
/** Stop one being made (what's made is kept), or remove one. */
|
|
8155
8164
|
stopAdVideo: (adId) => api2.request(`${base}/social/ad-videos/${adId}`, { method: "DELETE" }),
|
|
8156
8165
|
/** Make a LinkedIn, Facebook or Instagram post a video post: it goes out as this video (its picture is dropped). */
|
|
@@ -8908,8 +8917,12 @@ var confirmCopy = {
|
|
|
8908
8917
|
"zh-Hant": (a) => `\u4FEE\u6539\u5EE3\u544A\u5F71\u7247 #${a.id} \u7684\u5206\u93E1\uFF1A${keys(a).filter((k) => k !== "id").join("\u3001") || "\u7121"}\u3002`
|
|
8909
8918
|
},
|
|
8910
8919
|
ad_video_make: {
|
|
8911
|
-
en: (a) => `Make ad video #${a.id} now. This costs about $${Number(a.estimate_usd ?? 0).toFixed(2)} (pictures, moving clips, voice and music), in the background
|
|
8912
|
-
"zh-Hant": (a) => `\u73FE\u5728\u88FD\u4F5C\u5EE3\u544A\u5F71\u7247 #${a.id}\uFF0C\u8CBB\u7528\u7D04 $${Number(a.estimate_usd ?? 0).toFixed(2)}\uFF08\u5716\u7247\u3001\u52D5\u614B\u7247\u6BB5\u3001\u914D\u97F3\u548C\u914D\u6A02\uFF09\uFF0C\u5728\u80CC\u666F\u9032\u884C\u3002`
|
|
8920
|
+
en: (a) => a.stage === "pictures" ? `Make the pictures of ad video #${a.id} now, to look at before the moving clips. This costs about $${Number(a.estimate_usd ?? 0).toFixed(2)}.` : `Make ad video #${a.id} now. This costs about $${Number(a.estimate_usd ?? 0).toFixed(2)} (pictures, moving clips, voice and music), in the background.${a.go_ahead ? " Its script doesn't fit its timing everywhere; it's made anyway." : ""}`,
|
|
8921
|
+
"zh-Hant": (a) => a.stage === "pictures" ? `\u73FE\u5728\u5148\u88FD\u4F5C\u5EE3\u544A\u5F71\u7247 #${a.id} \u7684\u5716\u7247\uFF0C\u770B\u904E\u518D\u505A\u52D5\u614B\u7247\u6BB5\u3002\u8CBB\u7528\u7D04 $${Number(a.estimate_usd ?? 0).toFixed(2)}\u3002` : `\u73FE\u5728\u88FD\u4F5C\u5EE3\u544A\u5F71\u7247 #${a.id}\uFF0C\u8CBB\u7528\u7D04 $${Number(a.estimate_usd ?? 0).toFixed(2)}\uFF08\u5716\u7247\u3001\u52D5\u614B\u7247\u6BB5\u3001\u914D\u97F3\u548C\u914D\u6A02\uFF09\uFF0C\u5728\u80CC\u666F\u9032\u884C\u3002${a.go_ahead ? "\u8173\u672C\u6709\u90E8\u5206\u6642\u9593\u4E0D\u5408\uFF0C\u4ECD\u7167\u6A23\u88FD\u4F5C\u3002" : ""}`
|
|
8922
|
+
},
|
|
8923
|
+
ad_video_picture: {
|
|
8924
|
+
en: (a) => `Use this picture as the first frame of scene ${a.scene} in ad video #${a.id} (its clip is made again).`,
|
|
8925
|
+
"zh-Hant": (a) => `\u628A\u9019\u5F35\u5716\u7247\u7528\u4F5C\u5EE3\u544A\u5F71\u7247 #${a.id} \u7B2C ${a.scene} \u683C\u7684\u7B2C\u4E00\u500B\u756B\u9762\uFF08\u9019\u683C\u7684\u52D5\u614B\u7247\u6BB5\u6703\u91CD\u505A\uFF09\u3002`
|
|
8913
8926
|
},
|
|
8914
8927
|
ad_video_stop: {
|
|
8915
8928
|
en: (a) => `Stop ad video #${a.id} if it's being made (what's made is kept), or remove it from the list.`,
|
|
@@ -11685,7 +11698,7 @@ var adVideo = (v) => ({
|
|
|
11685
11698
|
voice: v.plan.voice,
|
|
11686
11699
|
music: v.plan.music,
|
|
11687
11700
|
seconds: v.plan.seconds,
|
|
11688
|
-
end_card: v.plan.cta,
|
|
11701
|
+
end_card: { ...v.plan.cta, seconds: v.plan.card_seconds ?? 2.5 },
|
|
11689
11702
|
scenes: v.plan.scenes.map((s) => ({
|
|
11690
11703
|
id: s.id,
|
|
11691
11704
|
seconds: s.seconds,
|
|
@@ -11693,15 +11706,23 @@ var adVideo = (v) => ({
|
|
|
11693
11706
|
motion: s.motion,
|
|
11694
11707
|
line: s.line,
|
|
11695
11708
|
caption: s.caption,
|
|
11696
|
-
picture_url: s.still_url ?? null
|
|
11709
|
+
picture_url: s.still_url ?? null,
|
|
11710
|
+
own_picture: s.own_picture ?? false,
|
|
11711
|
+
...s.caption_in != null ? { caption_in: s.caption_in } : {},
|
|
11712
|
+
...s.caption_out != null ? { caption_out: s.caption_out } : {},
|
|
11713
|
+
...s.voice_at != null ? { voice_at: s.voice_at } : {}
|
|
11697
11714
|
}))
|
|
11698
11715
|
} : null,
|
|
11716
|
+
timeline: v.timeline ?? null,
|
|
11717
|
+
script_check: v.script_check ? { ok: v.script_check.ok, total: v.script_check.total, issues: v.script_check.issues } : null,
|
|
11718
|
+
pictures_ready: v.pictures_ready ?? false,
|
|
11699
11719
|
estimate: v.estimate,
|
|
11700
11720
|
cost_usd: v.cost_usd,
|
|
11701
11721
|
video_id: v.video_id,
|
|
11722
|
+
post: v.item ?? null,
|
|
11702
11723
|
video: v.video ? { status: v.video.status, preview_url: v.video.preview_url, poster_url: v.video.poster_url } : null,
|
|
11703
11724
|
error: v.error,
|
|
11704
|
-
next: v.status === "planned" ? `Show the storyboard and the cost (about $${(v.estimate?.usd ?? 0).toFixed(2)}); change it with ad_video_change,
|
|
11725
|
+
next: v.status === "planned" ? `Show the storyboard, the timeline, any script_check issues and the cost (about $${(v.estimate?.usd ?? 0).toFixed(2)}${v.pictures_ready ? "" : `; the pictures alone about $${(v.estimate?.pictures_usd ?? 0).toFixed(2)}`}); change it with ad_video_change (or ad_video_picture for the user's own photo); ${v.pictures_ready ? "the pictures are made: show them (picture_url), then" : "suggest ad_video_make stage pictures first to see the pictures cheaply, then"} ad_video_make when the user agrees to that cost.` : v.status === "running" ? "Being made; check again with ad_video_get in a minute or so." : v.status === "ready" ? v.item?.attached ? `Ready, and it's on the post it was made from (post ${v.item.id}): that post goes out as this video. To post it elsewhere too: social_video_add (video_id and channels) once video.status is ready.` : `Ready: post it with social_video_add (video_id and channels) once video.status is ready.${v.item?.skipped ? ` It wasn't put on post ${v.item.id}: ${v.item.skipped}` : ""}` : v.status === "failed" ? "Failed: say why; ad_video_make again carries on from what was made." : ""
|
|
11705
11726
|
});
|
|
11706
11727
|
var channelsParam = {
|
|
11707
11728
|
type: "array",
|
|
@@ -13122,7 +13143,7 @@ var socialTools = [
|
|
|
13122
13143
|
}),
|
|
13123
13144
|
tool({
|
|
13124
13145
|
name: "ad_video_plan",
|
|
13125
|
-
description: "Plan a short ad video (beta) and say what making it costs. Maggie writes a storyboard: 2-5 scenes, each with the first picture's brief (no words in pictures), what moves and one camera move, the narrator's line and the words on screen; an end card with the next step and the logo; a voice and music. One AI generation; nothing is billed by the second yet. brief: what the ad should do, in the user's words, or item_id: a post whose text is the brief. aspect 9:16 (Reels, TikTok, Shorts; default) or 16:9 (LinkedIn, YouTube); seconds 15, 20 (default) or 30; reference_url: a public YouTube ad whose rhythm to follow (Gemini watches it; never downloaded). Show the storyboard and the cost (estimate.items, estimate.usd) before ad_video_make. Preview first.",
|
|
13146
|
+
description: "Plan a short ad video (beta) and say what making it costs. Maggie writes a storyboard: 2-5 scenes, each with the first picture's brief (no words in pictures), what moves and one camera move, the narrator's line and the words on screen; an end card with the next step and the logo; a voice and music. One AI generation; nothing is billed by the second yet. brief: what the ad should do, in the user's words, or item_id: a post whose text is the brief (once made, the video goes on that post if it's still to go out on LinkedIn, Facebook or Instagram). aspect 9:16 (Reels, TikTok, Shorts; default) or 16:9 (LinkedIn, YouTube); seconds 15, 20 (default) or 30; reference_url: a public YouTube ad whose rhythm to follow (Gemini watches it; never downloaded). Show the storyboard and the cost (estimate.items, estimate.usd) before ad_video_make. Preview first.",
|
|
13126
13147
|
parameters: {
|
|
13127
13148
|
type: "object",
|
|
13128
13149
|
properties: {
|
|
@@ -13169,6 +13190,8 @@ var socialTools = [
|
|
|
13169
13190
|
cost_usd: v.cost_usd,
|
|
13170
13191
|
video_id: v.video_id,
|
|
13171
13192
|
video_status: v.video?.status ?? null,
|
|
13193
|
+
post_id: v.item?.id ?? null,
|
|
13194
|
+
on_post: v.item?.attached ?? false,
|
|
13172
13195
|
error: v.error
|
|
13173
13196
|
})),
|
|
13174
13197
|
voices: out.voices
|
|
@@ -13190,7 +13213,7 @@ var socialTools = [
|
|
|
13190
13213
|
}),
|
|
13191
13214
|
tool({
|
|
13192
13215
|
name: "ad_video_change",
|
|
13193
|
-
description:
|
|
13216
|
+
description: `Change an ad video's storyboard (beta) as the user asks, before making it (or after: only what changed is made again). A scene (scenes[]): its picture brief (still), movement (motion), the narrator's line, the words on screen (caption), its seconds (3-8), and timing inside it: caption_in / caption_out (when the words show and go, seconds into the scene) and voice_at (when the narrator starts); -1 puts a time back to its default; picture "ai" swaps the user's own photo back to an AI picture. add_scenes (still required; after: a scene id, else at the end); order: the scene ids to keep, in order (removes and reorders; 2-5 scenes); redo_scenes: make scenes' pictures and clips again. The whole video: style (the look; every AI picture and clip again), aspect 9:16 or 16:9 (every picture and clip again), seconds 15/20/30 (scenes rescaled), card_seconds (1.5-4); the end card (cta_headline, cta_sub); the voice (a name from ad_video_list voices, or none); the music (words, or none). redo says what's made again: a picture brief, the look or the shape mean new paid pictures and clips, a movement a new paid clip; lines, words, timing, order, end card, voice or music are cheap. Returns the new cost, the timeline and the script check (lines that don't fit their time, captions too fast to read, length); fix errors before ad_video_make. Not while it's being made. Preview first.`,
|
|
13194
13217
|
parameters: {
|
|
13195
13218
|
type: "object",
|
|
13196
13219
|
properties: {
|
|
@@ -13205,12 +13228,36 @@ var socialTools = [
|
|
|
13205
13228
|
motion: { type: "string" },
|
|
13206
13229
|
line: { type: "string" },
|
|
13207
13230
|
caption: { type: "string" },
|
|
13208
|
-
seconds: { type: "number" }
|
|
13231
|
+
seconds: { type: "number" },
|
|
13232
|
+
caption_in: { type: "number", description: "Words show at, seconds into the scene (-1: default)" },
|
|
13233
|
+
caption_out: { type: "number", description: "Words go at, seconds into the scene (-1: default)" },
|
|
13234
|
+
voice_at: { type: "number", description: "Narrator starts at, seconds into the scene (-1: default)" },
|
|
13235
|
+
picture: { type: "string", enum: ["ai"], description: "Back to an AI picture" }
|
|
13209
13236
|
},
|
|
13210
13237
|
required: ["id"]
|
|
13211
13238
|
}
|
|
13212
13239
|
},
|
|
13240
|
+
add_scenes: {
|
|
13241
|
+
type: "array",
|
|
13242
|
+
items: {
|
|
13243
|
+
type: "object",
|
|
13244
|
+
properties: {
|
|
13245
|
+
still: { type: "string", description: "The first frame's brief (no words in it)" },
|
|
13246
|
+
motion: { type: "string" },
|
|
13247
|
+
line: { type: "string" },
|
|
13248
|
+
caption: { type: "string" },
|
|
13249
|
+
seconds: { type: "number" },
|
|
13250
|
+
after: { type: "string", description: "Put it after this scene id" }
|
|
13251
|
+
},
|
|
13252
|
+
required: ["still"]
|
|
13253
|
+
}
|
|
13254
|
+
},
|
|
13255
|
+
order: { type: "array", items: { type: "string" }, description: "Scene ids to keep, in order" },
|
|
13213
13256
|
redo_scenes: { type: "array", items: { type: "string" } },
|
|
13257
|
+
style: { type: "string", description: "The look of every scene, one sentence" },
|
|
13258
|
+
aspect: { type: "string", enum: ["9:16", "16:9"] },
|
|
13259
|
+
seconds: { type: "integer", description: "15, 20 or 30" },
|
|
13260
|
+
card_seconds: { type: "number", description: "The end card's seconds, 1.5-4" },
|
|
13214
13261
|
cta_headline: { type: "string" },
|
|
13215
13262
|
cta_sub: { type: "string" },
|
|
13216
13263
|
voice: { type: "string", description: "A voice name, or none" },
|
|
@@ -13229,8 +13276,22 @@ var socialTools = [
|
|
|
13229
13276
|
...a.cta_sub != null ? { sub: a.cta_sub } : {}
|
|
13230
13277
|
};
|
|
13231
13278
|
const out = await ws(ctx).changeAdVideo(Number(a.id), {
|
|
13232
|
-
...a.scenes?.length ? {
|
|
13279
|
+
...a.scenes?.length ? {
|
|
13280
|
+
scenes: a.scenes.map((sc) => {
|
|
13281
|
+
const out2 = { ...sc };
|
|
13282
|
+
for (const k of ["caption_in", "caption_out", "voice_at"]) {
|
|
13283
|
+
if (out2[k] != null && Number(out2[k]) < 0) out2[k] = null;
|
|
13284
|
+
}
|
|
13285
|
+
return out2;
|
|
13286
|
+
})
|
|
13287
|
+
} : {},
|
|
13288
|
+
...a.add_scenes?.length ? { add_scenes: a.add_scenes } : {},
|
|
13289
|
+
...a.order?.length ? { order: a.order.map(String) } : {},
|
|
13233
13290
|
...a.redo_scenes?.length ? { redo_scenes: a.redo_scenes } : {},
|
|
13291
|
+
...a.style ? { style: a.style } : {},
|
|
13292
|
+
...a.aspect ? { aspect: a.aspect } : {},
|
|
13293
|
+
...a.seconds ? { seconds: Number(a.seconds) } : {},
|
|
13294
|
+
...a.card_seconds != null ? { card_seconds: Number(a.card_seconds) } : {},
|
|
13234
13295
|
...Object.keys(cta).length ? { cta } : {},
|
|
13235
13296
|
...a.voice != null ? { voice: /^none$/i.test(a.voice) ? false : a.voice } : {},
|
|
13236
13297
|
...a.music != null ? { music: /^none$/i.test(a.music) ? "" : a.music } : {},
|
|
@@ -13241,12 +13302,14 @@ var socialTools = [
|
|
|
13241
13302
|
}),
|
|
13242
13303
|
tool({
|
|
13243
13304
|
name: "ad_video_make",
|
|
13244
|
-
description:
|
|
13305
|
+
description: `Make the ad video (beta). stage "pictures" makes only the first frames (cheap: estimate.pictures_usd) so the user sees them (picture_url) and changes any before the paid clips; then make it again (stage all) for the rest. Stage all: its pictures (on the user's own ChatGPT when their Maggie Bridge has images on, else Gemini), the moving clips (Gemini, billed per second), the voice, the music, the words and the end card, cut into one video, in the background (several minutes; follow it with ad_video_get). It COSTS MONEY: estimate_usd must be the estimate.usd (or estimate.pictures_usd for stage pictures) from ad_video_plan / ad_video_get / ad_video_change that the user agreed to; if the cost changed it is refused with the new one. A script that doesn't fit its timing (script_check errors) is refused: fix it with ad_video_change, or go_ahead true only when the user says to make it anyway. Each website has a daily limit. Making it again after a change or a failure only makes what's missing. When ready, post it with social_video_add and its video_id. Preview first.`,
|
|
13245
13306
|
parameters: {
|
|
13246
13307
|
type: "object",
|
|
13247
13308
|
properties: {
|
|
13248
13309
|
id: { type: "integer", description: "The ad video" },
|
|
13249
|
-
estimate_usd: { type: "number", description: "The cost the user agreed to (estimate.usd)" }
|
|
13310
|
+
estimate_usd: { type: "number", description: "The cost the user agreed to (estimate.usd, or pictures_usd)" },
|
|
13311
|
+
stage: { type: "string", enum: ["all", "pictures"], description: "pictures: only the first frames" },
|
|
13312
|
+
go_ahead: { type: "boolean", description: "Make it although the script check found errors" }
|
|
13250
13313
|
},
|
|
13251
13314
|
required: ["id", "estimate_usd"]
|
|
13252
13315
|
},
|
|
@@ -13254,7 +13317,32 @@ var socialTools = [
|
|
|
13254
13317
|
need: write5,
|
|
13255
13318
|
risk: "W3",
|
|
13256
13319
|
gates: ["VER"],
|
|
13257
|
-
run: async (ctx, { id, estimate_usd }) => adVideo(
|
|
13320
|
+
run: async (ctx, { id, estimate_usd, stage, go_ahead }) => adVideo(
|
|
13321
|
+
await ws(ctx).makeAdVideo(Number(id), Number(estimate_usd), {
|
|
13322
|
+
...stage ? { stage } : {},
|
|
13323
|
+
...go_ahead ? { goAhead: true } : {}
|
|
13324
|
+
})
|
|
13325
|
+
)
|
|
13326
|
+
}),
|
|
13327
|
+
tool({
|
|
13328
|
+
name: "ad_video_picture",
|
|
13329
|
+
description: `Use the user's own photo as an ad video scene's first frame (beta): a picture already on CMO.so (picture_url: a post's picture from social_list / social_post_get). It is cropped to the video's shape; no AI picture, no cost for it; the scene's moving clip is made again. For a photo on their device, they use the Ad video screen in the CMO.so app. Back to an AI picture: ad_video_change scenes [{id, picture: "ai"}]. Not while it's being made. Preview first.`,
|
|
13330
|
+
parameters: {
|
|
13331
|
+
type: "object",
|
|
13332
|
+
properties: {
|
|
13333
|
+
id: { type: "integer", description: "The ad video" },
|
|
13334
|
+
scene: { type: "string", description: "Scene id, e.g. s2" },
|
|
13335
|
+
picture_url: { type: "string", description: "A picture on CMO.so (a post's picture)" }
|
|
13336
|
+
},
|
|
13337
|
+
required: ["id", "scene", "picture_url"]
|
|
13338
|
+
},
|
|
13339
|
+
group: "social",
|
|
13340
|
+
need: write5,
|
|
13341
|
+
risk: "W1",
|
|
13342
|
+
gates: ["VER"],
|
|
13343
|
+
run: async (ctx, a) => adVideo(
|
|
13344
|
+
await ws(ctx).adVideoScenePicture(Number(a.id), String(a.scene), { photo_url: String(a.picture_url).trim() })
|
|
13345
|
+
)
|
|
13258
13346
|
}),
|
|
13259
13347
|
tool({
|
|
13260
13348
|
name: "ad_video_stop",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmo-so/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.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",
|