Skip to main content
Glama
wanjau2

Immich MCP Server

by wanjau2

Immich MCP Server

Предоставляет доступ к вашей локальной библиотеке Immich для ChatGPT (и любого другого MCP-клиента) через Streamable HTTP, чтобы вы могли задавать вопросы типа «найди фотографии с визита на площадку в Кигали в марте» и получать реальные ответы с вашего собственного NAS.

ChatGPT  ──HTTPS──▶  Cloudflare Tunnel  ──▶  immich_mcp:8080  ──▶  immich_server:2283
          bearer token                        MCP → REST            x-api-key

Пользовательские коннекторы ChatGPT принимают только удалённый HTTPS-эндпоинт — варианта stdio или localhost нет. Поэтому сервер должен быть доступен из интернета, отсюда туннель, и он должен защищать себя, отсюда bearer-токен.


Содержание


Related MCP server: immich-photo-manager

Инструменты

Инструмент

Назначение

search

CLIP-семантический поиск по содержимому изображений

fetch

Полные EXIF-данные для одного объекта по UUID

search_by_metadata

Фильтрация по дате, месту, камере, человеку, избранному

list_albums

Все альбомы с количеством

get_album

Детали и содержимое одного альбома

list_people

Распознанные лица с ID для фильтрации

library_stats

Количество фото/видео и дисковое пространство

server_info

Версия Immich и включённые возможности

create_share_link

Публичная ссылка на конкретные объекты — по умолчанию отключено

search и fetch названы намеренно: режим Deep Research в ChatGPT игнорирует все остальные инструменты, поэтому эти два несут основную нагрузку, если режим разработчика недоступен.

Ограничение доступа к определённым альбомам

По умолчанию сервер предоставляет доступ ко всему, что видит API-ключ. Чтобы предоставить доступ только к подмножеству, укажите UUID альбомов в ALLOWED_ALBUM_IDS:

python list_albums.py          # prints every album with its UUID
ALLOWED_ALBUM_IDS=a1b2c3d4-...,e5f6g7h8-...

После этого каждый инструмент будет ограничен объектами внутри этих альбомов. У умного поиска Immich нет фильтра по альбомам, поэтому сервер самостоятельно строит набор разрешённых ID объектов и отбрасывает всё, что не входит в него — включая прямой fetch по UUID, который возвращает отказ, а не объект. Набор кэшируется на SCOPE_TTL секунд, так что добавленные в разрешённый альбом фотографии появляются без перезапуска.

Стоит комбинировать два уровня: ограничить API-ключ Immich для отдельного пользователя и установить ALLOWED_ALBUM_IDS. Ключ определяет, до чего этот сервер может добраться в принципе; список альбомов ограничивает то, что он реально предоставляет.

Подключение разных клиентов

Сервер принимает токен тремя способами, потому что MCP-клиенты различаются по тому, что могут отправлять:

Клиент

URL

Аутентификация

Коннектор ChatGPT

https://host/mcp

Authorization: Bearer <token>

Коннектор Claude

https://host/<token>/mcp

поля OAuth оставить пустыми

Claude Code, Cursor, Zed

https://host/mcp

--header / заголовки в конфиге

Что угодно только по URL

https://host/mcp?key=<token>

—

Диалог настройки пользовательского коннектора Claude предлагает только OAuth Client ID и Secret, которые этот сервер не реализует — отсюда форма с путём. Безопасность эквивалентна при использовании токена с высокой энтропией, но пути и строки запроса чаще попадают в логи прокси и историю командной оболочки, чем заголовки, поэтому предпочитайте заголовок там, где клиент это позволяет.

Структура проекта

immich-mcp/
├── Dockerfile
├── docker-compose.yml
├── .env                  <- you create this, never commit it
├── .env.example
├── .dockerignore
├── preflight.py          <- validate config before building
├── run_local.py          <- run without Docker, with auto-reload
├── list_albums.py        <- discover album UUIDs for scoping
├── smoke_test.py         <- full MCP handshake test
├── cloudflared/
│   └── config.example.yml
└── app/
    ├── immich_mcp.py
    └── requirements.txt

