Skip to main content
Glama

gemini-image-mcp

An MCP server that generates and edits images by driving the consumer Gemini web app (gemini.google.com) with your own browser session cookies, via the gemini-webapi library — instead of the paid, metered Gemini API.

Why this exists: the official Gemini API bills per image. If you already have a Gemini web account where image generation works, this lets you use that account instead of a metered API key. The trade-off is described below — read it before using this.

This project is not affiliated with, endorsed by, or supported by Google. "Gemini" is a Google product; this is an independent, unofficial client built on top of the third-party gemini-webapi library.

Disclaimer

Driving the consumer web app with your own session cookies, instead of an official API key, is outside Google's Terms of Service for that product. Any consequence — rate limiting, a challenge, or account action — lands on your Google account, not on this code. This tool doesn't take a position on whether that trade-off is worth it beyond making sure you know it up front. See the License section for the full no-warranty disclaimer.

Related MCP server: nano-banana-mcpv2

Features

  • generate_image and edit_image MCP tools backed by your own Gemini web session — no API key, no per-image billing.

  • list_models to discover which models your account can use.

  • Every generated or edited image accumulates into a single, self-contained, interactive HTML gallery (output/gallery.html) — the primary way to browse your output. Click any image for a detail view with its full prompt, metadata, and copy buttons.

  • Optional GitHub publishing: point it at a repository you own and every new image is also uploaded there, giving you a stable public URL to use in other projects. Off unless you configure it — see Publishing images to GitHub.

  • gemini_image_mcp.core has zero mcp imports, so it can be imported directly by other Python code (e.g. a Telegram bot) without going through the MCP protocol at all.

  • Automatic image-format correction: Gemini doesn't always return the format you'd expect, so saved files are renamed to match their actual content (e.g. .jpg instead of a mislabeled .png).

Requirements

  • Python >= 3.11

  • uv

  • A Gemini web account where image generation already works manually in your browser. Image generation is 18+ and region-limited, and requires Gemini Apps Activity to be turned on for your account. If the web UI itself won't generate an image, this tool can't either — fix that first.

Install / Quickstart

uv sync
copy .env.example .env

Edit .env and paste in GEMINI_1PSID / GEMINI_1PSIDTS (see Getting your cookies below), then run the smoke test:

uv run python scripts/smoke_test.py "a watercolor fox"

The smoke test prints the saved image path(s) and the gallery path on success, or a clean error message (e.g. about missing/expired cookies) on failure.

Getting your cookies

  1. In Chrome, sign in and go to https://gemini.google.com. Manually generate an image there first (e.g. ask it to "generate an image of a fox") and confirm it actually works. If the web UI itself won't generate an image, this tool cannot either — fix that first.

  2. Press F12 to open Chrome DevTools.

  3. Go to the Application tab -> Storage -> Cookies -> https://gemini.google.com.

  4. Find the cookie named __Secure-1PSID. Click it and copy its Value column (a long string). This is your GEMINI_1PSID.

  5. Find the cookie named __Secure-1PSIDTS. Copy its Value the same way. This is your GEMINI_1PSIDTS.

  6. Copy .env.example to .env and paste the two values into GEMINI_1PSID and GEMINI_1PSIDTS.

Instead of pasting cookies, sign in to https://gemini.google.com in a supported browser and leave GEMINI_1PSID / GEMINI_1PSIDTS empty. The server reads both cookies straight from the browser's cookie store (via browser-cookie3) at startup, and again whenever Gemini reports the session as signed out - so a fresh login is picked up without touching .env. The browser doesn't need to be running. Stay signed in there (no private window, don't clear its cookies).

In auto mode the server tries Firefox, LibreWolf, Edge, Chrome, Brave, Chromium, Vivaldi and Opera in that order, and uses the first one whose Gemini login works. On macOS only Firefox and LibreWolf are tried automatically, because reading Chromium-based browsers there triggers a Keychain password prompt. Name the browser explicitly to use it anyway.

Browser

Windows

macOS

Linux

Firefox, LibreWolf

Yes

Yes

Yes

Edge, Brave, Vivaldi, Opera, Chromium

Yes

Yes (Keychain prompt)

Yes

Chrome

No - see below

Yes (Keychain prompt)

Yes

Safari

-

Yes (with Full Disk Access)

-

  • GEMINI_COOKIE_SOURCE - auto (default: .env values if set, else the browsers above, also used as a fallback when the .env values are stale), env (only .env), or one browser: firefox, librewolf, edge, chrome, brave, chromium, vivaldi, opera, safari.

  • GEMINI_BROWSER_COOKIE_FILE - path to a specific profile's cookie database, if you have several profiles (for auto, it applies to Firefox). GEMINI_FIREFOX_COOKIE_FILE still works as the older name.

Run uv run gemini-image-mcp doctor --offline to see which browser was found, or why none could be read.

