apple-tools-mcp 2.1.5 → 3.0.1

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/README.md CHANGED
@@ -374,6 +374,81 @@ launchctl load ~/Library/LaunchAgents/com.apple-tools-mcp.indexer.plist
374
374
 
375
375
  KeepAlive belongs on this indexer job only — not on the MCP stdio process.
376
376
 
377
+ ## Remote HTTP transport (v3.0.0)
378
+
379
+ Every tool the stdio server exposes — including the write tools — is also
380
+ available over **Streamable HTTP**, so it's reachable from other machines,
381
+ not just whatever process spawned it locally. This is additive: stdio still
382
+ works exactly as before for local same-machine MCP clients that spawn it
383
+ directly. The intended MacBook clients are Claude Desktop, Claude Code,
384
+ Codex Desktop, and ChatGPT Desktop. Claude Desktop uses the included local
385
+ HTTP-to-stdio proxy; Claude Code and Codex connect to the Mini's HTTP
386
+ endpoint directly. ChatGPT Desktop does not currently support this private
387
+ MCP connection; see the client guide for its provider-supported options.
388
+
389
+ Because HTTP reaches beyond "whoever spawned this process," which stdio's
390
+ trust model relies on, **every HTTP request needs a bearer token.** stdio
391
+ has no equivalent check — a locally spawned child process is already
392
+ trusted by whoever spawned it.
393
+
394
+ **Entrypoint:** `node index.js --transport=http`
395
+ **Convenience bin:** `apple-tools-http` (`bin/apple-tools-http.js`; npm global install provides it)
396
+ **npm script (clone only):** `npm run http`
397
+
398
+ ### Auth token
399
+
400
+ The token is a random secret generated on first run and stored in the
401
+ macOS Keychain (service `apple-tools-mcp-http`) — never in a config file,
402
+ the server's config file, or logs after the one-time generation banner.
403
+ There's no external account and no cost; it's a self-issued password,
404
+ like an SSH key.
405
+
406
+ ```bash
407
+ apple-tools-mcp http-token # prints the token, generating one first if needed
408
+ ```
409
+
410
+ Clients send it as `Authorization: Bearer <token>`. Rotate it by deleting
411
+ the Keychain item and restarting the server (it generates a fresh one on
412
+ the next run), then update every client using the old value.
413
+
414
+ ### Config
415
+
416
+ `~/.apple-tools-mcp/config.json` (same file the index interval uses):
417
+
418
+ ```json
419
+ {
420
+ "httpHost": "127.0.0.1",
421
+ "httpPort": 8421
422
+ }
423
+ ```
424
+
425
+ Env overrides: `APPLE_TOOLS_HTTP_HOST`, `APPLE_TOOLS_HTTP_PORT`. The default
426
+ host is `127.0.0.1`, so HTTP is local-only until you explicitly set a network
427
+ address such as `0.0.0.0`. Default port is 8421 (the indexer's stdio process
428
+ needs no port; this is only for `--transport=http`). For remote access, use a
429
+ Tailscale address for clients that connect directly from your tailnet, or
430
+ put the server behind a TLS-terminating reverse proxy. Do not send the
431
+ bearer token over an untrusted LAN. Cloud-hosted connectors need a separate
432
+ way to reach the server; a private Tailscale address alone is insufficient.
433
+
434
+ ### LaunchAgent
435
+
436
+ See `examples/com.apple-tools-http.plist` (copy to
437
+ `~/Library/LaunchAgents/`, replace the `REPLACE_ME*` placeholders the same
438
+ way as the indexer plist above, then `launchctl load` it). Runs alongside
439
+ the indexer LaunchAgent, not instead of it — the HTTP server is a second,
440
+ independent process.
441
+
442
+ ### Wiring up clients
443
+
444
+ See `examples/mcp-client.md` for the MacBook setup. Short version:
445
+
446
+ - **On the Mini:** set `httpHost` to its LAN or Tailscale IP and restart the HTTP server. Retrieve the bearer token with `apple-tools-mcp http-token`.
447
+ - **Claude Desktop on the MacBook:** configure the included `apple-tools-http-proxy` as a local MCP server. It forwards tool calls to the Mini over HTTP.
448
+ - **Claude Code and Codex Desktop on the MacBook:** add `http://<mini-address>:8421/mcp` and the token. The client guide has commands for both.
449
+ - **ChatGPT Desktop on the MacBook:** current custom MCP support does not provide a direct private HTTP connection in the desktop app. The client guide describes the documented ChatGPT web route.
450
+ - **Claude / ChatGPT cloud connectors:** a connector does not connect from your device's tailnet interface. [Claude requires a publicly reachable server](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp); [ChatGPT directs private-network servers to Secure MCP Tunnel and currently supports MCP apps on web only](https://help.openai.com/en/articles/12584461-developer-mode-and-mcp-apps-in-chatgpt). Use the provider's supported network setup before adding this server as a cloud connector.
451
+
377
452
  ## Available Tools