app/ имеет значение. Если эти два файла окажутся рядом с Dockerfile вместо app/, сборка завершится ошибкой "/app/immich_mcp.py": not found.


Часть 1 — Запуск на вашем ноутбуке

Необязательно, но гораздо быстрее, чем пересобирать образ для каждого изменения конфигурации. Всё, что здесь описано, работает и на NAS.

1. Получите API-ключ Immich

Immich → Настройки аккаунта → API-ключи → Новый API-ключ. Ограничьте его только чтением, если не планируете включать ссылки для общего доступа.

В Immich 3.x ключи ограничены по эндпоинтам. Инструментам здесь нужен доступ на чтение к объектам, альбомам, людям и поиску. /users/me не требуется — предварительная проверка сообщает об отсутствии области user.read как предупреждение, а не как ошибку.

2. Настройка

cp .env.example .env
openssl rand -hex 32          # paste into MCP_BEARER_TOKEN
$EDITOR .env

С ноутбука IMMICH_URL должен быть LAN-адресом NAS — immich_server — это имя контейнера Docker, которое разрешается только на самом NAS:

IMMICH_URL=http://192.168.0.43:2283

Обратите внимание: нет второго http://. Двойная схема — это частая ошибка при вставке, которая приводит к непонятному сбою имени хоста.

3. Предварительная проверка

pip install httpx python-dotenv
python preflight.py

Проверяет структуру проекта, валидирует .env, открывает TCP-соединение с Immich, подтверждает, что API-ключ может читать объекты, и сообщает, включены ли умный поиск и распознавание лиц. Для каждой ошибки даётся точное исправление.

Стоит прочитать количество объектов, которое она показывает. Если там написано 1 объект виден, а в вашей библиотеке тысячи, значит ключ принадлежит пользователю, у которого почти ничего нет — всё остальное будет работать идеально, но ничего не возвращать.

4. Запуск без Docker

pip install -r app/requirements.txt
python run_local.py

Сервер работает на http://127.0.0.1:8099 с автоматической перезагрузкой. Во втором терминале:

python smoke_test.py http://127.0.0.1:8099 <your-bearer-token>

Это выполняет именно то рукопожатие, которое делает ChatGPT: инициализация, tools/list, затем вызов инструмента — и подтверждает, что неаутентифицированные запросы получают 401.

5. Сборка образа (опционально на ноутбуке)

Если хотите проверить сборку Docker перед отправкой, сначала удалите блок networks: из docker-compose.yml — immich_default существует только на NAS.

docker compose up -d --build
curl.exe http://127.0.0.1:8099/healthz

Часть 2 — Развёртывание на NAS

Меняются четыре вещи: как контейнер достигает Immich, какая Docker-сеть используется, владелец файлов и как собирается образ.

0. Сначала смените оба секрета

Если API-ключ Immich или bearer-токен были вставлены в чат, электронное письмо или общий документ, считайте их скомпрометированными. Этот эндпоинт скоро будет выходить в интернет.

  • Immich → Настройки аккаунта → API-ключи → удалите старый, создайте новый

  • Новый bearer-токен: openssl rand -hex 32

Не копируйте ваш .env с ноутбука. Он указывает IMMICH_URL на LAN-адрес, что работает, но направляет метаданные фото в LAN и обратно без необходимости. Начните с .env.example на NAS.

1. Скопируйте проект на NAS

Разместите его рядом с другими вашими стеками, например /volume1/docker/immich-mcp/. Либо перетащите через File Station, либо:

scp -r . wanjau@<nas-ip>:/volume1/docker/immich-mcp/

Убедитесь, что app/ сохранилась — перетаскивание в File Station иногда сглаживает папки:

ls -la /volume1/docker/immich-mcp/app/

2. Найдите реальное имя контейнера и сеть

Подключитесь по SSH (Панель управления → Терминал и SNMP → Включить SSH), затем:

