gemini-image-mcp-http
by soloniki007
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: там сервер работает
локально на вашей машине и никуда наружу не торчит.
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues