Skip to main content
Glama
wanjau2

Immich MCP Server

by wanjau2

Immich MCP Server

Stellt eine selbst gehostete Immich-Fotobibliothek für ChatGPT (und andere MCP-Clients) über Streamable HTTP bereit, sodass Sie Fragen wie „finde die Fotos vom Kigali-Standortbesuch im März“ stellen und echte Antworten von Ihrem eigenen NAS erhalten können.

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

ChatGPT benutzerdefinierte Connectors akzeptieren nur einen remote HTTPS-Endpunkt — es gibt keine stdio- oder localhost-Option. Der Server muss also aus dem Internet erreichbar sein, daher der Tunnel, und er muss sich verteidigen, daher das Bearer-Token.


Inhaltsverzeichnis


Related MCP server: immich-photo-manager

Werkzeuge

Werkzeug

Zweck

search

CLIP semantische Suche über Bildinhalte

fetch

Vollständige EXIF-Daten für ein Asset per UUID

search_by_metadata

Filtern nach Datum, Ort, Kamera, Person, Favorit

list_albums

Alle Alben mit Anzahl

get_album

Details und Inhalt eines Albums

list_people

Erkannte Gesichter mit IDs zum Filtern

library_stats

Foto-/Videoanzahl und Speichernutzung

server_info

Immich-Version und aktivierte Funktionen

create_share_link

Öffentlicher Link zu bestimmten Assets — standardmäßig deaktiviert

search und fetch sind bewusst benannt: ChatGPTs Deep Research-Modus ignoriert alle anderen Werkzeuge, daher tragen diese beiden die Last, wenn der Entwicklermodus nicht verfügbar ist.

Zugriff auf bestimmte Alben beschränken

Standardmäßig legt der Server alles offen, was der API-Schlüssel sehen kann. Um nur eine Teilmenge freizugeben, fügen Sie Album-UUIDs in ALLOWED_ALBUM_IDS ein:

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

Jedes Werkzeug ist dann auf Assets in diesen Alben beschränkt. Immichs intelligente Suche hat keinen Albumfilter, daher erstellt der Server selbst die Menge der erlaubten Asset-IDs und verwirft alles außerhalb — einschließlich direktem fetch per UUID, das eine Ablehnung statt des Assets zurückgibt. Die Menge wird für SCOPE_TTL Sekunden zwischengespeichert, sodass Fotos, die zu einem erlaubten Album hinzugefügt werden, ohne Neustart erscheinen.

Zwei Ebenen sind kombinierenswert: Beschränken Sie den Immich-API-Schlüssel auf einen dedizierten Benutzer und setzen Sie ALLOWED_ALBUM_IDS. Der Schlüssel begrenzt, was dieser Server jemals erreichen könnte; die Albumliste begrenzt, was er tatsächlich offenlegt.

Verschiedene Clients verbinden

Der Server akzeptiert das Token auf drei Arten, da MCP-Clients sich darin unterscheiden, was sie senden können:

Client

URL

Authentifizierung

ChatGPT-Connector

https://host/mcp

Authorization: Bearer <token>

Claude-Connector

https://host/<token>/mcp

OAuth-Felder leer lassen

Claude Code, Cursor, Zed

https://host/mcp

--header / Konfigurations-Header

Alles URL-only

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

—

Claudes benutzerdefinierter Connector-Dialog bietet nur OAuth-Client-ID und -Secret, die dieser Server nicht implementiert — daher die Pfadform. Die Sicherheit ist bei einem Token mit hoher Entropie gleichwertig, aber Pfade und Abfragezeichenfolgen landen leichter in Proxy-Logs und Shell-Verlauf als Header, daher bevorzugen Sie den Header, wo der Client es erlaubt.

Projektstruktur

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/ ist wichtig. Wenn diese beiden Dateien neben der Dockerfile statt in app/ landen, schlägt der Build mit "/app/immich_mcp.py": not found fehl.


Teil 1 — Zum Laufen auf Ihrem Laptop bringen

Optional, aber eine viel schnellere Schleife als ein Image für jede Konfigurationsänderung neu zu erstellen. Alles hier funktioniert auch auf dem NAS.

