@facelessad/mcp 2.0.0 → 2.1.1

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/README.md CHANGED
@@ -49,7 +49,7 @@ with your account. Same twelve tools, same fields.
49
49
  | `facelessad_list_brand_kits` | Your brands and their ids (for `brand_kit_id`) |
50
50
  | `facelessad_voices` | Curated voice pool |
51
51
  | `facelessad_list_parts` | The parts of a finished video and how each is fixed |
52
- | `facelessad_regenerate_part` | Redo ONE part (clip, image card or graphics block) |
52
+ | `facelessad_regenerate_part` | Redo ONE part (clip, image card, graphics block, or a `bg-N` AI photo background) |
53
53
  | `facelessad_regenerate_video` | Rebuild the whole video as a new id |
54
54
  | `facelessad_render_settings` | Re-render a finished video with new caption/audio settings |
55
55
 
package/SKILL.md CHANGED
@@ -165,7 +165,7 @@ Video Banner is a silent loop: no voice, no script, no music, no SFX.
165
165
 
166
166
  `voiceover_text` makes the narration spoken **word-for-word** — the AI script
167
167
  writer is skipped and not charged. The word limit follows the duration: 15 s
168
- fits ~40 words, 30 s ~60, 50 s ~95. Over the limit is a clear error, never a
168
+ fits ~45 words, 30 s ~80, 50 s ~130. Over the limit is a clear error, never a
169
169
  silent trim, so count before sending. Not on music-video (its script is sung)
170
170
  or video-banner.
171
171
 
@@ -212,6 +212,11 @@ Which field a part takes:
212
212
  text-animation, video-banner, and the graphics layer of product-showcase):
213
213
  a plain-language change like "make the headline say Faster onboarding". The
214
214
  server applies it to the block's current code — you never send code.
215
+ - `prompt` on a `bg-N` part — AI photo backgrounds (styles flagged
216
+ `genBg:true` in `facelessad_list_tools`): describe the new backdrop, e.g.
217
+ "warm sunset gradient with soft haze". The graphics stay untouched,
218
+ text/logos/UI are always excluded automatically, and the video re-renders.
219
+ 6 credits per image.
215
220
 
216
221
  Product Showcase lists two parts per scene: the product clip (`prompt`) and
217
222
  the graphics over it (`instruction`). Continuous videos chain their clips and
@@ -302,6 +307,7 @@ Every tool returns the API's own JSON; on failure `{ok:false, error, code}`.
302
307
  - `card_needs_image_prompt` — a card needs `image_prompt`, not `prompt`.
303
308
  - `webhook_limit` / `webhook_not_found` / `invalid_url` — webhook endpoints: five per account; no such id; or a URL we cannot reach. (You manage these through the API or CLI, not through a tool here.)
304
309
  - `graphics_needs_instruction` / `instruction_not_supported` — graphics blocks take `instruction`, and only they do.
310
+ - `bg_needs_prompt` — a `bg-N` background image is regenerated with `prompt` describing the backdrop.
305
311
 
306
312
  ## Rules for agents
307
313
 
package/index.js CHANGED
@@ -82,7 +82,7 @@ const server = new McpServer({ name: 'facelessad', version: '2.0.0' });
82
82
 
83
83
  server.tool(
84
84
  'facelessad_list_tools',
85
- 'The FacelessAd registry: available video tools with their styles, ad structures, hook formulas, duration bounds and aspect ratios. Call this FIRST to learn valid ids — style/structure/hook ids passed to other tools are validated against this list.',
85
+ 'The FacelessAd registry: available video tools with their styles, ad structures, hook formulas, duration bounds and aspect ratios. Call this FIRST to learn valid ids — style/structure/hook ids passed to other tools are validated against this list. Styles flagged genBg:true generate an AI photo background behind every part (+6 credits per part in the estimate); their finished videos expose bg-N parts for background regeneration.',
86
86
  {},
87
87
  async () => result(await api('GET', '/api/v1/tools'))
88
88
  );
@@ -200,7 +200,7 @@ const createShape = {
200
200
  badge: z.enum(['none', 'random_face']).optional().describe('video-banner only: "random_face" picks the same AI face the app offers. Ignored when badge_image_url is set.'),
201
201
  photo_query: z.string().optional().describe('video-banner only: steer the automatic background photo search, e.g. "nordic office"'),
202
202
  // 1.4.0 (§799): oma käsikirjoitus + visuaalinen ohjaus.
203
- voiceover_text: z.string().optional().describe('Your own voice-over, spoken WORD-FOR-WORD — the AI script writer is skipped entirely (and not charged). Word limit follows duration: 15s fits 40 words, 30s fits 60, 50s fits 95; over the limit is an error, never a silent trim. Single narrator only; not on music-video (its script is sung lyrics) or video-banner (no narration).'),
203
+ voiceover_text: z.string().optional().describe('Your own voice-over, spoken WORD-FOR-WORD — the AI script writer is skipped entirely (and not charged). Word limit follows duration: 15s fits 45 words, 30s fits 80, 50s fits 130; over the limit is an error, never a silent trim. Single narrator only; not on music-video (its script is sung lyrics) or video-banner (no narration).'),
204
204
  visual_direction: z.string().optional().describe('How the video should LOOK and what happens visually (max 600 chars): setting, emotional arc, recurring motif, when the product appears. Steers the storyboard — the art style still comes from style/custom_style.'),
205
205
  hook_text: z.string().optional().describe('Your own first-frame hook card text, used as-is (max 120 chars). Omitted, it is derived from the script.'),
206
206
  // 1.5.0 (§806): tekstitysten ulkoasu.
@@ -226,7 +226,7 @@ server.tool(
226
226
 
227
227
  server.tool(
228
228
  'facelessad_get_video',
229
- 'Status of one video by id. When finished, includes a download URL valid ~1 hour — call again for a fresh one rather than storing it.',
229
+ 'Status of one video by id. When finished, includes a download URL valid ~24 hours — call again for a fresh one rather than storing it.',
230
230
  { id: z.union([z.string(), z.number()]).describe('The id returned by facelessad_create_video') },
231
231
  async ({ id }) => result(await api('GET', '/api/v1/videos/' + encodeURIComponent(String(id))))
232
232
  );
@@ -253,18 +253,18 @@ server.tool(
253
253
 
254
254
  server.tool(
255
255
  'facelessad_list_parts',
256
- 'List the parts of a finished video so one of them can be regenerated. Model A / image-card videos return scene clips and image cards (uid, type, duration, current motion prompt, image_prompt, preview links). Graphics tools return graphics_block parts (gfx-0, gfx-1, ...). Product Showcase returns BOTH layers per scene: the product clip and the graphics block over it. Each part says whether it is regenerable and which field it needs (regenerate_requires).',
256
+ 'List the parts of a finished video so one of them can be regenerated. Model A / image-card videos return scene clips and image cards (uid, type, duration, current motion prompt, image_prompt, preview links). Graphics tools return graphics_block parts (gfx-0, gfx-1, ...) — and on background-image styles (styles flagged genBg in facelessad_list_tools) ALSO a background_image layer per part (bg-0, bg-1, ...), regenerated with prompt. Product Showcase returns BOTH layers per scene: the product clip and the graphics block over it. Each part says whether it is regenerable and which field it needs (regenerate_requires).',
257
257
  { video_id: z.string().describe('Video id from facelessad_create_video') },
258
258
  async ({ video_id }) => result(await api('GET', '/api/v1/videos/' + encodeURIComponent(video_id) + '/parts'))
259
259
  );
260
260
 
261
261
  server.tool(
262
262
  'facelessad_regenerate_part',
263
- 'Write prompt as CONCRETE PHYSICAL MOTION of characters and objects, never camera moves ("she sets the mug down and exhales" works, "slow zoom in on the product" does not — the pipeline forbids camera movement). Regenerate or edit ONE part of a finished video — far cheaper than rebuilding it. prompt = new take of a scene clip from the same start image. image_prompt = a new image first (scene clips and image cards; required for cards), then the clip/card is rebuilt from it. instruction = plain-language edit of a graphics block ("make the headline say Faster onboarding") applied server-side to the block\'s current code — you never send or receive code. The whole video re-renders automatically and the new file replaces the video url; the previous render stays as an asset version. Works within 7 days of the build. Poll facelessad_get_video for the new url.',
263
+ 'Write prompt as CONCRETE PHYSICAL MOTION of characters and objects, never camera moves ("she sets the mug down and exhales" works, "slow zoom in on the product" does not — the pipeline forbids camera movement). Regenerate or edit ONE part of a finished video — far cheaper than rebuilding it. prompt = new take of a scene clip from the same start image. image_prompt = a new image first (scene clips and image cards; required for cards), then the clip/card is rebuilt from it. instruction = plain-language edit of a graphics block ("make the headline say Faster onboarding") applied server-side to the block\'s current code — you never send or receive code. For bg-N background images (genBg styles) pass prompt describing the new backdrop ("warm sunset gradient, soft haze") — the graphics stay untouched, text/logos/UI are always excluded automatically, and it bills 6 credits per image. The whole video re-renders automatically and the new file replaces the video url; the previous render stays as an asset version. Works within 7 days of the build. Poll facelessad_get_video for the new url.',
264
264
  {
265
265
  video_id: z.string().describe('Video id'),
266
266
  part_uid: z.string().describe('Part uid from facelessad_list_parts (must be regenerable:true)'),
267
- prompt: z.string().optional().describe('New motion prompt for a scene clip (max 900 chars)'),
267
+ prompt: z.string().optional().describe('New motion prompt for a scene clip, OR for a bg-N part the new backdrop description (max 900 chars)'),
268
268
  image_prompt: z.string().optional().describe('New image description (max 900 chars) — required for image cards'),
269
269
  instruction: z.string().optional().describe('Plain-language change for a graphics_block part (max 900 chars)'),
270
270
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@facelessad/mcp",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "FacelessAd as MCP tools \u2014 let your AI assistant create faceless video ads (Claude Desktop, Claude Code, Cursor, Windsurf, OpenClaw).",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -28,4 +28,4 @@
28
28
  "ai"
29
29
  ],
30
30
  "homepage": "https://facelessad.com/developers"
31
- }
31
+ }