apple-notes-mcp 2.9.1 → 2.9.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/README.md +103 -3
- package/build/index.js +1174 -457
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ Install as a Claude Code plugin for automatic configuration and enhanced AI beha
|
|
|
56
56
|
|
|
57
57
|
This method also installs a **skill** that teaches Claude when and how to use Apple Notes effectively.
|
|
58
58
|
|
|
59
|
-
On the first tool call, macOS shows an Automation permission prompt ("Claude" wants access to control "Notes") — click **OK**. Optionally, grant **Full Disk Access** (under Claude Desktop, to the Node binary that runs the server; from a terminal, to the terminal app) to enable the database-backed tools (`get-checklist-state`, `get-note-metadata`, `get-audio-transcripts`, `list-special-notes`, `list-native-tags`, `get-note-link`, checklist annotations in `get-note-markdown`, and full `get-sync-status` detail); see the [Full Disk Access Setup Guide](https://github.com/sweetrb/apple-notes-mcp/blob/main/docs/FULL-DISK-ACCESS.md). The rest of the server is pure AppleScript and works without it.
|
|
59
|
+
On the first tool call, macOS shows an Automation permission prompt ("Claude" wants access to control "Notes") — click **OK**. Optionally, grant **Full Disk Access** (under Claude Desktop, to the Node binary that runs the server; from a terminal, to the terminal app) to enable the database-backed tools (`get-checklist-state`, `get-note-metadata`, `get-audio-transcripts`, `list-special-notes`, `list-native-tags`, `list-recent-notes`, `list-folder-tree`, `get-note-link`, checklist annotations in `get-note-markdown`, and full `get-sync-status` detail); see the [Full Disk Access Setup Guide](https://github.com/sweetrb/apple-notes-mcp/blob/main/docs/FULL-DISK-ACCESS.md). The rest of the server is pure AppleScript and works without it.
|
|
60
60
|
|
|
61
61
|
Native tag, checklist, table, pin, and rich append operations use two packaged
|
|
62
62
|
Apple Shortcuts. A third, `Apple Notes MCP - Create Markdown Note`, is optional:
|
|
@@ -634,6 +634,50 @@ stable code in brackets, such as `[encrypted]` or `[no-full-disk-access]`.
|
|
|
634
634
|
|
|
635
635
|
---
|
|
636
636
|
|
|
637
|
+
#### `get-note-structure`
|
|
638
|
+
|
|
639
|
+
Returns a read-only overview of one note from the NoteStore database, in one
|
|
640
|
+
call:
|
|
641
|
+
|
|
642
|
+
- `text` (decoded body), `textLength`, `wordCount`, `charCount` (Unicode
|
|
643
|
+
characters, attachment placeholders excluded), and `blockSummary` (the
|
|
644
|
+
`get-note-blocks` summary counts).
|
|
645
|
+
- `links`, each with a `kind`: `inline` (a hyperlink on text), `card` (a rich
|
|
646
|
+
link preview attachment, with `attachmentId` and `previewPath`), `note` (a
|
|
647
|
+
native link chip to another note), or `section` (a native link chip to a
|
|
648
|
+
heading or paragraph, with `section`). Notes deep links also carry
|
|
649
|
+
`targetNote` and `paragraphId`. `linkCounts` totals them.
|
|
650
|
+
- `tags` (native tags in body order) and `attachments`, listed the way
|
|
651
|
+
[`list-attachments`](#list-attachments) with `includePaths` lists them: the
|
|
652
|
+
same `kind` (`image`, `scan`, `drawing`, `pdf`, `audio`, `video`, `url`,
|
|
653
|
+
`table`, `other`), the same body order, and the same `previewPath`, plus the
|
|
654
|
+
card `title`/`url`, `fileSize`, and body position. Gallery items and
|
|
655
|
+
recording parts are nested under `children`; `attachmentCount` counts
|
|
656
|
+
top-level attachments only.
|
|
657
|
+
- `deepLink`, `isShared` (the note or any enclosing folder is shared),
|
|
658
|
+
`isLocked`, `isPinned`, `inRecentlyDeleted`, `lastViewed`,
|
|
659
|
+
`checklistTotal`, `checklistDone`, `hasDrawing` (classic sketches and Paper
|
|
660
|
+
drawings), and `firstImage` (the same lead visual `list-attachments`
|
|
661
|
+
returns with `firstImage`, plus its attachment `id`).
|
|
662
|
+
|
|
663
|
+
`lastViewed` is an ISO date, or null with `lastViewedStatus` set to
|
|
664
|
+
`never-viewed`, `not-recorded`, `malformed`, or `unsupported` (the column
|
|
665
|
+
does not exist on this macOS version). A password-protected note returns its
|
|
666
|
+
metadata and attachment rows with `bodyDecoded: false` and the body-derived
|
|
667
|
+
fields null.
|
|
668
|
+
|
|
669
|
+
**Requires:** Full Disk Access.
|
|
670
|
+
|
|
671
|
+
| Parameter | Type | Required | Description |
|
|
672
|
+
|-----------|------|----------|-------------|
|
|
673
|
+
| `id` | string | Yes | Exact note ID: the `x-coredata://` id, or the note's Notes UUID or numeric key (see [Identifier forms](#identifier-forms)) |
|
|
674
|
+
| `includeText` | boolean | No | Include the decoded text (default true). Text larger than `APPLE_NOTES_MCP_BLOCKS_MAX_BYTES` is omitted with `textOmitted: true` |
|
|
675
|
+
|
|
676
|
+
Link URLs are returned as stored; check `linkSafe` before emitting one into
|
|
677
|
+
HTML.
|
|
678
|
+
|
|
679
|
+
---
|
|
680
|
+
|
|
637
681
|
#### `list-native-tags`
|
|
638
682
|
|
|
639
683
|
Lists actual native Notes tags. This differs from textual hashtag search. It is
|
|
@@ -1096,6 +1140,46 @@ Use the returned `id` for any follow-up read/update/move/delete rather than re-r
|
|
|
1096
1140
|
|
|
1097
1141
|
> **Changed in 2.7.0:** `notes` was previously `string[]` (titles only). Callers that treated the array as strings must now read `.title`.
|
|
1098
1142
|
|
|
1143
|
+
For date order, incremental sync cursors, Recently Deleted, or word counts, use [`list-recent-notes`](#list-recent-notes).
|
|
1144
|
+
|
|
1145
|
+
---
|
|
1146
|
+
|
|
1147
|
+
#### `list-recent-notes`
|
|
1148
|
+
|
|
1149
|
+
Lists notes from the NoteStore database (read-only) by stored modification time, with an exact cursor for incremental sync. With `since`, it pages through changes oldest first; without it, it shows the newest notes first. Unlike `list-notes`, it can include Recently Deleted and can count words.
|
|
1150
|
+
|
|
1151
|
+
**Requires:** Full Disk Access for the MCP host process (see [Full Disk Access Setup](#full-disk-access)).
|
|
1152
|
+
|
|
1153
|
+
| Parameter | Type | Required | Description |
|
|
1154
|
+
|-----------|------|----------|-------------|
|
|
1155
|
+
| `account` | string | No | Only this account (exact or unique-prefix name). Omit for every account |
|
|
1156
|
+
| `folder` | string | No | Only notes directly in this folder: a full path in `list-folders` syntax, or a unique folder name |
|
|
1157
|
+
| `since` | string | No | Return notes after this point, **oldest first**. A `modifiedCheckpoint` cursor (from a row or `nextSince`), or an ISO 8601 date (local midnight) or date-time (local time unless it carries `Z` or an offset), meaning modified strictly after it |
|
|
1158
|
+
| `limit` | number | No | Maximum rows, 1–1000 (default 50) |
|
|
1159
|
+
| `includeDeleted` | boolean | No | Also return notes in Recently Deleted, notes awaiting deletion, and folderless notes (default `false`) |
|
|
1160
|
+
| `wordCounts` | boolean | No | Decode each body and add `wordCount` and `charCount` (default `false`) |
|
|
1161
|
+
| `bodyPreview` | boolean | No | Add `bodyPreview` (up to 180 characters) and `textDecoded` (default `false`) |
|
|
1162
|
+
|
|
1163
|
+
**Returns:** `notes`, each with `id`, `identifier`, `title`, `folder`, `account`, `created`, `modified`, `modifiedCheckpoint`, `pinned`, `locked`, `inRecentlyDeleted`, and `markedForDeletion`. Also `count`, `limit`, `order` (`oldest-first` or `newest-first`), `saturated`, and `nextSince`.
|
|
1164
|
+
|
|
1165
|
+
- **Cursors.** `modifiedCheckpoint` is an opaque token (`cdts1:`, 16 hex digits, `:`, the note's database key). It carries the exact stored timestamp bits, so it never loses precision the way an ISO string can, and the key orders notes that share one timestamp. Pass it back as `since`.
|
|
1166
|
+
- **Syncing.** Call with `since`, store `nextSince`, and pass it as the next `since`. `nextSince` is the last returned row's cursor, or the incoming boundary when nothing matched, so every call advances. `saturated` is `true` when `count` equals `limit`: more changes may follow, so call again right away. When it is `false`, you are caught up. Notes that share a timestamp are split across pages by key, so none is skipped or repeated.
|
|
1167
|
+
- **First sync.** Start with `since: "1970-01-01"` and page the same way. A library larger than the 1000-row maximum is reached in full.
|
|
1168
|
+
- **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`.
|
|
1169
|
+
- **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.
|
|
1170
|
+
- **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.
|
|
1171
|
+
- **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.
|
|
1172
|
+
- **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.
|
|
1173
|
+
- 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.
|
|
1174
|
+
|
|
1175
|
+
**Example - incremental sync:**
|
|
1176
|
+
```json
|
|
1177
|
+
{
|
|
1178
|
+
"since": "cdts1:41c7e0ef438fcd6f:4312",
|
|
1179
|
+
"limit": 200
|
|
1180
|
+
}
|
|
1181
|
+
```
|
|
1182
|
+
|
|
1099
1183
|
---
|
|
1100
1184
|
|
|
1101
1185
|
#### `get-selected-notes`
|
|
@@ -1168,6 +1252,21 @@ carries `matchingNotesError` instead.
|
|
|
1168
1252
|
|
|
1169
1253
|
---
|
|
1170
1254
|
|
|
1255
|
+
#### `list-folder-tree`
|
|
1256
|
+
|
|
1257
|
+
Returns the folder hierarchy with note counts for each account, read from the NoteStore database in one pass.
|
|
1258
|
+
|
|
1259
|
+
**Requires:** Full Disk Access for the MCP host process (see [Full Disk Access Setup](#full-disk-access)).
|
|
1260
|
+
|
|
1261
|
+
| Parameter | Type | Required | Description |
|
|
1262
|
+
|-----------|------|----------|-------------|
|
|
1263
|
+
| `account` | string | No | Only this account (exact or unique-prefix name). Omit for every account |
|
|
1264
|
+
| `includeDeleted` | boolean | No | Include folders marked for deletion (flagged `markedForDeletion`) and folders whose account no longer exists (default `false`) |
|
|
1265
|
+
|
|
1266
|
+
**Returns:** `accounts`, each with `account`, `identifier`, `noteCount`, and `folders`. Each folder node has `id`, `identifier`, `name`, `path` (in `list-folders` syntax), `kind` (`folder`, `smart`, or `trash`), `noteCount` (notes directly inside), `totalNoteCount` (including subfolders), and `children`. Regular folders sort by name, then smart folders, then Recently Deleted. An account's `noteCount` sums its regular folders. Smart folders report 0 because their contents are a saved search. Also returns `folderCount`.
|
|
1267
|
+
|
|
1268
|
+
---
|
|
1269
|
+
|
|
1171
1270
|
#### `create-folder`
|
|
1172
1271
|
|
|
1173
1272
|
Creates a new folder, including a whole nested hierarchy in one call.
|
|
@@ -2159,7 +2258,7 @@ All configuration is optional — the server works out of the box. Override beha
|
|
|
2159
2258
|
| `APPLE_NOTES_MCP_CONFIG_FILE` | `~/Library/Application Support/apple-notes-mcp/config.json` | Path to the JSON config file (see below). |
|
|
2160
2259
|
| `APPLE_NOTES_MCP_TIMEOUT_MS` | `30000` (30 s) | Total AppleScript operation timeout, including retry attempts and delays. Raise it if full-library operations (large searches, exports) time out on a big Notes library. Per-call `timeoutMs` options still win, and a write tool's `timeoutSeconds` argument overrides it for that call. |
|
|
2161
2260
|
| `APPLE_NOTES_MCP_EXPORT_MAX_BYTES` | `8388608` (8 MB) | Largest response `export-notes-json` sends; a page closes early to stay under it. `export-notes-markdown` returns inline Markdown up to half of it. The default sits below the 10 MB per-message limit of MCP SDK stdio clients, which drop the connection on anything larger. Raise it only if your MCP client accepts bigger messages. |
|
|
2162
|
-
| `APPLE_NOTES_MCP_BLOCKS_MAX_BYTES` | `4194304` (4 MB) | Largest block payload one [`get-note-blocks`](#get-note-blocks) page returns; the page closes early to stay under it, and a single oversized paragraph comes back with `textOmitted: true`. |
|
|
2261
|
+
| `APPLE_NOTES_MCP_BLOCKS_MAX_BYTES` | `4194304` (4 MB) | Largest block payload one [`get-note-blocks`](#get-note-blocks) page returns; the page closes early to stay under it, and a single oversized paragraph comes back with `textOmitted: true`. [`get-note-structure`](#get-note-structure) also omits note text larger than this. |
|
|
2163
2262
|
| `APPLE_NOTES_MCP_MAX_RETRIES` | `2` | Maximum attempts for a read-only AppleScript call that fails with a **transient** error (Notes.app busy / not responding / lost connection). `2` means one retry; set `1` to fail fast with no retries. Retries share the single `APPLE_NOTES_MCP_TIMEOUT_MS` budget rather than each getting a fresh one, and a retry is skipped when under a second of that budget remains — so this is a ceiling, not a guarantee. In particular a call that exhausts the budget with a **timeout** has no time left to retry by construction. Mutating operations run once because a timeout can occur after Notes.app applied the change. Non-transient errors (e.g. "note not found") never retry. |
|
|
2164
2263
|
| `APPLE_NOTES_MCP_RETRY_DELAY_MS` | `1000` (1 s) | Base delay before the first retry; subsequent retries back off exponentially (1s, 2s, 4s, ...). |
|
|
2165
2264
|
| `APPLE_NOTES_MCP_ENABLE_PRIVATE` | unset | Set to `1` to allow the opt-in [private helper](#private-helper-opt-in-unsupported-apple-api). Any other value keeps it off. |
|
|
@@ -2192,7 +2291,7 @@ MCP stores no secrets, but as a general rule keep only non-secret config here.
|
|
|
2192
2291
|
|
|
2193
2292
|
## Full Disk Access
|
|
2194
2293
|
|
|
2195
|
-
Several tools read directly from the Apple Notes SQLite database, which lives in a macOS-protected directory. Those tools require **Full Disk Access** for the process running the MCP server: `get-checklist-state`, `get-note-metadata`, `get-note-blocks`, `export-notes-markdown`, `export-notes-html`, `get-audio-transcripts`, `list-special-notes`, `list-native-tags`, `get-note-link`, the checklist annotations in `get-note-markdown`, `list-attachments` with `includePaths` or `firstImage`, `export-attachments`, `list-paper-attachments`, `export-paper-image`, and the database half of `get-sync-status`.
|
|
2294
|
+
Several tools read directly from the Apple Notes SQLite database, which lives in a macOS-protected directory. Those tools require **Full Disk Access** for the process running the MCP server: `get-checklist-state`, `get-note-metadata`, `get-note-blocks`, `get-note-structure`, `export-notes-markdown`, `export-notes-html`, `get-audio-transcripts`, `list-special-notes`, `list-native-tags`, `list-recent-notes`, `list-folder-tree`, `get-note-link`, the checklist annotations in `get-note-markdown`, `list-attachments` with `includePaths` or `firstImage`, `export-attachments`, `list-paper-attachments`, `export-paper-image`, and the database half of `get-sync-status`.
|
|
2196
2295
|
|
|
2197
2296
|
> 📘 **For the full why-and-how walkthrough (which app to grant, verifying with `doctor`, graceful degradation), see the [Full Disk Access Setup Guide](https://github.com/sweetrb/apple-notes-mcp/blob/main/docs/FULL-DISK-ACCESS.md).** The summary below is the quick version.
|
|
2198
2297
|
|
|
@@ -2214,6 +2313,7 @@ Every tool that does not read the Notes database works normally without Full Dis
|
|
|
2214
2313
|
- `get-checklist-state` returns an error explaining that database access is needed
|
|
2215
2314
|
- `get-note-metadata` returns the same kind of error — it has no non-database path
|
|
2216
2315
|
- `list-special-notes` and the `list-native-tags` inventory return the same kind of error
|
|
2316
|
+
- `list-recent-notes` and `list-folder-tree` return the same kind of error
|
|
2217
2317
|
- `get-note-link` returns an error on macOS 26+; on macOS 12–15 it still works via the AppleScript `note link` fallback
|
|
2218
2318
|
- `get-note-markdown` returns plain list items without `[x]`/`[ ]` annotations (graceful fallback)
|
|
2219
2319
|
- `get-sync-status` still answers, but reports no pending uploads and no active sync — treat that as "unknown", not "idle"
|