npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@thenavidm/apple-photos-mcp-cli

v2.0.0

Published

Apple Photos MCP server and CLI for Claude Code and AI agents. 13 tools to search, look at, organise and export your own Photos library, entirely on your Mac.

Readme

Apple Photos MCP + CLI

npm License YouTube X LinkedIn

Apple Photos MCP server and CLI for Claude Code, Codex and AI agents. 13 tools to search, look at, organise and export your own library, entirely on your Mac.

Give any AI agent real access to your own Apple Photos library, so it can find, see, organise and export your photos instead of guessing.

Built and maintained by Navid Moazzez. Built on Slipway, which turns one definition of each tool into the MCP server and the CLI.

Everything runs on your Mac. There is no backend.

Two ways to use it

Command line

apple-photos-cli in your terminal, for scripting, cron, pipes, or a quick question without opening anything:

apple-photos-cli                                    # every command, one line each
apple-photos-cli library-stats --json               # real totals, one call
apple-photos-cli search-photos "sunset" --limit 5 --screenshots exclude
apple-photos-cli photo-info --refs IMG_2073.MOV
apple-photos-cli export-originals --refs <uuid> --directory ./out
apple-photos-cli which save my photos to disk       # find the command for a task
apple-photos-cli <command> --help                   # what any command takes

--json gives JSON, --compact puts it on one line, --select total,videos keeps only the fields you name, and errors are JSON on stderr whichever you pick. --confirm is the shell spelling of the confirmation archiving requires.

MCP server, for AI agents

apple-photos-mcp is what Claude Code, Claude Desktop, Cursor and the rest launch. You never run it by hand:

claude mcp add apple-photos -- npx -y @thenavidm/apple-photos-mcp-cli@latest

Then just ask: "which receipts do I have from Vietnam?"

Which one

| Where you are | What you can reach | |---|---| | An agent that can run shell commands, like Claude Code or Cursor | Both. The CLI is the cheaper one: it costs nothing until you type it | | A terminal, a script, cron or CI | The CLI only. There is no MCP client in a shell |

They are the same program reading the same tool definitions, so anything one can do, the other can. A test asserts they cannot drift.

Features

Every tool is both a command and an MCP tool, with the same name. The command is the tool name with dashes.

| Capability | CLI command | MCP tool | |---|---|---| | Search the whole library | apple-photos-cli search-photos | search_photos | | Actually look at photos | apple-photos-cli look-at-photos | look_at_photos | | Full metadata, camera and lens | apple-photos-cli photo-info | photo_info | | Real totals in one call | apple-photos-cli library-stats | library_stats | | What Apple can search for | apple-photos-cli list-vocabulary | list_vocabulary | | Export originals to disk | apple-photos-cli export-originals | export_originals | | Favourite or unfavourite | apple-photos-cli favorite-photos | favorite_photos | | Title and description | apple-photos-cli set-photo-title / set-photo-description | set_photo_title / set_photo_description | | Keywords and albums | apple-photos-cli add-keywords / add-to-album | add_keywords / add_to_album | | Move into an archive album | apple-photos-cli archive-photos | archive_photos | | Check the setup | apple-photos-cli doctor, or check-setup for the engine's report alone | doctor | | Find the right command | apple-photos-cli which "..." | not a tool |

All 13 with their arguments are in section 6.

Output and exit codes

Results on stdout, errors on stderr as JSON, so one parse handles both.

| Flag | Result | |---|---| | none | pretty JSON | | --json | JSON, always | | --compact | the same JSON on one line | | --select a,b.c | keep only these fields | | --agent | one-line JSON, no prompts and no color, for a script or an agent |

| Code | Means | |---|---| | 0 | it worked | | 1 | something unexpected went wrong | | 2 | it was typed wrong, or a write was refused: a missing flag, a bad value, no --confirm, or read only | | 3 | a photo or album wasn't found | | 4 | macOS refused access: Full Disk Access, or Automation for Photos | | 5 | the engine or Photos failed | | 10 | the engine could not start: install uv, or set APPLE_PHOTOS_PYTHON |

Which surface, and what each costs

Both surfaces are the same program with the same 13 tools. The difference is when the model pays for them. Measured in Claude Code:

| | MCP server | CLI | |---|---|---| | Every message, with every tool loaded | 3,400 tokens | nothing | | Every message, Claude Code's default | 650 tokens | nothing | | When Apple Photos comes up | nothing more, or the tools it picks | 2,500 tokens for SKILL.md, once | | 20 messages with Apple Photos in 1, every tool loaded | 68,000 tokens | 2,500 tokens |