1. Einen Immich-API-Schlüssel erhalten

Immich → Kontoeinstellungen → API-Schlüssel → Neuer API-Schlüssel. Beschränken Sie ihn auf schreibgeschützt, es sei denn, Sie planen, Freigabelinks zu aktivieren.

Immich 3.x beschränkt Schlüssel pro Endpunkt. Die Werkzeuge hier benötigen Lesezugriff auf Assets, Alben, Personen und Suche. /users/me ist nicht erforderlich — der Preflight meldet einen fehlenden user.read-Bereich als Warnung, nicht als Fehler.

2. Konfigurieren

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

Vom Laptop aus muss IMMICH_URL die LAN-Adresse des NAS sein — immich_server ist ein Docker-Containername, der nur auf dem NAS selbst aufgelöst wird:

IMMICH_URL=http://192.168.0.43:2283

Beachten Sie, dass es kein zweites http:// gibt. Ein doppeltes Schema ist ein häufiger Einfügefehler und führt zu einem verwirrenden Hostname-Fehler.

3. Preflight

pip install httpx python-dotenv
python preflight.py

Überprüft die Projektstruktur, validiert .env, öffnet eine TCP-Verbindung zu Immich, bestätigt, dass der API-Schlüssel Assets lesen kann, und meldet, ob die intelligente Suche und Gesichtserkennung tatsächlich aktiviert sind. Es nennt die genaue Lösung für jeden Fehler.

Es lohnt sich, die gemeldete Asset-Anzahl zu lesen. Wenn es 1 Asset sichtbar sagt und Ihre Bibliothek Tausende hat, gehört der Schlüssel einem Benutzer, der fast nichts besitzt — alles nachgelagerte wird perfekt funktionieren und nichts zurückgeben.

4. Ohne Docker ausführen

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

Bedient auf http://127.0.0.1:8099 mit automatischem Neuladen. In einem zweiten Terminal:

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

Dies führt den exakten Handshake aus, den ChatGPT macht — initialize, tools/list, dann einen Live-Tool-Aufruf — und bestätigt, dass nicht authentifizierte Anfragen einen 401 erhalten.

5. Das Image erstellen (optional auf dem Laptop)

Wenn Sie den Docker-Build überprüfen möchten, bevor Sie ihn ausliefern, löschen Sie zuerst den networks:-Block aus docker-compose.yml — immich_default existiert nur auf dem NAS.

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

Teil 2 — Auf dem NAS bereitstellen

Vier Dinge ändern sich: wie der Container Immich erreicht, welches Docker-Netzwerk er beitritt, Dateibesitzer und wie das Image erstellt wird.

0. Beide Geheimnisse zuerst rotieren

Wenn der Immich-API-Schlüssel oder das Bearer-Token in einen Chat, eine E-Mail oder ein freigegebenes Dokument eingefügt wurde, behandeln Sie es als kompromittiert. Dieser Endpunkt wird dem Internet ausgesetzt.

  • Immich → Kontoeinstellungen → API-Schlüssel → alten löschen, neuen erstellen

  • Neues Bearer-Token: openssl rand -hex 32

Kopieren Sie nicht Ihr Laptop-.env rüber. Es zeigt IMMICH_URL auf eine LAN-Adresse, was funktioniert, aber Foto-Metadaten unnötig über das LAN hin und her leitet. Beginnen Sie mit .env.example auf dem NAS.

1. Das Projekt rüberkopieren

Platzieren Sie es neben Ihren anderen Stacks, z.B. /volume1/docker/immich-mcp/. Entweder per Drag & Drop über File Station oder:

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

Überprüfen Sie, ob app/ überlebt hat — File Station Drag & Drop glättet manchmal Verzeichnisse:

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

2. Den tatsächlichen Containernamen und das Netzwerk finden

SSH einloggen (Systemsteuerung → Terminal & SNMP → SSH aktivieren), dann:

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