__Secure-1PSIDTS rotates frequently. gemini-webapi refreshes it in the background while the server is running and persists the refreshed value to the path in GEMINI_COOKIE_PATH (default: a private per-user folder: %LOCALAPPDATA%\gemini-image-mcp\cookies on Windows, ~/Library/Application Support/gemini-image-mcp/cookies on macOS, ~/.local/state/gemini-image-mcp/cookies on Linux), so in the happy path you only paste cookies once. The cache is kept outside output/ on purpose, so sharing or publishing your images never exposes your session. If you paste cookies by hand and find yourself re-pasting often, keeping Firefox or Edge signed in to Gemini and letting the server read them is a more durable workaround.

Chrome on Windows can't be read automatically. Since Chrome 127, Chrome on Windows encrypts its cookies with app-bound encryption, which can only be decrypted with administrator rights, and an MCP server should never run as administrator. If Chrome is your main browser, sign in to Gemini once in Firefox or Edge just for this server, or copy the two values by hand as above.

These cookies are your account

__Secure-1PSID and __Secure-1PSIDTS are equivalent to being logged in as you. Never commit them, paste them into a chat, or share them with anyone. .env is gitignored by default — keep it that way.

Registering with Claude Code

claude mcp add gemini-image-mcp -- uv run --directory "/path/to/gemini-image-generator-mcp" gemini-image-mcp

(On Windows this might look like uv run --directory "C:\Users\you\projects\gemini-image-generator-mcp" gemini-image-mcp.)

This registers the server to run via the gemini-image-mcp console script that uv sync installs into the project's virtual environment (defined in pyproject.toml's [project.scripts]), always executed from the correct project directory regardless of your current working directory.

Equivalent JSON (e.g. for claude_desktop_config.json or .mcp.json):

{
  "mcpServers": {
    "gemini-image-mcp": {
      "command": "uv",
      "args": [
        "run",
        "--directory",
        "/path/to/gemini-image-generator-mcp",
        "gemini-image-mcp"
      ]
    }
  }
}

Tools

Tool

Arguments

Returns

generate_image

prompt: str, model: str | None = None, publish: bool | None = None

Absolute path(s) of the newly saved image(s), the absolute path to output/gallery.html, the image count, the model actually used, and each image's public URL if it was published.

edit_image

prompt: str, image_paths: list[str], model: str | None = None, publish: bool | None = None

Same return shape as generate_image, applied to edits of the given source image(s).

publish_image

image_paths: list[str]

Uploads existing images (absolute paths, images/<file> paths, or gallery ids) to your configured GitHub repo and returns their public URLs.

list_models

(none)

The models (image/chat) available to the signed-in account, as display name + internal model name/id, so you can pick a non-default model for the other two tools.

doctor

(none)

A setup health check, one ok/warn/fail line per item (see Troubleshooting).

None of the tools return base64 image data — the gallery is the intended viewing surface, and every tool result includes its path so you can always click through to it.

Publishing images to GitHub

Optionally, every generated or edited image can also be committed to a GitHub repository of your choice (for example a public my-images repo), so you get a direct link you can drop into websites, READMEs, or other projects:

https://raw.githubusercontent.com/<owner>/<repo>/<branch>/images/65157777b2c94e0f8d1a3c5e7f902468.jpg

Files are named by their gallery id, and commit messages carry only a short id, so your prompts stay private even in a public repo (see GEMINI_GITHUB_INCLUDE_PROMPT below to opt in to prompt-based names). Upload goes through the GitHub REST API, one commit per image, so no local clone is needed. To turn it on, add to .env:

