Skip to content

Tools

Framehood exposes a small, functional toolset over MCP. You think in outcomes; the server picks the model. Every generation tool requires an out filename.

Discover at runtime

Use models(list) to browse reachable models and models(guide, model=…) for a model's parameters and prompting tips (or GET /v1/models/{kind} for the raw input schema).

What the MCP server exposes

The core generation and account tools:

image · video · audio · qa · files · billing · org · get_status

Two helpers — browse the catalog and send feedback:

models · submit_feedback

Three more manage your workspace:

library · project · api_keys

Actors temporarily disabled

The actor tool and the actor-dependent actions (image(actor_sheet), video(scene), and actor_id routing on image / video) are temporarily disabled while we rework them. The rest of the toolset is unaffected.

The CLI and the REST API wrap these same tools and add a few surface-only endpoints (raw model access, uploads, and the Stripe card/portal billing flows) — see CLI / REST surface below.

ChatGPT clients see live status text

image, video, audio, and qa — the tools that submit a generation job — carry status strings (e.g. "Generating image…" while running, "Image job submitted — poll get_status" once the call settles) that ChatGPT's MCP client shows while the call is in flight. These jobs are usually still processing when the call settles, so the status text reflects submission, not a finished asset. Other clients are unaffected; this is purely a ChatGPT UI nicety.

Result shape

Every MCP tool result carries a small, predictable envelope on top of its own fields: ok (boolean), result_kind ("job" for an async generation still in flight or its terminal outcome, "result" for an immediate data/management reply, or "error"), plus tool and action identifying the call. Nothing about a tool's existing response changes shape or gets removed — the envelope is purely additive, so code written against the old response keeps working unchanged.

Job-shaped results (image, video, audio, qa, and get_status for a single job — the default status action, or cancel) also carry artifacts[] — a normalized [{url, type?}, ...] list of the job's output files — alongside the original outputs map, which is unchanged. Use whichever is more convenient: outputs.image_url etc. for the legacy shape, or artifacts[] to iterate output files generically regardless of media type.

get_status's batch (job_ids) and list actions are result_kind: "result", not "job" — the envelope describes the call as a whole (summary-only, no top-level artifacts[]); the individual entries inside jobs[] keep their plain {job_id, status, ...} shape (and their own outputs, if terminal).

Three optional steering fields may also appear (each omitted entirely when there is nothing to say):

  • note (string) — advice about this specific result, e.g. "prompt was truncated" or "URL expires in 24h".
  • next_step (object) — the recommended next call, machine-readable: {tool, action?, args?, why}. args carries concrete values (e.g. {"job_id": "job_abc123"}) you can pass verbatim. Non-terminal job results carry a get_status poll here; some errors carry a recovery call on top of the prose hints. Breaking (server 2.12.0): next_step used to be a prose string on submit/poll replies — it is now always this object on MCP.
  • notifications[] ({type, text, id?, url?}, max 3) — global account-level notices, independent of the tool called. Currently always absent; the channel ships ahead of its producers.

MCP tools

What you can pass as a media reference

Every media input — image_url, video_url, audio, reference_images, clips, tracks, vo, music, and the like across image / video / audio / qa — accepts any of:

  • A cdn URL returned by an earlier job or by files(upload / import_remote)public or private. A private cdn.framehood.ai/… URL works as a reference as-is — you do not need to publish it first. (publish only mints a public, shareable/downloadable URL; it is not required to reuse a file in another job.)
  • A library asset_id — the id of any item in your library (from library(list), a generated result, or files(import_to_library)). Pass it straight in as the image_url / video_url / etc. and it resolves to the asset automatically — no URL lookup, no publish. Library items are shared across your organization, so a teammate's asset_id works too; an id from a different organization (or a deleted item) returns a clear "not found" error.
  • A data-URI (data:<mime>;base64,…, up to 25 MB) — a local file inlined into the call; it is uploaded for you and the resulting URL is used. Best for small files (e.g. a downscaled reference image): some clients truncate a large inline payload in transit — for larger or original-quality files use files(create_upload) + PUT instead.

The asset_id and data-URI shortcuts are resolved by the image / video / audio / qa tools. If you call the REST job API directly (POST /v1/jobs/{kind}), pass a media URL (an asset's url) rather than a bare asset_id or data-URI.

Calling from ChatGPT? A chat attachment does not populate a tool's media field (these tools don't declare openai/fileParams) — pass a URL or asset_id instead, bringing a file in first via files(import_remote) / files(upload). See ChatGPT / OpenAI MCP compatibility.