Container Manager stellt oft Projektnamen voran, daher erhalten Sie möglicherweise immich-immich_server-1 statt immich_server. Beweisen Sie, dass der Name von innerhalb von Docker aufgelöst wird, was tatsächlich zählt:

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

Ein 200 hier bedeutet, dass der Rest davon langweilig ist. Wenn Sie es überspringen, erhalten Sie später einen Tunnel-502, der wie ein Cloudflare-Problem aussieht, aber keines ist.

3. .env auf dem NAS schreiben

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

Jetzt verwendet IMMICH_URL den Containernamen aus Schritt 2 und hält den Datenverkehr innerhalb von 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. Netzwerknamen und Benutzer korrigieren

Setzen Sie in docker-compose.yml das Netzwerk auf das, was Schritt 2 gemeldet hat:

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

Die Dockerfile erstellt einen Benutzer mit UID 1027, der üblichen Synology-Konvention. Überprüfen Sie Ihre mit id; wenn sie abweicht, bearbeiten Sie entweder die Dockerfile oder überschreiben Sie in der Compose mit user: "1026:100". Ist nur wichtig, wenn Sie Volumes einbinden — eine Abweichung ist vorerst harmlos.

5. Preflight und Alben auswählen, von innerhalb eines Containers

DSMs Python ist umständlich, um Pakete zu installieren, und das Ausführen von Preflight auf dem Host würde die Container-zu-Container-Namensauflösung ohnehin nicht testen:

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"

Derselbe Einzeiler führt list_albums.py aus. Kopieren Sie die UUIDs, die Sie freigeben möchten, in ALLOWED_ALBUM_IDS.

6. Erstellen und starten

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

Achten Sie auf drei Zeilen:

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

Wenn N 0 ist, ist die Album-ID falsch oder der Schlüssel kann dieses Album nicht lesen.

Die Container Manager GUI funktioniert auch — Projekt → Erstellen → auf den Ordner zeigen — aber sie hat manchmal Probleme mit external: true-Netzwerken. Verwenden Sie SSH, wenn es einen Fehler gibt.

7. Auf dem NAS überprüfen, bevor etwas freigegeben wird

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

Erwarten Sie Status ok, die Immich-Version und Ihre Bereichszusammenfassung. Dann den vollständigen Handshake:

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>"

Ein hier gefundenes Problem ist ein Konfigurationsproblem. Das gleiche Problem, das nach dem nächsten Abschnitt gefunden wird, sieht wie ein Tunnelproblem aus.


Teil 3 — Freigeben und ChatGPT verbinden

1. Den Cloudflare-Tunnel-Hostnamen hinzufügen

Zero Trust-Dashboard → Netzwerke → Tunnel → Ihr Tunnel → Öffentlicher Hostname → Hinzufügen:

  • Subdomain: immich-mcp

  • Domain: yourdomain.com

  • Service: HTTP → immich_mcp:8080

Wenn cloudflared als Container läuft, muss es ein Netzwerk mit immich_mcp teilen, damit dieser Name aufgelöst wird; wenn es auf dem Host läuft, verwenden Sie http://127.0.0.1:8099. Siehe cloudflared/config.example.yml für das Äquivalent in der Konfigurationsdatei.

Fügen Sie keine Access-Richtlinie hinzu. ChatGPT kann keinen interaktiven Access-Login abschließen. Das Bearer-Token ist das einzige Tor — weshalb das Rotieren wichtig war.

Überprüfen Sie von außerhalb des LAN, wenn möglich; ein Telefon-Hotspot ist ein guter Test:

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

2. Den Connector erstellen

Einstellungen → Connectors → Erweiterte Einstellungen → Entwicklermodus aktivieren (erfordert einen kostenpflichtigen Plan), dann Erstellen:

  • Name: Immich Photos

  • Description: dies ist wichtig — das Modell liest es, um zu entscheiden, ob der Connector aufgerufen werden soll. So etwas wie „Persönliche Foto- und Videobibliothek. Verwenden Sie sie zum Finden, Beschreiben oder Auflisten von Fotos, Alben und erkannten Personen.“

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

  • Authentication: API key / custom header → Authorization: Bearer <token>

