A Model Context Protocol (MCP) server for Immich - the self-hosted photo and video management solution. This server provides a first-class AI interface to manage your Immich library.
- Asset Management: Search, browse, upload, update, and delete photos/videos
- Direct Local Upload: Authorize a short-lived, upload-only URL and stream a local folder straight to Immich — no API key exposed, nothing to install beyond
curl, resumable by content dedup - Smart Search: ML-powered semantic search using CLIP (e.g., "sunset at the beach")
- Metadata Search: Filter by date, location, camera, people, and more
- Albums: Create, manage, and share photo albums
- People: View and manage face recognition clusters
- Tags: Organize assets with custom tags
- Shared Links: Create shareable URLs for albums and assets
- Activities: Add comments and likes to albums/assets
- .NET 10.0 SDK
- Immich v3.0 or newer server instance
- Immich API key
ImmichMCP 3.x targets Immich v3 APIs. Use an older ImmichMCP release for Immich v2 servers.
Read-only integration tests can run against an existing Immich server without deploying ImmichMCP:
export IMMICH_BASE_URL="http://127.0.0.1:2283"
export IMMICH_API_KEY="your-api-key"
export IMMICH_INTEGRATION_TESTS=true
dotnet test ImmichMCP.Tests/ImmichMCP.Tests.csproj --filter "Category=Integration"Mutation coverage (create/update/delete paths) is disabled by default. Enable it explicitly to also run the full 49-tool smoke:
export IMMICH_INTEGRATION_MUTATION_TESTS=true
dotnet test ImmichMCP.Tests/ImmichMCP.Tests.csproj --filter "Category=Integration"(If your Immich runs somewhere not directly reachable, point IMMICH_BASE_URL at it however
you normally reach it — e.g. a port-forward or tunnel — before running the tests.)
With mutation coverage enabled, ToolCoverageIntegrationTests exercises all 49 tools
against the live server. It is strictly non-destructive to existing data: every mutation
runs on throwaway fixtures the test creates (uploaded PNGs, an album, a tag, shared links,
an activity) and teardown deletes only those; the two tools that would mutate real,
un-creatable data (immich_people_update, immich_people_merge) are exercised with bogus
IDs only and must refuse safely.
ImmichMCP is published as a container image at ghcr.io/barryw/immichmcp. Run it wherever you
host containers — Docker, Docker Compose, or Kubernetes.
- Set
IMMICH_BASE_URLandIMMICH_API_KEY(see Environment Variables). - Expose the HTTP port (default
5000). The MCP endpoint is served at/mcp. Two health endpoints are available:/health(liveness, use for restarts) and/health/ready(readiness, pings Immich and returns503if unreachable, use for traffic routing). - For remote/HTTP clients, set
IMMICH_TOOL_MODE=gatewayso clients enable tool categories on demand instead of loading all tools up front.
cp .env.example .env # set IMMICH_BASE_URL and IMMICH_API_KEY
docker compose up --buildA sample manifest is provided in k8s/deployment.yaml — set the image,
the two environment variables, and IMMICH_TOOL_MODE=gateway, then apply it with kubectl.
# Clone the repository
git clone https://github.com/barryw/ImmichMCP.git
cd ImmichMCP
# Set environment variables
export IMMICH_BASE_URL="https://photos.example.com"
export IMMICH_API_KEY="your-api-key"
# Run with stdio transport (for Claude Desktop)
dotnet run --project ImmichMCP -- --stdio
# Or run with HTTP transport (for remote usage)
dotnet run --project ImmichMCPdocker run -e IMMICH_BASE_URL="https://photos.example.com" \
-e IMMICH_API_KEY="your-api-key" \
-p 5000:5000 \
ghcr.io/barryw/immichmcp:latest| Variable | Required | Default | Description |
|---|---|---|---|
IMMICH_BASE_URL |
Yes | - | Base URL of your Immich instance |
IMMICH_API_KEY |
Yes | - | API key for authentication |
MCP_LOG_LEVEL |
No | Information |
Logging level |
DOWNLOAD_MODE |
No | url |
url returns URLs, base64 returns the file content inline as MCP image/resource content |
MAX_INLINE_DOWNLOAD_BYTES |
No | 26214400 |
Max asset size returned inline with DOWNLOAD_MODE=base64; larger assets get a PAYLOAD_TOO_LARGE error that includes the download URL |
MAX_PAGE_SIZE |
No | 100 |
Maximum items per page |
MCP_PORT |
No | 5000 |
HTTP server port |
IMMICH_TOOL_MODE |
No | static |
static exposes all tools; gateway exposes immich_tools_list and immich_tools_enable first |
In gateway mode, immich_tools_enable emits the MCP notifications/tools/list_changed notification so clients can refresh the normal tools/list inventory after enabling a category or tool.
Add to your Claude Desktop config (~/.config/claude/claude_desktop_config.json on Linux/macOS or %APPDATA%\Claude\claude_desktop_config.json on Windows):
{
"mcpServers": {
"immich": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/ImmichMCP/ImmichMCP", "--", "--stdio"],
"env": {
"IMMICH_BASE_URL": "https://photos.example.com",
"IMMICH_API_KEY": "your-api-key"
}
}
}
}Or with Docker:
{
"mcpServers": {
"immich": {
"command": "docker",
"args": ["run", "-i", "--rm",
"-e", "IMMICH_BASE_URL=https://photos.example.com",
"-e", "IMMICH_API_KEY=your-api-key",
"ghcr.io/barryw/immichmcp:latest", "--stdio"]
}
}
}| Tool | Description |
|---|---|
immich_ping |
Verify connectivity and return server version |
immich_capabilities |
List available API features |
| Tool | Description |
|---|---|
immich_assets_list |
List recent assets with filters |
immich_assets_get |
Get full asset metadata |
immich_assets_exif |
Get EXIF data for an asset |
immich_assets_download_original |
Get download URL for original (or inline content with DOWNLOAD_MODE=base64) |
immich_assets_download_thumbnail |
Get thumbnail/preview URLs (or inline preview image with DOWNLOAD_MODE=base64) |
immich_assets_upload |
Upload asset (base64) |
immich_assets_upload_from_path |
Upload from local file path |
immich_assets_upload_authorize |
Mint a short-lived, upload-only URL so a client can upload local files directly to Immich (no API key exposed) |
immich_assets_upload_init |
Start an out-of-band upload session; returns a URL to POST a file to |
immich_assets_upload_status |
Check the status of an out-of-band upload session |
immich_assets_update |
Update asset metadata |
immich_assets_bulk_update |
Bulk update multiple assets |
immich_assets_delete |
Delete asset(s) |
immich_assets_statistics |
Get asset statistics |
| Tool | Description |
|---|---|
immich_search_metadata |
Search by metadata filters |
immich_search_smart |
ML-based semantic search (CLIP) |
immich_search_ocr |
OCR text search inside images |
immich_search_explore |
Get explore/discovery data |
| Tool | Description |
|---|---|
immich_albums_list |
List all albums |
immich_albums_get |
Get album details |
immich_albums_create |
Create new album |
immich_albums_update |
Update album metadata |
immich_albums_assets_add |
Add assets to album |
immich_albums_assets_remove |
Remove assets from album |
immich_albums_delete |
Delete album |
immich_albums_statistics |
Get album statistics |
| Tool | Description |
|---|---|
immich_people_list |
List all recognized people |
immich_people_get |
Get person details |
immich_people_update |
Update person info |
immich_people_merge |
Merge duplicate people |
immich_people_assets |
List assets for a person |
| Tool | Description |
|---|---|
immich_tags_list |
List all tags |
immich_tags_get |
Get tag by ID |
immich_tags_create |
Create new tag |
immich_tags_update |
Update tag |
immich_tags_delete |
Delete tag |
immich_tags_assets_add |
Tag assets |
immich_tags_assets_remove |
Remove tag from assets |
| Tool | Description |
|---|---|
immich_shared_links_list |
List all shared links |
immich_shared_links_get |
Get shared link details |
immich_shared_links_create |
Create shared link |
immich_shared_links_update |
Update shared link |
immich_shared_links_delete |
Delete shared link |
| Tool | Description |
|---|---|
immich_activities_list |
List comments/likes |
immich_activities_create |
Add comment or like |
immich_activities_delete |
Delete activity |
immich_activities_statistics |
Get activity statistics |
Search for photos taken in the last 30 days that are favorites
Create a new album called "2026 Winter Vacation" and add all photos from January 2026
Find photos of sunset at the beach
Archive all photos from 2020 that aren't favorites
Upload ~/Photos/Iceland2026 to Immich into an album called "Iceland 2026"
Because the MCP server is remote and cannot read your disk, immich_assets_upload_authorize
mints a short-lived, upload-only shared-link URL scoped to a (dynamically created) album.
The client then uploads the files directly to Immich with curl it already has — the master
API key never leaves the server, and no CLI/script needs to be installed. Re-running is safe and
resumable: Immich deduplicates by content, so already-uploaded files return duplicate. See the
uploading-local-media doc for the exact client recipe.
- All destructive operations require explicit
confirm: trueparameter - Bulk operations default to
dryRun: truemode - Dry runs return what would be affected without making changes
All tools return a consistent JSON envelope:
{
"ok": true,
"result": { ... },
"meta": {
"request_id": "uuid",
"page": 1,
"page_size": 25,
"total": 123,
"next": "cursor-or-null",
"immich_base_url": "https://photos.example.com"
},
"warnings": []
}Error responses:
{
"ok": false,
"error": {
"code": "NOT_FOUND",
"message": "Asset not found",
"details": { ... }
},
"meta": { ... }
}Upstream failures are never swallowed into empty/success-looking results: a non-2xx
response from Immich surfaces as an error, and per the MCP spec every tool-execution
error is returned as a result with isError: true (not a JSON-RPC protocol error), so
the calling model can see and react to it. Error code maps the upstream status
(AUTH_FAILED, NOT_FOUND, VALIDATION, RATE_LIMIT, UPSTREAM_ERROR).
MIT License - see LICENSE file for details.
- Immich - Self-hosted photo and video management
- PaperlessMCP - MCP server for Paperless-ngx