image

Create and edit still images (and image→video).

ActionKey argumentsDoes
createprompt, out, tier?, format?text → image
editimage_url or reference_images[], prompt, outmodify an image. Pass up to 10 references as reference_images and cite them in the prompt as @Image1@ImageN — for identity work a headshot plus a full-body shot holds a face far better than one image. image_url is the single-image shorthand
upscaleimage_url, outhigher resolution
animateimage_url, out, duration?image → short video
actor_sheetactor_id, out_prefix, variations?multi-angle character sheet

tier: draft < fine < photo. actor_id (act_…) routes create/animate through an actor's LoRA. Some models are reachable only by name — e.g. Nano Banana Pro: image(create, model="nano_banana", …) (it is not a tier); see the models tool.

seed? (any action): an optional integer for reproducible output — reuse the same seed (with the same prompt/params) to get consistent results. Ignored, with no error, by models that don't support seeding.

video

Generate, edit, and compose video.

ActionKey argumentsDoes
createprompt, out, reference_images?, duration?, format?text → video (no actor needed)
editvideo_url, prompt, out, duration?restyle / edit footage
edit_refvideo_url, prompt, reference_images, outedit guided by reference photos (@Image1…)
swapvideo_url, image_url, swap_mode, outreplace a person, object, or background
lipsyncvideo_url, audio_url, outmatch lips to an audio track
captionsvideo_url, outburn in auto subtitles
upscalevideo_url, outhigher resolution
assembleclips, out, audio bed (music?, vo?, vo_offset_sec?, vo_cues?, sfx_ambient? …)combine clips + transitions and mix an audio bed into one video
mix_audiovideo_url, tracks, outoverlay VO / music / SFX onto a video
blurvideo_url, out, region?, sigma?, windows?blur/redact a region (or the whole frame), optionally only during time windows
watermarkvideo_url, image_url, out, position?, x?, y?, margin?, opacity?, scale?, window?overlay a logo/watermark PNG at a corner (or explicit x/y), for the whole clip or a time window
sceneactor_id, scene_prompt, outactor full-scene composite (image → motion → optional speech)

swap_mode: person · object · background. In edit_ref, the images you pass in reference_images are cited in the prompt as @Image1…@Image4. scene routes through an actor (act_…) and can auto-script a spoken line from the actor's personality.

For MORE than one narration line, assemble accepts vo_cues ([{audio_url, start_sec, level?}, …]) — each line is placed at its own timecode in one call, INSTEAD of vo/vo_offset_sec (passing both is an error). mix_audio tracks accepts the same cue shape: a plain URL, or a {audio_url, start_sec?, level?, label?} object placed at a timecode. Levels are static per cue; pass duck: true to auto-duck the music bed under the voice — assemble keys it off the clip audio + VO, and mix_audio off tracks labeled "music" and "vo".

seed? (any action): an optional integer for reproducible output — reuse the same seed (with the same prompt/params) to get consistent results. Ignored, with no error, by models that don't support seeding.

audio

ActionKey argumentsDoes
speaktext, out, voice?text → voice
sfxprompt, outsound effects
musicprompt, out, lyrics?music / ambient
mixtracks (2+; or 1+ with music?/music_level?), outblend audio files — flat mix, or a music bed ducked under the voice
trimaudio, start_sec?, duration_sec?, outcut an audio file to a window
concattracks, outjoin audio in sequence

To overlay audio onto a video, use video(mix_audio).

qa

Inspect media for problems. Returns a pass/fail report.

ActionKey argumentsDoes
fullvideo, plan?run nine checks at once
personimage1, image2same person in two images?
voiceaudioconsistent voice?
scenevideo, plandoes the video match the scene plan?
transcriptvideo|audio, expected_text?, language?transcribe media (video OR audio) with timecoded segments; if expected_text is given, also check the spoken words match
imageimage_url, descriptiondoes the image match the description?
describevideo, fps?, focus?timecoded scene-by-scene description (what happens, speech, sounds, music); returns a job_id — poll get_status

Omit expected_text on transcript for transcription-only mode (no compare, verdict PASS); the result carries actual_transcript, duration_sec, and timecoded segments either way.

files

