Atlas / MCP servers / drolosoft / Immich Photo Manager

Immich Photo ManagerBLOCK

mcp/drolosoft/immich-photo-manager

MCP server and Claude Code plugin for self-hosted Immich: CLIP and OCR search, geographic albums, duplicates, people and faces, metadata repair, PDF photobooks. 94 tools, tested live on Immich 2.x and 3.x.

Verdict
BLOCK
Grade
D
Trust score
69 /100
Exposed tools
94 59r · 22w · 13d
Transport
stdio · streamable-http
License
MIT
Stars
52
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

immich-photo-manager

MCP server for intelligent photo management with [Immich](https://immich.app): your self-hosted library, understood.
An unofficial community plugin by Drolosoft. It is not affiliated with, sponsored by or endorsed by Immich or FUTO; "Immich" is their name and is used here only to say which server the plugin works with. It talks to your Immich server through its public API.

If your [Immic

Read from source at commit 3ce653a10a01OBSERVED · 2026-10-08
Advertisement
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code (pypi)
claude mcp add immich-photo-manager --env IMMICH_API_KEY=${IMMICH_API_KEY} --env IMMICH_API_KEY=${IMMICH_API_KEY} -- uvx immich-photo-manager==2.0.13
claude-code (oci)
claude mcp add immich-photo-manager:2.0.13 --env IMMICH_API_KEY=${IMMICH_API_KEY} --env IMMICH_API_KEY=${IMMICH_API_KEY} -- docker run -i --rm ghcr.io/drolosoft/immich-photo-manager:2.0.13:None
03

Exposed tools (94)

59 read · 22 write · 13 destructive. Blast radius: 13 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.

ToolRiskDescription
add_assets_to_albumwriteAdd existing assets to an album. Use this to curate albums from search results
clear_asset_notesdestructiveForget the plugin
create_activitywritePost a comment (or a like) on a shared album or on one asset in it.
create_albumwriteCreate a new album, optionally pre-populated with assets. Use this to organize
create_memorywriteCreate an
create_partnerwriteShare this account
create_shared_linkwriteCreate a public shared link for an album, making it accessible via URL without
create_stackwriteGroup near-identical assets (a burst, retries of the same shot) into one
create_tagwriteCreate a new tag for categorizing assets. Use list_tags first to avoid duplicates.
delete_activitydestructiveRemove one comment or like. Side effect: deletes it for everyone.
delete_albumdestructiveDelete an album container. The photos inside are NOT deleted — they remain in
delete_assetsdestructiveDelete assets (soft-delete to trash or permanent). Use this to remove unwanted
delete_memorydestructiveDelete a memory. The photos stay in the library — only the memory entry
delete_shared_linkdestructiveDelete (revoke) a shared link, making the public URL immediately inaccessible.
delete_stackdestructiveDissolve a stack. The assets are NOT deleted — they simply show as
delete_tagdestructiveDelete a tag and remove it from all assets. The assets themselves are unaffected.
download_archivereadDownload an album or a selection as one zip of the original files, written
empty_trashdestructivePermanently delete ALL assets currently in trash. DESTRUCTIVE and IRREVERSIBLE.
export_pdfreadBuild a PDF (cover, index, places, one section per asset) from an album or a
get_albumreadGet full details for a specific album including all its asset IDs. Use this to
get_album_imagesreadGet an album
get_album_thumbnailsreadGet base64-encoded thumbnails for photos in an album. Use this to generate visual
get_asset_facesreadGet all detected faces in a photo with their person assignments. Use this to see
get_asset_imagereadGet a single asset
get_asset_inforeadGet full metadata for a single asset. Use this when you need EXIF details,
get_asset_notesreadThe plugin
get_asset_thumbnailreadGet a base64-encoded thumbnail image for a single asset. Use this to visually
get_assets_notesreadWhich of these assets already carry notes, and their last verdict — the
get_calendar_heatmapreadHow many photos per day, over a date range — the data behind a calendar
get_capabilitiesreadWhat this Immich server can do: version, feature flags and known quirks.
get_connection_inforeadReturn the Immich base URL and a masked API key. Use this to populate gallery
get_download_inforeadHow big the zip of an album or selection would be, BEFORE building it.
get_duplicatesreadGet ML-detected duplicate asset groups (same image stored more than once). Use this
get_export_previewreadList what export_pdf would include (id, type, filename, date, place, people,
get_images_batchreadGet thumbnails for arbitrary asset IDs as image blocks for inline visual
get_map_markersreadGet GPS map markers for all geotagged assets. Use this to discover where photos
get_personreadGet full details for a specific person including name, birth date, and photo count.
get_person_thumbnailreadGet a base64-encoded face crop thumbnail for a person. Use this to visually
get_server_versionreadGet the Immich server version. Use this to check compatibility or report
get_shared_linkreadGet full details of a shared link including permissions, expiry, and linked assets.
get_stackreadOne stack with its assets. Use this after list_stacks to see everything a
get_statisticsreadGet library statistics. Use this for a quick overview of library size
get_tagreadGet details for a specific tag. Use this to inspect a tag
get_thumbnails_batchreadGet base64-encoded thumbnails for arbitrary asset IDs without needing an album.
get_timeline_bucketreadThe assets of one month bucket from get_timeline_buckets. Use the two tools
get_timeline_bucketsreadMonth-by-month map of the library: one bucket per month with its asset count.
get_video_framesreadGet frames of a video as image blocks, to
get_video_frames_jsonreadFrames of a video as base64 JPEG with timestamps, for HTML galleries and
list_activitiesreadComments and likes on a shared album, newest context included. Use this to
list_albumsreadList all albums in the library with summary info. Use this to discover existing
list_assetsreadList assets with simple filters (no search query needed). Use this to browse
list_memoriesreadList memories — Immich
list_partnersreadWho shares their library with this account, and who this account shares
list_peoplereadList all recognized people (face clusters) in the library. Use this to browse
list_shared_linksreadList all shared links (public gallery URLs). Use this to see what
list_stacksreadList every stack in the library. Use this to see what is already grouped
list_tagsreadList all tags in the library. Use this to discover existing tags before creating
list_usersreadThe users visible on this Immich server. Use this to find the id that
merge_peoplewriteMerge multiple person clusters into one. Use this when the same real person has
pingreadCheck Immich server connectivity. Use this to verify the server is reachable
reassign_facereadReassign a detected face to a different person. Use this to correct face recognition
record_actionreadRemember something the plugin did to assets and why, for audit or undo:
remove_assets_from_albumdestructiveRemove assets from an album without deleting them. The photos remain in the
remove_partnerdestructiveStop sharing this account
resolve_duplicatesreadResolve duplicate groups by choosing which assets to keep and which to trash.
restore_assetsreadRestore specific assets from trash back to the active library. Use this to
restore_trashreadRestore ALL trashed assets back to the library. Use this to undo an accidental
reverse_geocodereadResolve GPS coordinates to a place name using Immich
revert_asset_editsdestructiveRemove all non-destructive edits (rotation, crop, mirror) from assets, restoring
review_assetsreadRemember a review verdict on assets, with the reason, so a later session
rotate_assetswriteApply a non-destructive clockwise rotation to one or more assets. Use this to
search_citiesreadEvery city that appears in the library, one representative asset each.
search_explorereadOverview of what the library contains, grouped by explore field: one
search_large_assetsreadThe biggest files in the library, largest first. Use this to find what is
search_metadatareadSearch assets by EXIF metadata fields. Use this when you know specific criteria
search_peoplereadSearch for people by name (partial match). Use this when you know the person
search_placesreadLook a place name up in Immich
search_randomreadRandom assets from the library, optionally filtered. Use this for sampling —
search_smartreadAI-powered visual search using CLIP embeddings. Use this when describing what a
search_statisticsreadCount how many assets match a filter WITHOUT fetching them. Use this instead
search_suggestionsreadDistinct values present in the library for one field — the exact spellings
tag_assetswriteApply a tag to multiple assets at once. Use this to bulk-categorize photos
untag_assetsdestructiveRemove a tag from multiple assets. The tag itself remains; only the association is
update_albumwriteUpdate an album
update_asset_metadatawriteUpdate metadata fields on a specific asset. Use this to fix dates, correct GPS,
update_assets_metadatawriteUpdate the same metadata fields on many assets in ONE call — the whole
update_credentialswriteUpdate the Immich connection credentials. Use this when the API key has been
update_memorywriteUpdate a memory: save it for later, move its date, or mark it seen.
update_partnerwriteShow or hide a partner
update_personwriteUpdate a person
update_shared_linkwriteUpdate a shared link
update_stackwriteChange which asset fronts a stack (the one the library shows). Side effect:
update_tagwriteUpdate a tag
upload_assetwriteUpload a local photo or video file to Immich. Use this to ingest new media into
04

Trust audit

BLOCKgrade D · trust 69/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeWARN
L2Instruction surface (what it tells the agent)FAIL
L3Class-specific surfaceWARN
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (2 observation(s))
Network
declared (6 observation(s))
Shell
none-observed
Dependencies
not all pinned
Secrets in source
found

Findings (25)

HIGHPrompt injection · prompt.hide_from_user · CWE-94, CWE-1427
skills/travel-map/SKILL.md:178
Do not tell the user to open the file directly. OpenStreetMap answers a page opened from disk
Why it matters. asks the agent to act without the user's knowledge
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
Dockerfile:56
python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8626/health', timeout=4)"
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
commands/cleanup.md:18
> 1. Your Immich server URL (e.g., `http://192.168.1.100:2283`)
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
commands/create-album.md:18
> 1. Your Immich server URL (e.g., `http://192.168.1.100:2283`)
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
commands/immich-status.md:17
> 1. Your Immich server URL (e.g., `http://192.168.1.100:2283`)
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
tests/fake_immich.py:23
API_KEY = "fake-immich-key-0123456789abcdef"
MEDIUMFilesystem / path · mcp.destructive_tools · CWE-22, CWE-59
clear_asset_notes, delete_activity, delete_album, delete_assets, delete_memory, delete_shared_link, delete_stack, delete_tag, empty_trash, remove_assets_from_album, remove_partner, revert_asset_edits,
Why it matters. 13 tool(s) can delete or overwrite
Fix. prefer a read-only mode or scoped tokens; the page states the blast radius
LOWInventory / provenance · inv.hidden_file · CWE-1104
.mcp.http.json.example
.mcp.http.json.example
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWInventory / provenance · inv.hidden_file · CWE-1104
.mcp.json.example
.mcp.json.example
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWInventory / provenance · inv.hidden_file · CWE-1104
.plugin-scanner.toml
.plugin-scanner.toml
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
.github/workflows/docker.yml:56
if curl -fsS http://127.0.0.1:8626/health; then echo; exit 0; fi
LOWObfuscation / stealth · obf.base64_blob · CWE-506, CWE-94
assets/viewer-template.html:18
@font-face{font-family:'Caveat';font-style:normal;font-weight:400 700;font-display:swap;src:url(data:font/woff2;base64,d09GMgABAAAAASNMABIAAAACdVAAASLbAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoFRG4GGchyXOD9IV
LOWObfuscation / stealth · obf.base64_blob · CWE-506, CWE-94
assets/viewer-template.html:85
.hero-bg{position:absolute;inset:0;background-image:url('data:image/webp;base64,UklGRrg6AABXRUJQVlA4WAoAAAAgAAAATAEA+QAASUNDUOABAAAAAAHgbGNtcwQgAABtbnRyUkdCIFhZWiAH4gADABQACQAOAB1hY3NwTVNGVAAAAABzYXdz
LOWObfuscation / stealth · obf.base64_blob · CWE-506, CWE-94
assets/viewer-template.html:301
<img class="header-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAACXBIWXMAAAsTAAALEwEAmpwYAAAk+UlEQVR4nO2dd7gcZ33vP++Undl+uk6Rjnq1ZMkW9tgU2xtSTIdLKsEBY0pYUjEOJRdIcglc
LOWObfuscation / stealth · obf.base64_blob · CWE-506, CWE-94
assets/viewer-template.html:400
<img class="footer-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAACXBIWXMAAAsTAAALEwEAmpwYAAAk+UlEQVR4nO2dd7gcZ33vP++Undl+uk6Rjnq1ZMkW9tgU2xtSTIdLKsEBY0pYUjEOJRdIcglc
LOWObfuscation / stealth · obf.decode_call · CWE-506, CWE-94
scripts/smoke-both-eras.py:82
decodable = all(len(base64.b64decode(t["data"])) > 50 for t in thumbs)
LOWObfuscation / stealth · obf.decode_call · CWE-506, CWE-94
scripts/smoke-both-eras.py:89
report("get_asset_image (image block)", img is not None and len(base64.b64decode(img.data)) > 50,
LOWObfuscation / stealth · obf.decode_call · CWE-506, CWE-94
src/immich_mcp_server/tools/_common.py:70
raw = base64.b64decode(data) if data else b""
LOWObfuscation / stealth · obf.decode_call · CWE-506, CWE-94
src/immich_mcp_server/tools/export.py:162
entry.images = [base64.b64decode(frame["data"]) for frame in result["frames"]]
LOWObfuscation / stealth · obf.decode_call · CWE-506, CWE-94
src/immich_mcp_server/tools/export.py:196
return base64.b64decode(thumb["data"])
LOWObfuscation / stealth · obf.decode_then_exec · CWE-506, CWE-94
tests/live/mcp_harness.py:340
b64decode( ... subprocess.
Why it matters. decodes a payload and executes it
LOWObfuscation / stealth · obf.decode_then_exec · CWE-506, CWE-94
tests/test_video_frames.py:304
b64decode( ... subprocess.
Why it matters. decodes a payload and executes it
LOWSupply chain · supply.unpinned · CWE-829, CWE-1357
src/requirements.txt
mcp, httpx, uvicorn, av, fpdf2
Why it matters. 5 requirement(s) not pinned with ==
Fix. pin exact versions
LOWPrompt injection · prompt.transfer_instruction · CWE-94, CWE-1427
CHANGELOG.md:21
- **The README lists everything the plugin runs, sends and fetches**: the local server process, the calls to your Immich, the map tiles of a PDF report, what the generated pages load in the browser (G
Why it matters. an instruction to move sensitive data to an outside destination
Fix. remove; a skill never needs the user's secrets off the machine
LOWPrompt injection · prompt.transfer_instruction · CWE-94, CWE-1427
README.md:114
A PDF report follows the same rule: `export_pdf` writes the file to disk on the machine running the server, and it is not sent anywhere unless you pass `return_base64=true`. The file goes where `outpu
Why it matters. an instruction to move sensitive data to an outside destination
Fix. remove; a skill never needs the user's secrets off the machine

Gates applied: instruction_override, no_behavioural_pass.

Audited 2026-10-08 · audit v0.4.1 · source sha 3ce653a10a01full audit observations/trust-audit/mcp-server/drolosoft__immich-photo-manager.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-083ce653a10a01BLOCKD69first audit
06

Questions

What is the Immich Photo Manager MCP server?

MCP server and Claude Code plugin for self-hosted Immich: CLIP and OCR search, geographic albums, duplicates, people and faces, metadata repair, PDF photobooks. 94 tools, tested live on Immich 2.x and 3.x.

What tools does Immich Photo Manager expose?

94 in total: 59 read-only, 22 that write, and 13 that can delete or overwrite (clear_asset_notes, delete_activity, delete_album, delete_assets, delete_memory). Every one is listed on this page with its risk.

Is Immich Photo Manager safe to connect to an agent?

No — not without reading the findings first. The audit graded it D (69/100) and found 1 critical or high issue in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 13 of its tools can destroy data, so scope the token you give it to what you actually need.

What credentials does Immich Photo Manager need?

It reads IMMICH_API_KEY and IMMICH_KEY from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does Immich Photo Manager run?

It speaks stdio and streamable-http, so it runs as a local process your client starts. It is published on npm as immich-mcp-crosscheck-ts-client at 2.0.13.

How current is this page?

The grade is for one exact copy of the source (3ce653a10a01), read on 2026-10-08. The repository is watched and re-audited when it changes.

Advertisement