Skip to main content
Glama

google-flow-mcp

Drive Google Flow (Veo video, Nano Banana images) from a terminal and from an AI agent: read projects, media and credits; create and delete projects, characters and scenes; upload media; generate images and video; assemble scenes into a film. Every paid action is written to a ledger before the click, and an MCP server exposes the whole surface to Claude Code or any MCP client.

Everything in this README was measured on a real account, not inferred from the code. Where a number has not been measured, it says so.

This is not an official Google project. It automates the Flow web app through a real browser session. Read Risk before you run anything.

What it is, and what it is not

It is a control layer: 50 MCP tools plus a CLI, with a spend ledger, a double-charge guard, and prices in every tool description.

It is not a video maker. The script, the shot list, the camera angles and the quality of the result are the job of the agent using these tools. The repo owner settled this on 2026-09-13; the story package is only a worked example and a place to exercise the paid paths for real.

Related MCP server: Google Flow Browser MCP

Will it run for you?

All four must be true. The first one is the one that catches people.

Requirement

Why

A Google account whose Flow has migrated to flow.google.com

On this account the old labs.google lane is dead: labs.google/fx/api/auth/session answers {} and every gflow command that goes through it fails. Re-running gflow auth login does not fix it

macOS with real Google Chrome

The browser lane drives Chrome with the gflow-cli profile at ~/Library/Application Support/gflow-cli/profile_default. Nothing here is tested on Linux or Windows

gflow-cli already logged in on that profile

This repo never logs in for you; it reuses the profile gflow created

ffmpeg and ffprobe on PATH

Post-production, duration checks and every measurement in the acceptance scripts

A Google AI Pro (or higher) plan is what the measured prices below come from. Flow tops the balance up by about 50 credits a day on that plan, which is why a balance can go up between two readings: never infer spending from the difference between two readings taken far apart.

Install

git clone https://github.com/hainguyen-keyti/google-flow-mcp.git
cd google-flow-mcp
uv sync --group dev
uv run video --help

Check the lane before anything else. This costs nothing and tells you whether the account is usable:

uv run video flow lane

verdict: MIGRATED means you are on the supported lane. Anything else means the tools here will not work for that account, and no amount of retrying will change it.

Quickstart

Free reads:

uv run video flow projects
uv run video flow credits
uv run video flow media <project_id>

A paid generation, 10 credits on the measured plan, written to out/ledger.jsonl:

uv run video gen t2v "a red paper boat drifting on a pond" --project <project_id> --model veo-lite --job boat-1 --out out

Using it from an agent (MCP)

cp .mcp.json.example .mcp.json

Edit the copy if uv is not on your PATH, then open the folder with an MCP client (Claude Code reads .mcp.json from the project root). The server serves 50 tools; every description carries its price.

A server that is already running does not pick up new code, and an open session keeps the old tool descriptions: after changing anything here, start a new session.

See docs/tools.md for the full tool list with prices, generated from the running server rather than typed by hand.

What a call costs

Measured on a Google AI Pro account in September 2026. A price marked unmeasured is one this repo refuses to guess about; the tool says so too.

Action

Credits

gen_video: any option Flow's composer offers, guarded by Flow's live price line and your max_credits

