apple-notes-mcp 2.9.26 → 2.9.28

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
@@ -527,8 +527,10 @@ and 64 levels of nesting. An unknown field such as `titel:x` is an error rather
527
527
  than a silent text search; quote it to search the literal text.
528
528
 
529
529
  Password-protected notes match on title and metadata only. Their bodies are
530
- encrypted, so body predicates never match them, and `-body:x` therefore does.
531
- Their snippets are always empty.
530
+ encrypted, so a body predicate is unknown for them rather than false: neither
531
+ `body:x` nor `-body:x` matches them, though `-body:x OR pinned` matches a
532
+ pinned one. Notes whose body cannot be decoded are treated the same way. Their
533
+ snippets are always empty.
532
534
 
533
535
  **Example - Open to-dos in a folder:**
534
536
  ```json
@@ -1355,7 +1357,7 @@ Lists notes from the NoteStore database (read-only) by stored modification time,
1355
1357
  - **Browsing.** Without `since`, rows come newest first. `nextSince` is then the newest row's cursor, set only when the call returned every matching note (`saturated` is `false`); otherwise it is `null`.
1356
1358
  - **Late edits.** A modification-date cursor can miss an edit that iCloud delivers later from another device with an older timestamp, for example after that device was offline. The row then sorts before the cursor. Run a full pass from the start now and then to catch these.
1357
1359
  - **Deletions.** Deleted notes are invisible unless `includeDeleted` is `true`. With it, notes in Recently Deleted and notes awaiting deletion appear, flagged, when their modification date is after the cursor. A note purged from the database leaves no row, so compare ids against a full pass to detect it.
1358
- - **Word counts.** A word is a whitespace-separated token containing a letter or digit; `charCount` counts Unicode code points. Attachment markers are not counted. Both are `null` for locked notes and bodies that are not downloaded or cannot be decoded, and `0` for a body known to be empty.
1360
+ - **Word counts.** A word is a whitespace-separated token containing a letter or digit, except that Chinese, Japanese, Thai, Lao, Khmer and Myanmar text, which has no spaces between words, is split at word boundaries (the same count `query-notes` uses for `words:` and `wordCount`); `charCount` counts Unicode code points. Attachment markers are not counted. Both are `null` for locked notes and bodies that are not downloaded or cannot be decoded, and `0` for a body known to be empty.
1359
1361
  - **Previews.** With `wordCounts`, `bodyPreview` comes from the decoded body and `textDecoded` is `true`. Otherwise it is the stored snippet. Locked notes never get a preview.
1360
1362
  - Folderless notes (abandoned Quick Note drafts Notes.app never shows) and Recently Deleted appear only with `includeDeleted`. Notes without a stored modification date never match a `since` query.
1361
1363
 
@@ -1750,11 +1752,12 @@ single note.
1750
1752
  | `assetsDir` | string | No | Absolute directory for attachment copies. Existing files are never replaced; a taken name gets `-2`, `-3`, ... |
1751
1753
  | `wrap` | number | No | Hard-wrap prose at this many columns. Code, tables and headings are never wrapped |
1752
1754
  | `template` | string | No | Render through a template: `standard-markdown`, `obsidian`, or a saved template's name. Exclusive with `templateFile` |
1753
- | `templateFile` | string | No | Render through the JSON template in this `.json` file (same path rules; at most 256 KiB) |
1755
+ | `templateFile` | string | No | Render through the JSON template in this `.json` file (at most 256 KiB), read under the same rules as `create-note`'s [`contentPath`](#create-note): hidden paths (such as `~/.docker` or a project `.env`) and `~/Library` other than iCloud Drive and `~/Library/CloudStorage` are refused, checked again after resolving symbolic links and letter case, unless the server sets `APPLE_NOTES_MCP_ALLOW_PRIVATE_CONTENT_PATHS=1`. Errors name the file, never its contents |
1754
1756
 
1755
1757
  Both paths follow the `save-attachment` rules (absolute, under the home
1756
1758
  directory, a temp directory, or `/Volumes`, no symlink escapes) and may not
1757
- point inside the Notes library container. With `outputPath`, asset links are
1759
+ point inside the Notes library container. `templateFile` is a read, so it
1760
+ also follows `contentPath`'s private-location rule. With `outputPath`, asset links are
1758
1761
  relative to the document's directory; without it they are absolute paths.
1759
1762
 
1760
1763
  **Returns:** without `outputPath`, the Markdown itself (refused with
@@ -1861,7 +1864,7 @@ or `templateFile`.
1861
1864
  |-----------|------|----------|-------------|
1862
1865
  | `name` | string | One of three | A saved or built-in template |
1863
1866
  | `template` | object or string | One of three | The template as a JSON object or JSON text |
1864
- | `templateFile` | string | One of three | Absolute path of a JSON template file (home, a temp directory, or `/Volumes`; at most 256 KiB) |
1867
+ | `templateFile` | string | One of three | Absolute path of a JSON template file (home, a temp directory, or `/Volumes`; at most 256 KiB), read under the same rules as `create-note`'s [`contentPath`](#create-note): hidden paths (such as `~/.docker` or a project `.env`) and `~/Library` other than iCloud Drive and `~/Library/CloudStorage` are refused, checked again after resolving symbolic links and letter case, unless the server sets `APPLE_NOTES_MCP_ALLOW_PRIVATE_CONTENT_PATHS=1` |
1865
1868
 
1866
1869
  **Returns:** `valid`, and `errors` as `{path, message}` pairs such as
1867
1870
  `$.rules["inline.bold"].after: is required when mode is "wrap"`. An invalid
@@ -1878,7 +1881,7 @@ can use it by `template` name.
1878
1881
  |-----------|------|----------|-------------|
1879
1882
  | `name` | string | Yes | Lowercase `a-z`, `0-9`, `-` and `_`, 1-64 characters, starting with a letter or digit. Built-in names are reserved |
1880
1883
  | `template` | object or string | One of `template`/`templateFile` | The template |
1881
- | `templateFile` | string | One of `template`/`templateFile` | A JSON template file |
1884
+ | `templateFile` | string | One of `template`/`templateFile` | A JSON template file, under the same rules as `validate-markdown-template`'s |
1882
1885
  | `force` | boolean | No | Replace an existing template of this name (default `false`) |
1883
1886
 
1884
1887
  Saving is create-only: an existing name is refused with `[template-exists]`
@@ -2015,7 +2018,7 @@ Decodes a note's classic PencilKit drawings (`com.apple.drawing.2` and the older
2015
2018
  | `format` | string | No | `"json"` (default) returns strokes, `"svg"` returns a standalone SVG document per drawing, `"both"` returns both |
2016
2019
  | `includePoints` | boolean | No | Include per-point `x`, `y`, `width`, `opacity`, and `force` in JSON strokes (default `true`) |
2017
2020
 
2018
- **Returns:** `status` (`ok`, `partial`, `error`, or `none` when the note has no classic drawing), `drawingCount`, and one entry per drawing with `attachmentId`, `identifier`, `typeUti`, `status` (`ok`, or `error` with a `code` such as `no_data`, `undecodable`, or `timeout`), `strokeCount`, `bounds`, `truncated`, `strokes` (each with `inkType`, sRGB `color` with alpha, mean `width`, `pointCount`, `bounds`, and `points`), and `svg`. Points are already in drawing coordinates. When a response would exceed `APPLE_NOTES_MCP_EXPORT_MAX_BYTES`, points are dropped and `pointsOmitted` is set. The SVG draws one path per stroke; it is a faithful outline, not a pixel-exact copy of PencilKit's ink textures.
2021
+ **Returns:** `status` (`ok`, `partial`, `error`, or `none` when the note has no classic drawing), `drawingCount`, and one entry per drawing with `attachmentId`, `identifier`, `typeUti`, `status` (`ok`, or `error` with a `code` such as `no_data`, `undecodable`, or `timeout`), `strokeCount`, `bounds`, `truncated`, `strokes` (each with `inkType`, sRGB `color` with alpha, mean `width`, `pointCount`, `bounds`, and `points`), and `svg`. Points are already in drawing coordinates. Ink removed with the pixel eraser is left out: a partly erased stroke comes back as one entry per visible piece, each marked `masked: true`, and `hiddenStrokeCount` counts strokes erased completely. `pointsTruncated: true` marks a stroke cut short by the helper's point limit. When a response would exceed `APPLE_NOTES_MCP_EXPORT_MAX_BYTES`, points are dropped and `pointsOmitted` is set, then SVG documents are dropped and `svgOmitted` is set; if it still does not fit, the call fails with an error instead. The SVG draws one path per stroke; it is a faithful outline, not a pixel-exact copy of PencilKit's ink textures.
2019
2022
 
2020
2023
  ---
2021
2024
 
@@ -2046,7 +2049,7 @@ Each take gets a deadline of 1.5 times its length plus a minute (at most 30 minu
2046
2049
 
2047
2050
  **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.
2048
2051
 
2049
- **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.
2052
+ **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. If the app has never asked for Speech Recognition access, macOS does not list it there yet, and the call returns `code: "permission_not_requested"` instead: use macOS 26 or later, or run the server from an app that already has the access. 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.
2050
2053
 
2051
2054
  ---
2052
2055
 
@@ -2135,8 +2138,10 @@ file then goes through [`add-attachment`](#add-attachment)'s checks.
2135
2138
 
2136
2139
  **Returns:** the `add-attachment` result plus `source` (`kind`: `file` or
2137
2140
  `data`, the pasteboard `type`, and the default `filename`). A copied file wins
2138
- over image data; among data types PNG is preferred, then JPEG, HEIC, GIF, TIFF,
2139
- and PDF.
2141
+ over image data; among data types PDF is preferred (a copied PDF usually comes
2142
+ with a raster preview of itself), then PNG, JPEG, HEIC, GIF, and TIFF. Several
2143
+ copied files or several image or PDF items are refused rather than attaching
2144
+ only the first.
2140
2145
 
2141
2146
  **Paste privacy (macOS 15.4 and later):** macOS can show an alert asking
2142
2147
  whether to allow a paste when a process reads the general pasteboard without a
@@ -2160,6 +2165,7 @@ before 15.4 the property does not exist and the pasteboard is read as before.
2160
2165
  | `pasteboard_empty` | `validation_error` | Nothing is on the pasteboard |
2161
2166
  | `unsupported_content` | `validation_error` | No PNG, JPEG, HEIC, GIF, TIFF, PDF, or copied file (text belongs in `append-to-note`); the message and `types` list the pasteboard types found |
2162
2167
  | `multiple_files` | `validation_error` | More than one copied file; `count` says how many. Copy one file, or use `add-attachment` per file |
2168
+ | `multiple_items` | `validation_error` | More than one image or PDF item (not files); `count` says how many. Copy one, or save each and use `add-attachment` |
2163
2169
  | `too_large` | `validation_error` | More than 64 MiB |
2164
2170
  | `file_unreadable` | `validation_error` | The copied file is a symlink, empty, over 64 MiB, or unreadable |
2165
2171
  | `pasteboard_changed` | `operation_failed` | The pasteboard changed while it was being read; try again |
@@ -2231,7 +2237,7 @@ Lists the Paper drawings (`com.apple.paper`) and classic drawings (`com.apple.dr
2231
2237
  |-----------|------|----------|-------------|
