apple-notes-mcp 2.9.10 → 2.9.12
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 +42 -4
- package/build/index.js +597 -99
- package/native/public-helper/apple-notes-public-helper.swift +331 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -982,6 +982,13 @@ Deletes a note (moves to Recently Deleted in Notes.app).
|
|
|
982
982
|
Title-only deletion is rejected. If the note changed after the supplied hash
|
|
983
983
|
was read, deletion is also rejected.
|
|
984
984
|
|
|
985
|
+
**Notes with large images.** Notes.app returns a note's body with each inline
|
|
986
|
+
image embedded as base64, so a note holding one 40 MB image has a body of about
|
|
987
|
+
110 MB. Body reads accept up to 512 MB of output, and `delete-note` compares a
|
|
988
|
+
body longer than 5 MB against a private temporary file rather than embedding it
|
|
989
|
+
in the AppleScript. The comparison still covers the whole body, and the file
|
|
990
|
+
is removed when the delete finishes.
|
|
991
|
+
|
|
985
992
|
**Copy-then-retire.** To delete an original only while its copy is still good,
|
|
986
993
|
read both notes, verify the copy, and pass the copy as `guardNoteId` with its
|
|
987
994
|
`contentHash` as `expectedGuardContentHash`. The copy's revision is re-read just
|
|
@@ -1857,6 +1864,37 @@ Decodes a note's classic PencilKit drawings (`com.apple.drawing.2` and the older
|
|
|
1857
1864
|
|
|
1858
1865
|
---
|
|
1859
1866
|
|
|
1867
|
+
#### `transcribe-note-audio`
|
|
1868
|
+
|
|
1869
|
+
Transcribes a note's voice recordings and audio attachments now, on this Mac, with Apple's Speech framework through the [public native helper](#public-native-helper). Recognition is on-device only: `SpeechAnalyzer` on macOS 26 and later, or `SFSpeechRecognizer` with on-device recognition required on older systems (a locale without on-device support is refused, never sent to a server). The audio files are opened read-only where Notes keeps them.
|
|
1870
|
+
|
|
1871
|
+
**Requires:** Full Disk Access for the MCP host process, and the public native helper built once with `apple-notes-mcp setup --public-helper`.
|
|
1872
|
+
|
|
1873
|
+
| Parameter | Type | Required | Description |
|
|
1874
|
+
|-----------|------|----------|-------------|
|
|
1875
|
+
| `id` | string | Yes | Note ID (use `search-notes` to find it first) |
|
|
1876
|
+
| `locale` | string | No | BCP-47 language of the speech, such as `"en-US"` (default), `"it-IT"`, or `"fr-FR"` |
|
|
1877
|
+
| `attachmentId` | string | No | Only transcribe this audio attachment (an `x-coredata://…/ICAttachment/pN` id) |
|
|
1878
|
+
| `includeText` | boolean | No | Include transcript text (default `true`); `false` returns statuses and word counts only |
|
|
1879
|
+
| `downloadAssets` | boolean | No | Let macOS download the language's on-device speech model when it is missing (default `false`: the call returns `asset_unavailable` at once) |
|
|
1880
|
+
| `maxSeconds` | integer | No | Total time budget for the call, 30 to 3600 seconds (default 900) |
|
|
1881
|
+
|
|
1882
|
+
**Returns:** Overall `status` and, per audio attachment, `status`, `durationSeconds`, `wordCount`, `transcript`, and `takes` (a Notes recording can hold several takes; each is transcribed and the texts are joined in stored order). Statuses:
|
|
1883
|
+
|
|
1884
|
+
- `ok`: the whole recording was transcribed.
|
|
1885
|
+
- `partial`: some text came back, but a take failed or the helper stopped at its deadline (`code: "incomplete"`).
|
|
1886
|
+
- `error`: nothing was transcribed; `code` says why (`asset_unavailable` when the audio file is not on this Mac or the language's speech model is not installed, `permission_required`, `unsupported_locale`, `unsupported_audio`, `time_limit`, ...).
|
|
1887
|
+
- `indeterminate`: the helper did not answer in time, so the outcome is unknown and a retry may succeed.
|
|
1888
|
+
- `none` (overall only): the note has no audio.
|
|
1889
|
+
|
|
1890
|
+
Each take gets a deadline of 1.5 times its length plus a minute (at most 30 minutes), shortened to what is left of `maxSeconds`. A take that cannot start before the budget runs out reports `code: "time_limit"`. The helper runs as a separate process without blocking the server, and cancelling the request stops it. On macOS 27 a 16-minute recording took about 22 seconds. Some MCP clients stop waiting for a tool after a fixed time, so transcribe long recordings one at a time with `attachmentId`. Transcripts longer than `APPLE_NOTES_MCP_EXPORT_MAX_BYTES` are shortened and marked `transcriptTruncated`.
|
|
1891
|
+
|
|
1892
|
+
**Speech models:** the call never starts a download on its own. When the language's on-device model is not installed, it returns `asset_unavailable` right away. Pass `downloadAssets: true` to let macOS download it (a one-time download); if it is still downloading when the call ends, try again shortly.
|
|
1893
|
+
|
|
1894
|
+
**Speech Recognition permission:** the server never shows the Speech Recognition prompt, because nobody may be watching an MCP server to answer it. The helper reads the current authorization first. On older macOS, the `SFSpeechRecognizer` path needs that access, and macOS attributes the grant to the app that launches the MCP server (Claude Desktop, Codex, Terminal, and so on), not to the helper. Without it the call returns `code: "permission_required"`; allow the app under System Settings > Privacy & Security > Speech Recognition. On macOS 26 and later, `SpeechAnalyzer` transcribed files without any grant in testing (authorization stayed "not determined"), so only an explicit refusal (denied or restricted) stops it.
|
|
1895
|
+
|
|
1896
|
+
---
|
|
1897
|
+
|
|
1860
1898
|
#### `add-attachment`
|
|
1861
1899
|
|
|
1862
1900
|
Adds one nonempty local file of at most 64 MiB to an exact note using `id`, the
|
|
@@ -2431,7 +2469,7 @@ All configuration is optional — the server works out of the box. Override beha
|
|
|
2431
2469
|
|
|
2432
2470
|
| Variable | Default | Description |
|
|
2433
2471
|
|----------|---------|-------------|
|
|
2434
|
-
| `APPLE_NOTES_MCP_MAX_BUFFER` | `67108864` (64 MB) | Max bytes captured from a single AppleScript invocation. Raise it if a very large export/list is truncated; lower it to cap memory. |
|
|
2472
|
+
| `APPLE_NOTES_MCP_MAX_BUFFER` | `67108864` (64 MB) | Max bytes captured from a single AppleScript invocation. Raise it if a very large export/list is truncated; lower it to cap memory. Reading one note body allows at least 512 MB regardless, since a body embeds its inline images. Output past the cap fails with an error naming this variable, not as a timeout. |
|
|
2435
2473
|
| `APPLE_NOTES_MCP_MAX_ATTACHMENT_BYTES` | `26214400` (25 MB) | Max size of an attachment that [`fetch-attachment`](#fetch-attachment) will base64-encode inline. Larger attachments are rejected with an error pointing at [`save-attachment`](#save-attachment) (which streams to disk and has no such limit). Raise it to fetch bigger attachments inline; lower it to cap memory. |
|
|
2436
2474
|
| `APPLE_NOTES_MCP_MAX_INLINE_IMAGE_BYTES` | `262144` (256 KB) | Per-image cap on the base64 payload kept inline in a [`get-note-content`](#get-note-content) response. Inline images over the cap are replaced with placeholders (with a warning appended) so an image-heavy note cannot exceed the MCP client's message limit and drop the connection; export the real files with [`save-attachment`](#save-attachment) or [`fetch-attachment`](#fetch-attachment). Raise it to keep bigger images inline. |
|
|
2437
2475
|
| `APPLE_NOTES_MCP_CONFIG_FILE` | `~/Library/Application Support/apple-notes-mcp/config.json` | Path to the JSON config file (see below). |
|
|
@@ -2496,13 +2534,13 @@ Every tool that does not read the Notes database works normally without Full Dis
|
|
|
2496
2534
|
- `get-note-link` returns an error on macOS 26+; on macOS 12–15 it still works via the AppleScript `note link` fallback
|
|
2497
2535
|
- `get-note-markdown` returns plain list items without `[x]`/`[ ]` annotations (graceful fallback)
|
|
2498
2536
|
- `get-sync-status` still answers, but reports no pending uploads and no active sync — treat that as "unknown", not "idle"
|
|
2499
|
-
- `get-note-drawings`
|
|
2537
|
+
- `get-note-drawings` and `transcribe-note-audio` return the same Full Disk Access error
|
|
2500
2538
|
|
|
2501
2539
|
---
|
|
2502
2540
|
|
|
2503
2541
|
## Public native helper
|
|
2504
2542
|
|
|
2505
|
-
`get-note-drawings` needs Apple's PencilKit framework
|
|
2543
|
+
`get-note-drawings` needs Apple's PencilKit framework and `transcribe-note-audio` needs the Speech framework; neither has an AppleScript or command-line interface. For them, the server uses a small Swift helper that links public Apple frameworks only (AppKit, PencilKit, AVFoundation, and Speech). No prebuilt binary ships with the package. Build it once on your Mac:
|
|
2506
2544
|
|
|
2507
2545
|
```bash
|
|
2508
2546
|
apple-notes-mcp setup --public-helper # compile, sign, verify, install
|
|
@@ -2511,7 +2549,7 @@ apple-notes-mcp setup --public-helper --check # report the installed state only
|
|
|
2511
2549
|
|
|
2512
2550
|
Setup compiles `native/public-helper/apple-notes-public-helper.swift` with `xcrun swiftc` (install the Command Line Tools with `xcode-select --install` if it is missing), signs it ad hoc, runs its `hello` handshake, and installs it in `~/Library/Application Support/apple-notes-mcp/public-helper/` next to a manifest recording the SHA-256 of the source and the binary. Before every use the server re-checks both digests: after an upgrade that changes the helper source, or if the binary is replaced, the helper is refused until you run setup again. `APPLE_NOTES_MCP_PUBLIC_HELPER_DIR` overrides the install folder and `APPLE_NOTES_MCP_PUBLIC_HELPER_TIMEOUT_MS` the per-call timeout.
|
|
2513
2551
|
|
|
2514
|
-
The helper never opens the Notes database and never writes under the Notes group container. The server reads the bytes it needs (read-only) and passes them to the helper on stdin; the helper answers with one JSON object on stdout.
|
|
2552
|
+
The helper never opens the Notes database and never writes under the Notes group container. The server reads the bytes it needs (read-only) and passes them to the helper on stdin, or, for transcription, names one audio file that the helper opens for reading; the helper answers with one JSON object on stdout.
|
|
2515
2553
|
|
|
2516
2554
|
---
|
|
2517
2555
|
|