immichctrl

mcp
Guvenlik Denetimi
Uyari
Health Uyari
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 6 GitHub stars
Code Uyari
  • process.env — Environment variable access in src/client.ts
  • process.env — Environment variable access in src/config.ts
  • process.env — Environment variable access in src/http.ts
  • process.env — Environment variable access in src/immich-client.ts
Permissions Gecti
  • Permissions — No dangerous permissions requested

Bu listing icin henuz AI raporu yok.

SUMMARY

Your photo library outgrew the click-grid. immichctrl gives shells, cron, and agents one typed control surface for Immich, with writes off by default.

README.md

immichctrl banner

Lidless Labs

immichctrl

An operator control CLI for Immich, with an MCP adapter so AI clients can search, curate, and clean up your self-hosted photo and video library through the same safe tool surface.

Website  |  npm  |  Immich

CI status npm version MCP compatible MIT License

What it is. immichctrl is an operator control CLI for Immich, the self-hosted photo and video library. It gives shells, cron, CI, and automation agents a typed way to inspect your library, search assets, audit storage, and run common read-only workflows. The same package keeps the Model Context Protocol surface available through immichctrl mcp and the back-compat immich-mcp binary, so MCP clients like Claude Desktop, Claude Code, OpenClaw, or Codex CLI can browse and search your photo library, manage albums and tags, recognize people, surface memories, and resolve duplicates in plain language.

Why use it. Immich already holds your whole life in photos, but the web UI is built for clicking, not for repeatable operator workflows. immichctrl gives you scriptable commands like immichctrl server stats, immichctrl search smart "sunset over the ocean", and immichctrl duplicates; the MCP adapter lets an AI client ask for the same kind of work through audited tool calls instead of hand-clicking.

How it differs. It is ctl-first and MCP-compatible: the package installs immichctrl for operator use, while immichctrl mcp and immich-mcp keep the full MCP adapter available. The MCP surface remains broad: 74 tools across 16 domains, including memories, duplicate detection with checksum-safe resolution, trash auditing, and motion-photo stacks that other Immich MCP servers do not cover. Writes are off by default and destructive calls demand explicit confirmation, so an agent cannot quietly delete your photos.

What it does

immichctrl connects a self-hosted Immich photo library to operator workflows and MCP-compatible AI clients. The CLI covers read-only server, library, search, people, album, tag, duplicate, jobs, and memories workflows. The MCP adapter turns Immich's REST API into 74 typed, schema-validated tool calls grouped into 16 domains, so an MCP-compatible AI client can drive your photo and video library directly:

  • Search your photo library by natural language (CLIP / smart search), by metadata (date, location, camera, people, tags), or by a server-side discovery feed.
  • Curate albums, tags, shared links, and stacks (motion photos, bracketed shots, RAW + JPEG pairs).
  • Recognize people: list recognized faces, rename them, merge duplicate face clusters, suggest names for unnamed clusters.
  • Surface memories: "on this day" lanes, a today digest, and recent-upload summaries suitable for a daily cron drop.
  • Clean up duplicates and trash: categorize duplicate groups, find byte-identical or CLIP-grouped dupes, audit the active library and trash for reclaimable space, and resolve with a configurable keep strategy.
  • Manage assets: read metadata and EXIF, favorite, archive, rate, geotag, soft-delete (trash), restore, and upload from a confined local directory.

Reads always work. Writes and deletes only appear when you opt in, and the most destructive ones require a per-call confirm: true.

Install

The MCP client config below uses npx -y immich-mcp, which needs no install and keeps the existing npm package name for compatibility. To install globally instead:

npm install -g immich-mcp

Or from source:

git clone https://github.com/lidless-labs/immichctrl.git
cd immichctrl
npm install
npm run build

When running from a source checkout, point your client's command at node and args at the absolute path to dist/index.js.

Quickstart

# 1. Get an Immich API key: Account Settings > API Keys > New API Key in the Immich web UI.

# 2. Run a CLI check without installing globally:
IMMICH_BASE_URL=https://photos.example.com/api \
IMMICH_API_KEY=your_key_here \
npm exec --yes --package immich-mcp -- immichctrl ping