Manage your storage.

ActionKey argumentsDoes
listprefix?, cursor?list your stored files
uploadfilename + url | databring a file into your storage — from a hosted URL, or a LOCAL file's raw bytes via data (data-URI / base64, ≤25 MB)
create_uploadfilename, content_typeget a token + upload_url to PUT a LARGE / original-quality local file directly (no 25 MB cap)
import_remotedownload_url (or url)pull a remote file (e.g. a file an assistant/chat app handed you as a URL) into your storage in one call — no manual download/re-upload. Returns a Framehood url you can pass straight into image/video/audio/qa.
deletefilenameremove a file
publishfilenamemake a file public, returns a public_url
unpublishfilenamemake a published file private again
downloadfilenameget a usable URL to fetch the bytes
import_to_libraryfilename (the uploaded key), name?, project_id?mint a library asset (asset_id) from one of your uploaded files, optionally assigning it to a project — so uploads can be organized/assigned like generated assets

You don't need to publish to reuse a file

publish is only for sharing a file publicly — it returns a public_url anyone can open or download. To use a file as a reference in another job (image_url, video_url, …) you do not publish it: pass its private cdn URL, or its library asset_id, directly (see What you can pass as a media reference above).

Bringing in a file from another app

If another app or assistant hands you a file only as a URL (a chat attachment, a generated image it made elsewhere), don't pass that URL straight into image/video/audio/qa — import it first:

  1. files(import_remote, download_url="https://…") → get back { url: "https://cdn.framehood.ai/…", content_type, size }.
  2. Use that returned url as image_url / video_url / etc. in any generation or qa call.

Only https:// sources are accepted, and only image/video/audio files — anything else (a PDF, an SVG, an http:// link) is rejected with a clear error. Files are capped at 200 MB. The URL you passed in is never stored or returned — only the resulting Framehood file.

Organizing an uploaded file into a project

Generated results are added to your library automatically, but a file you brought in yourself (upload / create_upload / import_remote) has no library entry, so it can't be assigned to a project. import_to_library mints one:

  1. files(import_to_library, filename="<the uploaded key>", project_id?="<id>") → get back { asset_id, url, type, size, project_id }.
  2. Use asset_id with project(assign) (or pass project_id above to assign in the same call).

It references your existing file — nothing is copied, and it's free. Only image/video/audio files can be imported. It resolves your OWN private uploads only — not a published (public/) file, and not a teammate's file. Re-importing the same file creates a new library asset each time.

actor

Temporarily disabled

Actors are being reworked — the actor tool is not currently advertised over MCP. The reference below is kept for when it returns.

Create and manage persistent actors. An actor carries visual identity, voice, personality, wardrobe, and motion across image / video / audio generations — pass its actor_id (act_…) to those tools to reuse the same actor. Training a custom actor is a paid feature; the free tier can use built-in actors.

ActionKey argumentsDoes
createname, images_data_urltrain a new actor from a ZIP of reference photos; optional voice, personality, wardrobe, motion, brand
updateactor_idchange voice, personality, wardrobe, motion, or brand
listprefix?list your actors, optionally filtered by name prefix
getactor_idfetch one actor's full profile
deleteactor_idremove an actor
batchactor_id, prompts, kind?, duration?, tier?generate many images or videos for one actor in a single call

images_data_url is a public ZIP URL with 4–30 reference photos. Attach a voice via voice_id (existing) or voice_sample_url (a clean 30–60s sample). Voice cloning is additionally gated behind its own flag, independent of the actor rework above — it stays disabled (pending pricing) even once actors return; linking an existing voice via voice_id is unaffected.

billing

billing(action) — credits, plan, and upgrades for your organization. Read actions are open to any member; the rest are owner-only.

ActionKey argumentsDoes
balanceshared credit balance + your role
transactionslimit?recent credit ledger (newest first)
planyour tier, monthly allowance, manage link (owner)
plansavailable packages
subscribestepowner: Stripe Checkout link for a package
previewstepowner: prorated cost of switching
changestepowner: switch package, prorated, charged now
cancelreactivate?owner: cancel at period end, or resume
manageowner: Stripe Customer Portal link
topupamount_eurowner: buy a one-off batch of extra credits now (min €20, at the extra-usage rate); returns a hosted invoice link
extra_usageowner: view the auto-top-up (Extra usage) config
set_extra_usageenabled?, trigger_below?, amount_eur?, extra_usage_cap_eur?owner: configure automatic overflow top-ups
request_upgradenote?member: email the owner to top up