sudo docker ps --format '{{.Names}}\t{{.Image}}' | grep -i immich
sudo docker network ls | grep -i immich

Container Manager часто добавляет префиксы к именам проектов, поэтому вы можете получить immich-immich_server-1, а не immich_server. Проверьте, что имя разрешается внутри Docker, что на самом деле и важно:

sudo docker run --rm --network <network-name> curlimages/curl:latest \
  -s -o /dev/null -w '%{http_code}\n' http://<container-name>:2283/api/server/version

200 здесь означает, что остальное неинтересно. Пропуск этого шага приведёт к ошибке 502 в туннеле, которая будет выглядеть как проблема Cloudflare, но это не так.

3. Запишите .env на NAS

cd /volume1/docker/immich-mcp
cp .env.example .env
vi .env
chmod 600 .env

Теперь IMMICH_URL использует имя контейнера из шага 2, оставляя трафик внутри Docker:

IMMICH_URL=http://immich_server:2283
IMMICH_API_KEY=<the new key>
MCP_BEARER_TOKEN=<the new token>
PUBLIC_URL=https://photos.yourdomain.com
ALLOWED_ALBUM_IDS=

4. Исправьте имя сети и пользователя

В docker-compose.yml установите сеть в соответствии с тем, что показал шаг 2:

networks:
  immich-net:
    external: true
    name: immich_default        # <- from step 2

Dockerfile создаёт пользователя с UID 1027 (обычная конвенция Synology). Проверьте свой с помощью id; если отличается, либо отредактируйте Dockerfile, либо переопределите в compose с помощью user: "1026:100". Это важно только при монтировании томов — несовпадение пока не имеет значения.

5. Предварительная проверка и выбор альбомов из контейнера

Установить пакеты Python в DSM неудобно, и запуск предварительной проверки на хосте не проверил бы разрешение имён контейнер-контейнер:

cd /volume1/docker/immich-mcp
sudo docker run --rm -it \
  --network <network-name> \
  -v "$PWD":/work -w /work \
  python:3.12-slim sh -c "pip install -q httpx python-dotenv && python preflight.py"

Та же однострочная команда запускает list_albums.py. Скопируйте нужные UUID в ALLOWED_ALBUM_IDS.

6. Сборка и запуск

sudo docker compose up -d --build
sudo docker compose logs -f immich-mcp

Следите за тремя строками:

Immich MCP server configured for http://immich_server:2283
Scope: restricted to <album-id>
Album scope refreshed: 1 album(s), N asset(s)

Если N равно 0, то ID альбома неверен или ключ не может читать этот альбом.

Container Manager GUI тоже работает: Проект → Создать → указать папку — но иногда плохо справляется с сетями external: true. Если возникнет ошибка, используйте SSH.

7. Проверка на NAS перед открытием доступа

curl -s http://127.0.0.1:8099/healthz | head -c 300

Ожидайте status ok, версию Immich и сводку по области видимости. Затем полное рукопожатие:

sudo docker run --rm -it --network host \
  -v "$PWD":/work -w /work \
  python:3.12-slim sh -c "pip install -q httpx && \
    python smoke_test.py http://127.0.0.1:8099 <bearer-token>"

Проблема, найденная здесь, — это проблема конфигурации. Та же проблема, найденная после следующего раздела, будет выглядеть как проблема туннеля.


Часть 3 — Открыть доступ и подключить ChatGPT

1. Добавьте имя хоста Cloudflare Tunnel

Панель Zero Trust → Сети → Туннели → ваш туннель → Публичное имя хоста → Добавить:

  • Поддомен: immich-mcp

  • Домен: yourdomain.com

  • Служба: HTTP → immich_mcp:8080

Если cloudflared работает как контейнер, он должен быть в одной сети с immich_mcp, чтобы это имя разрешалось; если он работает на хосте, используйте http://127.0.0.1:8099. См. cloudflared/config.example.yml для эквивалента в файле конфигурации.

Не прикрепляйте политику доступа. ChatGPT не может выполнить интерактивный вход через Access. Bearer-токен — единственный шлюз, поэтому его смена была важна.