Claude Code's tool search is on by default: it sends only the tool names and the server instructions, and loads a tool's full definition when the model reaches for it. An app that loads every tool up front pays the first line on every message, whether Apple Photos comes up or not. With the skill added, Claude Code also lists its one-line description, about 180 tokens.

To spend less, turn the server off when you are not using it, which in Claude Code is the /mcp panel. APPLE_PHOTOS_READ_ONLY=1 takes the 6 write tools off the list, leaving 7. Or install the CLI and add the server on the days it earns its place.

Measured on 2026-10-05 against 1.1.1, with Claude Code 2.1.286 on Claude Opus 5.5 (one short prompt with and without the server connected, once with ENABLE_TOOL_SEARCH=false and once with the default, the difference read from the API's own usage figures; SKILL.md the same way) and Codex 0.159.3 on gpt-6.1-sol, with an empty home folder and an engine that could not start, so nothing read the library:

| Cost | 1.1.1 | 2.0.0 | | --- | --- | --- | | Claude Code, every tool loaded, every message | 3,843 | 3,402 | | Claude Code's default, tool search, every message | 656 | 654 | | SKILL.md, read once | 2,510 | 2,490 | | Codex over the CLI, one task, median of five | 191,767 | 53,232 | | Codex over MCP, the same task, median of five | 39,915 | 39,959 |

The task was "find the command that exports original photo files to a folder on this Mac, and the flags it requires". In 1.1.1, <command> --help printed the general help, so every run tried seven to ten commands before it found the flags; every 2.0.0 run read the general help and the command's own: two. Over MCP the server's printout was shorter in every 2.0.0 run, and the medians differ by the model's own replies. Other apps and models count tokens a little differently, and tool-list characters divided by four are not API usage.

Contents

| | Section | | |---|---|---| | | Features | Every tool, both surfaces | | | Output and exit codes | What scripts branch on | | 1 | What you can ask it | Real prompts, not features | | 2 | Quick install | One command, no credential | | 3 | Setup | One permission, once | | 4 | Connect your client | Every client, copy and paste | | 5 | Check it worked | doctor | | 6 | Tools | All 13 | | 7 | Working safely | What asks, what does not | | 8 | What Apple Photos actually does | The things that surprise people | | 9 | Your data | What is stored, and where | | 10 | Configuration | Every setting | | 11 | Troubleshooting | When something breaks | | 12 | FAQ | Start here if you are new |

1. What you can ask it 💬

  • Find my photo of that whiteboard from the Bogota trip.
  • Which receipts do I have from Vietnam?
  • Show me videos from Dubai in 2024.
  • Do I have a picture of my passport?
  • How many photos do I actually have, and how many are just screenshots?
  • Pull up the sunset shots from Miami Beach.
  • Add these five to an album called Best of Bali.
  • Export the original of that one to my Desktop.
  • Which places show up most in my library?

The first one is the point. Your library already knows what is in every photo, because Apple ran machine learning across all of it on your device and wrote the results into the library. Photos gives you a search box for that. This gives an agent the entire index, so it can filter, cross-reference and then actually look at the results before answering.

2. Quick install ⚡

macOS, and Node 20 or newer.

npx -y @thenavidm/apple-photos-mcp-cli@latest --version

That is the whole install. npx fetches it on demand, so there is nothing to update later.

The engine underneath is Python, because osxphotos and photoscript are the only libraries that can read a Photos library and both are Python-only. You do not install them: uv fetches them on first run and caches them. If you do not have uv:

curl -LsSf https://astral.sh/uv/install.sh | sh

No account, no API key, no credential. macOS will ask for permission the first time something reads the library.

3. Setup 🔑

There is no login. The only setup is one macOS permission, because your Photos library is protected and an app has to be allowed to read it.

Full Disk Access, once:

  1. Open System Settings.
  2. Go to Privacy & Security, then Full Disk Access.
  3. Click + and add the app that will run the server:
    • Claude Desktop, if you use Claude Desktop.
    • Terminal or iTerm, if you use Claude Code.
    • Cursor, VS Code or Windsurf, if you use one of those.
  4. Make sure its toggle is on.
  5. Quit that app completely and reopen it. Cmd+Q, not just closing the window. The permission is only picked up on a fresh launch.

That is it. Skipping step 5 is the single most common reason this looks broken.

A second permission appears later, only if you organize. The first time a tool changes something, macOS asks whether the app may control Photos. Click OK. If you miss it, it is under Privacy & Security, then Automation.

Have an agent do it

The agent cannot grant the permission for you, because macOS deliberately requires a human. It can do everything either side of it.

Paste this into Claude Code, Cursor, or any agent with terminal access:

Set up apple-photos-mcp for me.

1. Install it and run `doctor`, then tell me exactly what failed.
2. Walk me through granting Full Disk Access one step at a time,
   naming the app I need to add. Stop and wait for me to confirm,
   and remind me to fully quit the app with Cmd+Q afterwards.
3. Run `doctor` again and show me how many photos it can see.
4. Then add it to my MCP client config.

4. Connect your client 🔌

Claude Code

claude mcp add apple-photos -s user \
  -- npx -y @thenavidm/apple-photos-mcp-cli@latest

-s user makes it available in every project rather than just the current one.

Check it registered:

claude mcp list

Claude Desktop

Open Settings, then Developer, then Edit Config. That opens the file in your editor.

| Platform | Path | |---|---| | macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |

open -e ~/Library/Application\ Support/Claude/claude_desktop_config.json

Apple Photos only exists on macOS, so there is no Windows or Linux path here.

If the file is empty or new, paste all of this:

{
  "mcpServers": {
    "apple-photos": {
      "command": "npx",
      "args": ["-y", "@thenavidm/apple-photos-mcp-cli@latest"]
    }
  }
}

If it already has other servers, add only the "apple-photos" block inside the existing "mcpServers" object, and put a comma after the previous server's closing brace. One misplaced comma invalidates the file, and then every server disappears, not just this one.

[!TIP] Claude Desktop does not inherit your shell PATH. If npx is not found, run which npx in a terminal and use that absolute path as "command".

Quit Claude Desktop completely with Cmd+Q and reopen it.

Logs, when you need them:

tail -f ~/Library/Logs/Claude/mcp-server-apple-photos.log

There is also a one-click .mcpb bundle on the releases page, installed through Settings, then Extensions, then Install Extension. It carries the server and the Python engine; uv still fetches the engine's dependencies on first run, because they build pyobjc and only work on macOS.

Cursor

Cursor Settings, then MCP, then Add new global MCP server. That opens ~/.cursor/mcp.json. Same JSON shape as Claude Desktop, same mcpServers key. Save, then click reload next to the server.

For one project instead of globally, use .cursor/mcp.json in that project.

Windsurf

Windsurf Settings, then Cascade, then Model Context Protocol (MCP), then Add Server. That opens ~/.codeium/windsurf/mcp_config.json. Same shape, key mcpServers. Save, then Refresh.

VS Code

.vscode/mcp.json. The key is servers, not mcpServers, and each entry takes a type:

{
  "servers": {
    "apple-photos": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@thenavidm/apple-photos-mcp-cli@latest"]
    }
  }
}