After a global install, the operator CLI is available as immichctrl. To start the MCP adapter instead, use immichctrl mcp or the back-compat immich-mcp binary. MCP launchers can keep using the config below.

HTTP mode

Run one persistent process for multiple MCP clients:

node dist/index.js --http
# Also: node dist/cli.js mcp --http
# Or: immichctrl mcp --http

Set the usual IMMICH_BASE_URL and IMMICH_API_KEY on the server, plus an
independent IMMICH_MCP_HTTP_TOKEN. Generate a random HTTP token, for example
with openssl rand -hex 32. Startup refuses a missing or blank token, or one
equal to the API key or credentials embedded in the upstream URL. Authentication
compares SHA-256 digests in constant time.

  • IMMICH_MCP_HTTP_TOKEN: required bearer token.
  • IMMICH_MCP_HTTP_HOST: defaults to IPv4 loopback.
  • IMMICH_MCP_HTTP_PORT: defaults to 3112. Use 0 to select a free port.
  • IMMICH_MCP_HTTP_LOCAL_FILES: false by default. HTTP mode then refuses immich_upload_asset_from_path and CSV exportTo. Set true only for trusted clients. Upload paths stay confined to IMMICH_UPLOAD_BASE_DIR. CSV exportTo in immich_resolve_with_keep_strategy and immich_audit_trash is a trusted-client feature: with writes enabled, clients can create files anywhere the server user can write, including through symlinked parent directories. These exports refuse to overwrite existing files and are not confined by IMMICH_UPLOAD_BASE_DIR. This export policy also applies over stdio.

/mcp supports Streamable HTTP POST, GET, and DELETE with authentication on every
request. GET /healthz returns only {"status":"ok"} without authentication.
Host and Origin checks run before authentication to reject DNS rebinding.
Bodies are limited to 1 MiB, including chunked requests. Request and header
timeouts are 30 and 10 seconds. The listener accepts at most 128 sessions and
reaps sessions idle for 30 minutes on a minute timer. Active tool calls are
excluded from idle expiry. An idle SSE channel does not keep a session alive.
SIGTERM and SIGINT close sessions and the listener. Clients must initialize again
after expiry or restart.

Each session owns a fresh MCP server and tool registry. Previews, keep-strategy
plans, duplicate groups, and album indexes are computed within each invocation.
There is no pending approval or plan store. Confirmation arguments apply only to
the current call, and IMMICH_ALLOW_WRITES remains off by default. The process
shares one fixed upstream SDK configuration and write policy. Session IDs route
protocol state, and all clients with the bearer token share the same Immich
account privileges. There is no per-client authorization or deferred tool set.

HTTP disables immich_upload_asset_from_path and filesystem CSV exports by
default, returning an error before accessing local files. With
IMMICH_MCP_HTTP_LOCAL_FILES=true, trusted clients can upload files confined to
IMMICH_UPLOAD_BASE_DIR and create CSV exports at arbitrary writable paths.
Both operations still require IMMICH_ALLOW_WRITES=true. Stdio uses the same
upload confinement and write gates.

Keep the default loopback binding for local clients. Remote access requires a
trusted TLS proxy or tunnel and network access controls. This listener provides
no TLS, OAuth, or browser CORS access. Host must be the bound host or a loopback
alias. A supplied Origin must be an HTTP or HTTPS loopback origin. Preserve an
allowed Host header through a proxy. A wildcard bind does not allow arbitrary
Host headers.

Claude Code

Configure an HTTP entry under mcpServers:

{
  "mcpServers": {
    "immich": {
      "type": "http",
      "url": "http://localhost:3112/mcp",
      "headersHelper": "/path/to/helper IMMICH_MCP_HTTP_TOKEN"
    }
  }
}

The executable helper reads the named variable from its environment or a secret
store and prints {"Authorization":"Bearer ..."} to stdout. Keep the token out
of the config and logs.

Codex

[mcp_servers.immich]
url = "http://localhost:3112/mcp"
bearer_token_env_var = "IMMICH_MCP_HTTP_TOKEN"

Set the token in the client's environment. Upstream credentials stay on the
server. See the example user service.
Create its EnvironmentFile with mode 0600, containing the upstream config and
HTTP token. Adjust the example installation paths before installing the unit.
The example enables NoNewPrivileges, PrivateTmp, and a 0077 umask.