GEMINI_GITHUB_REPO=yourname/my-images
  • Token - GEMINI_GITHUB_TOKEN, else GITHUB_TOKEN, else the GitHub CLI's login (gh auth token). Recommended: create a fine-grained token limited to that one repository with only Contents: read and write, and set it as GEMINI_GITHUB_TOKEN. The gh fallback is convenient but its token usually has full repo access to all your repositories, far more than this server needs.

  • GEMINI_GITHUB_BRANCH - branch to commit to (default: the repo's default branch).

  • GEMINI_GITHUB_PATH - folder inside the repo (default: images).

  • GEMINI_GITHUB_AUTO_PUBLISH - false (default) publishes only when a call passes publish=true or you use the publish_image tool; true publishes every new image.

  • GEMINI_GITHUB_INCLUDE_PROMPT - false (default). Set to true to name files after the prompt (images/a-watercolor-fox-65157777.jpg) and put the prompt in the commit message. Remember that anything in a public repo, including its history, is public.

  • Only images inside output/images/ can be published; any other path is refused.

You can also override per call ("generate ... and publish it"), and publish older images later with publish_image. Published images show a Published badge in the gallery with Copy link / Markdown buttons.

A publishing failure (bad token, network) never loses the image: it's still saved locally and added to the gallery, and the tool result explains what went wrong.

Raw links only work without authentication if the target repository is public. Keep in mind that anything you publish there is visible to everyone.

Using the core library directly

gemini_image_mcp.core is deliberately MCP-free, so it can be imported directly — for example from a Telegram bot:

from gemini_image_mcp.config import get_settings
from gemini_image_mcp import core

async def handle_image_request(prompt: str) -> None:
    settings = get_settings()
    records = await core.generate_images(prompt, settings=settings)
    for record in records:
        absolute_path = settings.output_dir / record.image_path
        # e.g. send `absolute_path` back to the Telegram chat

Troubleshooting

Start with the built-in health check:

uv run gemini-image-mcp doctor

It checks, in order:

Check

What it looks at

Output directory

GEMINI_OUTPUT_DIR exists and is writable.

Cookie cache

The cache is outside the output folder (so sharing images never shares your session).

Cookies

GEMINI_1PSID / GEMINI_1PSIDTS are set, or a supported browser has a Gemini login (and if not, why each browser couldn't be read).

Gemini sign-in

The cookies actually work, and how many models the account can use.

Gallery

How many images the manifest holds, and whether a corrupt one was set aside.

GitHub publishing

Where the token comes from, that it can push to the repo, and whether the repo is public.

Each line is [ OK ], [WARN], [FAIL] or [SKIP] with a hint on how to fix it, and the command exits with status 1 if anything failed. Add --offline to skip the calls to Gemini and GitHub. Cookie and token values are never printed. You can also just ask Claude to "run the doctor", which calls the doctor tool.

  • Auth / cookie expiry — generate_image, edit_image, and list_models all raise a clean error naming the exact problem when GEMINI_1PSID/GEMINI_1PSIDTS are missing or have expired. Re-copy both values from Chrome DevTools (see above) and update .env (or the running process's environment).

  • "No images returned" for a prompt that seems reasonable — this is almost always Gemini refusing the request (safety filter, region restriction, age-gating) rather than a bug. The error message includes the model's own text response, which usually explains the refusal directly.

  • Usage limits / temporarily blocked — Gemini's own rate limiting on the web app. Wait before retrying; there is no bypass.

  • GitHub publish failed - the tool result includes GitHub's message. 401/403 means the token is missing, expired, or lacks Contents write access to the repo; 404 means GEMINI_GITHUB_REPO is wrong or the token can't see that repository.

  • Where things live on disk — generated/edited images: output/images/; the gallery: output/gallery.html; the manifest backing the gallery: output/manifest.json; the persisted cookie cache: wherever GEMINI_COOKIE_PATH points (default: a per-user folder outside the project, see Cookie lifetime; an old output/.cookies cache is moved there automatically). All of output/ is gitignored.

Known limitations

  • Unofficial and fragile by nature. This drives a consumer web app that Google can change at any time without notice; a Google-side change can break this project until it's updated.

  • Region/age gated. Image generation availability depends on your Google account's region and age, not on this project.

  • Output format is whatever Gemini returns. Currently that's typically JPEG, regardless of the extension you might expect — this project sniffs the real format and corrects the file extension accordingly rather than trusting the request.

  • The manifest grows unbounded. output/manifest.json accumulates every record ever generated; there's no pruning or rotation.

  • Not a daemon. The MCP server's lifetime is tied to the Claude session that launched it — it's not designed to run as a standalone, long-lived background service.

Contributing

See CONTRIBUTING.md.

Security

See SECURITY.md for the credential-handling model and how to report a vulnerability.

License

MIT — see the disclaimer above for the ToS and warranty caveats specific to this project; the MIT license text itself covers the standard no-warranty terms.

Available Tools

3 tools
edit_imageA

Edit one or more existing local image files using a text instruction.

image_paths must be paths to existing image files on disk (e.g. a photo or a previously generated image) describing what to edit; prompt describes the desired change. The edited image(s) Gemini returns are saved to disk and appended to the cumulative HTML gallery; this tool returns the absolute paths of the new images plus the gallery path so the result can be viewed.

Parameters

prompt: str Instructions describing the desired edit. image_paths: list[str] Paths to existing local image files to edit. model: str | None, optional Model name/alias/id to use (see list_models). Defaults to the server's configured default model, or the account's own default if unset.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelNo
promptYes
image_pathsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It explicitly states that edited images are saved to disk and appended to an HTML gallery, and that it returns absolute paths and the gallery path. This covers side effects and return behavior. It does not mention permissions or whether original files are overwritten, but the mention of 'new images' implies non-destructive behavior. Overall, it provides meaningful behavioral context beyond a bare operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is structured with a clear opening sentence, a behavioral summary, and a parameter list. It is slightly verbose but every sentence adds value. The key behavioral facts are front-loaded, and the parameter details are organized for quick reference. It could be tightened slightly, but it is appropriately sized for a tool with three parameters and side effects.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (3 params, side effects, output schema), the description covers the essential context: it explains input requirements, the editing process, the return values, and the model selection mechanism. It does not explicitly address file overwrite behavior or permission requirements, but it does state that new images are returned, implying safe handling. The description is sufficient for an agent to call the tool correctly without further lookup.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must fully compensate. It does so by explaining all three parameters: prompt (instructions), image_paths (existing local files), and model (with defaults and reference to list_models). Each parameter is given a clear semantic meaning that goes well beyond the schema's type-only definitions. This is exemplary parameter documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('edit'), a clear resource ('existing local image files'), and the method ('using a text instruction'). It distinguishes from siblings by explicitly requiring existing files, which sets it apart from generate_image and list_models. The purpose is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage by requiring 'paths to existing image files' and noting the edited images are saved, but it does not explicitly name alternative tools or state when not to use it. The reference to list_models for the model parameter gives some guidance, but no direct comparison to generate_image is provided. The 'must be paths to existing' hints at a prerequisite but leaves the alternative selection to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

generate_imageA

Generate one or more new images from a text prompt using the Gemini web app.

The prompt should describe the desired image in as much visual detail as helpful (subject, style, composition, lighting, etc.) - it is sent to Gemini as an image generation request. Newly generated images are saved to disk and appended to the cumulative HTML gallery; this tool returns the absolute paths of the new images plus the gallery path so the result can be viewed.

Parameters

prompt: str A description of the image to generate. model: str | None, optional Model name/alias/id to use (see list_models). Defaults to the server's configured default model, or the account's own default if unset.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelNo
promptYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure and does so thoroughly. It states that the prompt is sent to Gemini as an image generation request, that generated images are saved to disk and appended to a cumulative HTML gallery, and that the tool returns absolute paths plus the gallery path.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and front-loaded with the core purpose, followed by important side-effect and return information, then parameter details. Every sentence adds meaningful value without unnecessary padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the essential behavior, side effects, return information, and both parameters. It also points to list_models for model selection, making the tool self-contained and complete for invocation despite the lack of annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate for both parameters, and it does. The prompt parameter is explained with specific visual-detail guidance, and the model parameter is documented with defaults and a pointer to list_models.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: generate one or more new images from a text prompt. It clearly distinguishes this from edit_image by emphasizing new image generation from a text prompt, and from list_models by targeting actual image creation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when to use the tool: when a new image should be generated from a text prompt and saved/viewable via the gallery. It does not explicitly name edit_image as the alternative for modifying existing images, so it stops short of full when-to-use vs alternatives guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_modelsA

List the Gemini models (image/chat) available to the currently signed-in account.

Returns each model's display name and internal model name/id, one per line. Use a model_name value from this list as the model argument to generate_image or edit_image to override the default model.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full disclosure burdencluster. It specifies account scoping ('available to the currently signed-in account'), the return contents ('display name and internal model name/id'), and the output format ('one per line'). It could add details about ordering or empty results, but this is a transparent read-only listing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is only two sentences, front-loaded with the core purpose, and each sentence earns its place. The first defines the tool; the second details the return format and how to use the result with sibling tools. No unnecessary filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter read-only list tool with an output schema, the description is effectively complete. It covers account scoping, the information returned, output formatting, and the integration path to `generate_image` and `edit_image`. Nothing an agent would need to invoke this tool correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has zero parameters and schema coverage is 100%, so there is nothing for the description to clarify about parameters. The baseline for no params is 4; the description appropriately focuses on output semantics and downstream usage instead.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description begins with 'List the Gemini models (image/chat) available to the currently signed-in account', giving a specific verb, resource, and scope. It also ties the tool to its siblings by stating that its output values are meant for `generate_image` or `edit_image`, differentiating its listing role from those generation tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description states a clear usage context: use the returned `model_name` as the `model` argument for `generate_image` or `edit_image` to override the default. It does not explicitly state when not to use the tool, but with no competing list-style siblings, the guidance is sufficient.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.1.0
    • First observededit_image
    • First observedgenerate_image
    • First observedlist_models

TDQS

A4.5/5.0

Scored across 3 tools

Disambiguation5/5

Each tool serves a clearly distinct purpose: generate new images, edit existing images, and list available models. There is no meaningful overlap between these operations, so an agent can reliably select the right tool.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case: generate_image, list_models, edit_image. This creates a predictable and readable naming convention across the entire set.

Tool Count5/5

Three tools is a well-scoped count for an image generation and editing server. Each tool covers a necessary core function without redundancy or unnecessary bloat.

Completeness4/5

The server covers the core image workflow: generating, editing, and choosing models. Minor gaps exist, such as no explicit gallery management or image deletion, but these are not essential to the stated purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers