A side-by-side look at the Distribea MCP and OpenFlow MCP servers: transport, auth, tools, quality signals, and the config to install either one in Claude, Cursor, Windsurf or VS Code.
Verdict: choose Distribea MCP for multimedia process work as a local process; choose OpenFlow for multimedia process over a hosted endpoint. You can also run both side by side in one mcpServers block.
DISTRIBEA_MCP_KEY.make_images, bring_alive, generate_image.generate_with_face, generate_image, music_generate.Rows where the two servers differ are marked.
| Spec | ||
|---|---|---|
| Category | Multimedia Process | Multimedia Process |
| Quality signal | 57/100 · Good | 57/100 · Good |
| Install command | Confirmed | Confirmed |
| Transport | Local subprocess (stdio) | Remote HTTP/SSE |
| Auth | Not declared | Not declared |
| Pricing | Paid service | Not declared |
| Required env vars | DISTRIBEA_MCP_KEY | None listed |
| Verified owner | Community listing | Community listing |
| GitHub stars | 1 | 8 |
| Directory activity | 2 views 0 installs 0 upvotes | 1 views 0 installs 0 upvotes |
| Tools | 21 | 45 |
| Full listing | View Distribea MCP | View OpenFlow |
make_images⭐ THE flagship one-call tool. page_path → dresses that page; no page_path → scans the WHOLE project. Finds every placeholder/stock slot (placehold.co, picsum, unsplash, pexels…), locks/infers the style automatically, generates every image IN PARALLEL (recurring characters/products auto-used), saves optimised WebP and patches src+alt in the code. REVIEW/TESTIMONIAL sections are detected automatically: their avatars come out as ultra-real casual smartphone selfies (UGC look — car/bedroom/living-room backdrop, real skin), each reviewer keeps the SAME face across THIS site; your other sites are independent by default (set cross_site_unique:true to also keep reviewer faces distinct across ALL your sites). rebrand:true targets EXISTING real images instead: first call lists them for FREE, then apply:true regenerates them all in place (code untouched, originals kept as *.original).bring_aliveMake an EXISTING site feel alive with on-brand imagery. Two things at once: (1) ADDS images where sections have none (hero, testimonials with ONE face per reviewer, team/about, key benefits, gallery — sized to the real layout), and (2) by DEFAULT REPLACES every existing image with an on-brand one (stock photos, old pictures…). page_path = one page; OMIT page_path = the WHOLE site. WORKFLOW: call it once for a FREE proposal (new spots + the list of existing images that will be replaced, 0 credits); show it, ask the user which to KEEP; then call AGAIN with apply:true to place + fill the new spots AND replace the existing images in one go. Spare specific images with keep:["filename"]; pass replace_existing:false to only ADD images and leave existing ones untouched. Everything is reversible with undo:true.generate_imageGenerate ONE website image for a SPECIFIC spot AND wire it straight into the page — DESTINATION = a page (placed in code), NOT a file on disk. Coherent with the locked style (and optionally a recurring character/product). Generation is tied to a placement: pass page_path + leave a placeholder (<img src="https://placehold.co/…">) where you want it; the image replaces that placeholder. NO page / NO placeholder = NOTHING is generated and NOTHING is billed (never produces an orphan image). Subjects mentioning a customer review/testimonial/avatar automatically switch to the UGC mode: ultra-real casual smartphone selfie of an everyday person (unique per site, same reviewer = same face). For a whole page or project, prefer make_images. CONTEXT: when you are building or editing a website (pages, components, placeholders), THIS or make_images is the default — that is the page-building job. If the user instead wants a downloadable image FILE to keep/reuse (an ad, a social/marketing visual, "download/save the png", a named model with no page), use generate_with_model. If it is unclear whether the image goes IN a page or is a downloaded FILE, ask one short question first.list_modelsReturns the catalog of image models to choose from: id, name, what it's best at, quality tiers, formats, max images per call, and an indicative price in credits. Call this BEFORE generate_with_model when the user wants to pick a specific model or compare options/prices. Image only for now.generate_with_modelStandalone image generator — DESTINATION = a FILE on the user's disk, never a website page. Use it for downloadable assets the user keeps or reuses elsewhere: ads, social posts, marketing/promo visuals, thumbnails, a reusable hero or logo, or any 'generate then download / save to a folder' request (often with a named model like Flux Pro / Seedream, or a png/jpg format). DESTINATION ALWAYS WINS: if the image must appear ON a website page — or you are MID-BUILD of a site, filling placeholders / dressing pages — use generate_image (one spot) or make_images (whole page), EVEN IF a model is named. If it is genuinely unclear whether the user wants the image IN a page or as a downloaded FILE, ASK one short question before generating — do NOT guess. Downloads a NATIVE png/jpg (never WebP) into a tidy folder, at the regular SITE price; nothing is placed into any page. Get model ids from list_models. DEFAULT when the user names NO model: nano-banana-pro at 2K. ORIENTATION: if the user didn't state one, ASK 'portrait or landscape?' before generating, then pass the matching format (16:9 = landscape, 9:16 = portrait). (Same idea as Higgsfield: pick a model, dial settings, download the file.)list_video_modelsReturns the catalog of VIDEO models to choose from: id, name, what it's best at, durations (seconds), resolutions, aspect ratios, and an indicative price in credits (for the default duration; longer clips cost more). Call this BEFORE generate_video when the user wants to pick a specific video model or compare options/prices.generate_videoStandalone VIDEO generator — DESTINATION = an mp4 FILE on the user's disk. Pick a specific video model + settings (duration, resolution, aspect ratio) and DOWNLOAD the result as a native mp4 into a tidy folder, billed at the regular SITE price. Video takes several MINUTES and needs a PAID plan (no free video). Use it for ads, social clips, b-roll, promos to download — never to place into a website page. If the call says the video is still rendering, run it again with the SAME settings in ~1 min to pick it up (no double charge). Get valid model ids + options from list_video_models. DEFAULT when the user names NO model: grok-imagine-video, 6s, 720p. ORIENTATION: if the user didn't state one, ASK 'vertical or horizontal?' before generating, then pass the matching format (16:9 = horizontal, 9:16 = vertical).list_music_modelsReturns the catalog of MUSIC models (id, name, indicative price in credits). Call this BEFORE generate_music when the user wants to pick a specific music model or compare prices.generate_musicStandalone MUSIC generator — DESTINATION = an audio FILE on the user's disk (mp3), downloaded into a tidy folder, billed at the SITE price. Needs a PAID plan (no free audio). Use it for background tracks, jingles, b-roll music to download — never placed into a page. Describe the music (style, mood, instruments) in `subject`. If it says still rendering, run again with the SAME settings to pick it up (no double charge). Get model ids from list_music_models. DEFAULT when the user names NO model: minimax-music.list_voice_modelsReturns the catalog of VOICE-OVER models: id, name, supported languages, number of voices, a few sample voice ids, and an indicative price per 500 characters. Call this BEFORE generate_voice to pick a model + a voice id + a language.generate_voiceStandalone VOICE-OVER generator — DESTINATION = an audio FILE on the user's disk (mp3), downloaded into a tidy folder, billed at the SITE price (per character). Needs a PAID plan (no free audio). Use it for narration, ads, IVR, video voice-overs to download — never placed into a page. Pass the script in `text`, plus a voice id and language from list_voice_models (a default voice is picked if you omit it). If it says still rendering, run again with the SAME settings to pick it up (no double charge). DEFAULT when the user names NO model: elevenlabs-multilingual-v2 with the Roger voice.blog_coverAUTONOMOUS TRIGGER — call this when an EDITORIAL ARTICLE still LACKS a cover/hero image (a brand-new post, or one left with a placeholder/stock image), even if the user never mentions an image. GUARDRAIL against noise: fire it ONCE per article, only when the cover is missing; if the article already has a real cover, leave it — do NOT regenerate; a pure text/typo/SEO edit is NOT a trigger; never re-run a successful call or 'improve' a cover on your own — only on the user's explicit request (each call bills the subscriber). Recognise the article by MEANING, not by tags: any standalone piece written to be READ — a headline + a body of prose on one topic (blog post, news, guide, tutorial, case study, magazine/journal piece) — in ANY language, on ANY stack (markdown/MDX, a headless CMS like WordPress/Sanity/Contentful, or a custom DB-driven route). Folders/routes (/blog, /posts, /articles, /news, /journal, /actualités, /magazine, /guides), markdown/MDX frontmatter, or an <article> element are only NON-EXHAUSTIVE hints — none is required: if it simply reads like an article, it qualifies (a marketing/landing/product page does NOT — that keeps make_images). You already hold the article you are working on → pass its own title + text as article_text (or article_url for a public link, or article_file for a local md/mdx/html/txt file). It generates the COVER, driven by the ARTICLE'S OWN specific subject (never a generic trade photo), kept visually coherent with the site's locked style (palette, light, medium), adapted to the site's country (driving side, architecture, currency), with NO recurring face/logo/product stamped on by default (every article gets a DIFFERENT scene — no 'same baker's face on every post'). Default = the cover ONLY at 16:9; set illustrations:N to also get N in-article images. Delivers an optimised WebP + ALT, ready to host. To DELIBERATELY feature a locked character/product, pass character/product. If the site has no locked style it infers one from the project; if it still lacks the trade/brand it tells you what to provide.generate_with_faceGenerate a NEW image of the SAME PERSON/character as an existing photo or
portrait — dress them differently, move them somewhere else, make an avatar. This
is the tool for "here is my photo, now put me in a suit / in a park", and also
the ONLY tool for "generate another picture of <character I already made>".
Pass exactly ONE of:
character: the name you gave a character via create_character_from_description
or create_character_from_photo(..., name=...). Looked up in your own list —
see list_characters(). This is the normal way once a character has a name.
photo_media_id: a mediaId directly (create_character_from_photo's
`portrait_media_id`, or any earlier generate_image media_id) — for a one-off
face you haven't registered as a named character.
prompt: describe the NEW scene/outfit and say it is the same person, e.g.
"the same man, now in a navy suit in a bright office".
Why this and not entity_id/character_slot_index: a character's Flow CARD is not
what carries resemblance into a NEW scene — the reference image itself does
(verified live, repeatedly). Combining entity_id with an image reference in the
same call also fails outright (HTTP 500). So this always generates from the
reference image alone, never from entity_id — that is deliberate, not a
workaround to fix later.
project_id: put the result into a project made with create_project instead of the
account's default one. photo_media_id itself stays account-bound, as always.
generate_imageGenerate an image from a text prompt via Google Flow.
model — pass ONE of these exact ids (from GET v1/flow/models, verified 2026-07-25):
BELUGA = "Nano Banana 2" — the DEFAULT, ~30s (legacy id NARWHAL is accepted as an alias)
GEM_PIX_2 = "Nano Banana Pro" — highest quality, ~40s, has a separate DAILY
per-account quota (429 rotates accounts)
HARBOR_SEAL = "Nano Banana 2 Lite" — ~40s
Anything else is rejected with HTTP 400 — there is no silent fallback, so a wrong id
wastes a round trip, not credits. Do NOT guess names like "nano_banana_pro": that is
the model FAMILY key from the config, not the id the generate call takes.
image_inputs: mediaIds from prior generations, edit-in-place (keeps them pixel-exact).
control_images: base64 image bytes (no data: prefix) of a locally rendered layout/control
image — uploaded first, then prepended to image_inputs so the generator follows an exact
spatial layout instead of prose. For whole-scene layout control prefer generate_scene.
seed: 1..900000, fixes the generation so the same request returns the same image. Omit
for a random seed. Needed to compare two prompts, two models or two control images
honestly — without it every run is a fresh roll and the difference you are measuring
drowns in noise. Measured 2026-08-09: with an UNCHANGED control image a fixed seed
reproduces the frame to ~0.1%; once the control image changes, the seed no longer keeps
the character — for that use image_inputs with a reference frame's mediaId.
project_id: put the result into a project made with create_project instead of the
account's default one — one project per end client keeps their work separate. Omit it
and nothing changes from before.
include_preview: ON by default since 2026-08-21 — a generated image nobody can see
in the chat is half a result. Pass False to get the plain dict back and nothing else
(worth doing in a loop of many generations, where the previews would fill the
context). When on and the job finished with at least one url, the call returns the
usual result dict, a short card naming the parameters actually used, and a small
compressed JPEG (long side capped at 768px, ~100-160KB once base64-encoded) as an
inline image content block, so a human can actually see the result without leaving
the chat. This is deliberately a shrunk preview, never the original — the real Flow
image is ~0.5MB (~740KB in base64), enough to burn a whole tool call's worth of a
client's context budget on its own. The preview is for EYES ONLY: urls/media_ids
stay the authoritative result in both modes, and every downstream call (upscale_image,
image_inputs edit-in-place, ...) must keep using media_ids, never the preview bytes.
If the preview download/shrink fails for any reason, this silently falls back to the
plain (no-preview) result instead of failing the whole call.
SAVE THE RESULT INTO THE USER'S PROJECT. A finished job also carries `download_urls`
(plain URLs, no auth header needed) and `save_as` (the filenames to use). Unless the
user said otherwise, write them to ./media/<save_as> in their working directory and
tell them the path. The server keeps its own copy, but only the file in their project
is theirs: our copy can be reclaimed when the disk fills, and the URLs expire within
the hour. Downloading costs no credits and no quota.
Returns {"urls": [...], "media_ids": [...]} when done, or a job_id to poll
with check_job if it's not ready within ~60s (rare for images unless the
device is cold). With the default include_preview=True and a finished result,
returns [that dict, <card>, <inline image>] instead — see include_preview above.
music_generateGenerate a full song from a text brief via Google Flow Music (Lyria).
prompt — free text: genre, mood, BPM, instruments, and whether you want vocals or an
instrumental (e.g. "dreamy synthwave, retro 80s, 110 bpm, instrumental"). The Producer
agent turns it into a finished track (usually ~2-3 minutes, and it returns TWO variants).
model — "lyria" (Lyria 3.5, the default flagship) or "lyria-pro" (Lyria 3 Pro, legacy).
lyrics — optional explicit words to sing; omit for the model to write its own / stay
instrumental.
SAVE THE RESULT. Each returned clip carries a public `audio_url` (a Google Cloud Storage
.m4a, no auth header needed) plus `download_path` on our server. Unless the user said
otherwise, download the audio into their project. Fields per clip: clip_id, title,
duration (seconds), lyrics, audio_url, wav_url, image_id (cover, feeds music_video),
image_url. Returns {"clips": [...], "media": [...], "conversation_id": "..."} when done,
or a job_id to poll with check_job if it isn't ready within ~90s.
conversation_id — pass the one from an earlier result to keep working on the same track
("same song but 30 seconds shorter"); the Producer remembers what it just made. Omit it
for a fresh start. Every result carries one, so a follow-up is always possible.
music_chatTalk to the Google Flow Music Producer agent instead of one-shotting a track.
Use this when the work is a conversation rather than a single brief: asking what it can
do, having it write lyrics first, or editing a track it already made ("drop the vocals",
"same song, 30 seconds shorter", "make the chorus bigger"). For a plain "make me a song
about X", music_generate is the shorter path.
message — what to say. conversation_id — omit on the first message, then pass the one
that comes back so the Producer keeps its memory of the track. model — same choices as
music_generate.
Returns {"conversation_id", "text", "suggested_actions", "clips": [...], "media": [...]}.
`text` is the Producer's reply. `suggested_actions` are the follow-ups it offers — show
them to the user, they are good prompts for the next turn. `clips` is EMPTY when the
Producer only talked, and filled when it decided to actually make audio; treat a filled
`clips` exactly like a music_generate result and save the audio.
A reply is usually seconds, but a turn that produces a song takes minutes and comes back
as a job_id to poll with check_job.
music_stemsSplit a track we generated into stems (vocals, instrumental, drums, bass, …).
clip_id — the id of a clip returned by music_generate (or music_video's song). Runs on
the same account that made the track. Returns {"stems": {name: "/v1/media/..."}, "media":
[...]} when done, or a job_id to poll with check_job. Each stem is a downloadable .m4a on
our server (public download_path). Save the ones you need into the user's project.
music_listList the user's music tracks.music_getGet metadata for a single music track.music_downloadDownload the raw .m4a file of a track to the server.music_creditsCheck remaining flowmusic credits and subscription tier.generate_sceneBuild a location precisely from a scene-layout/v2 map and generate its plate.
This is the "exact location building" path: instead of describing the room in prose
(which the model reinterprets — furniture drifts, depths change between shots), it
renders a control image from the map's boxes (each object a colored block at its true
position/size/depth, plus a 1-meter floor grid in true perspective), then asks the
generator to REPLACE each block with its real object in the same camera — so the plate
follows the geometry pixel-wise. Same room from another camera_id is the same space.
scene_layout: a scene-layout/v2 dict — {format, units, room{w,d,h}, objects{...boxes},
cameras{<id>:{pos,look_at,fov_deg,framing?}}, ...}. The camera must carry fov_deg.
camera_id: which camera in scene_layout.cameras to render from.
aspect: PORTRAIT (9:16), LANDSCAPE (16:9) or SQUARE. 9:16 and 16:9 from one camera share
the vertical FOV, so depths are identical across aspects.
style / extra: prepended / appended prose (art style, mood) — geometry comes from the map.
A box may carry `rot: [rx, ry, rz]` (degrees around the world X/Y/Z axes) and `pivot:
[x, y, z]`, applied as p' = Rx·Ry·Rz·(p − pivot) + pivot, pivot defaulting to the box
centre. That is how a POSE is expressed — a raised arm is a box rotated about the
shoulder. Measured live 2026-08-09: moving a hand by 2–20 cm is ignored by the
generator, rotating the arm by 15–60° comes through. Build motion out of angles.
seed / image_inputs: same meaning as in generate_image. For a SEQUENCE of frames of one
character, generate a reference frame first, then pass its mediaId as image_inputs on
every following frame — that is what keeps the face, clothes and colours identical.
A fixed seed alone does not: it only repeats an unchanged control image.
depth: render the guide as a plain greyscale depth map instead of the colour hybrid
(for an external depth-ControlNet). calibration: add frame markers, a back-wall grid
and a 2 m ruler with 10 cm ticks — measured to cut the framing drift roughly fourfold.
background: "dark" (default, unchanged) or "light". Use "light" when the plate must be
on a white background: the generator sometimes copies the guide's own palette into the
result, and a light guide makes that leak land as white rather than as a dark grid.
control_png: return the layout guide itself, base64-encoded. OFF by default because it is
hundreds of thousands of characters of TEXT — one guide can cost more context than the
whole conversation around it. `control_png_kb` always reports its size.
Returns {"urls", "media_ids", "legend", "control_png_kb"} — legend maps block colors to
objects. Add control_png=True to also get the guide itself for inspection/acceptance.
generate_videoGenerate a video from a text prompt via Google Flow (Veo models).
video_model_key options: abra_t2v_4s (default, 7 credits), veo_3_1_t2v_lite
(10cr, visibly cleaner), veo_3_1_t2v (100cr, "Quality" tier), veo_3_1_t2v_fast (20cr).
project_id: put the clip into a project made with create_project instead of the
account's default one — one project per end client keeps their work separate.
Video generation routinely takes 1-3+ minutes, so this almost always returns
a job_id rather than a finished result — call check_job with it, waiting a
few seconds between checks, until status is 'done' or 'failed'.
beats: how many DISTINCT action phases the prompt describes — "ears flick back",
"tail lashes", "strikes the ball", "ball flies off" are four. Give it and the server
picks the clip length for you (about two phases per second) and says in the reply what
it picked and why. Measured 31.08.2026: the model STRETCHES whatever you describe over
whatever length you ask for, so one phase in four seconds comes out as slow motion, and
the same text at six seconds instead of four loses 15% of its movement. Adjectives are
not phases: "springy cartoon motion" adds nothing. Leave beats out and the length you
passed is used unchanged.
seed (all video tools): the result always reports the seed it used. Same seed + same
prompt + same inputs = the same clip, so a good take can be re-made. A fixed seed does
NOT keep the composition when the prompt changes — use edit_video for that.
edit_videoRewrite a video from a plain description: "make the sky stormy", "take the
passer-by out of the shot", "warmer light", "put the product from the image on the
table".
Source — ONE of:
media_id: id from a previous generate_video* result (OUR OWN generation). Job is
pinned to the account that produced it.
video_base64: base64-encoded YOUR OWN clip (mp4/mov/avi/3gp, up to 60s/1GB).
Worker uploads it via Flow's Scotty resumable upload (reversed via
Flow Web Ingredients, 2026-10-14) onto a healthy account, then runs
the edit on that account. The upload itself costs no credits.
start_sec / end_sec: edit only this piece of the source (both or neither, at most
10 s). The result is ONLY that piece — not the full clip with the piece replaced.
reference_images_base64: up to 3 raw base64 images (no data: prefix); the object in
the image is put into the clip — say in the prompt what to do with it.
20 credits per edit (abra_edit_360p: 10). Not a mask tool — describe the change and
where it goes ("on the left", "in the sky"); mask/style image types are not honored.
Prompt template that lands best — fill each part, one or two sentences each:
Goal: what changes ("Replace the man on the left with the character from image 1").
Source: "The source video drives camera, motion, timing and lip movement."
Reference: what to take from each image ("use only the character's look; ignore
the image background").
Scene: describe the room/background in words (helps the model keep it intact).
Keep: "Everything else stays exactly as in the source."
Timing: "The new character inherits the exact movement and position of the one
it replaces, from the first frame to the last."
Draft on abra_edit_360p (10 credits) to check the edit lands, then run abra_edit; the
seed does not carry an edit take across resolutions, so the final can differ in details.
Only edit footage the user owns or is licensed to use; do not put real people's
likeness into clips without their consent.
Paste either block (or both) into your client config, e.g. claude_desktop_config.json or ~/.cursor/mcp.json. We only show a config when the install command is confirmed.
{
"mcpServers": {
"distribea-mcp": {
"command": "npx",
"args": [
"-y",
"distribea-mcp@latest"
],
"env": {
"DISTRIBEA_MCP_KEY": "YOUR_DISTRIBEA_MCP_KEY_HERE"
}
}
}
}
{
"mcpServers": {
"openflow": {
"url": "https://openflowmcp.com/mcp"
}
}
}