See Credits & plans.

org

org(action) — your organization. Members share a credit pool and actors.

ActionKey argumentsDoes
infoyour org + your role
memberslist members (role + suspended state)
spendper-member credit spend
trenddays?daily org spend (7–90 days, default 30)
inviteemailowner: invite by email
accept_invitetokenjoin an org with an invite token
removeemailowner: remove a member
set_roleemail, roleowner: memberadmin
suspend / enableemailowner or admin: block / unblock a member

A suspended member loses org access and can't draw on the shared credit pool. Plan and payment live in the billing tool; out of credits, members use billing(request_upgrade).

get_status

get_status(action) — poll or manage jobs.

ActionKey argumentsDoes
statusjob_idpoll one job → queued · running · succeeded (with outputs) · failed (with error)
status (batch)job_idscheck up to 50 jobs in ONE call → {summary, jobs[]}
listkind?, status?, since?, limit?, cursor?the generation-history feed (since = RFC3339 or "1h" / "30m" shorthand)
canceljob_idcancel a non-terminal job — a queued job cancels immediately, no charge. A running job's cancel is a best-effort request: it errors and the job keeps running if the model doesn't support cancellation at all; otherwise the request is accepted but the job may still complete and be charged if the model doesn't honor a mid-run stop — poll status for the outcome

status is the default action.

Submitting several jobs? Fire all the submits in parallel, collect the returned job ids, then poll ONCE with job_ids=[…] every ~30–60s until summary.running + summary.queued is 0 — don't poll jobs individually. Each batch entry carries status, done, and (when terminal) outputs/credits or error; an id you don't own (or that doesn't exist) comes back as status: "not_found" without failing the batch.

models

models(action) — browse the model catalog. Every tool already picks a sensible default model, so reach for this only when you want a specific one.

ActionKey argumentsDoes
listtool?reachable models grouped by tool (optionally filtered to image / video / audio / qa)
guidemodelone model's parameters + prompting tips

To use a specific model, pass model (and optional params) to the generation tool — e.g. image(create, model="flux_pro", params={…}).

submit_feedback

submit_feedback — send a note to the Framehood team: a bug, a feature request, or general feedback.

ArgumentDoes
messagethe feedback text
category?bug · feature · other
context?what you were doing / which tool or model
job_id?the job this feedback is about (e.g. job_abc123) — links the ticket to that generation

Workspace tools (also over MCP)

These three are advertised over MCP alongside the generation and account tools and let you organize and authenticate your work.

library

library(action) — search and manage your generated assets:

  • list (query, type, project, limit, offset) — search past generations by prompt/name, filter by media type or project, paginate.
  • trashed — list the trash.
  • trash (id) / restore (id) — soft-delete or recover an asset. The trash is auto-purged after 10 days. You can trash your own assets; org owners/admins any.

project

project(action) — group generations into projects:

  • list — your personal projects + the org's shared ones.
  • create (name, visibility personal|shared, description).
  • update (id) — rename, change visibility / description, or owner.
  • delete (id) — owner only; the assets stay in the library.
  • assign (asset_id, id) — put an asset in a project; omit id to unassign.
  • use (id) — set your active/default project; new generations land there automatically. Omit id to clear.
  • current — show your active project.

api_keys

api_keys(action) — programmatic keys for the REST API and CLI:

  • list — your keys (metadata only).
  • create — mint a key; the secret is returned once.
  • delete (key) — revoke a key.

CLI / REST surface

The CLI and the REST API drive the same tools listed above — the CLI maps its commands onto them, and the REST API exposes the same operations as plain HTTP endpoints. They additionally surface a few things the MCP tools intentionally don't:

  • Raw job submissionPOST /v1/jobs/{kind} to run a specific model kind directly. (Over MCP you don't submit to a kind — pass model + params to image / video / audio / qa, and browse the catalog with the models tool.)
  • UploadsPUT /upload and POST /upload-from-url to bring your own input files into storage.
  • Browser billing flows — the Stripe card-entry and customer-portal endpoints (POST /billing/card, /billing/portal, …), which finish in a browser.

See the REST API reference for the full endpoint list. Over MCP your client handles auth, so you rarely need to touch these directly.

Framehood