MCP client config

Copy this into your MCP client. It uses npx -y immich-mcp so there is nothing to install globally:

{
  "mcpServers": {
    "immich-mcp": {
      "command": "npx",
      "args": ["-y", "immich-mcp"],
      "env": {
        "IMMICH_BASE_URL": "https://photos.example.com/api",
        "IMMICH_API_KEY": "YOUR_KEY",
        "IMMICH_ALLOW_WRITES": "false"
      }
    }
  }
}
  • Claude Desktop: add the block above to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows), then restart Claude.

  • Claude Code:

    claude mcp add immich-mcp \
      -e IMMICH_BASE_URL=https://photos.example.com/api \
      -e IMMICH_API_KEY=YOUR_KEY \
      -e IMMICH_ALLOW_WRITES=false \
      -- npx -y immich-mcp
    

    Add --scope user to make it available from any directory.

  • OpenClaw: add the same command / args / env under mcps.entries.immich-mcp in ~/.openclaw/openclaw.json, then systemctl --user restart openclaw-gateway and openclaw mcp list to confirm.

  • Codex CLI: add a [mcp_servers.immich-mcp] block to ~/.codex/config.toml:

    [mcp_servers.immich-mcp]
    command = "npx"
    args = ["-y", "immich-mcp"]
    env = { IMMICH_BASE_URL = "https://photos.example.com/api", IMMICH_API_KEY = "YOUR_KEY", IMMICH_ALLOW_WRITES = "false" }
    

Prefer a global install or a source checkout? See Install.

Tools

74 tools across 16 domains. Tools marked (requires confirm: true) are destructive and refuse to run without an explicit confirm flag on the call; all write and delete tools additionally require IMMICH_ALLOW_WRITES=true.

System (5)

  • immich_ping - verify connectivity, return server pong
  • immich_get_server_info - server config (login page, OAuth, theme)
  • immich_get_server_statistics - photo, video, and user counts plus per-user storage
  • immich_get_capabilities - enabled features (search, ML, OAuth)
  • immich_get_storage - storage used, available, total, and template

Assets (11)

  • immich_list_assets - paginated list/search with filters (favorite, archived, date, type, person, album, tag)
  • immich_get_asset - full metadata for one asset
  • immich_get_asset_exif - EXIF / IPTC block for an asset
  • immich_get_asset_statistics - per-user image and video counts
  • immich_download_asset_original - Immich URL path for the original file
  • immich_download_asset_thumbnail - Immich URL path for the thumbnail
  • immich_upload_asset_from_path - upload a local file (confined to IMMICH_UPLOAD_BASE_DIR; refused when unset)
  • immich_update_asset - description, favorite, archive, rating, date, geotag
  • immich_bulk_update_assets - bulk favorite / archive / visibility (requires confirm: true)
  • immich_delete_asset - soft delete (trash) by default; permanent: true bypasses trash (permanent requires confirm: true)
  • immich_restore_from_trash - restore previously trashed assets

Search (3)

  • immich_search_smart - CLIP / semantic search by natural-language query
  • immich_search_metadata - structured search (date, location, camera, people, tags, albums)
  • immich_search_explore - random sample for discovery / "explore" lanes

Albums (8)

  • immich_list_albums
  • immich_get_album
  • immich_get_album_statistics
  • immich_create_album
  • immich_update_album - rename, set cover, set description
  • immich_add_assets_to_album
  • immich_remove_assets_from_album
  • immich_delete_album - assets are NOT deleted (requires confirm: true)

Album flows (1)

  • immich_search_then_album - run a smart or metadata search, then create an album from the matches (writes-gated)

People (7)

  • immich_list_people
  • immich_get_person
  • immich_get_person_assets - photos and videos a face appears in
  • immich_update_person - name, birthdate, visibility, favorite, feature face
  • immich_hide_person - exclude from default lists without deleting
  • immich_merge_people - fold duplicate face clusters into one (requires confirm: true)
  • immich_suggest_face_names - top unnamed people by face count, for triage

Tags (7)

  • immich_list_tags
  • immich_get_tag
  • immich_create_tag
  • immich_update_tag - rename or recolor
  • immich_delete_tag (requires confirm: true)
  • immich_add_tag_to_assets
  • immich_remove_tag_from_assets

