apple-icloud-mcp 0.3.3 → 0.3.5

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.
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Unofficial Apple Music, iCloud Calendar/Contacts/Mail, Apple Maps and WeatherKit tools for Claude Code",
9
- "version": "0.3.3"
9
+ "version": "0.3.5"
10
10
  },
11
11
  "plugins": [
12
12
  {
@@ -14,7 +14,7 @@
14
14
  "displayName": "Apple iCloud",
15
15
  "source": "./",
16
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.3.3",
17
+ "version": "0.3.5",
18
18
  "author": {
19
19
  "name": "Chris Chall"
20
20
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "apple-icloud",
3
3
  "displayName": "Apple iCloud",
4
- "version": "0.3.3",
4
+ "version": "0.3.5",
5
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
6
  "author": {
7
7
  "name": "Chris Chall"
@@ -21,5 +21,5 @@
21
21
  "mcp"
22
22
  ],
23
23
  "skills": "./skills/",
24
- "mcp": "./.mcp.json"
24
+ "mcpServers": "./.mcp.json"
25
25
  }
package/README.md CHANGED
@@ -270,7 +270,7 @@ read in `DISPLAY_TZ` — so are calendar events stored without a time zone of th
270
270
  | `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 | |
271
271
  | `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 (not in APPLE_WRITE_MODE=additive). | additive | |
272
272
  | `apple_music_add_playlist_tracks` | Append songs (up to 500 catalog or library ids) to the end of one of your library playlists. | additive | |
273
- | `apple_music_create_folder` | Create a playlist folder in your Apple Music library, at the top level or inside another folder. | additive | |
273
+ | `apple_music_create_folder` | Create a playlist folder in your Apple Music library, at the top level or inside another folder. | all | |
274
274
  | `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 | |
275
275
  | `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 | |
276
276
  | `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 | |
@@ -351,7 +351,7 @@ read in `DISPLAY_TZ` — so are calendar events stored without a time zone of th
351
351
  | Value | What is registered |
352
352
  |---|---|
353
353
  | `none` | Read tools only. |
354
- | `additive` | Reads, plus writes that only **add** to your own account: create a (private) 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. |
354
+ | `additive` | Reads, plus writes that only **add** to your own account: create a (private) playlist, 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. |
355
355
  | `all` (default) | Everything. |
356
356
 
357
357
  Gated tools are not registered at all below their mode, so no prompt or injected instruction can call them.
@@ -22,7 +22,7 @@ MPL-2.0 is a file-level license: it covers ical.js's own files and does not exte
22
22
 
23
23
  | Package | Version | License | Source |
24
24
  |---|---|---|---|
25
- | @chrischall/mcp-utils | 2.15.0 | MIT | https://github.com/chrischall/mcp-utils |
25
+ | @chrischall/mcp-utils | 3.0.0 | MIT | https://github.com/chrischall/mcp-utils |
26
26
  | @esbuild/aix-ppc64 | 0.28.2 | MIT | — |
27
27
  | @esbuild/android-arm | 0.28.2 | MIT | — |
28
28
  | @esbuild/android-arm64 | 0.28.2 | MIT | — |
@@ -49,8 +49,8 @@ MPL-2.0 is a file-level license: it covers ical.js's own files and does not exte
49
49
  | @esbuild/win32-arm64 | 0.28.2 | MIT | — |
50
50
  | @esbuild/win32-ia32 | 0.28.2 | MIT | — |
51
51
  | @esbuild/win32-x64 | 0.28.2 | MIT | — |
52
- | @modelcontextprotocol/core | 2.3.0 | Apache-2.0 | https://github.com/modelcontextprotocol/typescript-sdk |
53
- | @modelcontextprotocol/server | 2.3.0 | Apache-2.0 | https://github.com/modelcontextprotocol/typescript-sdk |
52
+ | @modelcontextprotocol/core | 2.3.1 | Apache-2.0 | https://github.com/modelcontextprotocol/typescript-sdk |
53
+ | @modelcontextprotocol/server | 2.3.1 | Apache-2.0 | https://github.com/modelcontextprotocol/typescript-sdk |
54
54
  | @pinojs/redact | 0.4.0 | MIT | https://github.com/pinojs/redact |
55
55
  | @rolldown/binding-android-arm-eabi | 1.2.12 | MIT | — |
56
56
  | @rolldown/binding-android-arm64 | 1.2.12 | MIT | — |
@@ -68,17 +68,17 @@ MPL-2.0 is a file-level license: it covers ical.js's own files and does not exte
68
68
  | @rolldown/binding-win32-arm64-msvc | 1.2.12 | MIT | — |
69
69
  | @rolldown/binding-win32-x64-msvc | 1.2.12 | MIT | — |
70
70
  | @xmldom/xmldom | 0.9.12 | MIT | https://github.com/xmldom/xmldom |
71
- | @zone-eu/mailsplit | 5.4.19 | (MIT OR EUPL-1.1+) | https://github.com/zone-eu/mailsplit |
71
+ | @zone-eu/mailsplit | 5.4.20 | (MIT OR EUPL-1.1+) | https://github.com/zone-eu/mailsplit |
72
72
  | atomic-sleep | 1.0.0 | MIT | https://github.com/davidmarkclements/atomic-sleep |
73
- | dotenv | 18.0.5 | BSD-2-Clause | https://github.com/motdotla/dotenv |
73
+ | dotenv | 18.0.6 | BSD-2-Clause | https://github.com/motdotla/dotenv |
74
74
  | encoding-japanese | 2.4.0 | MIT | https://github.com/polygonplanet/encoding.js |
75
75
  | fsevents | 2.3.3 | MIT | — |
76
76
  | ical.js | 2.2.1 | MPL-2.0 | https://github.com/kewisch/ical.js |
77
77
  | iconv-lite | 0.7.3 | MIT | https://github.com/pillarjs/iconv-lite |
78
- | imapflow | 2.1.2 | MIT | https://github.com/postalsys/imapflow |
78
+ | imapflow | 2.2.10 | MIT | https://github.com/postalsys/imapflow |
79
79
  | ip-address | 10.7.2 | MIT | https://github.com/beaugunderson/ip-address |
80
- | libbase64 | 1.3.1 | MIT | https://github.com/nodemailer/libbase64 |
81
- | libmime | 5.4.6 | MIT | https://github.com/nodemailer/libmime |
80
+ | libbase64 | 1.3.2 | MIT | https://github.com/nodemailer/libbase64 |
81
+ | libmime | 5.4.7 | MIT | https://github.com/nodemailer/libmime |
82
82
  | libqp | 2.1.2 | MIT | https://github.com/nodemailer/libqp |
83
83
  | lightningcss-android-arm64 | 1.33.0 | MPL-2.0 | — |
84
84
  | lightningcss-darwin-arm64 | 1.33.0 | MPL-2.0 | — |
@@ -91,12 +91,12 @@ MPL-2.0 is a file-level license: it covers ical.js's own files and does not exte
91
91
  | lightningcss-linux-x64-musl | 1.33.0 | MPL-2.0 | — |
92
92
  | lightningcss-win32-arm64-msvc | 1.33.0 | MPL-2.0 | — |
93
93
  | lightningcss-win32-x64-msvc | 1.33.0 | MPL-2.0 | — |
94
- | nodemailer | 10.0.13 | MIT-0 | https://github.com/nodemailer/nodemailer |
94
+ | nodemailer | 10.0.16 | MIT-0 | https://github.com/nodemailer/nodemailer |
95
95
  | on-exit-leak-free | 2.1.2 | MIT | https://github.com/mcollina/on-exit-or-gc |
96
96
  | pino | 10.3.1 | MIT | https://github.com/pinojs/pino |
97
97
  | pino-abstract-transport | 3.0.0 | MIT | https://github.com/pinojs/pino-abstract-transport |
98
98
  | pino-std-serializers | 7.1.0 | MIT | https://github.com/pinojs/pino-std-serializers |
99
- | postal-mime | 4.0.2 | MIT-0 | https://github.com/postalsys/postal-mime |
99
+ | postal-mime | 4.0.5 | MIT-0 | https://github.com/postalsys/postal-mime |
100
100
  | process-warning | 5.1.0 | MIT | https://github.com/fastify/process-warning |
101
101
  | quick-format-unescaped | 4.0.4 | MIT | https://github.com/davidmarkclements/quick-format |
102
102
  | real-require | 0.2.0 | MIT | https://github.com/pinojs/real-require |
@@ -113,7 +113,7 @@ MPL-2.0 is a file-level license: it covers ical.js's own files and does not exte
113
113
 
114
114
  ## License and notice texts
115
115
 
116
- ### @chrischall/mcp-utils@2.15.0
116
+ ### @chrischall/mcp-utils@3.0.0
117
117
 
118
118
  - License: MIT
119
119
  - Source: https://github.com/chrischall/mcp-utils
@@ -301,7 +301,7 @@ _An optional dependency that was not installed where this file was generated; se
301
301
 
302
302
  _An optional dependency that was not installed where this file was generated; see its package on npm._
303
303
 
304
- ### @modelcontextprotocol/core@2.3.0
304
+ ### @modelcontextprotocol/core@2.3.1
305
305
 
306
306
  - License: Apache-2.0
307
307
  - Source: https://github.com/modelcontextprotocol/typescript-sdk
@@ -527,7 +527,7 @@ CC-BY-4.0. See https://creativecommons.org/licenses/by/4.0/legalcode for
527
527
  the full license text.
528
528
  ```
529
529
 
530
- ### @modelcontextprotocol/server@2.3.0
530
+ ### @modelcontextprotocol/server@2.3.1
531
531
 
532
532
  - License: Apache-2.0
533
533
  - Source: https://github.com/modelcontextprotocol/typescript-sdk
@@ -893,7 +893,7 @@ The above copyright notice and this permission notice shall be included in all c
893
893
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
894
894
  ```
895
895
 
896
- ### @zone-eu/mailsplit@5.4.19
896
+ ### @zone-eu/mailsplit@5.4.20
897
897
 
898
898
  - License: (MIT OR EUPL-1.1+)
899
899
  - Source: https://github.com/zone-eu/mailsplit
@@ -1113,7 +1113,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
1113
1113
  OR OTHER DEALINGS IN THE SOFTWARE.
1114
1114
  ```
1115
1115
 
1116
- ### dotenv@18.0.5
1116
+ ### dotenv@18.0.6
1117
1117
 
1118
1118
  - License: BSD-2-Clause
1119
1119
  - Source: https://github.com/motdotla/dotenv
@@ -1620,7 +1620,7 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1620
1620
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1621
1621
  ```
1622
1622
 
1623
- ### imapflow@2.1.2
1623
+ ### imapflow@2.2.10
1624
1624
 
1625
1625
  - License: MIT
1626
1626
  - Source: https://github.com/postalsys/imapflow
@@ -1675,7 +1675,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1675
1675
  THE SOFTWARE.
1676
1676
  ```
1677
1677
 
1678
- ### libbase64@1.3.1
1678
+ ### libbase64@1.3.2
1679
1679
 
1680
1680
  - License: MIT
1681
1681
  - Source: https://github.com/nodemailer/libbase64
@@ -1704,7 +1704,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1704
1704
  THE SOFTWARE.
1705
1705
  ```
1706
1706
 
1707
- ### libmime@5.4.6
1707
+ ### libmime@5.4.7
1708
1708
 
1709
1709
  - License: MIT
1710
1710
  - Source: https://github.com/nodemailer/libmime
@@ -2205,7 +2205,7 @@ _An optional dependency that was not installed where this file was generated; se
2205
2205
 
2206
2206
  _An optional dependency that was not installed where this file was generated; see its package on npm._
2207
2207
 
2208
- ### nodemailer@10.0.13
2208
+ ### nodemailer@10.0.16
2209
2209
 
2210
2210
  - License: MIT-0
2211
2211
  - Source: https://github.com/nodemailer/nodemailer
@@ -2341,7 +2341,7 @@ The above copyright notice and this permission notice shall be included in all c
2341
2341
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2342
2342
  ```
2343
2343
 
2344
- ### postal-mime@4.0.2
2344
+ ### postal-mime@4.0.5
2345
2345
 
2346
2346
  - License: MIT-0
2347
2347
  - Source: https://github.com/postalsys/postal-mime
@@ -2,10 +2,14 @@ import { createPrivateKey } from 'node:crypto';
2
2
  import { readFileSync } from 'node:fs';
3
3
  import { expandPath, readEnvVar, signEs256Jwt } from '@chrischall/mcp-utils';
4
4
  import { ConfigError, rememberSecret } from './errors.js';
5
- const PREFIX = {
6
- music: 'APPLE_MUSIC',
7
- maps: 'APPLE_MAPS',
8
- weather: 'APPLE_WEATHERKIT',
5
+ /**
6
+ * Each service's own key pair, spelled out in full (not built from a name
7
+ * stem) so every variable the server reads appears literally in the code.
8
+ */
9
+ const OWN_VARS = {
10
+ music: { keyId: 'APPLE_MUSIC_KEY_ID', privateKey: 'APPLE_MUSIC_PRIVATE_KEY' },
11
+ maps: { keyId: 'APPLE_MAPS_KEY_ID', privateKey: 'APPLE_MAPS_PRIVATE_KEY' },
12
+ weather: { keyId: 'APPLE_WEATHERKIT_KEY_ID', privateKey: 'APPLE_WEATHERKIT_PRIVATE_KEY' },
9
13
  };
10
14
  /**
11
15
  * Accept the shapes a .p8 actually arrives in through an env block:
@@ -73,16 +77,16 @@ function readKeyFile(path, varName, service) {
73
77
  */
74
78
  export function resolveDeveloperKey(service, env = process.env) {
75
79
  const svcName = service;
76
- const prefix = PREFIX[service];
80
+ const own = OWN_VARS[service];
77
81
  const teamId = readEnvVar('APPLE_TEAM_ID', { env });
78
- const ownKeyId = readEnvVar(`${prefix}_KEY_ID`, { env });
79
- const ownKey = readEnvVar(`${prefix}_PRIVATE_KEY`, { env });
82
+ const ownKeyId = readEnvVar(own.keyId, { env });
83
+ const ownKey = readEnvVar(own.privateKey, { env });
80
84
  const keyId = ownKeyId ?? readEnvVar('APPLE_KEY_ID', { env });
81
85
  let rawKey;
82
86
  let keyVar;
83
87
  if (ownKey !== undefined) {
84
88
  rawKey = ownKey;
85
- keyVar = `${prefix}_PRIVATE_KEY`;
89
+ keyVar = own.privateKey;
86
90
  }
87
91
  else if (readEnvVar('APPLE_PRIVATE_KEY', { env }) !== undefined) {
88
92
  rawKey = readEnvVar('APPLE_PRIVATE_KEY', { env });
@@ -98,9 +102,9 @@ export function resolveDeveloperKey(service, env = process.env) {
98
102
  if (!teamId)
99
103
  missing.push('APPLE_TEAM_ID');
100
104
  if (!keyId)
101
- missing.push(`APPLE_KEY_ID (or ${prefix}_KEY_ID)`);
105
+ missing.push(`APPLE_KEY_ID (or ${own.keyId})`);
102
106
  if (rawKey === undefined)
103
- missing.push(`APPLE_PRIVATE_KEY (or ${prefix}_PRIVATE_KEY / APPLE_PRIVATE_KEY_PATH)`);
107
+ missing.push(`APPLE_PRIVATE_KEY (or ${own.privateKey} / APPLE_PRIVATE_KEY_PATH)`);
104
108
  if (missing.length === 0)
105
109
  assertPairMatches(service, env);
106
110
  if (missing.length > 0) {
@@ -116,7 +120,7 @@ export function resolveDeveloperKey(service, env = process.env) {
116
120
  teamId: teamId,
117
121
  keyId: keyId,
118
122
  privateKeyPem: pem,
119
- source: `${ownKeyId ? `${prefix}_KEY_ID` : 'APPLE_KEY_ID'} + ${keyVar}`,
123
+ source: `${ownKeyId ? own.keyId : 'APPLE_KEY_ID'} + ${keyVar}`,
120
124
  };
121
125
  }
122
126
  /**
@@ -130,9 +134,9 @@ export function resolveDeveloperKey(service, env = process.env) {
130
134
  * APPLE_PRIVATE_KEY for one Music key) and is allowed.
131
135
  */
132
136
  function assertPairMatches(service, env) {
133
- const prefix = PREFIX[service];
134
- const ownKeyId = readEnvVar(`${prefix}_KEY_ID`, { env });
135
- const ownKey = readEnvVar(`${prefix}_PRIVATE_KEY`, { env });
137
+ const own = OWN_VARS[service];
138
+ const ownKeyId = readEnvVar(own.keyId, { env });
139
+ const ownKey = readEnvVar(own.privateKey, { env });
136
140
  const sharedKeyId = readEnvVar('APPLE_KEY_ID', { env });
137
141
  const sharedKeyVar = readEnvVar('APPLE_PRIVATE_KEY', { env }) !== undefined
138
142
  ? 'APPLE_PRIVATE_KEY'
@@ -142,12 +146,12 @@ function assertPairMatches(service, env) {
142
146
  if (sharedKeyId === undefined || sharedKeyVar === undefined)
143
147
  return;
144
148
  if (ownKey !== undefined && ownKeyId === undefined) {
145
- throw new ConfigError(service, `${prefix}_PRIVATE_KEY is set but ${prefix}_KEY_ID is not, and APPLE_KEY_ID belongs to the shared key in ${sharedKeyVar} — ` +
146
- 'a key id must name the key that signs the token.', [`${prefix}_KEY_ID`], `Set ${prefix}_KEY_ID to the Key ID of the key in ${prefix}_PRIVATE_KEY (Apple Developer portal → Keys), or unset ${prefix}_PRIVATE_KEY to use the shared key.`);
149
+ throw new ConfigError(service, `${own.privateKey} is set but ${own.keyId} is not, and APPLE_KEY_ID belongs to the shared key in ${sharedKeyVar} — ` +
150
+ 'a key id must name the key that signs the token.', [own.keyId], `Set ${own.keyId} to the Key ID of the key in ${own.privateKey} (Apple Developer portal → Keys), or unset ${own.privateKey} to use the shared key.`);
147
151
  }
148
152
  if (ownKeyId !== undefined && ownKey === undefined && ownKeyId !== sharedKeyId) {
149
- throw new ConfigError(service, `${prefix}_KEY_ID is set but ${prefix}_PRIVATE_KEY is not, and the shared key in ${sharedKeyVar} belongs to APPLE_KEY_ID — ` +
150
- 'a key id must name the key that signs the token.', [`${prefix}_PRIVATE_KEY`], `Set ${prefix}_PRIVATE_KEY to the .p8 contents of key ${prefix}_KEY_ID, or unset ${prefix}_KEY_ID to use the shared key.`);
153
+ throw new ConfigError(service, `${own.keyId} is set but ${own.privateKey} is not, and the shared key in ${sharedKeyVar} belongs to APPLE_KEY_ID — ` +
154
+ 'a key id must name the key that signs the token.', [own.privateKey], `Set ${own.privateKey} to the .p8 contents of key ${own.keyId}, or unset ${own.keyId} to use the shared key.`);
151
155
  }
152
156
  }
153
157
  function serviceLabel(service) {