Aktivieren Sie dann den Connector im Chat-Komponisten und testen Sie mit einem expliziten Werkzeugnamen:

Verwende immich search, um Fotos der Trockengestelle zu finden


Betrieb

Nennen Sie das Werkzeug in Ihrer Eingabeaufforderung. ChatGPT wird nicht zuverlässig erraten, wann es einen benutzerdefinierten Connector verwenden soll. „Verwende immich search, um Fotos der Trockengestelle zu finden“ funktioniert, wo „finde meine Trockengestell-Fotos“ oft nicht funktioniert.

ChatGPT kann Ihre Fotos nicht sehen. Werkzeugergebnisse sind Text — Beschreibungen und Metadaten, keine Pixel. create_share_link überbrückt diese Lücke, aber ein Freigabelink ist für jeden, der die URL hat, öffentlich, weshalb er standardmäßig deaktiviert ist.

Code aktualisieren. Bearbeiten Sie app/immich_mcp.py, dann sudo docker compose up -d --build.

Bearer-Token rotieren. Bearbeiten Sie .env, docker compose up -d --force-recreate, dann aktualisieren Sie den Connector in ChatGPT. Es gibt ein Zeitfenster, in dem ChatGPT defekt ist — tun Sie es, wenn Sie nicht mitten in einem Gespräch sind.

Fotos zu einem eingeschränkten Album hinzufügen. Nichts zu tun. Der Bereichscache wird alle SCOPE_TTL Sekunden (Standard 300) neu aufgebaut.

Autostart nach einem Neustart. restart: unless-stopped erledigt das, aber Container Manager-Projekte benötigen manchmal ein Häkchen für Autostart in der GUI. Starten Sie einmal bewusst neu, zu einem Zeitpunkt, der Ihnen passt, anstatt es zu entdecken, während Sie weg sind.

Fixieren Sie Ihre Immich-Version. Die API ändert sich zwischen Versionen — /server/statistics war vor nicht allzu langer Zeit /server-info/statistics. Ihre Instanz veröffentlicht die genaue Spezifikation unter https://photos.yourdomain.com/api/docs; überprüfen Sie dort, bevor Sie einen 404 debuggen.


Fehlerbehebung

Symptom

Cause

Build: "/app/immich_mcp.py": nicht gefunden, Kontext ist 2 B

Dateien sind flach; sie gehören in app/

network immich_default nicht gefunden

Falscher Netzwerkname – wiederhole Teil 2 Schritt 2

/healthz gibt 503 zurück

Immich nicht erreichbar – falsche IMMICH_URL, oder die Container sind nicht im selben Netzwerk

Container wird sofort beendet

Fehlende erforderliche Umgebungsvariable – überprüfe docker compose logs

Scope refreshed: 0 assets

Falsche Album-ID, oder der Schlüssel kann dieses Album nicht lesen

Preflight: API-Schlüssel mit 403 auf /users/me abgelehnt

Fehlender user.read-Scope – harmlos, kein Tool benötigt ihn

Preflight: nur 1 Asset sichtbar

Schlüssel gehört einem Benutzer, der fast nichts besitzt

401 bei jeder Anfrage

Bearer-Token stimmt nicht zwischen .env und dem Connector überein

Funktioniert auf dem NAS, 502 durch den Tunnel

cloudflared kann immich_mcp nicht auflösen – gleiches Netzwerk, oder die Host-IP verwenden

Tunnel gibt eine Login-Seite zurück

Eine Access-Richtlinie ist angehängt; entferne sie

ChatGPT: "search action not found"

Im Deep Research-Modus hinzugefügt; aktiviere den Entwicklermodus

Connector hinzugefügt, wird aber nie ausgelöst

Beschreibung zu vage, oder das Tool ist im Chat nicht aktiviert

search gibt nie etwas zurück

Immich Machine Learning deaktiviert – überprüfe server_info

Immich lehnt den Schlüssel ab (401 in Logs)

Schlüssel widerrufen oder gehört zu einem anderen Immich-Benutzer

Related MCP Connectors

Related MCP Servers