Shared links (5)

  • immich_list_shared_links
  • immich_get_shared_link
  • immich_create_shared_link
  • immich_update_shared_link
  • immich_delete_shared_link (requires confirm: true)

Activities (4)

  • immich_list_activities - comments and likes on albums or assets
  • immich_get_activity_statistics
  • immich_create_activity
  • immich_delete_activity (requires confirm: true)

Memories (2)

  • immich_list_memories - memory lanes ("years ago", etc.)
  • immich_get_memory

Memory flows (2)

  • immich_memories_today - today's "X years ago" lanes, chat-formatted
  • immich_daily_digest - server stats + today's memories + recent uploads as a markdown drop

Duplicates (2)

  • immich_list_duplicates - duplicate groups detected by Immich's hashing pass
  • immich_resolve_duplicates - keep[] / discard[], dry-run by default (delete: true + confirm: true to remove)

Duplicate flows (8)

  • immich_categorize_duplicates - bin duplicate groups (checksum-exact, name-size, resolution variants, bursts, edits)
  • immich_find_byte_dupes - ready-to-trash candidates with a safetyMode (strict-checksum default)
  • immich_resolve_with_keep_strategy - end-to-end dedupe, dry-run by default, album-aware
  • immich_explain_duplicate_group - per-asset detail and a recommended keeper with rationale
  • immich_find_clip_dupes - visual-but-not-byte-identical CLIP-grouped pairs (read-only)
  • immich_compare_assets - side-by-side metadata diff of 2-10 assets with a recommendation
  • immich_audit_active - reclaimable duplicate candidates still in the active library
  • immich_audit_trash - cross-check trashed assets against the active library for orphans

Stacks (4)

  • immich_list_stacks - stack groups (motion photos, bracketed shots, RAW + JPEG pairs)
  • immich_create_stack
  • immich_update_stack - reassign the primary asset
  • immich_delete_stack - assets stay (requires confirm: true)

Trash (3)

  • immich_list_trash - paginated trashed assets, scoped to trash
  • immich_restore_by_query - restore trashed assets matching a filter (no filter requires confirm: true)
  • immich_empty_trash - permanently delete EVERYTHING in trash, NOT REVERSIBLE (requires confirm: true)

Jobs (2)

  • immich_list_jobs - queue status for background jobs (thumbnails, ML, metadata, sidecar)
  • immich_run_job - send a command to a background job (destructive commands require confirm: true)

Configuration

Set these environment variables in your shell or MCP client config:

Variable Required Default Description
IMMICH_BASE_URL yes - Base URL of your Immich API, e.g. https://photos.example.com/api (or http://192.0.2.10:2283/api for a LAN host).
IMMICH_API_KEY yes - API key from Account Settings > API Keys in the Immich web UI.
IMMICH_ALLOW_WRITES no false Set to true to expose write and delete tools. Reads always work.
IMMICH_VERIFY_SSL no true Set to false to accept self-signed certs. The relaxed TLS check is scoped to the Immich client only (a dedicated request dispatcher); it does not disable certificate validation process-wide.
IMMICH_UPLOAD_BASE_DIR no - Absolute directory that immich_upload_asset_from_path is confined to. When unset, path-based upload is refused. The directory must exist at startup. Files must resolve (after following symlinks) inside this directory and must be regular files. Path uploads currently require Linux with /proc/self/fd to verify the opened file remains inside the directory. Other platforms refuse path uploads rather than relying on pathname checks that can race.

Getting an API key

  1. Log into Immich.
  2. Account Settings > API Keys > New API Key.
  3. Name it (e.g. mcp) and copy the value.

CLI

immichctrl is the primary operator interface for shells, cron, and CI. It shares the @immich/sdk core with the MCP adapter and reads the same IMMICH_BASE_URL / IMMICH_API_KEY env config. It exposes only the read tools (server, library, and search lookups); every write, delete, upload, and job-control tool stays in the MCP surface behind the IMMICH_ALLOW_WRITES gate and is unreachable from the CLI.