378
453
 
379
454
  Once configured, your MCP client can use these tools:
@@ -593,7 +668,7 @@ Ask your MCP client things like:
593
668
 
594
669
  ## Privacy & Security
595
670
 
596
- - **Local Processing**: All embeddings are generated locally using Xenova/Transformers
671
+ - **Local Processing**: All embeddings are generated locally using Hugging Face Transformers.js
597
672
  - **No Cloud Services**: No data is sent to external servers; the write bridge is a local unix socket, never a network port
598
673
  - **Reads are read-only**: Search and lookup tools never modify your data. The [write tools](#write-tools-200) are the only ones that change anything, and they are opt-in per call, with `confirm` required for deletes and multi-recipient sends
599
674
  - **No credentials**: The server holds no tokens or passwords. It uses the Mail, Messages, Calendar, and Contacts apps you are already signed into
@@ -722,4 +797,4 @@ MIT License - see [LICENSE](LICENSE) for details.
722
797
 
723
798
  - Built with the [Model Context Protocol SDK](https://github.com/modelcontextprotocol/sdk)
724
799
  - Vector search powered by [LanceDB](https://lancedb.com/)
725
- - Local embeddings via [Xenova/Transformers](https://github.com/xenova/transformers.js)
800
+ - Local embeddings via [Hugging Face Transformers.js](https://github.com/huggingface/transformers.js)
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import { runHttpStdioProxy } from "../lib/httpStdioProxy.js";
3
+
4
+ const url = process.argv[2];
5
+ if (!url || process.argv.length !== 3) {
6
+ console.error("Usage: apple-tools-http-proxy <http://mini-address:8421/mcp>");
7
+ process.exitCode = 2;
8
+ } else {
9
+ try {
10
+ await runHttpStdioProxy({ url, token: process.env.APPLE_TOOLS_MCP_TOKEN });
11
+ } catch (error) {
12
+ console.error(`Apple Tools HTTP proxy: ${error.message}`);
13
+ process.exitCode = 1;
14
+ }
15
+ }
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * npm bin for the HTTP transport.
4
+ * Dedicated wrapper so npm 12 pack/publish keeps the CLI — `index.js` as a
5
+ * bin target is rewritten with "script name index.js was invalid and removed".
6
+ * Injects `--transport=http` so a realpath to this file still starts the
7
+ * HTTP server. `permissions` / `http-token` still win (same contract as the
8
+ * apple-tools-indexer bin name for `--mode=indexer`).
9
+ */
10
+ if (!process.argv.includes('--transport=http')) {
11
+ const transportIdx = process.argv.indexOf('--transport');
12
+ if (transportIdx === -1 || process.argv[transportIdx + 1] !== 'http') {
13
+ process.argv.splice(2, 0, '--transport=http');
14
+ }
15
+ }
16
+ await import('../index.js');
@@ -0,0 +1,35 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Label</key>
6
+ <string>com.REPLACE_ME.apple-tools-http</string>
7
+ <key>ProgramArguments</key>
8
+ <array>
9
+ <string>/usr/bin/env</string>
10
+ <string>node</string>
11
+ <string>REPLACE_ME_WITH_REPO_PATH/bin/apple-tools-http.js</string>
12
+ </array>
13
+ <key>RunAtLoad</key>
14
+ <true/>
15
+ <key>KeepAlive</key>
16
+ <true/>
17
+ <key>ProcessType</key>
18
+ <string>Background</string>
19
+ <key>WorkingDirectory</key>
20
+ <string>/Users/REPLACE_ME</string>
21
+ <key>EnvironmentVariables</key>
22
+ <dict>
23
+ <key>PATH</key>
24
+ <string>REPLACE_ME_WITH_NODE_BIN_DIR:/usr/bin:/bin:/usr/sbin:/sbin</string>
25
+ <key>NODE_OPTIONS</key>
26
+ <string>--max-old-space-size=4096</string>
27
+ <key>HOME</key>
28
+ <string>/Users/REPLACE_ME</string>
29
+ </dict>
30
+ <key>StandardOutPath</key>
31
+ <string>/Users/REPLACE_ME/Library/Logs/apple-tools-http.out.log</string>
32
+ <key>StandardErrorPath</key>
33
+ <string>/Users/REPLACE_ME/Library/Logs/apple-tools-http.err.log</string>
34
+ </dict>
35
+ </plist>
@@ -0,0 +1,5 @@
1
+ {
2
+ "indexInterval": "5m",
3
+ "httpHost": "127.0.0.1",
4
+ "httpPort": 8421
5
+ }
@@ -0,0 +1,98 @@
1
+ # MacBook MCP client setup (Streamable HTTP, v3.0.0+)
2
+
3
+ `--transport=http` exposes the same tools as stdio mode (including writes:
4
+ sending iMessage, editing contacts/calendar) over the network, so every
5
+ request must carry the bearer token from `apple-tools-mcp http-token`.
6
+ This HTTP transport is for connecting the MacBook's Claude Desktop,
7
+ Claude Code, and Codex Desktop to the MCP server on the Mac Mini. ChatGPT
8
+ Desktop is also a target, but its current custom MCP support does not
9
+ accept a private server directly in the desktop app.
10
+
11
+ ## Server on the Mac Mini
12
+
13
+ Set `httpHost` in `~/.apple-tools-mcp/config.json` to the Mini's LAN or
14
+ Tailscale IP (or set `APPLE_TOOLS_HTTP_HOST` to that address), then restart
15
+ the HTTP server. The default `127.0.0.1` bind only accepts clients on the
16
+ Mini. Retrieve the token on the Mini with `apple-tools-mcp http-token`.
17
+
18
+ ## Claude Desktop on the MacBook
19
+
20
+ Install this package on the MacBook and find the absolute path of
21
+ `apple-tools-http-proxy` with `command -v apple-tools-http-proxy`. In
22
+ `~/Library/Application Support/Claude/claude_desktop_config.json`, add a
23
+ local MCP server entry using that path:
24
+
25
+ ```json
26
+ {
27
+ "mcpServers": {
28
+ "apple-tools": {
29
+ "command": "/absolute/path/to/apple-tools-http-proxy",
30
+ "args": ["http://<mini-address>:8421/mcp"],
31
+ "env": { "APPLE_TOOLS_MCP_TOKEN": "<token-from-mini>" }
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ Merge this entry into any existing `mcpServers` object, then fully quit and
38
+ reopen Claude Desktop. This local proxy makes the private-network request
39
+ from the MacBook. Claude Desktop's **custom connector** instead connects
40
+ from Anthropic's cloud and cannot use the Mini's private LAN or Tailscale IP.
41
+ [Anthropic documents the distinction](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp).
42
+ The example puts the token in Claude Desktop's local configuration; restrict
43
+ that file to your account.
44
+
45
+ ## Claude Code on the MacBook
46
+
47
+ ```bash
48
+ claude mcp add --transport http apple-tools http://<mini-address>:8421/mcp \
49
+ -H "Authorization: Bearer <token-from-mini>" \
50
+ -s user
51
+ ```
52
+
53
+ `<mini-address>` is the Mini's LAN or Tailscale IP, matching the address
54
+ on which the server listens.
55
+
56
+ ## Codex Desktop on the MacBook
57
+
58
+ Make the token from the Mini available as `APPLE_TOOLS_MCP_TOKEN` in the
59
+ MacBook environment that runs Codex, then add the server:
60
+
61
+ ```bash
62
+ codex mcp add apple-tools --url http://<mini-address>:8421/mcp \
63
+ --bearer-token-env-var APPLE_TOOLS_MCP_TOKEN
64
+ ```
65
+
66
+ The Codex CLI and desktop app share MCP configuration, but the token
67
+ environment variable must be available to whichever Codex process connects.
68
+ [OpenAI's Codex MCP setup guide](https://developers.openai.com/learn/docs-mcp)
69
+ describes their shared configuration.
70
+
71
+ ## Network access
72
+
73
+ For access away from the LAN, run Tailscale on both the Mini and MacBook and
74
+ use the Mini's Tailscale IP. Use TLS or a trusted private network before
75
+ sending the bearer token across the network. Keep the Mini's HTTP server
76
+ running while either client uses its tools.
77
+
78
+ ## ChatGPT Desktop on the MacBook
79
+
80
+ [OpenAI currently documents custom MCP apps for ChatGPT web](https://help.openai.com/en/articles/12584461-developer-mode-and-mcp-apps-in-chatgpt),
81
+ not ChatGPT Desktop. ChatGPT also cannot connect directly to the Mini's
82
+ private address. If you use ChatGPT web, OpenAI's
83
+ [Secure MCP Tunnel](https://developers.openai.com/api/docs/guides/secure-mcp-tunnels)
84
+ is the documented way to reach a private MCP server, subject to the
85
+ account and workspace access described there. This repository's HTTP
86
+ server does not by itself enable the requested ChatGPT Desktop connection.
87
+
88
+ ## Getting/rotating the token
89
+
90
+ ```bash
91
+ apple-tools-mcp http-token # print the current token (generates one if missing)
92
+ ```
93
+
94
+ On the Mini, the token lives in the macOS Keychain (service
95
+ `apple-tools-mcp-http`), never in the server's config file or the repo. To
96
+ rotate it, delete the Keychain item and restart the HTTP server — it'll
97
+ generate a new one on the next run —
98
+ then update every client that was using the old value.