@post-ripple/mcp 0.6.0 → 0.8.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.
Files changed (2) hide show
  1. package/dist/index.js +72 -4
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -45,7 +45,7 @@ function toEpochMs(value, field) {
45
45
  }
46
46
  return parsed;
47
47
  }
48
- const server = new McpServer({ name: "postripple", version: "0.6.0" });
48
+ const server = new McpServer({ name: "postripple", version: "0.7.0" });
49
49
  function register(name, description, shape, transform) {
50
50
  server.tool(name, description, shape, async (args) => {
51
51
  try {
@@ -127,13 +127,13 @@ const slideTextStyleSchema = z
127
127
  .optional(),
128
128
  color: z.string().optional().describe("Text color (hex)"),
129
129
  treatment: z
130
- .enum(["none", "shadow", "outline", "highlight"])
130
+ .enum(["none", "shadow", "outline", "highlight", "bar"])
131
131
  .optional()
132
- .describe("'highlight' = solid box behind each line (classic TikTok caption)"),
132
+ .describe("'highlight' = solid box hugging each line (classic TikTok caption); 'bar' = full-width translucent band behind the text (subtitle look)"),
133
133
  accentColor: z
134
134
  .string()
135
135
  .optional()
136
- .describe("Box color for 'highlight' / stroke color for 'outline' (hex)"),
136
+ .describe("Box color for 'highlight' / stroke color for 'outline' / band color for 'bar' (hex)"),
137
137
  fontScale: z.number().min(0.5).max(2.5).optional(),
138
138
  x: z.number().min(0).max(1).optional().describe("Anchor x (0..1 of canvas width)"),
139
139
  y: z.number().min(0).max(1).optional().describe("Top y (0..1 of canvas height)"),
@@ -200,6 +200,25 @@ register("list_images", "List or search the workspace's image library. Every ima
200
200
  .describe("Filter by origin (ignored when text is set)"),
201
201
  limit: z.number().min(1).max(200).optional().describe("Default 100, max 200"),
202
202
  });
203
+ register("list_hooks", "List or search the shared HOOK VIDEO library — short vertical (9:16) clips (talking-head selfies, reactions, unboxings, B-roll) meant to open a short-form video. Each is auto-captioned + tagged by AI. Pass `text` for a keyword search over titles, tags, and AI captions (e.g. 'guy talking to camera', 'unboxing'); pass `tags` to require specific tags; omit both to list newest-first. Each result has a hookId, title, type ('ai' or 'human'), merged tags, aiCaption, and signed preview/video URLs (~1h). This library is shared platform-wide, not per-workspace.", {
204
+ text: z
205
+ .string()
206
+ .optional()
207
+ .describe("Keyword query over hook title, tags, description, and AI caption"),
208
+ tags: z
209
+ .array(z.string())
210
+ .optional()
211
+ .describe("Only hooks carrying ALL of these tags (human or AI tags)"),
212
+ type: z
213
+ .enum(["ai", "human"])
214
+ .optional()
215
+ .describe("Filter by origin: AI-generated or human-recorded"),
216
+ limit: z.number().min(1).max(200).optional().describe("Default 50, max 200"),
217
+ });
218
+ register("list_green_screens", "List the shared GREEN SCREEN clip library — talking/reacting people cut out on a green screen, composited over a background image by create_video (type 'green_screen_meme'). Each result has a greenScreenId, title, and signed preview/video URLs (~1h). Shared platform-wide, not per-workspace.", { limit: z.number().min(1).max(200).optional().describe("Default 50, max 200") });
219
+ register("list_backgrounds", "List the shared BACKGROUND image library used behind green screen memes (create_video type 'green_screen_meme'). Each result has a backgroundId, title, and a signed image URL (~1h). Shared platform-wide, not per-workspace.", { limit: z.number().min(1).max(200).optional().describe("Default 50, max 200") });
220
+ register("list_music", "List the platform MUSIC library — background tracks that can be laid over a hook+demo video (create_video type 'hook_demo', via musicId). Each result has a musicId, title, duration, and a signed audio URL (~1h). Shared platform-wide, not per-workspace.", { limit: z.number().min(1).max(200).optional().describe("Default 50, max 200") });
221
+ register("get_creation", "Get the render status of a video created with create_video. Poll until status is 'completed' — the result then includes resultVideoId (publish it with schedule_post or add it to a group) plus signed video/preview URLs. status 'failed' includes the error.", { ...orgParam, creationId: z.string().describe("The creationId returned by create_video") });
203
222
  register("list_slideshows", "List photo-carousel slideshows with status ('draft' = still being composed, 'ready' = publishable) and a signed coverUrl thumbnail (first rendered slide, or a background for drafts).", { ...orgParam, limit: z.number().min(1).max(200).optional() });
204
223
  register("list_slideshow_templates", "List the slideshow layout templates: canvas size, each template's text slots with exact geometry (x/y anchor, maxWidth, fontSize, lineHeight — all normalized to the canvas) and defaults (font, color, treatment), the template's default overlay scrim, available fonts and text treatments, and the max slide count. Call before create_slideshow when composing template-based slides — use the slot geometry rather than inventing your own placement.", {});
205
224
  register("get_slideshow", "Get one slideshow in full detail: per-slide render state, each text field's text AND its style overrides (font, color, treatment, fontScale, x/y position, maxWidth, align, rotation — null style means the template slot defaults apply), the slide's overlay scrim, and signed image URLs (renderedUrl = the finished slide, backgroundUrl = the photo behind it; both expire in ~1h). Use it to study how existing slides are actually styled before composing new ones, or poll it after create_slideshow returns status 'rendering' — publish once status is 'ready'.", { ...orgParam, slideshowId: z.string() });
@@ -296,6 +315,55 @@ register("create_slideshow", "Create a photo slideshow (1-10 slides). Each slide
296
315
  .describe("Layout template id (see list_slideshow_templates). Default 'bold-bottom'; use 'blank' for custom-only text."),
297
316
  slides: z.array(slideSchema).min(1).max(10),
298
317
  });
318
+ const captionStyleSchema = z
319
+ .object({
320
+ font: z
321
+ .enum(["classic", "impact", "serif", "typewriter", "handwriting"])
322
+ .optional(),
323
+ color: z.string().optional().describe("Text color, hex (default white)"),
324
+ treatment: z
325
+ .enum(["none", "shadow", "outline", "highlight", "bar"])
326
+ .optional()
327
+ .describe("'highlight' = box hugging each line; 'bar' = full-width translucent band behind the text (subtitle look)"),
328
+ accentColor: z
329
+ .string()
330
+ .optional()
331
+ .describe("Highlight box / outline stroke / 'bar' band color, hex"),
332
+ fontScale: z
333
+ .number()
334
+ .optional()
335
+ .describe("Multiplier on the base caption size (1 = default)"),
336
+ align: z.enum(["left", "center", "right"]).optional(),
337
+ x: z
338
+ .number()
339
+ .min(0)
340
+ .max(1)
341
+ .optional()
342
+ .describe("Free caption position: normalized center anchor (overrides captionPosition)"),
343
+ y: z.number().min(0).max(1).optional(),
344
+ })
345
+ .describe("Caption styling; defaults to white TikTok-bold text with a black outline");
346
+ register("create_video", "Render a short-form (9:16) video from library ingredients. Two types: 'hook_demo' stitches a hook clip (list_hooks) in front of your demo/product video (a completed library video via demoVideoId, or a raw upload via demoFileId from get_video_upload_url), with optional background music (musicId from list_music). 'green_screen_meme' composites a green-screen clip (list_green_screens) over a background image (list_backgrounds). Both take an optional caption with styling. Rendering is asynchronous — poll get_creation with the returned creationId until 'completed', then publish resultVideoId with schedule_post. Uses one 'creations' credit from the plan.", {
347
+ ...orgParam,
348
+ type: z.enum(["hook_demo", "green_screen_meme"]),
349
+ title: z.string().optional().describe("Library title for the finished video"),
350
+ caption: z.string().optional().describe("Text overlaid on the video (hook part only for hook_demo)"),
351
+ captionPosition: z.enum(["top", "middle", "bottom"]).optional(),
352
+ captionStyle: captionStyleSchema.optional(),
353
+ hookId: z.string().optional().describe("hook_demo: hook clip id from list_hooks (required)"),
354
+ demoVideoId: z
355
+ .string()
356
+ .optional()
357
+ .describe("hook_demo: a COMPLETED library video id (list_videos) to play after the hook. Exactly one of demoVideoId/demoFileId."),
358
+ demoFileId: z
359
+ .string()
360
+ .optional()
361
+ .describe("hook_demo: raw uploaded file key from get_video_upload_url (alternative to demoVideoId)"),
362
+ musicId: z.string().optional().describe("hook_demo: optional background track from list_music"),
363
+ soundId: z.string().optional().describe("hook_demo: optional org-uploaded sound id (alternative to musicId)"),
364
+ greenScreenId: z.string().optional().describe("green_screen_meme: clip id from list_green_screens (required)"),
365
+ backgroundId: z.string().optional().describe("green_screen_meme: image id from list_backgrounds (required)"),
366
+ });
299
367
  // ---- publish tools ----
300
368
  register("schedule_post", "Schedule a completed library video to publish on a connected account at a future time. This posts to a REAL social account when the time arrives. The platform is derived from the account. Uses one 'posts' credit (refunded if canceled). ALWAYS pass idempotencyKey (any unique string) so retries can't double-post. For TikTok, pass tiktokSettings to control privacy — omitting it publishes as private (SELF_ONLY). For YouTube, pass title.", {
301
369
  ...orgParam,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@post-ripple/mcp",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "MCP server that lets AI agents (Claude Code, Codex, opencode) manage a Post Ripple workspace: content, scheduling, publishing, and analytics.",
5
5
  "type": "module",
6
6
  "bin": {