Skip to main content
Glama
README.md
# gemini-image-mcp

A standalone, user-scoped [Model Context Protocol](https://modelcontextprotocol.io) server
that lets Claude Code **generate and edit images** with Google's Gemini image models
(**Nano Banana** / **Nano Banana Pro**) and **Imagen 4** — running on **Vertex AI** with
**Application Default Credentials (ADC)**. No API key, no JSON key file.

- **Default model:** `nano-banana` = Gemini 2.5 Flash Image (GA).
- **Also exposed:** `nano-banana-pro` (Gemini 3 Pro Image, preview) and the `imagen-4*` family.
- **Transport:** stdio (local) or streamable-http (remote), via the official Python MCP SDK (FastMCP).
- **Auth:** Vertex AI + ADC only. You bring your own GCP project.

## Quick start (one command, no clone)

`uvx` fetches and runs the server straight from GitHub — nothing to clone or install.
Register it with Claude Code at user scope in a single command:

```bash
claude mcp add gemini-image -s user \
  -e GOOGLE_CLOUD_PROJECT=your-gcp-project-id \
  -- uvx --from git+https://github.com/someshwarpatil/gemini-image-mcp.git gemini-image-mcp
```

Then authenticate once with ADC and restart Claude Code:

```bash
gcloud auth application-default login
```

**Prereqs:** Python 3.12 + [uv](https://docs.astral.sh/uv/), the
[gcloud CLI](https://cloud.google.com/sdk/docs/install), and a GCP project with the
**Vertex AI API enabled**. Verify with `claude mcp list` / `claude mcp get gemini-image`.

## How it works

The server runs as its own process (Claude Code spawns it over stdio). Because it is a
separate process, it **cannot see the client's per-session scratchpad** — so every tool takes
an explicit `output_dir`. The full-resolution PNG is **always saved to disk** and its
**absolute path is always returned**. A small downscaled preview image is returned **only**
when `return_image=True`, to protect the client's token budget (a full-res MCP image can cost
~15-25k tokens).

## Setup from a clone (for development)

```bash
git clone https://github.com/someshwarpatil/gemini-image-mcp.git
cd gemini-image-mcp

# One command: sync deps + check ADC + register with Claude Code.
GOOGLE_CLOUD_PROJECT=your-gcp-project-id ./scripts/setup.sh
```

`scripts/setup.sh` runs `uv sync`, checks ADC, and registers the server at user scope
(idempotent — safe to re-run). Or do it manually:

```bash
uv sync
gcloud auth application-default login          # one-time ADC; no API key, no JSON key file
export GOOGLE_CLOUD_PROJECT=your-gcp-project-id
```

Prefer a file over shell exports? Copy `.env.example` → `.env` and fill in your values
(`.env` is gitignored).

## Environment

| Variable | Default | Purpose |
|---|---|---|
| `GOOGLE_CLOUD_PROJECT` | _(auto-detected from ADC / gcloud)_ | GCP project serving the Vertex image models. |
| `GOOGLE_CLOUD_LOCATION` | `global` | Vertex location for the **Gemini** models. Gemini image models are **global-only** on Vertex — leave as `global`. |
| `GEMINI_IMAGE_IMAGEN_LOCATION` | `us-central1` | Vertex location for the **Imagen** models (Imagen is **not** served on `global`). |
| `GEMINI_IMAGE_OUTPUT_DIR` | _(unset)_ | Default dir for saved PNGs when a call omits `output_dir`. Falls back to the server CWD. |
| `GEMINI_IMAGE_LOG_LEVEL` | `INFO` | stderr log level for the server (`DEBUG`/`INFO`/`WARNING`/`ERROR`). |
| `GEMINI_IMAGE_RETURN_MODE` | `file` | `file` (save + path, local) · `inline` (image bytes) · `gcs` (upload + signed URL — best for the Claude apps). |
| `GEMINI_IMAGE_GCS_BUCKET` | _(unset)_ | Private bucket for `gcs` mode. Objects are v4-signed (not public); pair with a lifecycle delete rule. |
| `GEMINI_IMAGE_GCS_TTL_DAYS` | `7` | Signed-URL lifetime (days) for `gcs` mode. |

`output_dir` resolution order: **explicit tool argument → `GEMINI_IMAGE_OUTPUT_DIR` → process CWD**.

## Models

Pass the friendly **alias** — never the raw model id.

| Alias | Vertex model id | Family | Edit? | Location | Notes |
|---|---|---|---|---|---|
| `nano-banana` | `gemini-2.5-flash-image` | gemini | yes | `global` | **Default.** GA. text→image + edit/fusion. |
| `nano-banana-pro` | `gemini-3-pro-image-preview` | gemini | yes | `global` | Preview on Vertex; up to 14 ref images, up to 4K. May 404 if the project isn't gated. |
| `imagen-4` | `imagen-4.0-generate-001` | imagen | no | `us-central1` | GA standard. text→image only. Deprecation risk (~2026-06-30). |
| `imagen-4-fast` | `imagen-4.0-fast-generate-001` | imagen | no | `us-central1` | GA fast/low-cost. text→image only. |
| `imagen-4-ultra` | `imagen-4.0-ultra-generate-001` | imagen | no | `us-central1` | GA highest quality. `n=1` only. |

Gemini aspect ratios: `1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9`.
Imagen aspect ratios: `1:1, 3:4, 4:3, 9:16, 16:9`.

> The Gemini models are the durable path. The `imagen-4*` aliases are best-effort: Imagen 4
> had an announced EOL around 2026-06-30 and may fail at runtime — the underlying Vertex
> error is surfaced verbatim.

## Tools

- **`generate_image(prompt, model="nano-banana", aspect_ratio="1:1", n=1, output_dir=None, return_image=True)`**
  Text → image. For Gemini, `n>1` loops one image per call; Imagen uses native batching
  (`imagen-4-ultra` is capped at 1). `n` is capped at 8 per call — each image is a separately
  billed generation.
- **`edit_image(image_paths, prompt, model="nano-banana", output_dir=None, return_image=True)`**
  Image(s) + instruction → image. One input = edit, two or more = fusion. **Gemini aliases
  only** — `imagen-4*` is rejected with a clear error.
- **`list_models()`** — the alias table + notes (cheap, offline).

## Register with Claude Code (from a clone)

The [Quick start](#quick-start-one-command-no-clone) uvx command needs no clone. If you've
cloned the repo instead, use the tracked script — it derives the repo path automatically and
reads your project from the environment. `~/.claude.json` is **not** committed.

```bash
GOOGLE_CLOUD_PROJECT=your-gcp-project-id bash scripts/register.sh
```

Equivalent raw command:

```bash
claude mcp add gemini-image \
  -e GOOGLE_CLOUD_PROJECT=your-gcp-project-id \
  -e GOOGLE_CLOUD_LOCATION=global \
  --scope user \
  -- uv --directory /path/to/gemini-image-mcp run gemini-image-mcp
```

`--scope user` is placed **after** the `-e` flags and immediately **before** the name (the
CLI rejects a name right after `-e`). `-t stdio` is implied by the `-- <command>` form.
Verify with `claude mcp list` and `claude mcp get gemini-image`.

## Remote deployment (Cloud Run / AWS / your VM)

Run the same server over **streamable-http** so the Claude apps (web / desktop / **mobile**)
can use it as a custom connector and generate images directly in chat. Because a remote client
can't read the server's disk, set the return mode to send the image back: **`gcs`** uploads
each image to a private bucket and returns a **signed URL** (the reliable choice — the Claude
apps don't render inline MCP image blocks), or `inline` returns the raw bytes for clients that
do. The Cloud Run deploy below uses `gcs`.

**Auth reality:** claude.ai custom connectors send no static bearer token and must reach a
public URL. So the deployment is **public**, guarded by a **secret path**: the MCP endpoint
lives at `/<secret>/mcp` and the whole URL is the credential. Keep it secret; rotate it (new
secret + redeploy) if it leaks. The service scales to zero and caps max-instances to bound
cost. For stronger auth, front it with OAuth 2.1 or an API gateway.

### Any container host (Docker)

```bash
docker build -t gemini-image-mcp .
docker run -p 8080:8080 \
  -e GOOGLE_CLOUD_PROJECT=your-gcp-project-id \
  -e GEMINI_IMAGE_RETURN_MODE=inline \
  -e MCP_PATH_SECRET="$(openssl rand -hex 24)" \
  gemini-image-mcp
# endpoint: http://localhost:8080/<secret>/mcp
```

On AWS / your own VM, front it with TLS (connectors require `https`) via your load balancer or
reverse proxy, and supply ADC through the platform's workload identity or a service account —
never a committed key file.

### Google Cloud Run (scripted)

```bash
GOOGLE_CLOUD_PROJECT=your-gcp-project-id ./scripts/deploy_cloudrun.sh
```

The script enables the required APIs, mints a secret path token in Secret Manager, grants the
Cloud Run runtime service account `roles/aiplatform.user` (Vertex via ADC — no key files) plus
secret access, builds from source, and deploys **public + scale-to-zero + max 2 instances**.
It prints the **connector URL** (`https://<service>/<secret>/mcp`). On Cloud Run, ADC is the
service account automatically.

### Add it as a Claude connector

1. claude.ai (or the Claude desktop app) → **Settings → Connectors → Add custom connector**.
2. Paste the **connector URL** (`https://<service>/<secret>/mcp`); leave auth as none.
3. **Add**, then in a chat ask Claude to *"generate an image of …"* — it calls `generate_image`
   and returns a viewable signed-URL link to the picture. Works on **web, desktop, and mobile**.

### Verify a deployment

```bash
uv run python scripts/smoke_remote.py "https://<service>/<secret>/mcp"                         # list tools
uv run python scripts/smoke_remote.py "https://<service>/<secret>/mcp" --generate "a red panda"  # one image
```

## Notes & caveats

- **SynthID watermark:** all Gemini image output carries an invisible
  [SynthID](https://deepmind.google/technologies/synthid/) watermark. This is not optional.
- **Data residency:** `global` does **not** satisfy data-residency requirements and has
  separate quotas from regional endpoints. Fine for most personal/dev use.
- **Previews may not render inline** in every Claude Code build and can be token-expensive —
  which is exactly why the full-res file is always on disk and the path is always returned.
- **stdio vs remote:** the stdio server (Quick start) targets **Claude Code** (terminal + IDE)
  and, via its own config, the Claude desktop app. For the **Claude apps (web/desktop/mobile)**
  and generating images in chat, deploy the HTTP server — see
  [Remote deployment](#remote-deployment-cloud-run--aws--your-vm).

## License

[MIT](LICENSE).

TDQS

A4.4/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: edit_image handles editing/fusion, generate_image handles generation from text, and list_models provides model information. No overlap or ambiguity.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern (edit_image, generate_image, list_models) using snake_case, making the set predictable and readable.

Tool Count4/5

With only 3 tools, the set is slightly underpopulated but reasonable for a focused image generation/editing server. The scope is narrow enough that each tool earns its place.

Completeness4/5

Core operations (generate, edit/fuse, list models) are covered. Minor gaps like delete or get metadata exist, but the surface is functional for the primary use cases.

Maintenance

ActivityInactive
ResponsivenessNo issues