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

Удалённый MCP-сервер (Streamable HTTP): генерация и редактирование изображений
через **Google Gemini 3.1 Flash Image** («Nano Banana 2»), который можно подключить
к **Claude.ai в браузере** (а также Claude Desktop/Cowork/мобильным приложениям)
как Custom Connector.

Проверено локально: сервер поднимается, отвечает на MCP `initialize`/`tools/list`/`tools/call`,
неверный секрет в URL получает 404. Единственное, что нельзя было протестировать здесь —
сам вызов Gemini API (в песочнице нет доступа к `generativelanguage.googleapis.com`),
но запрос к нему формируется по официальной REST-схеме Gemini.

## Как это устроено

- Один HTTP-эндпоинт: `POST/GET /mcp/<MCP_SHARED_SECRET>`
- `<MCP_SHARED_SECRET>` — длинная случайная строка, которую вы сами зададите.
  Она одновременно служит и частью URL, и защитой: без неё запрос получает 404.
  **Никому не показывайте итоговый URL целиком.**
- Внутри — два инструмента: `generate_image` и `edit_image`, оба обращаются
  к Gemini REST API вашим ключом (ключ хранится только на сервере, Claude его не видит).
- Изображение возвращается сразу в чат (как картинка), без сохранения на диск —
  на большинстве хостингов файловая система эфемерна, так что это осознанный выбор.

⚠️ **Про ключ, который вы уже присылали в чат:** это больше похоже не на обычный
Gemini API-ключ (те выглядят как `AIzaSy...`), а на другой тип токена Google.
Перед деплоем зайдите на https://aistudio.google.com/apikey, создайте (или перевыпустите)
именно API-ключ и используйте его — не токен из чата.

---

## Шаг 1. Сгенерируйте секрет

```bash
openssl rand -hex 24
```

Сохраните результат — это будет и `MCP_SHARED_SECRET`, и часть URL коннектора.

## Шаг 2. Задеплойте сервер

Ниже — вариант через **Render.com** (проще всего для одного файла, есть бесплатный план).
Подойдут и Railway/Fly.io/любой VPS — везде логика одна: Node 18+, переменные окружения,
публичный HTTPS-домен. В архиве есть `Dockerfile`, так что подойдёт и любой Docker-хостинг.

### Render.com (без своего сервера)

1. Зайдите на https://render.com → New → Web Service.
2. Вариант «Deploy an existing image / upload code» — загрузите содержимое этой папки
   в свой GitHub-репозиторий (пустой репозиторий, залить файлы можно и через веб-интерфейс
   GitHub) и подключите его к Render.
3. Runtime: **Node**. Build command: `npm install`. Start command: `npm start`.
4. В разделе **Environment** добавьте:
   - `GEMINI_API_KEY` = ваш настоящий ключ из AI Studio
   - `MCP_SHARED_SECRET` = строка из шага 1
   - (необязательно) `GEMINI_IMAGE_MODEL` = `gemini-3.1-flash-image`
5. Deploy. После сборки Render даст домен вида `https://ваш-сервис.onrender.com`.

### Через Docker (Fly.io / Railway / свой VPS)

```bash
docker build -t gemini-image-mcp-http .
docker run -p 3000:3000 \
  -e GEMINI_API_KEY=ваш-ключ \
  -e MCP_SHARED_SECRET=строка-из-шага-1 \
  gemini-image-mcp-http
```

Дальше — по инструкции конкретного хостинга, как опубликовать контейнер на HTTPS-домене
(на Fly.io — `fly launch` + `fly deploy`, на Railway — просто подключить репозиторий).

## Шаг 3. Проверьте, что сервер отвечает

```bash
curl https://ваш-домен/           # health-check, должен вернуть "OK"
```

## Шаг 4. Добавьте коннектор в Claude.ai

1. В Claude.ai: **Settings → Connectors** (или «Настроить» → «Коннекторы»).
2. Нажмите «+» → **Add custom connector**.
3. В поле URL укажите:
   ```
   https://ваш-домен/mcp/MCP_SHARED_SECRET_СЮДА
   ```
   (полный секретный URL, без пробелов)
4. Advanced settings можно оставить пустыми — авторизация уже встроена в сам URL.
5. Нажмите «Add», затем включите коннектор для нужного чата через «+» → Connectors.

Готово — в чате можно будет попросить: «сгенерируй через Gemini картинку рыжего кота
на подоконнике» или «отредактируй это изображение: сделай фон синим».

---

## Переменные окружения

