mcp-icloud 2.1.2 → 2.1.3
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.
- package/PRIVACY.md +55 -0
- package/README.md +4 -2
- package/calendar/index.js +1 -1
- package/contacts/index.js +1 -1
- package/email/index.js +1 -1
- package/index.js +4 -3
- package/messages/index.js +3 -3
- package/package.json +2 -1
- package/reminders/index.js +1 -1
package/PRIVACY.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Privacy policy
|
|
2
|
+
|
|
3
|
+
Effective 10 August 2026. Applies to the mcp-icloud server (the software you
|
|
4
|
+
run), not to any AI client you connect it to.
|
|
5
|
+
|
|
6
|
+
## The short version
|
|
7
|
+
|
|
8
|
+
mcp-icloud runs on your machine and works for you. It has no servers of its
|
|
9
|
+
own, no analytics, no telemetry, and no way to see your data. The author
|
|
10
|
+
never receives anything.
|
|
11
|
+
|
|
12
|
+
## What the software touches, and where it goes
|
|
13
|
+
|
|
14
|
+
When a connected AI client (Claude Desktop, for example) calls a tool, the
|
|
15
|
+
server reads or writes data in your Apple services: mail, calendar events,
|
|
16
|
+
contacts, reminders, notes, messages, and Safari tabs. Two things happen
|
|
17
|
+
with that data, and nothing else.
|
|
18
|
+
|
|
19
|
+
First, tool results are returned to the AI client that asked for them. What
|
|
20
|
+
that client does with the data is governed by its own privacy policy, not
|
|
21
|
+
this one. Nothing is sent anywhere unless a client you connected asks.
|
|
22
|
+
|
|
23
|
+
Second, in cloud mode the server talks to Apple's servers on your behalf
|
|
24
|
+
(imap.mail.me.com, smtp.mail.me.com, caldav.icloud.com,
|
|
25
|
+
contacts.icloud.com), over TLS, authenticated with credentials you
|
|
26
|
+
provided. In local mode the server makes no network connections at all; it
|
|
27
|
+
drives the apps already on your Mac, and macOS asks for your consent per
|
|
28
|
+
app before any of that works. You can revoke that consent at any time in
|
|
29
|
+
System Settings under Privacy and Security.
|
|
30
|
+
|
|
31
|
+
## Credentials
|
|
32
|
+
|
|
33
|
+
Cloud mode needs your iCloud address and an app-specific password. You
|
|
34
|
+
store them yourself, either in a local .env file or in the macOS Keychain
|
|
35
|
+
when you install the desktop extension. The server reads them once at
|
|
36
|
+
startup, sends them only to Apple, and never writes them to any log.
|
|
37
|
+
Diagnostics print a fixed mask instead of the value. Local mode needs no
|
|
38
|
+
credentials at all.
|
|
39
|
+
|
|
40
|
+
## What is kept
|
|
41
|
+
|
|
42
|
+
Nothing. The server is stateless: no database, no cache, no files written.
|
|
43
|
+
When it stops, nothing of yours remains in it.
|
|
44
|
+
|
|
45
|
+
## Third parties
|
|
46
|
+
|
|
47
|
+
There are none. No data is sold, shared, or transferred to anyone. The only
|
|
48
|
+
parties that ever see your data are Apple (which already has it) and the AI
|
|
49
|
+
client you chose to connect.
|
|
50
|
+
|
|
51
|
+
## Changes and contact
|
|
52
|
+
|
|
53
|
+
Changes to this policy are made in this file, in the open, with the
|
|
54
|
+
repository's history as the record. Questions and concerns:
|
|
55
|
+
https://github.com/MrGo2/icloud-mcp/issues
|
package/README.md
CHANGED
|
@@ -34,7 +34,9 @@ Credentials are never logged. `ICLOUD_APP_PASSWORD` is read once at startup and
|
|
|
34
34
|
|
|
35
35
|
Every tool argument is validated against a zod schema before the handler runs. Arguments are also coerced at each AppleScript interpolation site, so a value that is not a number cannot reach a script template.
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
## Privacy Policy
|
|
38
|
+
|
|
39
|
+
The server collects nothing and keeps nothing: no telemetry, no analytics, no state on disk. Your data moves only between your machine, the AI client you connect and Apple's services. The full policy, covering collection, storage, third-party sharing, retention and contact, is in [PRIVACY.md](PRIVACY.md).
|
|
38
40
|
|
|
39
41
|
## Tools
|
|
40
42
|
|
|
@@ -115,7 +117,7 @@ Reading requires the [`imsg`](https://github.com/steipete/imsg) CLI and Full Dis
|
|
|
115
117
|
|
|
116
118
|
### Tool annotations (MCP hints)
|
|
117
119
|
|
|
118
|
-
Every tool declares its behaviour explicitly instead of relying on the spec defaults, which are deliberately pessimistic. All `list-*`, `read-*`, `search-*` and `get-*` tools, plus `about` and `check-auth-status`, are marked read-only.
|
|
120
|
+
Every tool declares its behaviour explicitly instead of relying on the spec defaults, which are deliberately pessimistic. All `list-*`, `read-*`, `search-*` and `get-*` tools, plus `about` and `check-auth-status`, are marked read-only. Nine tools carry `destructiveHint`: the four deletions (`delete-event`, `delete-contact`, `delete-reminder`, `close-safari-tab`), the three that reach another person irrevocably (`send-email`, `send-message`, `react-message`) and the two in-place updates (`update-event`, `update-reminder`). Tools that reach the network or another person carry `openWorldHint`: all Email and Calendar tools, `send-message`, `react-message` and `open-safari-url`. The read-only tools plus `mark-as-read`, `complete-reminder`, `update-reminder`, `update-event` and `set-mode` are marked idempotent.
|
|
119
121
|
|
|
120
122
|
## Installation
|
|
121
123
|
|
package/calendar/index.js
CHANGED
|
@@ -218,7 +218,7 @@ const calendarTools = [
|
|
|
218
218
|
description: z.string().optional().describe('New description (optional)'),
|
|
219
219
|
location: z.string().optional().describe('New location (optional)')
|
|
220
220
|
},
|
|
221
|
-
annotations: {"readOnlyHint":false,"destructiveHint":
|
|
221
|
+
annotations: {"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true},
|
|
222
222
|
handler: withErrorHandler(handleUpdateEvent, 'update-event')
|
|
223
223
|
},
|
|
224
224
|
{
|
package/contacts/index.js
CHANGED
|
@@ -309,7 +309,7 @@ const contactsTools = [
|
|
|
309
309
|
{
|
|
310
310
|
name: 'delete-contact',
|
|
311
311
|
title: 'Delete Contact',
|
|
312
|
-
description: 'Permanently deletes a contact from the user\'s address book. Takes the handle returned by list-contacts or search-contacts;
|
|
312
|
+
description: 'Permanently deletes a contact from the user\'s address book. Takes the handle returned by list-contacts or search-contacts; there is no undo through this server.',
|
|
313
313
|
inputSchema: {
|
|
314
314
|
contactUrl: z.string().describe('URL or ID of the contact to delete (from list-contacts output)')
|
|
315
315
|
},
|
package/email/index.js
CHANGED
|
@@ -225,7 +225,7 @@ const emailTools = [
|
|
|
225
225
|
body: z.string().describe('Email body content'),
|
|
226
226
|
isHtml: z.boolean().optional().describe('Whether the body is HTML (default: false)')
|
|
227
227
|
},
|
|
228
|
-
annotations: {"readOnlyHint":false,"destructiveHint":
|
|
228
|
+
annotations: {"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true},
|
|
229
229
|
handler: withErrorHandler(handleSendEmail, 'send-email')
|
|
230
230
|
},
|
|
231
231
|
{
|
package/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* iCloud MCP Server
|
|
4
|
+
* iCloud MCP Server
|
|
5
5
|
*
|
|
6
6
|
* Provides Claude with access to Apple services:
|
|
7
7
|
* - Email (via IMAP/SMTP or Mail.app)
|
|
@@ -21,6 +21,7 @@ const { McpServer } = require('@modelcontextprotocol/server');
|
|
|
21
21
|
const { serveStdio } = require('@modelcontextprotocol/server/stdio');
|
|
22
22
|
|
|
23
23
|
const config = require('./config');
|
|
24
|
+
const { version } = require('./package.json');
|
|
24
25
|
const { getMode, onModeChange } = require('./mode');
|
|
25
26
|
|
|
26
27
|
// Import all modules - tools are always available, handlers check mode
|
|
@@ -56,7 +57,7 @@ function buildServer() {
|
|
|
56
57
|
const server = new McpServer(
|
|
57
58
|
{
|
|
58
59
|
name: 'icloud-mcp',
|
|
59
|
-
version
|
|
60
|
+
version,
|
|
60
61
|
title: 'iCloud MCP'
|
|
61
62
|
},
|
|
62
63
|
{
|
|
@@ -98,7 +99,7 @@ mode returns an error. Use set-mode to switch without restarting.`
|
|
|
98
99
|
return server;
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
console.error(
|
|
102
|
+
console.error(`[icloud-mcp] Starting iCloud MCP server v${version}...`);
|
|
102
103
|
console.error(`[icloud-mcp] Initial mode: ${getMode().toUpperCase()}`);
|
|
103
104
|
console.error(`[icloud-mcp] Tools available: ${TOOLS.length}`);
|
|
104
105
|
|
package/messages/index.js
CHANGED
|
@@ -110,13 +110,13 @@ const messagesTools = [
|
|
|
110
110
|
{
|
|
111
111
|
name: 'send-message',
|
|
112
112
|
title: 'Send Message',
|
|
113
|
-
description: '
|
|
113
|
+
description: 'Sends an iMessage or SMS to a phone number or email handle, with an optional file attachment. The message is delivered as soon as the tool runs; there is no draft step and no recall.',
|
|
114
114
|
inputSchema: {
|
|
115
115
|
to: z.string().describe('Recipient phone number (with country code) or email'),
|
|
116
116
|
body: z.string().describe('Message content'),
|
|
117
117
|
file: z.string().optional().describe('Path to file attachment (optional)')
|
|
118
118
|
},
|
|
119
|
-
annotations: {"readOnlyHint":false,"destructiveHint":
|
|
119
|
+
annotations: {"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true},
|
|
120
120
|
handler: withErrorHandler(async ({ to, body, file }) => {
|
|
121
121
|
const modeError = requireLocalMode('send-message');
|
|
122
122
|
if (modeError) return modeError;
|
|
@@ -144,7 +144,7 @@ const messagesTools = [
|
|
|
144
144
|
chatId: z.number().int().describe('Chat ID'),
|
|
145
145
|
type: z.enum(['love', 'like', 'dislike', 'laugh', 'emphasis', 'question']).describe('Reaction type')
|
|
146
146
|
},
|
|
147
|
-
annotations: {"readOnlyHint":false,"destructiveHint":
|
|
147
|
+
annotations: {"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true},
|
|
148
148
|
handler: withErrorHandler(async ({ chatId, type }) => {
|
|
149
149
|
const modeError = requireLocalMode('react-message');
|
|
150
150
|
if (modeError) return modeError;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-icloud",
|
|
3
3
|
"mcpName": "io.github.MrGo2/icloud-mcp",
|
|
4
|
-
"version": "2.1.
|
|
4
|
+
"version": "2.1.3",
|
|
5
5
|
"description": "MCP server for Apple services - Email, Calendar, Contacts, Reminders, Notes, Messages and Safari - with dual local (AppleScript) and cloud (IMAP/CalDAV/CardDAV) modes",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"bin": {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"utils/",
|
|
23
23
|
"LICENSE",
|
|
24
24
|
"README.md",
|
|
25
|
+
"PRIVACY.md",
|
|
25
26
|
"DISCLOSURE"
|
|
26
27
|
],
|
|
27
28
|
"scripts": {
|
package/reminders/index.js
CHANGED
|
@@ -115,7 +115,7 @@ const remindersTools = [
|
|
|
115
115
|
dueDate: z.string().optional().describe('New due date in ISO format'),
|
|
116
116
|
priority: z.number().int().min(0).max(9).optional().describe('New priority level')
|
|
117
117
|
},
|
|
118
|
-
annotations: {"readOnlyHint":false,"destructiveHint":
|
|
118
|
+
annotations: {"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},
|
|
119
119
|
handler: async ({ reminderId, ...updates }) => {
|
|
120
120
|
const modeError = requireLocalMode('update-reminder');
|
|
121
121
|
if (modeError) return modeError;
|