Проверьте из-за пределов LAN, если возможно; точка доступа телефона — хороший тест:

python smoke_test.py https://immich-mcp.yourdomain.com <bearer-token>

2. Создайте коннектор

Настройки → Коннекторы → Расширенные настройки → включите Режим разработчика (требуется платный план), затем Создать:

  • Имя: Immich Photos

  • Описание: это важно — модель читает его, чтобы решить, вызывать ли коннектор. Что-то вроде «Личная библиотека фото и видео. Используется для поиска, описания или перечисления фотографий, альбомов и распознанных людей.»

  • URL: https://immich-mcp.yourdomain.com/mcp

  • Аутентификация: API-ключ / пользовательский заголовок → Authorization: Bearer <token>

Затем включите коннектор в композиторе чата и протестируйте с явным именем инструмента:

Используй immich search, чтобы найти фотографии с drying racks


Эксплуатация

Называйте инструмент в своём запросе. ChatGPT не всегда надёжно угадает, когда нужно обратиться к пользовательскому коннектору. «Используй immich search, чтобы найти фотографии с drying racks» работает, а «найди мои фотографии с drying racks» — часто нет.

ChatGPT не видит ваши фотографии. Результаты работы инструментов — это текст: описания и метаданные, а не пиксели. create_share_link устраняет этот разрыв, но ссылка общего доступа публична для любого, у кого есть URL, поэтому она отключена по умолчанию.

Обновление кода. Отредактируйте app/immich_mcp.py, затем sudo docker compose up -d --build.

Смена bearer-токена. Отредактируйте .env, docker compose up -d --force-recreate, затем обновите коннектор в ChatGPT. Будет промежуток, когда ChatGPT не работает — делайте это, когда не в середине разговора.

Добавление фотографий в ограниченный альбом. Ничего не нужно делать. Кэш области видимости перестраивается каждые SCOPE_TTL секунд (по умолчанию 300).

Автозапуск после перезагрузки. restart: unless-stopped обрабатывает это, но проекты Container Manager иногда требуют отметить галочку автозапуска в GUI. Перезагрузитесь один раз намеренно, в удобное для вас время, а не обнаружьте неработоспособность, когда вас нет рядом.

Зафиксируйте версию Immich. API меняется между релизами — /server/statistics был /server-info/statistics ещё недавно. Ваш экземпляр публикует точную спецификацию по адресу https://photos.yourdomain.com/api/docs; проверьте там, прежде чем отлаживать 404.

Симптом

Причина

Сборка: "/app/immich_mcp.py": not found, контекст 2 B

Файлы плоские; они должны находиться в app/

network immich_default not found

Неправильное имя сети — переделайте шаг 2 из части 2

/healthz возвращает 503

Нет доступа к Immich — неправильный IMMICH_URL, или контейнеры не в одной сети

Контейнер завершается сразу

Отсутствует обязательная переменная окружения — проверьте docker compose logs

Scope refreshed: 0 assets

Неправильный ID альбома, или ключ не может читать этот альбом

Предварительная проверка: ключ API отклонён 403 на /users/me

Отсутствует scope user.read — безвредно, ни одному инструменту он не нужен

Предварительная проверка: виден только 1 актив

Ключ принадлежит пользователю, у которого почти нет своих активов

401 на каждом запросе

Несовпадение Bearer токена между .env и коннектором

Работает на NAS, 502 через туннель

cloudflared не может разрешить immich_mcp — общая сеть, или используйте IP хоста

Туннель возвращает страницу входа

Прикреплена политика Access; удалите её

ChatGPT: "search action not found"

Добавлено в режиме Deep Research; включите Developer Mode

Коннектор добавлен, но никогда не срабатывает

Слишком расплывчатое описание, или инструмент не включён в чате

search ничего не возвращает никогда

Машинное обучение Immich отключено — проверьте server_info

Immich отклоняет ключ (401 в логах)

Ключ отозван или принадлежит другому пользователю Immich

Related MCP Connectors

Related MCP Servers