2232
2238
  | `id` | string | Yes | Exact CoreData note ID |
2233
2239
 
2234
- **Returns:** Per drawing: `attachmentId`, `identifier`, `uti`, `kind` (`paper` or `drawing`), `handwritingSummary` (the handwriting text Notes recognized, or `null` when it stored none), `bundlePresent` (the Paper data bundle is on disk), `fallbackImagePath` (Notes' full rendering), `previewPath` (its largest thumbnail), and `raster` `{source, format, width, height}`: the validated image `export-paper-image` would copy, or `null`.
2240
+ **Returns:** Per drawing: `attachmentId`, `identifier`, `uti`, `kind` (`paper` or `drawing`), `handwritingSummary` (the handwriting text Notes recognized, or `null` when it stored none), `bundlePresent` (the Paper data bundle is on disk), `fallbackImagePath` (Notes' full rendering), `fallbackImageStale` (true when Notes recorded a newer rendering than the one on disk, so the image may not show the latest strokes; `export-paper-image` then reports `stale: true`), `previewPath` (its largest thumbnail), and `raster` `{source, format, width, height}`: the validated image `export-paper-image` would copy, or `null`.
2235
2241
 
2236
2242
  Strokes are not decoded. Notes' Paper bundle has no public reader, so the image is Notes' own rendering.
2237
2243
 
@@ -2259,7 +2265,7 @@ Analyzes one local SVG file and reports whether it can be represented as editabl
2259
2265
 
2260
2266
  | Parameter | Type | Required | Description |
2261
2267
  |-----------|------|----------|-------------|
2262
- | `path` | string | Yes | Absolute path of one `.svg` file: a regular file, not a symbolic link, at most 1 MiB of UTF-8, in home, temp, or `/Volumes` |
2268
+ | `path` | string | Yes | Absolute path of one `.svg` file: a regular file, not a symbolic link, at most 1 MiB of UTF-8, in home, temp, or `/Volumes`, read under the same rules as `create-note`'s [`contentPath`](#create-note): hidden paths (such as `~/.docker` or a project `.env`) and `~/Library` other than iCloud Drive and `~/Library/CloudStorage` are refused, checked again after resolving symbolic links and letter case, unless the server sets `APPLE_NOTES_MCP_ALLOW_PRIVATE_CONTENT_PATHS=1`. A file whose first element is not `<svg>` is refused without quoting any of it |
2263
2269
  | `includeDrawing` | boolean | No | Also return the normalized drawing. Off by default because it can be large |
2264
2270
 
2265
2271
  **Returns:** `classification`, `importable`, `defaultWriteAllowed`, `requiredLosses`, `issues` (each with a `code`, the `loss` it causes or `null`, an element `location` such as `svg/g[2]/path[1]#id`, and a message), `viewport`, `counts` (elements, references, path segments, output strokes and points, and the `geometryWork`, `dashWork`, and `scanWork` budgets as `{used, max}`), `source` (`sha256`, `bytes`), `drawingBytes`, and `analysisDigest`.
@@ -2292,7 +2298,7 @@ Copies a note's attachment files into a directory without opening Notes.app.
2292
2298
  | `exportDir` | string | Yes | Absolute destination directory, created if missing. Same allowlist as `save-attachment` (home, temp, or `/Volumes`), and never inside the Notes data folder |
2293
2299
  | `firstImageOnly` | boolean | No | Export only the lead visual that `list-attachments` `firstImage` reports |
2294
2300
 
2295
- **Returns:** `exportDir`, counts (`exported`, `previews`, `skipped`, `failed`), and per attachment its `attachmentId`, `identifier`, `kind`, `exportedTo`, and `exportedKind`: `"asset"` for the real file, `"preview"` when the asset never downloaded and only Notes' thumbnail was on disk, or `null` when nothing was on disk. A preview is never chosen over an available asset, and it is named `<name>-preview.<ext>` so it is not mistaken for the original. A scan gallery with no file of its own exports its pages.
2301
+ **Returns:** `exportDir`, counts (`exported`, `previews`, `fallbacks`, `skipped`, `failed`), and per attachment its `attachmentId`, `identifier`, `kind`, `exportedTo`, and `exportedKind`: `"asset"` for the real file, `"fallback"` for Notes' own full rendering of it (a drawing's PNG or a scan's PDF, named with that format's extension), `"preview"` when the asset never downloaded and only Notes' thumbnail was on disk, or `null` when nothing was on disk. `inBody: false` marks an attachment the note body no longer shows, and `stale: true` marks a rendering taken from an older generation because the one Notes recorded is missing; attachments inside a container Notes has deleted are not exported. A preview is never chosen over an available asset, and it is named `<name>-preview.<ext>` so it is not mistaken for the original. A scan gallery with no file of its own exports its pages.
2296
2302
 
2297
2303
  **⚠️ Safety:** Existing files are never replaced. A name that is taken gets `-2`, `-3`, and so on. Reads NoteStore and the Notes data folder read-only and needs Full Disk Access.
2298
2304
 
@@ -2775,7 +2781,7 @@ All configuration is optional — the server works out of the box. Override beha
2775
2781
  | `APPLE_NOTES_MCP_BACKGROUND_SHORTCUT` | `Apple Notes MCP - Background Operations v5` | Name or UUID of the installed Background Operations bridge to run. `setup` still installs and checks the default name. |
2776
2782
  | `APPLE_NOTES_MCP_MARKDOWN_SHORTCUT` | `Apple Notes MCP - Create Markdown Note` | Name or UUID of the installed Create Markdown Note bridge to run. `setup` still installs and checks the default name. |
2777
2783
  | `APPLE_NOTES_MCP_PASTEBOARD_NAME` | unset | Testing only: makes [`add-attachment-from-pasteboard`](#add-attachment-from-pasteboard) read a private named pasteboard instead of the general clipboard. |
2778
- | `APPLE_NOTES_MCP_ALLOW_PRIVATE_CONTENT_PATHS` | unset | Set to `1` to let `create-note` read a [`contentPath`](#create-note), and [`add-attachment`](#add-attachment) and [`create-note-with-attachment`](#create-note-with-attachment) attach a `path`, inside a hidden directory or file (such as `~/.config`) or `~/Library` outside iCloud Drive and `~/Library/CloudStorage`. Off by default because those places hold keys, tokens and app data. |
2784
+ | `APPLE_NOTES_MCP_ALLOW_PRIVATE_CONTENT_PATHS` | unset | Set to `1` to let `create-note` read a [`contentPath`](#create-note), [`add-attachment`](#add-attachment) and [`create-note-with-attachment`](#create-note-with-attachment) attach a `path`, [`analyze-svg`](#analyze-svg) read a `path`, and the Markdown template tools read a `templateFile`, inside a hidden directory or file (such as `~/.config`) or `~/Library` outside iCloud Drive and `~/Library/CloudStorage`. Off by default because those places hold keys, tokens and app data. |
2779
2785
  | `DEBUG` / `VERBOSE` | unset | Set either to enable verbose diagnostic logging to stderr. |
2780
2786
 
2781
2787
  ### Configuration file (when the host strips `env`)