| Переменная              | Обязательна | По умолчанию              | Описание                                     |
|--------------------------|:-----------:|----------------------------|-----------------------------------------------|
| `GEMINI_API_KEY`         | да          | —                           | Ключ Gemini API из Google AI Studio            |
| `MCP_SHARED_SECRET`      | да          | —                           | Секрет в URL, защищающий эндпоинт от чужих     |
| `GEMINI_IMAGE_MODEL`     | нет         | `gemini-3.1-flash-image`   | Имя модели                                     |
| `PORT`                   | нет         | `3000`                      | Обычно задаётся хостингом автоматически        |
| `S3_ENDPOINT`            | нет         | —                           | Эндпоинт S3-совместимого хранилища (см. ниже)  |
| `S3_BUCKET`              | нет         | —                           | Имя бакета                                     |
| `S3_ACCESS_KEY_ID`       | нет         | —                           | Access key                                     |
| `S3_SECRET_ACCESS_KEY`   | нет         | —                           | Secret key                                     |
| `S3_REGION`              | нет         | `auto`                      | Регион (для R2 оставить `auto`)                |
| `S3_PUBLIC_URL`          | нет         | собирается из endpoint+bucket | Публичный базовый URL для отдачи файлов     |
| `S3_FORCE_PATH_STYLE`    | нет         | `true`                      | Path-style URL (нужно для R2/MinIO)            |
| `PUBLIC_BASE_URL`        | нет         | определяется автоматически | Базовый URL сервиса — для ссылок локального фолбэка |

## Постоянное хранение изображений (важно!)

Каждый вызов `generate_image`/`edit_image` **всегда сохраняет файл целиком**, независимо
от его веса и разрешения, и возвращает в ответе текстовую ссылку `Image URL: ...`.
Инлайн-превью в самом чате при этом появляется только если файл укладывается в
безопасный лимит показа (~900 КБ) — но ссылка работает всегда, для файлов любого размера.

Есть два режима:

1. **Без настройки (по умолчанию).** Файлы хранятся в памяти самого сервиса и
   отдаются по адресу `/images/<id>.<ext>`. Просто и без доп. шагов, но:
   - ссылки живут максимум 6 часов;
   - на бесплатном тарифе Render контейнер засыпает при простое и теряет память
     при перезапуске — старые ссылки после этого перестают открываться.

2. **С постоянным хранилищем (рекомендуется) — Cloudflare R2.**
   1. Зайдите в Cloudflare Dashboard → R2 → Create bucket. Название, например `gemini-images`.
   2. В настройках бакета включите публичный доступ (Public Access → Allow Access),
      скопируйте выданный публичный URL (`https://pub-xxxxxxxx.r2.dev`) — это и есть `S3_PUBLIC_URL`.
   3. R2 → Manage API Tokens → Create API Token → права Object Read & Write на этот бакет.
      Скопируйте Access Key ID, Secret Access Key и Account ID.
   4. В переменных окружения хостинга (Render → ваш сервис → Environment) добавьте:
      ```
      S3_ENDPOINT=https://<ACCOUNT_ID>.r2.cloudflarestorage.com
      S3_BUCKET=gemini-images
      S3_ACCESS_KEY_ID=<access key>
      S3_SECRET_ACCESS_KEY=<secret key>
      S3_PUBLIC_URL=https://pub-xxxxxxxx.r2.dev
      ```
   5. Redeploy. В логах при старте должно появиться:
      `Постоянное хранилище: S3-совместимое (https://<ACCOUNT_ID>.r2.cloudflarestorage.com).`
   6. Готово — теперь ссылки на изображения не пропадают ни при засыпании сервиса,
      ни при редеплое, и работают для файлов любого веса и разрешения (1K/2K/4K).

   Вместо R2 подойдёт любое S3-совместимое хранилище (AWS S3, Backblaze B2, MinIO) —
   просто укажите соответствующие `S3_ENDPOINT`/регион.

## Безопасность и стоимость

- Секрет в URL — единственная защита. Держите ссылку приватной, не публикуйте её,
  не коммитьте в открытый репозиторий вместе со значением переменных окружения.
- Каждый вызов `generate_image`/`edit_image` тратит квоту/деньги вашего Gemini-ключа —
  теоретически любой, кто узнает секретный URL, сможет им пользоваться. Если нужна
  более серьёзная защита (OAuth, ротация секрета, лимиты запросов) — можно усилить
  отдельно, дайте знать.
- Хотите вообще не выставлять свой Gemini-ключ в интернет — тогда лучше вариант
  из первого архива (`gemini-image-mcp.zip`) под Claude Desktop: там сервер работает
  локально на вашей машине и никуда наружу не торчит.

Maintenance

ActivityStale
ResponsivenessNo issues