npm exec --yes --package immich-mcp -- immichctrl ping
# or, installed globally:
immichctrl ping
immichctrl server stats
immichctrl storage
immichctrl capabilities
immichctrl albums list
immichctrl albums get 00000000-0000-0000-0000-000000000001
immichctrl assets list --type image --favorite --size 20
immichctrl assets stats
immichctrl people list --with-hidden
immichctrl tags list
immichctrl duplicates
immichctrl jobs
immichctrl memories --saved
immichctrl search metadata --city Madrid --type image
immichctrl search smart "sunset over the ocean"
immichctrl server stats --json        # raw JSON for piping

Run immichctrl help for the full command and flag list. --json emits raw JSON instead of the concise human-readable summary. Exit codes: 0 success, 1 runtime error (Immich unreachable / call failed), 2 usage error (unknown command/flag or bad value).

Point IMMICH_BASE_URL at your Immich API, e.g. https://photos.example.com/api (or http://192.0.2.10:2283/api for a LAN host).

Starting the MCP adapter

immichctrl mcp (or the back-compat immich-mcp bin) starts the stdio MCP adapter. If a launcher referenced the file path dist/index.js directly, it keeps working; new launchers can point at dist/mcp-bin.js (or dist/cli.js mcp). Launchers that use the immich-mcp bin name need no change.

Example prompts

Show me memories from this week.

Calls immich_memories_today / immich_list_memories and filters by the current week.

Find duplicate photos and tell me which to delete (don't delete yet).

Calls immich_categorize_duplicates / immich_list_duplicates and returns clusters as a dry run, without resolving anything.

Group these motion photos into a stack.

Calls immich_create_stack with the asset IDs and a primary pick.

Make an album of every beach photo from last August.

Calls immich_search_then_album to search and create the album in one writes-gated step.

Safety model

immichctrl and its MCP adapter are designed to be safe to hand to automation:

  • Reads are always allowed. Writes are opt-in. Write and delete tools only register when IMMICH_ALLOW_WRITES=true.
  • Destructive calls require an explicit confirm: true. Bulk updates, permanent deletes, merges, emptying trash, and similar refuse to run otherwise, even with writes enabled.
  • Dry-run by default for dedupe. Resolution tools report what they would do before they touch anything.
  • Path-based upload is confined. immich_upload_asset_from_path only reads inside IMMICH_UPLOAD_BASE_DIR (after resolving symlinks), and is refused entirely when that variable is unset.
  • Relaxed TLS is scoped. IMMICH_VERIFY_SSL=false only relaxes the Immich client's dispatcher; it does not weaken certificate validation for the rest of the process.

Why not the other options?

  • The Immich web UI is built for clicking through a grid. It is great for browsing and awkward for repeatable "do X across thousands of photos" operator workflows.
  • The Immich CLI uploads and manages assets from scripts, but it is not an MCP adapter and an LLM cannot call it as typed tools. immichctrl focuses on operator reads, while immichctrl mcp and immich-mcp provide the MCP tool-call surface for an agent.
  • Other Immich MCP servers tend to cover the basics (browse, search, albums). This one is broader: 74 tools spanning memories, motion-photo stacks, checksum-safe duplicate resolution, trash auditing, and job control, with a two-tier write-protection model built in.
  • Writing your own glue around the Immich REST API works, but you would re-implement schema validation, pagination, write-gating, confirmation guards, and the dedupe safety logic that this server already ships and tests.

What this package is not

  • It is not a replacement for Immich. You still run your own Immich server; this connects an AI client to it.
  • It is not a hosted service. The CLI runs locally, and the MCP adapter runs locally on stdio when launched by your MCP client. Nothing is sent anywhere except to the Immich server you point it at.
  • It is not a photo editor or an ML model. It calls Immich's existing search, recognition, and dedup features; it does not run its own.
  • It does not delete or modify anything unless you set IMMICH_ALLOW_WRITES=true, and the destructive tools still demand a per-call confirm: true.
  • It is not an official Immich project. It is a community operator CLI and MCP adapter that uses the public Immich API.

License

MIT - see LICENSE.


Part of Lidless Labs · the eye does not close

Homelab: proxmox-mcp · adguardctrl · jellyctrl · proxguard

All tools · Lidless Labs on GitHub

Yorumlar (0)

Sonuc bulunamadi