Reload the window: Cmd+Shift+P, then Developer: Reload Window.

Codex CLI

~/.codex/config.toml:

[mcp_servers.apple-photos]
command = "npx"
args = ["-y", "@thenavidm/apple-photos-mcp-cli@latest"]

Gemini CLI

~/.gemini/settings.json, key mcpServers, same shape as Claude Desktop.

Everything else

Any stdio MCP client takes the same two things: the command npx, and the args above.

claude.ai on the web, with a relay

claude.ai runs connectors from Anthropic's cloud, so it cannot start a process on your Mac. That does not make it impossible, it makes it a two-part job.

This package ships stdio only. To reach it from a browser you put a small remote MCP server in front of it, and have a local agent on the Mac poll that server for queued work and post the results back. The cloud half is reachable from claude.ai, the Mac half holds the library, and no port on your machine is ever exposed to the internet.

That relay is not included here. It is a separate deployment with its own hosting and auth, so it is out of scope for a package you install with one command. Everything needed on the Mac side is already in this server.

5. Check it worked 🩺

npx -y @thenavidm/apple-photos-mcp-cli@latest doctor

Or just ask your agent: "run doctor on apple photos".

Healthy output includes a line like:

  ✓ index          37129 assets indexed (35983 with ML labels, 10807 with readable text)

--json prints the same checks as JSON, and apple-photos-cli check-setup prints the engine's own report.

The two things that actually fail:

| It says | Do this | |---|---| | full disk access: permission denied | Section 3, and remember Cmd+Q | | library found: false | Open Photos once, or set APPLE_PHOTOS_LIBRARY |

6. Tools 🛠️

Finding and seeing

| Tool | What it does | |---|---| | search_photos | Search your entire library by look, text, place, person, date | | look_at_photos | Render photos so the agent can actually see them | | photo_info | Everything known about specific items, including text read inside them | | list_vocabulary | The visual words this library knows |

The library itself

| Tool | What it does | |---|---| | library_stats | Totals, albums, named people, how much is iCloud only | | doctor | Diagnose setup. On the CLI it is check-setup, because doctor there runs these checks with the CLI's own |

Organizing

| Tool | What it does | |---|---| | favorite_photos | Heart items, or remove the heart | | add_to_album | Add to an album, creating it if needed | | add_keywords | Add keywords, keeping existing ones | | set_photo_title | Set one item's title | | set_photo_description | Set one item's caption | | archive_photos | Move to an archive album. Needs confirming |

Getting files out

| Tool | What it does | |---|---| | export_originals | Full quality originals to a folder on your Mac |

7. Working safely 🛡️

Organizing works out of the box, because that is the point of the tool. Three things guard it.

Nothing can delete a photo. macOS does not expose scripted deletion to any application, and this server does not try to route around that. archive_photos moves items into an album so they leave your main view, and you empty that album yourself.

archive_photos is the only tool that asks. Over MCP a person approves it: Claude Code (2.1.246 and later) shows its own prompt, and an app that can show forms asks with an approval form whose one box starts unticked. Where an app can do neither, the model's confirm: true still counts, and APPLE_PHOTOS_CONFIRM=model makes it enough everywhere; in a terminal it is --confirm, which --agent never adds. APPLE_PHOTOS_ALLOW_DESTRUCTIVE=0 refuses it, confirmed or not. Everything else it can do is one click to undo in Photos, and requiring confirmation on all of them would just teach a model to pass confirm reflexively, including on the one that matters.

APPLE_PHOTOS_READ_ONLY=1 removes every write tool. They vanish from the tool list rather than erroring when called, because a model cannot call a tool it cannot see. This is the right setting for an agent working unattended.

APPLE_PHOTOS_AUDIT_LOG=~/.apple-photos-mcp/writes.jsonl records one JSON line per attempted write, allowed and blocked alike, with who approved it, then whether it was done or failed.

Every tool carries MCP annotations, so a client can decide what to auto-approve: reads are marked read-only, organizing is marked non-destructive, and archive_photos is marked destructive. Nothing is marked open-world, because nothing here leaves your machine.

On prompt injection: text read out of your own photos, mostly OCR, is content you photographed rather than content a stranger sent you, so the exposure is far smaller than a server that reads a public feed. It is not zero. A screenshot of a web page can contain instructions. READ_ONLY=1 is the real defense for unattended work.

8. What Apple Photos actually does 📸

The part that makes this worth more than the Photos search box.

Apple already indexed everything, on your device. Every photo carries scene labels from a classifier with a closed vocabulary of roughly 1,500 words, the text its OCR read inside the image, a guess at the activity, the venue type, and a reverse geocoded place. None of that needs Photos.app running to read.

Your typed metadata is almost certainly empty. In the 37,129 item library this was built against, 3 items had a title and 3 had keywords. So searching for what you call a photo will fail. Search for what the photo looks like.

The vocabulary is closed, and that is a real limit. Apple knows "Sunset" but not "golden hour". Ask for a word it has never heard of and the response says so in unmatched_terms and suggests words that do exist, rather than quietly returning something that looks like a match. list_vocabulary shows every term it knows.

Text found inside an image is weak evidence. A screenshot full of words will match almost any query if you let it, and about one in five items in a typical library is a screenshot. Matches resting only on OCR are scored down, and screenshots compete at a discount unless you actually asked for a screenshot or a document.

Most of your photos are not on your Mac. iCloud keeps the originals in the cloud and leaves thumbnails behind. In the test library, 36,996 of 37,129 assets had no local original. Previews still work, because they read Apple's cached thumbnails. Exporting an original downloads it first, which is why exporting is slow and looking is not.

Faces only work if you named them. Photos recognizes faces on its own, but they are anonymous until you attach a name in the People album. Searching for a person only finds people you have actually named.

9. Your data 💾

Nothing leaves your Mac. There is no backend, no account, and no telemetry.

| What | Where | Contents | |---|---|---| | Search index | ~/.apple-photos-mcp/index/ | Compressed filenames, dates, labels, places and OCR text. No image data. | | Previews | ~/.apple-photos-mcp/previews/ | Downscaled JPEGs. Safe to delete any time. | | Audit log | Only if you set APPLE_PHOTOS_AUDIT_LOG | One line per attempted write. | | Exports | ~/Downloads/Photos Exports | Only what you explicitly export. |

Delete ~/.apple-photos-mcp/ to clear all of it.

Previews are passed to whichever model you are talking to, exactly like attaching a photo to a chat yourself. That is the purpose of look_at_photos, and it is the only path by which image data leaves your machine.

10. Configuration ⚙️

Every setting is an environment variable, set in your client's env block.

| Variable | Default | What it does | |---|---|---| | APPLE_PHOTOS_READ_ONLY | off | Removes every write tool from the tool list | | APPLE_PHOTOS_ALLOW_DESTRUCTIVE | on | 0 refuses archive_photos, confirmed or not | | APPLE_PHOTOS_CONFIRM | human | model lets confirm: true alone approve an archive over MCP, for an agent with no person to ask | | APPLE_PHOTOS_AUDIT_LOG | off | Path for one JSON line per attempted write | | APPLE_PHOTOS_PYTHON | uv | A Python that has osxphotos and photoscript; uv fetches them on demand when unset | | APPLE_PHOTOS_PYTHONPATH | the copy in this package | Where the engine's package lives | | APPLE_PHOTOS_STARTUP_TIMEOUT_MS | 300000 | How long the engine may take to start, since a cold uv run builds pyobjc | | APPLE_PHOTOS_REQUEST_TIMEOUT_MS | 300000 | How long one call may take | | APPLE_PHOTOS_LIBRARY | last opened | Path to a specific .photoslibrary | | APPLE_PHOTOS_EXPORT_DIR | ~/Downloads/Photos Exports | Default export folder | | APPLE_PHOTOS_PREVIEW_DIR | ~/.apple-photos-mcp/previews | Where previews are cached | | APPLE_PHOTOS_PREVIEW_PX | 640 | Longest edge of a preview | | APPLE_PHOTOS_PREVIEW_MAX | 8 | Most items rendered per look_at_photos call | | APPLE_PHOTOS_WRITE_BATCH_MAX | 100 | Most items a single write may touch | | APPLE_PHOTOS_ARCHIVE_ALBUM | Archived by Claude | Album archive_photos moves items into | | APPLE_PHOTOS_SURFACE | full | search lists three tools that find, describe and run the rest | | APPLE_PHOTOS_TOOL_TIMEOUT_MS | none | Give up on any tool after this long | | APPLE_PHOTOS_HTTP_PORT, APPLE_PHOTOS_HTTP_HOST, APPLE_PHOTOS_HTTP_TOKEN | 8787, 127.0.0.1, none | For --http. Any host but 127.0.0.1 needs the bearer token | | APPLE_PHOTOS_HTTP_ALLOWED_ORIGINS | none | Comma-separated browser origins allowed to call --http; a page from any other site is refused | | APPLE_PHOTOS_DEBUG | 0 | 1 prints debug lines on stderr |

11. Troubleshooting 🔧

Run doctor before guessing. It names which of these it is.

| Symptom | Cause | Fix | |---|---|---| | Permission denied reading the library | No Full Disk Access | Section 3. Quit the app with Cmd+Q, not just the window. | | Server does not appear in the client | Bad JSON, usually a comma | Paste the config into a JSON validator. One bad comma hides every server. | | npx: command not found | The app cannot see your shell PATH | Use the absolute path from which npx | | Write tools are missing | APPLE_PHOTOS_READ_ONLY is set | Unset it and restart the client | | Reads work, writes fail | Photos automation not approved | Approve the popup, or Privacy & Security, then Automation | | First search takes half a minute | Building the index | One time, about 25 seconds for 37,000 items. Cached afterwards. | | A photo has no preview | iCloud only, with no cached thumbnail | Open it once in Photos, or export it | | Search finds nothing for an obvious word | Apple has no such label | Check unmatched_terms in the response, or run list_vocabulary |

12. FAQ ❓

A standard way to give an AI assistant real access to a tool, so it can act rather than guess. You install it once, your assistant gains a set of tools, and it works the same in Claude, Cursor, Codex and anything else that speaks MCP.

apple-photos-cli is the same program as the MCP server, run as commands. AI agents that run commands, like Claude Code, Codex and OpenCode, use it on their own, and you can type the same commands in a terminal, a script or a cron job. Every tool is a command with dashes, so search_photos runs as apple-photos-cli search-photos.

Use the MCP server in an app with no terminal, like Claude Desktop's chat. Use the CLI anywhere commands run: an agent like Claude Code, Codex or OpenCode, a script or a cron job. The MCP server's tools take up context on every message, and the CLI costs nothing until it runs.

The photo app built into every Mac, iPhone and iPad. It stores your photos and videos and, on the device itself, runs machine learning over them to work out what is in each one. That analysis is what this server searches.

You need to run one install command in Terminal and grant one macOS permission. After that you talk to it in plain English. Section 3 has an agent-guided path that walks you through the permission step by step.

No, and nobody. The library is read on your Mac and there is no backend, no account and no telemetry.

The one exception worth knowing: when you ask your assistant to look at a photo, that preview is sent to whichever model you are already chatting with, exactly as if you had attached it yourself. That is what makes "find my photo of X" work.

Photos gives you one search box. This gives an agent the entire index at once, so it can combine things the app cannot: a scene label, a place, a date range and a person in a single query, then look at the results and tell you which one you meant.

It can also act on what it finds. "Find every receipt from Vietnam last year and put them in an album" is one sentence here and a long afternoon in the app.

It cannot delete them at all. macOS does not allow any app to delete photos by script, so there is no delete tool and no way to add one.

The closest thing is archive_photos, which moves items into an album called "Archived by Claude" so they leave your main view. It refuses to run without confirm: true, and you empty that album yourself in Photos. Everything else it can change, favorites, albums, keywords, titles, is one click to undo.

Yes. Set APPLE_PHOTOS_READ_ONLY=1 in your client config and every write tool disappears from the tool list. This is the right setting if an agent is running unattended.

No. It is MIT licensed and it talks to nothing but your own Mac, so there is no API bill and no subscription. Your assistant's own usage is whatever you already pay for it.

It works with any client that runs a local MCP server: Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, Codex CLI, Gemini CLI.

For claude.ai in a browser you need one extra piece. Those connectors run in Anthropic's cloud and cannot start anything on your Mac, so it takes a small remote server that queues the work plus a local agent that carries it out and posts results back. It works, it is just a separate deployment rather than something this package installs for you.

Yes for searching and looking. Apple keeps thumbnails on the Mac even when the full size original is in the cloud, and previews read those, so they are fast.

Exporting a full quality original downloads it first, which is much slower. In the library this was built against, 36,996 of 37,129 assets were iCloud only and every preview still rendered.

The first search builds an index, which takes about 25 seconds for a 37,000 item library. After that it is served from a small cache and searches take about a second. Reading does not involve Photos.app at all, so nothing has to be open.

Delete the server from your client's config, or run claude mcp remove apple-photos in Claude Code. Then delete ~/.apple-photos-mcp/ to remove the index and cached previews. Nothing is left behind, and nothing in your Photos library is changed by removing it.

Questions

Run into a problem or have a question? Open an issue and I will help.

About the author

Navid Moazzez is a leading AI business strategist, and the host of the AI Creator Summit, watched by 100,000+ creators. He helps creators and founders master AI and build their own AI Operating System (AI OS) to automate their business and life. He creates useful free tools, MCP servers and CLIs that creators and founders can use in their own workflows.

Links

If this is useful, star the repo and come say hi on X.

Dependencies

| Package | License | Why | |---|---|---| | Slipway | Apache-2.0 | The MCP server and the CLI from one definition of each tool | | MCP TypeScript SDK | Apache-2.0 | The MCP protocol and its transports, through Slipway | | mcp | MIT | The MCP protocol for the Python engine | | osxphotos | MIT | Reads the Photos library database and Apple's on-device ML metadata | | photoscript | MIT | Drives Photos.app for writes |

License

MIT. Free to use, modify, and share.

Not affiliated with, endorsed by, or connected to Apple Inc. Apple, macOS, Photos and iCloud are trademarks of Apple Inc.


© 2026 Navid Media. Made with ❤️ by Navid Moazzez.