Skip to main content
Glama
README.md
# google-flow-mcp

MCP server that generates **images and video on [Google Flow](https://labs.google/flow)**
through browser automation, so you can use your own **Google AI Pro** subscription
instead of paying per-credit services. Ships with a Claude Code skill.

Validated end-to-end: images (Nano Banana / Imagen) and video (Veo 3.1 / Omni Flash)
are generated in a real Flow project and downloaded to disk.

> Adapted and hardened for the current agent-first Flow UI (and Windows) from
> [TMSSS05/google-flow-browser-mcp](https://github.com/TMSSS05/google-flow-browser-mcp).
>
> This repository is a fork of
> [GabrielGargiuloDev/google-flow-mcp](https://github.com/GabrielGargiuloDev/google-flow-mcp)
> (MIT, see `LICENSE`), maintained here because upstream stopped working when Google
> moved Flow to `flow.google.com` in 2026-09. See [Fork changes](#fork-changes).

## flow_generate — the agent-free path

Flow's prompt bar has an **Agent** chip. Pressed, a language model reads the prompt,
rewrites it and picks the parameters; ratio and model are account-wide defaults and no price
is shown anywhere before the spend. Released, the bar exposes its own control panel — mode,
ratio, model, resolution, duration, count — and prints the exact credit cost of the next
click.

`flow_generate` drives the released state and is the preferred tool. `flow_generate_image`
and `flow_generate_video` remain for the agent path.

```jsonc
// Costs nothing: configures, reads the price off the page, returns.
{ "prompt": "a red bicycle against a yellow brick wall",
  "mode": "image", "ratio": "9:16", "model": "Nano Banana Pro", "count": "x1" }
// -> { "credits_required": 0, "configured": "Nano Banana Pro · crop_9_16 · x1", ... }

// Same call plus auto_confirm submits that exact configuration.
{ "...": "...", "auto_confirm": true }
```

What it buys:

- **The price before the spend.** Read from the panel, so `auto_confirm: false` is a real
  quote and asking never submits. Images are 0 credits; a 720p/10s/x1 video is 15.
- **Parameters that are per call and verified.** Every toggle carries `aria-checked` and is
  read back after clicking, so a parameter that did not take throws instead of being
  reported as applied.
- **The prompt reaches the model verbatim** — nothing rewrites it, and the imperative
  wrapper the agent path needs is gone.

Three defects found while building it, all of which also affect the agent path:

- `createNewProject` ran its "did Flow ask for a project name?" step unconditionally. Inside
  a project the only `[contenteditable]` is the **prompt box**, and its confirm list included
  `[type="submit"]` — the generate button. So every new project silently generated an extra
  image captioned with the project name. Free for images; **15 credits a call for video.**
- Taking the first media that appears after submitting returned a valid, correctly sized,
  entirely unrelated image — the spurious generation above landed first. The scan now waits
  for the set to stop growing.
- The same asset is served at several signed URLs, so comparing whole URLs downloaded one
  image twice. Identity is now the media id (`mediaId` in `src/utils/media-urls.js`).

Each downloaded file is reported with the title Flow gave its tile, which is what says
whether the output answered the prompt.

## Fork changes

Upstream was written against `labs.google/fx/tools/flow` and no longer runs: Google moved
Flow to its own domain and changed how media is served. Every fix below was measured against
the live app, not inferred.

| # | Broken upstream | Fix |
|---|---|---|
| 1 | `logger.info` wrote to **stdout**, corrupting the MCP JSON-RPC channel | log to stderr |
| 2 | `labs.google/fx/tools/flow` now redirects to `flow.google.com` | `flowUrl` config + host checks accept both |
| 3 | Download endpoint `labs.google/fx/api/trpc/media.getMediaUrlRedirect` is **gone** (404 / CORS) | fetch the media URL directly on the session cookie |
| 4 | Media URLs no longer carry a uuid | `src/utils/media-urls.js` matches `flow-content.google/` (fresh generations) and `flow.google.com/asb/` (thumbnails) |
| 5 | `isVisible()` does not wait, so a late-rendering Angular button read as absent | `waitFor({ state: 'visible' })` |
| 6 | Aspect ratio was accepted as an argument and silently ignored — a 9:16 request returned 1024x1024 | applied in the Settings panel, and the result reports whether it landed |

The result payload also reported `ratio`, `model_used` and `credits_consumed` as claims rather
than measurements. They now say what actually happened, including "unknown" where the UI
exposes no number.

**Locale:** set `flowUrl` to `https://flow.google.com/?hl=en`. Without `hl=en` the UI renders
in the account's language and every English selector misses. Upstream's French/Italian
selectors are unnecessary with the override.

## What it does

Playwright connects over the Chrome DevTools Protocol to a dedicated Chrome that is
logged into your Google account. It drives Flow's agent to generate media and
downloads the result through the authenticated session. **No API keys, no password
handling** — it uses your existing browser session.

Tools (17): `flow_connect`, `flow_status`, `flow_account_check`, `flow_discover_ui`,
`flow_generate_image`, `flow_generate_video`, `flow_download_latest`, character/scene
tools, `flow_use_grid_architect`, `flow_screenshot`, `flow_queue_status`, …

## ⚠️ Terms of Service

This is **unofficial browser automation**. There is no official Google API for Flow.
The launcher starts Chrome directly so `navigator.webdriver` is false, which is an
explicit anti-bot measure. Automating Google properties can violate Google's Terms of
Service and may put your account at risk. **Use at your own risk, on your own account.**

## Requirements

- Node.js ≥ 18
- Google Chrome (Chrome 149+ needs Playwright ≥ 1.61.1, already pinned)
- A Google account with access to Flow (Google AI Pro recommended)

## Setup

```bash
npm install
cp config/flow.config.example.json config/flow.config.json
# edit config/flow.config.json → set expectedAccount and chromeUserDataDir
```

Start the dedicated Chrome (idempotent — launches only if needed):

```powershell
powershell -File scripts/ensure-flow-chrome.ps1
```

First run: in that Chrome window, sign in to your Google account **and** click
**"Sign in to Flow"** on labs.google (Flow uses a separate sign-in). The session is
saved in the dedicated profile and reused.

Register the server with your MCP client (Claude Code, etc.):

```json
{
  "mcpServers": {
    "google-flow": { "type": "stdio", "command": "node", "args": ["<path>/src/index.js"] }
  }
}
```

Restart the client afterwards (the server loads into memory at startup).

## Notes that matter

- **Images are effectively free** against the monthly Flow credit pool; **video
  consumes credits** (Veo 3.1 Lite ~10, Fast ~20, Quality ~100; Omni Flash ~15-30 of
  ~1000/month). Video shows a credit-confirmation dialog which the server approves.
- **Model/duration must be a valid combo** or Flow's agent asks for clarification and
  nothing generates (e.g. Veo 3.1 Lite is 8s-only on the Pro plan; Omni Flash 4-10s).
- Flow is **agent-first**: prompts are wrapped imperatively so the agent generates
  directly instead of asking questions.
- The UI language follows your Google account; navigation selectors cover IT/FR/EN.

## Claude Code skill

`skill/SKILL.md` is a ready-to-use skill: drop it in `~/.claude/skills/google-flow-generate/`
and Claude will pick the right tool, handle Chrome startup and fallbacks automatically.

## License

MIT — see [LICENSE](./LICENSE).