Skip to main content
Glama
robworks-code

icloud-mcp

README.md
# icloud-mcp

MCP server for iCloud Drive. It talks to iCloud directly, so it can list, read
and write files whether or not they have been synced to this machine. When a
full copy of a file does exist in the local iCloud Drive folder, reads use it
and skip the network.

## How it decides

| Operation | Where it goes |
| --- | --- |
| list, info, search | iCloud (the source of truth). Each entry carries a `local` field: `hydrated`, `placeholder`, or `absent`. |
| read_file, download | A hydrated local copy if there is one, otherwise streamed from iCloud. |
| upload, write_file, mkdir, rename, move, trash, restore | Always iCloud, so every device sees the change at once. |

If the saved session stops working, reads of hydrated local files still succeed
(with a `warning`); everything else returns one error telling you to sign in again.

Paths are forward-slash and relative to the Drive root, for example
`Documents/notes.txt`. An empty path is the root. `..` is rejected.

## Tools

| Tool | Purpose |
| --- | --- |
| `icloud_status` | Apple ID in use, whether the session works, local folder path |
| `icloud_list` | List a folder |
| `icloud_info` | Metadata for one item |
| `icloud_search` | Name search under a folder (substring, or glob with `*` `?` `[`) |
| `icloud_read_file` | Read a file as text, capped per call, page with `offset` |
| `icloud_download` | Save a file to a local path |
| `icloud_upload` | Upload a local file into a folder |
| `icloud_write_file` | Create a text file from a string |
| `icloud_mkdir` | Create a folder |
| `icloud_rename` | Rename in place |
| `icloud_move` | Move into another folder |
| `icloud_trash` | Move to the iCloud trash |
| `icloud_list_trash` | List the trash |
| `icloud_restore` | Restore from the trash by name |

Nothing is deleted permanently.

## Setup

Requires Python 3.12+ and [uv](https://docs.astral.sh/uv/).

Sign in once at a terminal. The password and 2FA code are typed there and never
stored; only Apple's session cookies are kept, under `~/.icloud-session`.

```
uv run icloud-mcp login
uv run icloud-mcp status
```

### Claude Code plugin

```
claude plugin marketplace add robworks-code/robworks-claude-code-plugins
claude plugin install icloud-mcp@robworks-claude-code-plugins
```

### Manual registration

```
claude mcp add icloud-mcp -- uv run --project /path/to/icloud-mcp icloud-mcp serve
```

## Configuration

| Variable | Default | Meaning |
| --- | --- | --- |
| `ICLOUD_APPLE_ID` | the ID saved by `login` | Apple ID to use |
| `ICLOUD_SESSION_DIR` | `~/.icloud-session` | Where session cookies live |
| `ICLOUD_LOCAL_ROOT` | `%USERPROFILE%\iCloudDrive` on Windows, `~/Library/Mobile Documents/com~apple~CloudDocs` on macOS | Local sync folder |
| `ICLOUD_MAX_READ_BYTES` | `200000` | Cap for one `icloud_read_file` call |

## Development

```
scripts/check.sh          # ruff + unit tests (PowerShell: scripts/check.ps1)
scripts/check.sh --live   # also runs a round-trip against the real account in _icloud-mcp-test
```

The unit tests use an in-memory stand-in for the Drive, so they need no account.