Omni 1.1 Flash 720p 4/6/8/10 s: 7/10/12/15; 360p: 4/5/6/7; Veo 3.1 Lite 10, Fast 20, Quality 100 (8 s); x2-x4 multiply (Flow's price line, 2026-09-29)

gen_video with voices (a preset or a voice of your own, beside an image or a character)

the same price: Veo 3.1 Lite with one image and one voice 10, Omni 1.1 Flash 8 s with one image and two voices 12 (paid 2026-10-01)

job_submit: gen_video that does not wait for the render (one clip per call, no dry run)

the same price as gen_video; omni-flash 360p 4 s paid twice at 4 (2026-10-03)

job_status, job_collect: where a submitted job stands, and fetching its clip

0

gen_t2v / gen_r2v, veo-lite, 8 s

10

gen_t2v / gen_i2v, omni-flash, 10 s

15

gen_r2v, omni-flash, 8 s (the only length gflow offers it)

12

gen_character (video starring a project character), omni-flash

12

gen_character, veo-lite

10

gen_character, veo-fast

20, from Flow's own price table, unmeasured

gen_character, omni-flash, 10 s, with characters or from project images alone (the only 10 s reference video; gen_r2v runs 8 s)

15

clip_extend (Veo clips only)

10

clip_edit (Omni 1.1 Flash)

20 measured, Flow's table says 40

gen_t2i / gen_i2i (Nano Banana 2.1, the model Flow offers in place of 2 since 2026-10-07)

0 credits, but a daily image quota

clip_download at 1080p, or at 720p on a 360p clip (its upscale, measured 2026-10-03; a 360p clip has no 1080p and is refused with what its menu offers)

0

clip_download at 4k (a Flow upscale)

not offered on Pro: greyed out, refused before any click (Flow's table: Ultra, 50)

Every read: lane, projects, media, credits, characters, scenes, voices, what a clip was made from (clip_recipe), and this table as data (flow_capabilities: every model's cells, lengths and caps, no browser)

0

Timing, so a slow call is not mistaken for a broken one: a read takes 15 to 50 s, a change about 50 s, a generation 2 to 5 min, clip_extend and clip_edit up to 7 min. job_submit answered in 153 s with the balance already charged, job_status and job_collect in about 47 s each, and two clips submitted back to back were both ready within about 4 min of their submits (measured 2026-10-03, omni-flash 360p 4 s, 4 credits each).

How the money is guarded

These are not suggestions; they are enforced in code and pinned by tests.

  • A ledger line is written before the click, not after. A driver that dies mid-action leaves a submitted row, never a silent charge. This exists because 20 credits were once spent with an empty ledger.

  • A job_id is spent once. Before opening a browser, a paid tool refuses any job_id that appears in ANY ledger.jsonl under out/, and refuses one that another call is running right now. Retrying with the same id is safe; inventing a new id for a job you already paid for is how you buy the same thing twice.

  • Every paid call says what it came to. The answer carries outcome {code, charged, retryable, advice} and an error opens with outcome code=... charged=... retryable=..., read off the job's own ledger rows: charged is what the balance bracket says left the account, UNKNOWN and CHARGED_NO_OUTPUT mean money may be gone, and an error with no outcome line was refused before any job started. Flow's refusals seen on this account all charged nothing: the audio filter (5 times), prominent people (2), unsafe generation (2), and once no reason at all.

  • One retry the server vouches for. When gen_video or gen_character says retryable=yes (Flow failed the job uncharged, for its audio filter or for no reason), call again with the same project and prompt, a new job_id and retry_of set to the refused one. The ledger is checked before a browser opens: the job must have failed uncharged, the project and prompt must be the same (the settings are not compared), a job is retried once (a second retry is refused once the first has clicked, and while it runs in the same server), and one original gets at most two retries. Any other new job_id after an error is still wrong.

  • Submit now, collect later, still one click. job_submit is gen_video's own run (the same checks, the same job_id guard, the same single click) that answers once Flow's submit request has been seen leaving, with outcome STARTED. job_status reads where the job stands and writes nothing; job_collect downloads the finished clip and writes the job's one settled row, and a job already settled is answered from that row with no browser. Neither can click or type. A clip is claimed only by the workflow id Flow's own submit reply named, or, when no reply was heard, by the single new clip carrying the exact prompt: two candidates are never chosen between. spent is the job's own balance bracket only when no other job could have moved the balance meanwhile; otherwise it is the price quoted before the click, and the row says which (spent_from, with balance_shared on the row and charged_from in the outcome). An Ingredients clip has its recipe read back at the collect, as gen_video does. Flow charged both measured jobs at the submit, not at the finish. What not waiting gives up is Flow's reason for a refusal, which only the page that submitted hears: such a job never shows, is settled as nothing generated ten minutes after its submit, and takes no retry_of (a refusal heard while the page was still open is settled there, typed, and job_submit takes retry_of for it as gen_video does). While a submitted job may still show its clip (from the moment job_submit is called until it is collected, or for an hour after it was settled with no clip), gen_video and gen_character are refused for the same project and prompt: a blocking run takes the one new clip carrying its prompt, which could be the submitted job's. And a blocking tool run beside a rendering job reads its own spend off a balance that job can still move.

  • Outputs stay inside out/. Every tool that writes a file or a ledger forces its target inside out/.

  • Click once, then wait. Flow submits late, about 20 s after the click. Leaving the page early cancels the request in flight and looks exactly like a dead button; clicking again submits a second, paid job.

  • Every ingredient is read back before the click, and the clip's recipe after it. Flow's price line did not move when it greyed out an image over the model's cap (measured: still 10), so the ingredient bar itself is read: each image by the workflow id its thumbnail names, each voice by the name on its hover card, and a chip Flow refuses (an image over the cap, a voice with nothing beside it) stops the run in Flow's own words. After the click the request's own voice field is checked, and once the clip is fetched its recipe is read back; an input Flow dropped is reported as an error even though it was paid.

  • Prices live in the tool description, and a tool refuses a cell whose price nobody has measured.

Risk, read this before the first run

  • This drives the Flow web app with your logged-in browser profile. That may be against Google's terms for your account; you are the one taking that risk. If Flow flags unusual activity (a WAF rejection), the tools stop and tell you: do not retry and do not re-authenticate.

  • Generations spend real credits. Nothing here asks for confirmation on your behalf; if you wire these tools into an autonomous agent, you are wiring it to your wallet.

  • Generated clips carry Google's visible sparkle watermark. Removing it is your decision and your jurisdiction's problem, not something this repo does for you.

Known limits

  • macOS only, one account lane (flow.google.com), one browser (real Chrome with the gflow profile).

  • Chrome cannot run headless here (reCAPTCHA answers a headless browser with a 403), so every call opens a real window and then moves it off the left edge of the screen; macOS keeps a strip of about 40 px visible. Set VIDEO_BROWSER_OFFSCREEN=0 to see the windows. Signing in (gflow auth login) always opens a visible window.

  • clip_edit does not read the live price line before clicking, unlike gen_character: the only guard is the balance read before and after.

  • Flow's Agent mode (the "Agent" chip in the prompt bar) blocks generation while on. The five gflow MCP tools and gen_character turn it off first and back on after (about 19 s, or 35 s when it was on); the CLI and the editor tools (clip_extend, clip_edit) do not, so turn it off with agent_mode before using them.

  • flow_upload is told by Flow's own reply. When that reply is not seen (it happened twice on 2026-10-02 while the image did reach the project, and not again since; the cause is unknown), the tool reads the listing four times, about a minute in all: one new image carrying the file's name is the upload, no new image at all means nothing was uploaded and a second try is safe, and anything else (two of that name, a new image under another title, a file that is no image) sends you to flow_media first. That branch is proven by tests only.

  • Trimming a clip's head or tail inside a scene is not implemented.

  • Deliberately out of scope: collections, media rename, media trash, project zip export, the Tools gallery, Flow's own agent mode beyond an on/off switch, project settings, GIF export, share links and publishing to YouTube.

When Flow changes

Flow changes without notice. uv run video flow survey --project <id> walks Flow's pages for $0, screenshots them, and compares their buttons, menus, options, prices and the selectors this repo relies on with baselines kept in the repo; exit code 1 means something changed. See docs/flow-updates.md.

Testing

uv run ruff check . && uv run ruff format --check . && uv run pytest

1875 tests (collected 2026-10-08), none of which call Flow or spend anything: tests use fixtures and fakes, which is a hard rule here. About 25 of them do render and measure real video, so ffmpeg must be installed, and two of them draw captions, so a unicode font must exist: macOS ships one, on Linux install fonts-dejavu-core or point VIDEO_FONT at a .ttf or .ttc of your own. The live acceptance scripts under scripts/acceptance/ do talk to Flow, are read-only by default, and say in their own output what they spent.

Documentation

File

What is in it

docs/tools.md

Every MCP tool with its price, generated from the running server

docs/flow-updates.md

When Google changes Flow: the $0 survey that finds what changed, and how to update the MCP

README.vi.md

The original Vietnamese README: the full measured record, including traps paid for in credits

docs/mcp-manual-test.md

A by-hand test pass over the tools, with a ready prompt for another agent

CONTRIBUTING.md

How to run the gate and the rules that keep the money safe

License

MIT, see LICENSE.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers