VODOO AI · AGENT SURFACE
Your agent can runthe whole studio.
Not a render endpoint with a docs page bolted on. 22 tools that walk the entire loop — find the ad that is working, pull its hook apart, write against it, render every variant, ship the one that won. Point Claude, Cursor or your own orchestrator at one URL and it has the studio.
What it can do, end to end
- 01
Find
Search the ad libraries the workspace can reach, then read an ad's hook, angle and beat structure.
search_adsextract_hook - 02
Write
Hang a brief off the product facts and turn it into a hook, body and CTA.
create_briefgenerate_script - 03
Word it
Hand it a picture, frames from a video or a rough idea and get the prompt back: the main one, a negative, other ways to say it, and a shot list for video.
write_prompt - 04
Page it
One person, a list of first lines and a handful of rooms, laid out as posts in the order to publish them — which room, which hand, and which of them are renders rather than the same room with different words over it.
plan_account - 05
Render
Make N variants of one prompt or one recipe row — pass `kind` for an image, a voice read, music, a 3D model or copy; it defaults to video — then poll until the files land.
render_variantsget_job_status - 06
Cut
Join the clips end to end in the order they play, with transitions, a voice track and a music bed under it, delivered in up to four aspect ratios at once.
assemble_cut - 07
Ship
Pull the finished files through short-lived signed links and record the publication so its performance can be attributed later.
list_assetspublish_draft
The boring part, which is the part that matters at 3am
An agent cannot see a spinner or a balance, so nothing here spends on its first call. Ask a tool to do something expensive and it comes back with the preflight instead: what it would make, what it would cost, and which key’s cap that lands against. It runs when you ask again with confirm: true — a yes with a number in front of it, which is the closest thing to informed consent a program can give.
Credits are held when the job is submitted and settled against what the provider actually billed. Anything unused comes back. Nothing expires. Of the 22 tools, 6 can move credits at all and each one carries a spends annotation in tools/list, so a client can show the gate before the model ever calls it.
→ render_variants { prompt, kind: "video", count: 4 }
← preflight — nothing was queued
4 variants · <credits> to run
against key "ci" · <remaining under its cap>
→ render_variants { …, confirm: true }
← queued · 4 job ids · credits held
poll get_job_statusThe shape of the exchange. The figures come back filled in from your own workspace’s rates.
Every tool, and what it costs you
search_adsfreeresearch:readSearch the ad libraries this workspace can reach and return what each source could and could not see. Free — no credits are spent. Results are saved to the workspace's hub so they can be analysed.
extract_hookcreditsresearch:readRead an ad's opening hook, angle, pain points and beat structure. Returns a finished analysis for free; running a new one transcribes the video and calls a model, so it costs credits and needs confirm: true.
create_brieffreegenerations:writeCreate the brief a script and its renders hang off. Free. Returns the brief id, which generate_script takes.
generate_scriptcreditsgenerations:writeWrite a hook, body and CTA from a brief and its product facts. Costs credits (one model call) and needs confirm: true. Returns a job id; poll get_job_status for the text.
render_variantscreditsgenerations:writeMake N variants of one prompt, or one recipe row — a video, an image, a voice read, a piece of music, a 3D model, or written copy. Pass `kind`; it defaults to video. Costs credits and needs confirm: true. Returns one job id per variant.
get_job_statusfreegenerations:readStatus, cost and finished asset for any generation started by this key's workspace. Free.
list_assetsfreeassets:readThe workspace's most recent finished renders, with short-lived signed links. Free.
publish_draftfreegenerations:writeRecord a finished assembly as published, with a snapshot of the recipe that made it, so its performance can be attributed later. Free. This records the publication; it does not upload to the ad platform.
plan_accountfreegenerations:writeLay out a creator page: one cast member, N first lines, and a handful of rooms. Returns the posts in the order to publish them — which room, which hand, and whether each one is a render or the same room with different words over it. Free, spends nothing. Every render comes back with a finished brief to hand to render_variants; the rest are an encode each, so ten posts over six rooms is six renders and four free. Consecutive posts never share a room or an opening angle, because that is what makes a page read as automated.
list_kindsfreegenerations:readEverything this studio makes — films, ads, room redesigns, turntables, characters, music, copy — with what each one asks for and whether an engine is connected for it right now. Free. Start here when you do not know what to call the thing you want.
list_enginesfreegenerations:readThe synced model catalogue: which engines exist, what each one does, what it costs per unit, and how likely it is to refuse work on likeness or content grounds. Free. Use it when you want to pin an engine rather than let the studio route.
plan_creationfreegenerations:readRead a brief, work out what it is asking for, and pick an engine for every step of the chain — with the reason each one won and what it beat. Free, and writes nothing: this is what the studio would do, shown before it does it.
create_projectfreegenerations:writeStart a project from a sentence. Free. The brief is stored on it, so plan_shots and the Studio both open knowing what it is for. Returns the project id everything else takes.
plan_shotsfreegenerations:writeBreak a brief into shots and write them to the project's timeline — each with a length, a framing and the engine that suits it. Free: this writes rows, it renders nothing. Call get_timeline afterwards, or edit_timeline to change it.
get_timelinefreegenerations:readThe shots on a project's timeline, in order, with their lengths and what each one shows. Free.
edit_timelinefreegenerations:writeEdit a cut by describing it — "drop the third shot, hold the opening, bring it to fifteen seconds" — or omit `request` and let VODOO shape it. Spends nothing, but needs confirm: true to write, because removing a shot deletes any clip already rendered from it. Without confirm you get the diff and a list of what would be lost.
assemble_cutcreditsgenerations:writeJoin finished clips end to end into one film, with transitions, an optional voice track and an optional music bed, delivered in up to four aspect ratios. Give it render ids from list_assets in the order they should play. Costs credits and needs confirm: true. Returns a job id.
list_changesfreegenerations:readThe fourteen things this studio can change about a finished clip, each with what moves, what is held still, and what has to be pointed at it. Seven are things a second shoot could have given you — a different person, a different place, a different wardrobe. Seven are things it could not: melting, swarming, folding, a size break. Free.
plan_reshootfreegenerations:readA dry run: the same rights checks, the same length limits, the same price and the same refusals as the real thing, with nothing queued and nothing held. A refusal comes back with what to do instead. Free — call it first, every time.
start_reshootcreditsgenerations:writeChange one named thing about a clip of your own and hold everything else still. The clip is given by render id — this door only works on footage this workspace made, because a key cannot sign for footage the way a person can. Costs credits and needs confirm: true. Returns a job id.
write_promptcreditsgenerations:writeGet the words to make something before you make it. describe: the prompt behind a picture. dissect: its light, lens, colour and mood named. video: a shot-by-shot breakdown from frames in playing order. brainstorm: directions from an idea. sharpen: a stronger version of a prompt. Pass picture addresses in imageUrls; they are read and not kept. One credit for words, two with pictures. Needs confirm: true. Returns the prompt, a negative prompt, other ways to say it, and where to take it next.
refine_textfreetext:refineEdit prose: cut opener phrases that carry no information, replace padding words, thin heavy connectives, turn passives around where the actor is named, split over-long sentences, and fit contractions to the voice. Deterministic and free — no model, no credits. Returns the tightened text, what changed, and the reading grade before and after. A passive it cannot turn round honestly — no stated actor, or a tense it cannot carry across — is flagged and left exactly as written. Flags are counted under `flagged`, apart from `total`, because nothing moved.
What a key is allowed to do
The list is deliberately short. A permission model nobody understands gets granted in full every time, which is the same as not having one. The key an agency pastes into a client’s CI can render and nothing else — not read the asset library, not register a webhook that forwards every future render somewhere.
generations:read- Check whether a render finished, and read its error if it did not.
generations:write- Start renders. This is the only scope that can spend credits.
assets:read- Download finished files through short-lived signed links.
usage:read- Read this key's own spend and rate-limit budget.
webhooks:write- Register and remove webhook endpoints for this workspace.
recipes:read- List saved recipes and the variables they take.
research:read- Search competitor ads and read saved ad analyses.
text:refine- Run written copy through the editing pass. Reads nothing, writes nothing, costs nothing.
orders:write- Report a sale back: this asset, this amount, this order id. Spends nothing, reads nothing, and cannot see anything else in the workspace.
Connecting it
Streamable HTTP, spoken as plain JSON-RPC over POST. Create a key under Settings → API keys, tick the scopes it needs, and point any MCP client at the endpoint.
{
"mcpServers": {
"vodoo": {
"url": "https://vodoo.ai/mcp",
"headers": {
"Authorization": "Bearer vd_live_…"
}
}
}
}Limits, stated plainly
- No SSE stream. A stream exists so a server can push, and this one pushes nothing: every tool that starts work returns a job id and you poll
get_job_status. A render outlives any connection an agent will hold open, and advertising a stream we never write to would be a promise clients wait on. - Twelve variants a call, one kind a call.
render_variantsmakes a video, an image, a voice read, a piece of music, a 3D model or written copy — whicheverkindyou pass. It will not take a hundred of them in one breath. - A refusal is not a protocol error. No credits, wrong id, gate declined — those come back as a successful result with
isErrorand a readable reason, so the model can act on it instead of retrying blind. - Schemas cannot drift. The tools are defined in Zod and their JSON Schemas are derived, so the schema an agent reads in
tools/listis the one the handler validates against.
Hand this page to the thing that will use it
Increasingly the first reader of a page like this is a model comparing tools on someone’s behalf. The button copies this page as markdown — endpoint, every tool, every scope, the confirm rule and the limits — built from the same array the list above renders, so it cannot describe a tool set we do not serve.