apple-icloud-mcp 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "chrischall",
3
+ "owner": {
4
+ "name": "Chris Chall",
5
+ "email": "chris.c.hall@gmail.com"
6
+ },
7
+ "metadata": {
8
+ "description": "Unofficial Apple Music, iCloud Calendar/Contacts/Mail, Apple Maps and WeatherKit tools for Claude Code",
9
+ "version": "0.0.0"
10
+ },
11
+ "plugins": [
12
+ {
13
+ "name": "apple-icloud",
14
+ "displayName": "Apple iCloud",
15
+ "source": "./",
16
+ "description": "Apple Music playlists and library, iCloud Calendar, Contacts and Mail, Apple Maps, WeatherKit and iTunes search for Claude via MCP — runs anywhere, no Mac required. Unofficial; not affiliated with Apple.",
17
+ "version": "0.0.0",
18
+ "author": {
19
+ "name": "Chris Chall"
20
+ },
21
+ "homepage": "https://github.com/chrischall/apple-icloud-mcp",
22
+ "repository": "https://github.com/chrischall/apple-icloud-mcp",
23
+ "license": "MIT",
24
+ "keywords": [
25
+ "apple",
26
+ "apple-music",
27
+ "icloud",
28
+ "calendar",
29
+ "contacts",
30
+ "mail",
31
+ "maps",
32
+ "weather",
33
+ "mcp"
34
+ ],
35
+ "category": "productivity"
36
+ }
37
+ ]
38
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "apple-icloud",
3
+ "displayName": "Apple iCloud",
4
+ "version": "0.0.0",
5
+ "description": "Apple Music playlists and library, iCloud Calendar, Contacts and Mail, Apple Maps, WeatherKit and iTunes search for Claude via MCP — runs anywhere, no Mac required. Unofficial; not affiliated with Apple.",
6
+ "author": {
7
+ "name": "Chris Chall"
8
+ },
9
+ "homepage": "https://github.com/chrischall/apple-icloud-mcp",
10
+ "repository": "https://github.com/chrischall/apple-icloud-mcp",
11
+ "license": "MIT",
12
+ "keywords": [
13
+ "apple",
14
+ "apple-music",
15
+ "icloud",
16
+ "calendar",
17
+ "contacts",
18
+ "mail",
19
+ "maps",
20
+ "weather",
21
+ "mcp"
22
+ ],
23
+ "skills": "./skills/",
24
+ "mcp": "./.mcp.json"
25
+ }
package/.mcp.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "mcpServers": {
3
+ "apple": {
4
+ "command": "npx",
5
+ "args": [
6
+ "-y",
7
+ "apple-icloud-mcp"
8
+ ],
9
+ "env": {
10
+ "APPLE_TEAM_ID": "${APPLE_TEAM_ID}",
11
+ "APPLE_KEY_ID": "${APPLE_KEY_ID}",
12
+ "APPLE_PRIVATE_KEY": "${APPLE_PRIVATE_KEY}",
13
+ "APPLE_MUSIC_USER_TOKEN": "${APPLE_MUSIC_USER_TOKEN}",
14
+ "APPLE_MUSIC_WEB_USER_TOKEN": "${APPLE_MUSIC_WEB_USER_TOKEN}",
15
+ "APPLE_WEATHERKIT_SERVICE_ID": "${APPLE_WEATHERKIT_SERVICE_ID}",
16
+ "ICLOUD_USERNAME": "${ICLOUD_USERNAME}",
17
+ "ICLOUD_APP_PASSWORD": "${ICLOUD_APP_PASSWORD}",
18
+ "DISPLAY_TZ": "${DISPLAY_TZ}"
19
+ }
20
+ }
21
+ }
22
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chris Hall
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,490 @@
1
+ # apple-icloud-mcp
2
+
3
+ [![CI](https://github.com/chrischall/apple-icloud-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/chrischall/apple-icloud-mcp/actions/workflows/ci.yml)
4
+ [![npm](https://img.shields.io/npm/v/apple-icloud-mcp)](https://www.npmjs.com/package/apple-icloud-mcp)
5
+ [![license](https://img.shields.io/npm/l/apple-icloud-mcp)](LICENSE)
6
+
7
+ A [Model Context Protocol](https://modelcontextprotocol.io) server that connects Claude to **Apple's web
8
+ services**: Apple Music (your playlists, library and the catalog), iCloud Calendar, Contacts and Mail,
9
+ Apple Maps, WeatherKit, and the iTunes Search API.
10
+
11
+ It talks to Apple over the network through Apple's own web APIs and standard protocols (CalDAV, CardDAV,
12
+ IMAP/SMTP), so — unlike Mac-only Apple integrations such as
13
+ [apple-swift-mcp](https://github.com/chrischall/apple-swift-mcp) — it runs anywhere: Linux, Windows, a
14
+ container, or hosted on [mcp-host](#running-on-mcp-host) as a claude.ai connector. The two complement each other:
15
+ `apple-swift-mcp` drives the Mac's own apps (Calendar, Reminders, Contacts, Mail, Messages, Notes, Photos, Maps),
16
+ while `apple-icloud-mcp` reaches Apple's web services from anywhere and adds Apple Music, WeatherKit and iTunes.
17
+
18
+ > [!NOTE]
19
+ > **Unofficial.** This project is not affiliated with, endorsed by or sponsored by Apple Inc. Apple, iCloud,
20
+ > Apple Music, Apple Maps and WeatherKit are trademarks of Apple Inc., used here only to name the services it
21
+ > connects to.
22
+
23
+ > [!WARNING]
24
+ > **AI-developed project.** This codebase was entirely built and is actively maintained by
25
+ > [Claude Code](https://www.anthropic.com/claude). No human has audited the implementation. Review all code
26
+ > and tool permissions before use.
27
+
28
+ > [!IMPORTANT]
29
+ > **Not yet verified against a live Apple account.** Every request shape comes from Apple's documentation or
30
+ > Apple's own web client and is covered by tests against faithful fakes, but the build environment had no
31
+ > Apple credentials. The first real run is the real verification — run `apple_healthcheck` first, and see
32
+ > [docs/APPLE-API.md](docs/APPLE-API.md) for what each call relies on.
33
+
34
+ ## What you can do
35
+
36
+ - *"Make a playlist called Road Trip 2026 with twenty upbeat 80s songs"*
37
+ - *"Add the top 5 songs from Taylor Swift's latest album to my Workout playlist"*
38
+ - *"Remove duplicates from my Chill playlist and sort it by artist"* (web-player mode)
39
+ - *"What have I been listening to on heavy rotation?"* / *"Show my Apple Music Replay for this year"*
40
+ - *"What's on my calendar next week?"* / *"Find me a free hour on Thursday afternoon"*
41
+ - *"Move my dentist appointment to Friday at 3pm"*
42
+ - *"What's Jane's phone number?"* / *"Add Bob Lee from Acme with bob@acme.com to my contacts"*
43
+ - *"Any unread email from my landlord?"* / *"Reply to the last message from Sam saying I'll be there"*
44
+ - *"How long will it take to drive to the airport at 5pm?"* / *"Coffee shops near Union Square"*
45
+ - *"Will it rain in Chicago tomorrow?"*
46
+ - *"Find the podcast Hard Fork and list its latest episodes"* / *"What are the top albums in the UK right now?"*
47
+
48
+ ## Services and what each needs
49
+
50
+ Every service is optional: each one switches on when its credentials are present, and
51
+ [`apple_healthcheck`](#troubleshooting) tells you which are working.
52
+
53
+ | Service | What you get | Credential | Cost |
54
+ |---|---|---|---|
55
+ | **Apple Music** (official API) | Catalog search, charts, your library, playlists (create, add tracks, folders), history, recommendations, Replay, ratings, favorites | Apple Developer key **+** a Music User Token | Apple Developer Program ($99/yr) + Apple Music subscription |
56
+ | **Apple Music** (web-player mode, opt-in, unofficial) | Everything above **plus** rename/delete playlists, remove/reorder/sort/dedupe tracks, move to folders, remove from library | The `media-user-token` cookie from music.apple.com | Apple Music subscription only |
57
+ | **iCloud Calendar** (CalDAV) | List/search events (recurring ones expanded), create/update/delete with correct time zones and recurrence, free-time finder | Apple ID + **app-specific password** | Free |
58
+ | **iCloud Contacts** (CardDAV) | Search, read, create, update (per-email/phone edits), delete, groups | Apple ID + app-specific password | Free |
59
+ | **iCloud Mail** (IMAP/SMTP) | List mailboxes, search, read (without marking read), send and reply, flag, move | Apple ID + app-specific password | Free |
60
+ | **Apple Maps** (Maps Server API) | Geocode, reverse geocode, place search, directions, ETAs, signed map-image URLs | Apple Developer key | Free up to 25,000 calls/day |
61
+ | **WeatherKit** | Current conditions, hourly/daily forecast, next-hour precipitation, severe-weather alerts | Apple Developer key + Services ID | Free up to 500,000 calls/month |
62
+ | **iTunes Search + charts** | Search/lookup songs, albums, podcasts (with episodes), apps, books, audiobooks; top charts | None | Free |
63
+
64
+ ## Requirements
65
+
66
+ - Node.js 22 or later (the hosted runner uses Node 26).
67
+ - Whatever the services you want need (table above).
68
+
69
+ ## Acknowledgement of Terms
70
+
71
+ By using this MCP server, you acknowledge and agree to the following:
72
+
73
+ **1. It accesses your own Apple accounts only**, with credentials you supply. It cannot reach anyone else's
74
+ data, and on a shared deployment each person's Apple ID stays in their own process.
75
+
76
+ **2. Apple's terms govern your use**, just as they govern your direct use of Apple's services — in
77
+ particular the [Apple Media Services Terms](https://www.apple.com/legal/internet-services/itunes/), the
78
+ [iCloud Terms and Conditions](https://www.apple.com/legal/internet-services/icloud/) and, for the developer-key
79
+ services, the [Apple Developer Program License Agreement](https://developer.apple.com/support/terms/). The
80
+ iCloud Terms say you may not *"interfere with or disrupt the Service (including accessing the Service through
81
+ any automated means, like scripts or web crawlers)"*. The iCloud paths here use the mechanism Apple provides
82
+ for third-party apps — app-specific passwords over CalDAV, CardDAV and IMAP/SMTP — at the pace of a person
83
+ using an assistant. **Apple Music web-player mode is different**: it uses Apple's private web-player API with
84
+ your browser session, which Apple has said may be blocked at any time. It is off unless you turn it on.
85
+ Terms read by the maintainer 2026-09-26.
86
+
87
+ **3. Personal use only.** This project is not affiliated with, endorsed by, or sponsored by Apple Inc.
88
+ "Apple", "Apple Music", "iCloud" and related marks are Apple's. Do not share your credentials, and do not use
89
+ this to bulk-extract data.
90
+
91
+ **4. Writes are real.** Creating a calendar event with attendees makes iCloud email them invitations; sending
92
+ mail sends it; deleting a playlist or contact deletes it. Those actions ask for confirmation first (see
93
+ [Confirmation](#confirmation-mcp_confirm_mode)), and [`APPLE_WRITE_MODE`](#write-protection-apple_write_mode)
94
+ can remove write tools entirely.
95
+
96
+ **5. You accept full responsibility** for the consequences, technical (rate limits, a locked account after
97
+ repeated failed sign-ins) and otherwise.
98
+
99
+ This is the maintainer's good-faith summary, not legal advice, and it does not modify or supersede Apple's
100
+ actual terms.
101
+
102
+ ## Installation
103
+
104
+ ### Claude Code
105
+
106
+ ```bash
107
+ claude mcp add apple -- npx -y apple-icloud-mcp
108
+ ```
109
+
110
+ then set the variables for the services you want (see [Setting up credentials](#setting-up-credentials)) in
111
+ the server's `env`, for example in `.mcp.json`:
112
+
113
+ ```json
114
+ {
115
+ "mcpServers": {
116
+ "apple": {
117
+ "command": "npx",
118
+ "args": ["-y", "apple-icloud-mcp"],
119
+ "env": {
120
+ "ICLOUD_USERNAME": "you@icloud.com",
121
+ "ICLOUD_APP_PASSWORD": "abcd-efgh-ijkl-mnop",
122
+ "DISPLAY_TZ": "America/New_York"
123
+ }
124
+ }
125
+ }
126
+ }
127
+ ```
128
+
129
+ ### Claude Desktop
130
+
131
+ Install the `.mcpb` bundle from the [latest release](https://github.com/chrischall/apple-icloud-mcp/releases) and fill
132
+ in the settings it asks for, or add the same `npx` entry to `claude_desktop_config.json`.
133
+
134
+ ### From source
135
+
136
+ ```bash
137
+ git clone https://github.com/chrischall/apple-icloud-mcp.git && cd apple-icloud-mcp
138
+ npm install && npm run build
139
+ cp .env.example .env # fill in what you need
140
+ npm run dev
141
+ ```
142
+
143
+ ## Setting up credentials
144
+
145
+ ### iCloud Calendar, Contacts and Mail — an app-specific password
146
+
147
+ 1. Sign in at [appleid.apple.com](https://appleid.apple.com) → **Sign-In and Security** → **App-Specific
148
+ Passwords** → generate one (two-factor authentication must be on).
149
+ 2. Set `ICLOUD_USERNAME` (your Apple ID email) and `ICLOUD_APP_PASSWORD` (the `xxxx-xxxx-xxxx-xxxx`
150
+ password). Your normal Apple ID password does **not** work here.
151
+ 3. If your Apple ID is not an `@icloud.com` / `@me.com` address, also set `ICLOUD_MAIL_ADDRESS` to your iCloud
152
+ Mail address (Mail only).
153
+
154
+ Changing your Apple ID password revokes every app-specific password — the usual reason a working setup
155
+ suddenly returns "credentials rejected". After a definitive rejection the server stops sending that password —
156
+ for 24 hours or until you change it, across restarts too (it records a digest of the rejected pair, never the
157
+ password) — because repeated failed sign-ins can lock an Apple ID.
158
+
159
+ **Reminders are not available**: since iOS 13, iCloud Reminders no longer sync over CalDAV (see
160
+ [Not supported](#not-supported-and-why)).
161
+
162
+ ### Apple Developer key — Apple Music (official), Apple Maps, WeatherKit
163
+
164
+ These three need a paid [Apple Developer Program](https://developer.apple.com/programs/) membership.
165
+
166
+ 1. In [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources/identifiers/list),
167
+ create the identifiers for the services you want: a **Media ID** (Apple Music), a **Maps ID** (Apple Maps),
168
+ and a **Services ID** for WeatherKit.
169
+ 2. Under **Keys**, create a key and tick **Media Services (MusicKit)**, **MapKit JS** and/or **WeatherKit**.
170
+ One key can carry all three. Download the `.p8` (you only get one chance).
171
+ 3. Set `APPLE_TEAM_ID`, `APPLE_KEY_ID` and `APPLE_PRIVATE_KEY` (the `.p8` contents — multi-line PEM, a
172
+ one-line value with `\n` escapes, or base64 all work). For WeatherKit also set
173
+ `APPLE_WEATHERKIT_SERVICE_ID`. Separate keys per service are supported with `APPLE_MUSIC_KEY_ID` /
174
+ `APPLE_MUSIC_PRIVATE_KEY`, `APPLE_MAPS_…` and `APPLE_WEATHERKIT_…`.
175
+
176
+ The server signs short-lived tokens itself (12 hours for Apple Music, 1 hour for Maps and WeatherKit).
177
+
178
+ ### Apple Music — your library (official API): a Music User Token
179
+
180
+ Catalog search works with the developer key alone. Your library and playlists also need a **Music User
181
+ Token**, which Apple only issues through an interactive MusicKit sign-in in a browser. With the developer key
182
+ set, run:
183
+
184
+ ```bash
185
+ npx apple-icloud-mcp music-auth
186
+ ```
187
+
188
+ It opens a page on `127.0.0.1`, you click **Sign in with Apple Music**, and it prints
189
+ `APPLE_MUSIC_USER_TOKEN=…`. Put that value in `APPLE_MUSIC_USER_TOKEN`. It lasts about six months, is tied to
190
+ the developer key that minted it, and changing your Apple ID password revokes it.
191
+
192
+ **Someone without the developer key** (another person on a shared deployment) never needs the `.p8`. The key's
193
+ owner runs `npx apple-icloud-mcp music-auth --print-developer-token --days 7` and sends them the short-lived
194
+ token it prints; they run `APPLE_MUSIC_DEVELOPER_TOKEN=<that token> npx apple-icloud-mcp music-auth` on their
195
+ own machine, sign in, and keep the user token it prints. The developer token expires on its own; the user token
196
+ keeps working with the server's key.
197
+
198
+ ### Apple Music — web-player mode (opt-in, unofficial)
199
+
200
+ Apple's official API cannot rename or delete playlists, remove or reorder tracks, or remove anything from your
201
+ library. Apple's own web player can. Web-player mode uses that same private API with your browser session:
202
+
203
+ 1. Sign in at [music.apple.com](https://music.apple.com) in a desktop browser.
204
+ 2. Open the developer tools → **Application/Storage** → **Cookies** → `https://music.apple.com` and copy the
205
+ value of the **`media-user-token`** cookie.
206
+ 3. Set it as `APPLE_MUSIC_WEB_USER_TOKEN`.
207
+
208
+ The web player's own developer token is read from music.apple.com automatically (and cached). This mode also
209
+ works with **no** Apple Developer account. It is unsupported by Apple and may stop working without notice; the
210
+ tools that need it say so in their descriptions, and their answers report which backend (`official` or `web`)
211
+ served them.
212
+
213
+ ## Running on mcp-host
214
+
215
+ The package ships a [`mint.yaml`](mint.yaml) that mcp-host reads when you register `apple-icloud-mcp`:
216
+
217
+ - **Owner settings** (the developer key, `APPLE_WRITE_MODE`, `APPLE_SERVICES`, `MCP_CONFIRM_SECRET`, …) go in
218
+ the registration's environment — store the private key and confirm secret as secrets.
219
+ - **Everything personal** (Apple ID, app-specific password, Music tokens, iCloud Mail address, time zone,
220
+ default calendar, Apple Music storefront) is declared as `auth.fields`, so mcp-host asks each person when they
221
+ connect and remembers the answers per person; each caller gets their own process and data directory.
222
+ - **State**: `dataDir` holds a few small files (see [Security](#security)) that keep a scale-to-zero cold start
223
+ cheap and stop a revoked password or a spent confirmation token from being reused after a restart.
224
+ - **Egress**: only the Apple hosts this server calls (`api.music.apple.com`, `amp-api.music.apple.com`,
225
+ `music.apple.com`, `caldav.icloud.com`, `contacts.icloud.com`, `*.icloud.com`, `imap.mail.me.com`,
226
+ `smtp.mail.me.com`, `maps-api.apple.com`, `weatherkit.apple.com`, `itunes.apple.com`,
227
+ `rss.marketingtools.apple.com`). HTTPS goes through the runner's proxy via Node's built-in fetch; IMAP and
228
+ SMTP are tunnelled through the same proxy with HTTP CONNECT.
229
+
230
+ Give it your time zone (`DISPLAY_TZ`): the runner is on UTC, and times you give without an offset ("3pm") are
231
+ read in `DISPLAY_TZ`. Set **`MCP_CONFIRM_SECRET`** too: without it, a confirmation token issued just before the
232
+ child restarts (a redeploy, a machine move) stops working and you have to preview again. Spent tokens are
233
+ recorded on disk, so a shared secret does not let one be replayed.
234
+
235
+ ## Tools
236
+
237
+ <!-- TOOLS:START -->
238
+ 58 tools. **Mode** is the lowest [`APPLE_WRITE_MODE`](#write-protection-apple_write_mode) that registers the tool; **Confirm** marks tools that ask first ([details](#confirmation-mcp_confirm_mode)); 🌐 marks Apple Music tools that need [web-player mode](#apple-music--web-player-mode-opt-in-unofficial).
239
+
240
+ ### Health
241
+
242
+ | Tool | What it does | Mode | Confirm |
243
+ |---|---|---|---|
244
+ | `apple_healthcheck` | Check which Apple services (Apple Music, iCloud Calendar, Contacts, Mail, Apple Maps, WeatherKit, iTunes) are configured and reachable. | read | |
245
+
246
+ ### Apple Music
247
+
248
+ | Tool | What it does | Mode | Confirm |
249
+ |---|---|---|---|
250
+ | `apple_music_search_catalog` | Search Apple Music's catalog by text for songs, albums, artists, playlists, music videos or stations. | read | |
251
+ | `apple_music_get_catalog_items` | Look up Apple Music catalog songs, albums, artists, playlists, music videos or stations by id — or songs/music videos by ISRC, albums by UPC. | read | |
252
+ | `apple_music_get_charts` | Get Apple Music's top charts (most played songs, albums, playlists, music videos) for a storefront, optionally for one genre. | read | |
253
+ | `apple_music_list_playlists` | List the playlists in your Apple Music library (alphabetical), or the contents of one playlist folder (folders and playlists). | read | |
254
+ | `apple_music_get_playlist` | Read one playlist — a library playlist (p.…) or a catalog playlist (pl.…) — with its tracks in order. | read | |
255
+ | `apple_music_list_folders` | List the playlist folders in your Apple Music library: the top level, or the sub-folders of one folder. | read | |
256
+ | `apple_music_search_library` | Search YOUR Apple Music library (not the whole catalog) by text for songs, albums, artists, playlists or music videos. | read | |
257
+ | `apple_music_list_library` | List what is in your Apple Music library: all songs, albums, artists or music videos (alphabetical, paged), or recently-added items. | read | |
258
+ | `apple_music_get_history` | Your recent Apple Music listening: recently-played (albums, playlists, stations), recently-played-tracks (songs), recent-stations, or heavy-rotation. | read | |
259
+ | `apple_music_get_recommendations` | Your personal Apple Music recommendations ("Made for You", "Recently Played" and similar groups), each with its title and the albums, playlists or stations in it (catalog ids). | read | |
260
+ | `apple_music_get_replay` | Apple Music Replay: your top songs, albums and artists for the latest Replay year, or for a given year (with play counts where Apple provides them). | read | |
261
+ | `apple_music_get_ratings` | Whether you have loved or disliked songs, albums, playlists, music videos or stations — catalog or library ids — returning love, dislike or none per id. | read | |
262
+ | `apple_music_create_playlist` | Create a new playlist in your Apple Music library, optionally with tracks (up to 500 catalog or library song ids; added 100 at a time), a description, a folder and public visibility. | additive | |
263
+ | `apple_music_add_playlist_tracks` | Append songs (up to 500 catalog or library ids) to the end of one of your library playlists. | additive | |
264
+ | `apple_music_create_folder` | Create a playlist folder in your Apple Music library, at the top level or inside another folder. | additive | |
265
+ | `apple_music_add_to_library` | Add catalog songs, albums, playlists or music videos to your Apple Music library by catalog id (up to 100 per type). | additive | |
266
+ | `apple_music_add_favorites` | Mark catalog songs, albums, playlists, artists or music videos as favorites (the star in Apple Music; favorite songs go to your Favorite Songs playlist), by catalog id, up to 100 per type. | additive | |
267
+ | `apple_music_set_rating` | Set your rating on a song, album, playlist, music video or station (catalog or library id): love, dislike, or none to clear it. | all | |
268
+ | `apple_music_update_playlist` 🌐 | Rename one of your Apple Music library playlists, change its description, or make it public/private. | all | |
269
+ | `apple_music_remove_playlist_tracks` 🌐 | Remove tracks from one of your library playlists by library track id and/or 1-based position (from apple_music_get_playlist). | all | yes |
270
+ | `apple_music_reorder_playlist` 🌐 | Reorder one of your library playlists: move tracks, sort (name, artist, album, release date, duration, date added), reverse, dedupe (keep the first copy of each song), or replace with a complete new order of its track ids (can drop tracks). | all | yes |
271
+ | `apple_music_move_playlist` 🌐 | Move one of your library playlists into a playlist folder, or back to the top level ("root"). | all | |
272
+ | `apple_music_delete_playlist` 🌐 | Delete one of your library playlists (songs stay in your library). | all | yes |
273
+ | `apple_music_remove_from_library` 🌐 | Remove songs, albums, music videos or playlists from your Apple Music library by LIBRARY id (i.…, l.…, p.… from apple_music_list_library / apple_music_search_library), up to 50 at a time; the preview names each item. | all | yes |
274
+ | `apple_music_remove_favorites` 🌐 | Remove the favorite (star) from catalog songs, albums, playlists, artists or music videos, by catalog id, up to 100 per type. | all | |
275
+
276
+ ### iCloud Calendar
277
+
278
+ | Tool | What it does | Mode | Confirm |
279
+ |---|---|---|---|
280
+ | `apple_calendar_list_calendars` | List your iCloud calendars (event calendars only): id, name, color, whether you can add events to it, whether it is shared (shared: with you by someone else; sharedByYou: by you with others), and which one new events go into by default. | read | |
281
+ | `apple_calendar_list_events` | List iCloud Calendar events (appointments, meetings) in a date window, recurring events expanded into occurrences, sorted by start. | read | |
282
+ | `apple_calendar_search_events` | Search iCloud Calendar events by text (case-insensitive match in title, location or notes) within a date window: fromDate (default today; may be in the past) + toDate or daysAhead (default 30), max 366 days. | read | |
283
+ | `apple_calendar_get_event` | Get one iCloud Calendar event in full (notes untruncated, attendees, alerts, recurrence rule in plain English) by the id list/search returned. | read | |
284
+ | `apple_calendar_create_event` | Create an iCloud Calendar event: title, startDate/endDate (timed default 1 hour; all-day endDate = last day), location, notes, url, alarms, recurrence, attendees. | additive | with attendees |
285
+ | `apple_calendar_update_event` | Change an iCloud Calendar event: title, startDate/endDate, isAllDay, location, notes, url ("" clears), alarms, attendees (full new list), calendar (moves it). | all | with attendees |
286
+ | `apple_calendar_delete_event` | Delete an iCloud Calendar event. Recurring: span thisEvent (default; the one occurrence an "#occ=" id names), futureEvents (it and all later ones) or allEvents (the whole series). | all | yes |
287
+ | `apple_calendar_find_free_time` | Find free time in your iCloud calendars: open slots per day within working hours (workdayStart/workdayEnd, default 09:00–17:00, weekdays only by default) at least minDurationMinutes long (default 30). | read | |
288
+
289
+ ### iCloud Contacts
290
+
291
+ | Tool | What it does | Mode | Confirm |
292
+ |---|---|---|---|
293
+ | `apple_contacts_search` | Search the user's iCloud Contacts (address book) by name, nickname, company, job title, email, or phone number digits — optionally only within one contact group. | read | |
294
+ | `apple_contacts_get` | Get one iCloud contact in full by id (from apple_contacts_search): names, organization, job title, emails, phones, postal addresses and URLs — each with its label and an entryId that apple_contacts_update can target — birthday, note, the… | read | |
295
+ | `apple_contacts_list_groups` | List the contact groups in iCloud Contacts (e.g. Family, Work): each group's id, name and member count. | read | |
296
+ | `apple_contacts_create` | Create a new contact in iCloud Contacts. Needs a givenName, familyName or organization; optional middleName, nickname, department, jobTitle, note, birthday (YYYY-MM-DD, or --MM-DD without a year), and lists of emails, phones, urls and po… | additive | |
297
+ | `apple_contacts_update` | Edit an existing iCloud contact in place. Scalar fields (givenName, familyName, middleName, nickname, organization, department, jobTitle, note, birthday) replace the current value; "" clears it. | all | |
298
+ | `apple_contacts_delete` | Permanently delete one contact from iCloud Contacts (on every device) by id. | all | yes |
299
+
300
+ ### iCloud Mail
301
+
302
+ | Tool | What it does | Mode | Confirm |
303
+ |---|---|---|---|
304
+ | `apple_mail_list_mailboxes` | List the iCloud Mail mailboxes (folders): path, name, special use (inbox, sent, drafts, trash, junk, archive) and, by default, message and unread counts. | read | |
305
+ | `apple_mail_search` | Search emails in one iCloud Mail mailbox (default INBOX) by sender, recipient, subject, full text, received date range, unread and flagged state. | read | |
306
+ | `apple_mail_get_message` | Read one iCloud Mail message by uid (from apple_mail_search): headers (from, to, cc, reply-to, date, subject, message-id), the body as plain text (HTML converted to readable text when there is no text part), a truncated flag, and attachm… | read | |
307
+ | `apple_mail_send` | Send a plain-text email from your iCloud Mail address (to/cc/bcc, subject, body; no attachments). | all | yes |
308
+ | `apple_mail_update_flags` | Mark iCloud Mail messages read or unread, and flag or unflag them, by uid (1–100 uids from apple_mail_search, one mailbox). | all | |
309
+ | `apple_mail_move` | Move iCloud Mail messages (1–100 uids from apple_mail_search, one mailbox) to another mailbox: a path from apple_mail_list_mailboxes or an alias (inbox, archive, trash, junk, sent, drafts). | all | |
310
+
311
+ ### Apple Maps
312
+
313
+ | Tool | What it does | Mode | Confirm |
314
+ |---|---|---|---|
315
+ | `apple_maps_geocode` | Turn an address or place name into coordinates with Apple Maps (geocoding). | read | |
316
+ | `apple_maps_reverse_geocode` | Find the street address at a latitude/longitude with Apple Maps (reverse geocoding) — e.g. "where is 37.33,-122.01?". | read | |
317
+ | `apple_maps_search` | Search Apple Maps for places: businesses, points of interest, addresses, landmarks (e.g. "coffee", "EV charger", "Golden Gate Bridge"). | read | |
318
+ | `apple_maps_directions` | Driving, walking or cycling directions between two places with Apple Maps (addresses or "lat,lng"). | read | |
319
+ | `apple_maps_etas` | Travel time and distance from one point to up to 10 destinations at once with Apple Maps — driving with live traffic, transit, walking or cycling (e.g. "which of these stores is closest by car?"). | read | |
320
+ | `apple_maps_lookup_place` | Look up Apple Maps places by place id — the id field from apple_maps_search, apple_maps_geocode or apple_maps_reverse_geocode results — 1 to 50 at once. | read | |
321
+ | `apple_maps_snapshot_url` | Make a signed link to a static Apple Maps image (PNG): centred on an address or "lat,lng", and/or with pins (each with an optional label, colour and one-character glyph; the map fits the pins when no center is given). | read | |
322
+
323
+ ### WeatherKit
324
+
325
+ | Tool | What it does | Mode | Confirm |
326
+ |---|---|---|---|
327
+ | `apple_weather_get` | Weather forecast for a place from Apple Weather (WeatherKit): current conditions, hourly (up to 240 h), daily (up to 10 days), next-hour rain, severe-weather alerts (need countryCode). | read | |
328
+ | `apple_weather_get_alert` | Get one severe-weather alert's full official text from Apple Weather (WeatherKit), unmodified, by its id (the alerts[].id from apple_weather_get called with countryCode). | read | |
329
+
330
+ ### iTunes Search and charts
331
+
332
+ | Tool | What it does | Mode | Confirm |
333
+ |---|---|---|---|
334
+ | `apple_itunes_search` | Search Apple's iTunes Store catalog — songs, albums, artists, podcasts and podcast episodes, audiobooks, apps and ebooks — with no Apple account or key. | read | |
335
+ | `apple_itunes_lookup` | Look up iTunes Store items (no Apple account or key) by ids — 1–200 trackId/collectionId/artistId values, e.g. from apple_itunes_search or an Apple Music link — or by one UPC/EAN (album), ISBN (book) or bundleId (app). | read | |
336
+ | `apple_charts_get` | Apple's current top charts (no Apple account or key): most-played songs, albums, music videos and playlists on Apple Music; top podcasts, trending podcast episodes and top subscriber channels; top free/paid apps and books; top audiobooks. | read | |
337
+ <!-- TOOLS:END -->
338
+
339
+ ## Write protection (`APPLE_WRITE_MODE`)
340
+
341
+ | Value | What is registered |
342
+ |---|---|
343
+ | `none` | Read tools only. |
344
+ | `additive` | Reads, plus writes that only **add** to your own account: create a playlist or folder, append tracks, add to library/favorites, create an event (without attendees, and not in a calendar shared with other people) or a contact. Nothing existing is modified or removed and nothing is sent to anyone. |
345
+ | `all` (default) | Everything. |
346
+
347
+ Gated tools are not registered at all below their mode, so no prompt or injected instruction can call them.
348
+ An unrecognised value fails closed to `none`. `APPLE_SERVICES` (comma-separated: `music`, `calendar`,
349
+ `contacts`, `mail`, `maps`, `weather`, `itunes`) narrows which services register tools at all.
350
+
351
+ ## Confirmation (`MCP_CONFIRM_MODE`)
352
+
353
+ Irreversible actions and anything that reaches another person ask for confirmation first: **sending mail**,
354
+ **deleting** an event, contact, playlist or library item, **removing or reordering** playlist tracks, and
355
+ **creating or changing an event with attendees** (iCloud emails them). A client that can show a prompt
356
+ (Claude Code) asks you directly. One that cannot (claude.ai) gets a two-step flow: the first call does nothing
357
+ and returns a preview plus a `confirmToken`; only a repeat call with that token acts, and it is refused if the
358
+ target changed in between.
359
+
360
+ | Variable | Meaning |
361
+ |---|---|
362
+ | `MCP_CONFIRM_MODE` | `ask-user` (default — the model must get your OK before repeating the call), `auto` (the model may confirm after reviewing the preview), `refuse` (never). Unknown values mean `refuse`. |
363
+ | `MCP_CONFIRM_TTL_SECONDS` | How long a token is valid (default 600). |
364
+ | `MCP_CONFIRM_SECRET` | Token signing key; random per process by default. Set it so a token survives a restart; spent tokens are recorded on disk (`confirm-spent.json`), so none can be replayed (unless `APPLE_STATE_CACHE=false` or the directory is unwritable — a warning says so). |
365
+
366
+ ## Environment variables
367
+
368
+ <!-- ENV:START -->
369
+ All optional; each service activates when its credentials are present. Values that are blank, `undefined`, `null` or an unexpanded `${VAR}` count as unset.
370
+
371
+ **Apple Developer key**
372
+
373
+ | Variable | Meaning |
374
+ |---|---|
375
+ | `APPLE_TEAM_ID` | Your Apple Developer Team ID (10 characters). Needed for Apple Music (official API), Apple Maps and WeatherKit. |
376
+ | `APPLE_KEY_ID` | Key ID of a private key created in Certificates, Identifiers & Profiles → Keys with Media Services (MusicKit), MapKit JS and/or WeatherKit enabled. |
377
+ | `APPLE_PRIVATE_KEY` 🔒 | Contents of that key's .p8 file (PEM; one-line values with \n escapes and base64 are accepted). |
378
+ | `APPLE_PRIVATE_KEY_PATH` | Local installs only: a path to the .p8 file instead of APPLE_PRIVATE_KEY. |
379
+ | `APPLE_MUSIC_KEY_ID` | Optional per-service override of APPLE_KEY_ID for Apple Music (pair with APPLE_MUSIC_PRIVATE_KEY). |
380
+ | `APPLE_MUSIC_PRIVATE_KEY` 🔒 | Optional per-service override of APPLE_PRIVATE_KEY for Apple Music. |
381
+ | `APPLE_MAPS_KEY_ID` | Optional per-service override of APPLE_KEY_ID for Apple Maps. |
382
+ | `APPLE_MAPS_PRIVATE_KEY` 🔒 | Optional per-service override of APPLE_PRIVATE_KEY for Apple Maps. |
383
+ | `APPLE_WEATHERKIT_KEY_ID` | Optional per-service override of APPLE_KEY_ID for WeatherKit. |
384
+ | `APPLE_WEATHERKIT_PRIVATE_KEY` 🔒 | Optional per-service override of APPLE_PRIVATE_KEY for WeatherKit. |
385
+ | `APPLE_WEATHERKIT_SERVICE_ID` | WeatherKit only: the Services ID registered for WeatherKit (e.g. com.example.weather). |
386
+
387
+ **Apple Music**
388
+
389
+ | Variable | Meaning |
390
+ |---|---|
391
+ | `APPLE_MUSIC_DEVELOPER_TOKEN` 🔒 | Optional: a pre-minted Apple Music developer token (JWT) instead of signing one from the key above. |
392
+ | `APPLE_MUSIC_USER_TOKEN` 🔒 | Music User Token for your library (official API), from a one-time MusicKit sign-in: `npx apple-icloud-mcp music-auth`. Without the Apple Developer key, ask the owner for a developer token (music-auth --print-developer-token) and run it with APPLE_MUSIC_DEVELOPER_TOKEN set. Lasts ~6 months. |
393
+ | `APPLE_MUSIC_WEB_USER_TOKEN` 🔒 | Opt-in web-player mode (no developer account needed; unlocks rename/delete/remove/reorder): the media-user-token cookie from a signed-in music.apple.com tab. |
394
+ | `APPLE_MUSIC_WEB_DEVELOPER_TOKEN` 🔒 | Optional override for the web-player developer token (normally read automatically from music.apple.com). |
395
+ | `APPLE_MUSIC_STOREFRONT` | Two-letter Apple Music storefront (e.g. us, gb). Default: your account's storefront, else us. |
396
+
397
+ **iCloud**
398
+
399
+ | Variable | Meaning |
400
+ |---|---|
401
+ | `ICLOUD_USERNAME` | Your Apple ID email, for iCloud Calendar, Contacts and Mail. |
402
+ | `ICLOUD_APP_PASSWORD` 🔒 | An app-specific password from appleid.apple.com → Sign-In and Security → App-Specific Passwords (NOT your Apple ID password). |
403
+ | `ICLOUD_MAIL_ADDRESS` | Your @icloud.com address, only if your Apple ID email is not an iCloud address (needed for Mail). |
404
+ | `ICLOUD_DEFAULT_CALENDAR` | Calendar new events go to when none is named (default: the first writable event calendar). |
405
+
406
+ **Behaviour**
407
+
408
+ | Variable | Meaning |
409
+ |---|---|
410
+ | `APPLE_WRITE_MODE` | "none" = read-only tools; "additive" = also create/append, never modify, delete or send; "all" = everything (default). Unrecognized values fail closed to "none". |
411
+ | `APPLE_SERVICES` | Comma-separated services to enable (music, calendar, contacts, mail, maps, weather, itunes). Default: all. |
412
+ | `DISPLAY_TZ` | IANA time zone (e.g. America/New_York) for displayed times and for dates you give without an offset. Set this on a hosted server, which runs in UTC. |
413
+ | `APPLE_UNITS` | "metric" (default) or "imperial" units for weather (Maps distances always show both). |
414
+ | `APPLE_STATE_CACHE` | Set to false to write nothing under $MCP_DATA_DIR/.apple-icloud-mcp: no web-player token or iCloud discovery cache, and the rejected-password latch and spent confirmation tokens then last only as long as the process. |
415
+ | `APPLE_REQUEST_TIMEOUT_MS` | Per-request timeout in milliseconds (default 30000). |
416
+ | `APPLE_DEBUG_LOG` | Set to 1 to log every upstream request line to stderr (credentials redacted). |
417
+
418
+ **Confirmation**
419
+
420
+ | Variable | Meaning |
421
+ |---|---|
422
+ | `MCP_CONFIRM_MODE` | How confirm-gated writes (send mail, deletes, removing tracks, invitations) behave on a client with no prompt, like claude.ai: "ask-user" (default: preview + confirmToken, the model must get your OK), "auto", or "refuse". Unknown values mean refuse. |
423
+ | `MCP_CONFIRM_TTL_SECONDS` | Lifetime of a confirmToken in seconds (default 600). |
424
+ | `MCP_CONFIRM_SECRET` 🔒 | Signing key for confirmTokens. Random per process by default; set it so a token issued just before a restart or redeploy still works (spent tokens are recorded on disk, so none can be replayed). |
425
+
426
+ 🔒 = a secret: store it as one.
427
+ <!-- ENV:END -->
428
+
429
+ ## Not supported (and why)
430
+
431
+ - **Reminders, Notes, Find My, iCloud Drive, Photos, Hide My Email.** None has a public API or a standard
432
+ protocol that still works: iCloud Reminders left CalDAV with iOS 13. The only route is iCloud.com's private
433
+ API, which needs your **full Apple ID password**, an SRP sign-in and a two-factor code, has broken four times in
434
+ about two years, is blocked by Advanced Data Protection, and is exactly the "automated means" the iCloud
435
+ Terms forbid. On a Mac, [apple-swift-mcp](https://github.com/chrischall/apple-swift-mcp) covers Reminders,
436
+ Notes and Photos natively.
437
+ - **Playing music.** Apple's web APIs manage your library; playback happens in an Apple Music app.
438
+ - **Creating or deleting calendars** — iCloud's CalDAV server does not reliably support it.
439
+ - **Mail attachments** — sending is plain text; reading lists attachments but does not download them.
440
+
441
+ ## Troubleshooting
442
+
443
+ Run **`apple_healthcheck`** first. For each service it reports whether credentials are configured (and which
444
+ variables to set if not), whether Apple accepted them just now, the active write mode and the display time zone.
445
+
446
+ | Symptom | Likely cause |
447
+ |---|---|
448
+ | iCloud "credentials rejected" | The app-specific password was revoked (Apple ID password changed) or the normal password was used. Generate a new app-specific password. |
449
+ | Apple Music 401 | Developer key problem: wrong Team/Key ID, or the key lacks MusicKit. In web mode: the `media-user-token` cookie expired — copy a fresh one. |
450
+ | Apple Music 403 | The Music User Token expired (≈6 months), was minted with a different key, or the account has no Apple Music subscription. Run `music-auth` again (without the developer key: ask its owner for `music-auth --print-developer-token`). |
451
+ | `PLAYLIST_CHANGED` | Apple has not caught up with the previous playlist change yet (its reads lag writes by seconds), or the playlist was edited elsewhere. Re-read with `apple_music_get_playlist` and retry. |
452
+ | Times are off by hours | Set `DISPLAY_TZ` to your IANA zone. |
453
+ | Mail times out on a hosted deployment | Check `imap.mail.me.com` / `smtp.mail.me.com` are in the egress allowlist. |
454
+
455
+ `APPLE_DEBUG_LOG=1` logs every upstream request line to stderr, with credentials redacted.
456
+
457
+ ## Security
458
+
459
+ - Credentials are read from the environment at call time and never written to disk, logged, or put in a URL;
460
+ every error and log line is scrubbed of every credential the process has used.
461
+ - Only Apple's hosts are contacted; a redirect or DAV href pointing anywhere else is refused before any
462
+ credential travels.
463
+ - Reading mail never marks it read (`apple_mail_update_flags` does that when asked). HTML mail is converted to
464
+ text with hidden content dropped, and mail and calendar text is labelled as content from its sender.
465
+ - **Local data:** small files under `$MCP_DATA_DIR/.apple-icloud-mcp/` (or `~/.apple-icloud-mcp/`), all mode 0600 and none holding
466
+ your password or tokens:
467
+ - `music-web-token.json` — Apple Music web player's own public developer token (web mode only);
468
+ - `dav-calendar.json`, `dav-contacts.json` — iCloud discovery URLs, bound to the credential they came from;
469
+ - `mail-login.json` — which IMAP login form iCloud accepted;
470
+ - `icloud-rejected.json` — salted digests of rejected Apple ID/password pairs and when, so a revoked
471
+ password is not re-sent for 24 hours even after a restart;
472
+ - `confirm-spent.json` — digests of used confirmation tokens, so none can be replayed after a restart.
473
+
474
+ Delete the directory to remove them, or set `APPLE_STATE_CACHE=false` to never write them (the latch and the
475
+ spent-token record then last only as long as the process, and a warning says so).
476
+
477
+ ## Development
478
+
479
+ ```bash
480
+ npm run build # tsc → dist/, then esbuild bundle → dist/bundle.js
481
+ npm test # typecheck + vitest
482
+ npm run test:coverage # 100% line/branch/function/statement coverage is enforced
483
+ ```
484
+
485
+ See [CLAUDE.md](CLAUDE.md) for the architecture and [docs/APPLE-API.md](docs/APPLE-API.md) for the provenance
486
+ of every Apple API detail.
487
+
488
+ ## License
489
+
490
+ MIT