apple-notes-mcp 2.9.20 → 2.9.22
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 +117 -27
- package/build/index.js +1 -1
- package/docs/APPLESCRIPT-LIMITATIONS.md +36 -25
- package/package.json +12 -3
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Apple Notes MCP Server
|
|
2
2
|
|
|
3
|
-
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that
|
|
3
|
+
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that lets Claude (Claude Code and Claude Desktop), Codex, and other MCP clients read, search, create, edit, organize, and export notes in Apple Notes on macOS. It runs locally on your Mac and talks to Notes through AppleScript, Apple Shortcuts, and read-only access to the Notes database.
|
|
4
|
+
|
|
5
|
+
Beyond creating and editing notes, it manages folders and accounts, native tags, checklists, tables, pinned notes, links, and attachments. It can also export notes as Markdown, HTML, or JSON, read audio transcripts and drawings, and run a query language across your whole library.
|
|
4
6
|
|
|
5
7
|
[](https://www.npmjs.com/package/apple-notes-mcp)
|
|
6
8
|
[](https://www.npmjs.com/package/apple-notes-mcp)
|
|
@@ -15,6 +17,13 @@ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that e
|
|
|
15
17
|
<img src="https://raw.githubusercontent.com/sweetrb/apple-notes-mcp/main/codex/assets/screenshot.png" alt="Apple Notes MCP — create, search, and organize Apple Notes from Codex, Claude, and other AI assistants" width="680">
|
|
16
18
|
</p>
|
|
17
19
|
|
|
20
|
+
## Contents
|
|
21
|
+
|
|
22
|
+
- [What is This?](#what-is-this) · [Quick Start](#quick-start) · [Requirements](#requirements) · [Features](#features)
|
|
23
|
+
- [Tool Reference](#tool-reference): [notes](#note-operations), [folders](#folder-operations), [accounts](#account-operations), [batch](#batch-operations), [export, attachments, and media](#export-operations), [diagnostics](#diagnostics), [native background operations](#native-background-operations), [private helper](#private-helper-opt-in-unsupported-apple-api)
|
|
24
|
+
- [Usage Patterns](#usage-patterns) · [Installation Options](#installation-options) · [Configuration](#configuration) · [Full Disk Access](#full-disk-access) · [Public native helper](#public-native-helper)
|
|
25
|
+
- [Security and Privacy](#security-and-privacy) · [Known Limitations](#known-limitations) · [Troubleshooting](#troubleshooting) · [Recurring macOS permission prompts](#recurring-macos-permission-prompts) · [Development](#development)
|
|
26
|
+
|
|
18
27
|
## What is This?
|
|
19
28
|
|
|
20
29
|
This server acts as a bridge between AI assistants and Apple Notes. Once configured, you can ask Claude (or any MCP-compatible AI) to:
|
|
@@ -25,7 +34,7 @@ This server acts as a bridge between AI assistants and Apple Notes. Once configu
|
|
|
25
34
|
- "Move my draft notes to the Archive folder"
|
|
26
35
|
- "What notes do I have in my Work folder?"
|
|
27
36
|
|
|
28
|
-
The AI assistant communicates with this server, which then uses AppleScript to interact with the Notes app on your Mac.
|
|
37
|
+
The AI assistant communicates with this server, which then uses AppleScript to interact with the Notes app on your Mac. Some features also use packaged Apple Shortcuts (native tags, checklists, tables, pinning) or read the Notes database read-only (queries, checklist state, transcripts). The server itself makes no network requests; what your MCP client does with the results is up to that client.
|
|
29
38
|
|
|
30
39
|
## Quick Start
|
|
31
40
|
|
|
@@ -56,7 +65,7 @@ Install as a Claude Code plugin for automatic configuration and enhanced AI beha
|
|
|
56
65
|
|
|
57
66
|
This method also installs a **skill** that teaches Claude when and how to use Apple Notes effectively.
|
|
58
67
|
|
|
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
|
|
68
|
+
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, such as `query-notes`, `get-checklist-state`, `get-note-tables`, `get-audio-transcripts`, `list-native-tags`, and `list-recent-notes` (the full list is under [Full Disk Access](#full-disk-access)); 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
69
|
|
|
61
70
|
Native tag, checklist, table, pin, and rich append operations use two packaged
|
|
62
71
|
Apple Shortcuts. A third, `Apple Notes MCP - Create Markdown Note`, is optional:
|
|
@@ -148,6 +157,10 @@ npm install -g apple-notes-mcp
|
|
|
148
157
|
|
|
149
158
|
On first use, macOS will ask for permission to automate Notes.app. Click "OK" to allow.
|
|
150
159
|
|
|
160
|
+
### Other MCP clients
|
|
161
|
+
|
|
162
|
+
The server is a standard MCP server over stdio, so any client that can launch a local stdio server can run it with the same command the hosts above use: `npx -y apple-notes-mcp`. Most clients take it in an `mcpServers` entry shaped like the Claude Desktop example. If your client cannot pass environment variables, use the [configuration file](#configuration-file-when-the-host-strips-env).
|
|
163
|
+
|
|
151
164
|
## Requirements
|
|
152
165
|
|
|
153
166
|
- **macOS** - Apple Notes and AppleScript are macOS-only
|
|
@@ -158,24 +171,30 @@ On first use, macOS will ask for permission to automate Notes.app. Click "OK" to
|
|
|
158
171
|
|
|
159
172
|
| Feature | Description |
|
|
160
173
|
|---------|-------------|
|
|
161
|
-
| **Create Notes** | Create notes
|
|
174
|
+
| **Create Notes** | Create notes from plaintext, HTML, or Markdown, with optional folder/account targeting (Markdown creation uses an optional Shortcut on macOS 26 or later) |
|
|
162
175
|
| **Search Notes** | Find notes by title or search within note content |
|
|
163
176
|
| **Query Language** | `query-notes` combines text, folder, account, tag, attachment, checklist, flag, word-count, and date conditions with AND/OR/NOT, read from the Notes database (requires Full Disk Access) |
|
|
164
|
-
| **Read Notes** | Retrieve note content
|
|
165
|
-
| **
|
|
177
|
+
| **Read Notes** | Retrieve note content as HTML, plain text, or Markdown, plus metadata that AppleScript does not expose (pinned, Quick Note, locked, Recently Deleted) |
|
|
178
|
+
| **Note Structure** | Decode a note into typed paragraph blocks, list its paragraphs and links, and get a direct link to one paragraph (requires Full Disk Access) |
|
|
179
|
+
| **Update Notes** | Replace, append to, or prepend to an existing note, guarded by a content hash so a note that changed since it was read is never overwritten |
|
|
166
180
|
| **Delete Notes** | Remove notes (moves to Recently Deleted) |
|
|
167
181
|
| **Move Notes** | Organize notes into folders (supports nested paths) |
|
|
168
|
-
| **Folder Management** | Create, list, and delete folders with full hierarchical path support |
|
|
182
|
+
| **Folder Management** | Create, list, rename, and delete folders with full hierarchical path support; read the folder tree with note counts and Smart Folder rules |
|
|
169
183
|
| **Multi-Account** | Work with iCloud, Gmail, Exchange, or any configured account, including account IDs and default folders |
|
|
170
184
|
| **Batch Operations** | Delete or move multiple notes at once |
|
|
171
|
-
| **
|
|
172
|
-
| **
|
|
173
|
-
| **
|
|
174
|
-
| **
|
|
175
|
-
| **
|
|
185
|
+
| **Native Tags** | List, add, remove, and replace real Notes tags (not just `#hashtag` text) |
|
|
186
|
+
| **Checklists** | Read checklist done/undone state from the Notes database, and append real checklist items through a Shortcut |
|
|
187
|
+
| **Tables** | Read native tables as Markdown and JSON, and append new native tables |
|
|
188
|
+
| **Pinning** | Read pinned state and pin or unpin a note |
|
|
189
|
+
| **Links** | Get a note's `notes://` deep link, insert web, mail, or note-to-note links, and list the links in a note or folder |
|
|
190
|
+
| **Export** | Export notes as paginated JSON, or render a note or folder as Markdown (with reusable templates) or standalone HTML |
|
|
191
|
+
| **Attachments** | Add files to notes (from a path or the pasteboard), list attachments with their on-disk paths, find a note's lead image, save or batch-export them, or fetch their bytes as base64 |
|
|
192
|
+
| **Audio and Drawings** | Read the transcripts Notes stored for recordings, transcribe audio on-device, and decode drawings to strokes and SVG |
|
|
193
|
+
| **Incremental Sync** | `list-recent-notes` pages through notes by modification time with an exact cursor |
|
|
194
|
+
| **Notes.app UI State** | Reveal a note, folder, account, or attachment in Notes.app, or read the current Notes.app selection |
|
|
176
195
|
| **Sync Awareness** | Detect iCloud sync in progress, warn about incomplete results |
|
|
177
196
|
| **Collaboration** | Detect shared notes, warn before modifying |
|
|
178
|
-
| **Diagnostics** | `health-check` plus a richer `doctor` (reachability, automation permission, accounts, Full Disk Access), sync status, and
|
|
197
|
+
| **Diagnostics** | `health-check` plus a richer `doctor` (reachability, automation permission, accounts, Full Disk Access), sync status, statistics, and `get-capabilities` for the Shortcut bridges |
|
|
179
198
|
|
|
180
199
|
Read/list/get tools also return **structured JSON** (`structuredContent`) alongside the text, so agents can consume results without parsing prose.
|
|
181
200
|
|
|
@@ -193,8 +212,8 @@ reading Notes' own database instead; the rest genuinely cannot be supported. See
|
|
|
193
212
|
**[docs/APPLESCRIPT-LIMITATIONS.md](https://github.com/sweetrb/apple-notes-mcp/blob/main/docs/APPLESCRIPT-LIMITATIONS.md)**
|
|
194
213
|
for the investigation and verification behind each:
|
|
195
214
|
|
|
196
|
-
- **Pinned notes** — Notes has no scriptable `pinned` property via AppleScript. Pin state
|
|
197
|
-
- **Note-to-note links** — AppleScript exposes no link property or link element
|
|
215
|
+
- **Pinned notes** — Notes has no scriptable `pinned` property via AppleScript. Pin state is **read** from the NoteStore database by the BETA `get-note-metadata` tool and `list-special-notes`, and **set** through the Background Operations Shortcut by [`set-note-pinned`](#set-note-pinned).
|
|
216
|
+
- **Note-to-note links** — AppleScript exposes no link property or link element. Links are instead read from the NoteStore database by [`list-note-links`](#list-note-links), and inserted by [`insert-note-link`](#insert-note-link) (through a Shortcut) or [`insert-link`](#insert-link). A shareable `notes://showNote?identifier=<uuid>` deep link is available via [`get-note-link`](#get-note-link).
|
|
198
217
|
|
|
199
218
|
---
|
|
200
219
|
|
|
@@ -256,14 +275,14 @@ Creates a new note in Apple Notes.
|
|
|
256
275
|
| `title` | string | Yes | The title of the note. Automatically prepended as `<h1>` — do NOT include the title in `content` |
|
|
257
276
|
| `content` | string | One of `content`/`contentPath` | The body content of the note (do not repeat the title here) |
|
|
258
277
|
| `contentPath` | string | One of `content`/`contentPath` | Absolute path of a local UTF-8 file to use as the body instead of `content`. Allowed in the same places [`save-attachment`](#save-attachment) may write (home, temp, `/Volumes`); symbolic links, non-regular files, invalid UTF-8 and files over 1 MiB are refused before anything is written. A leading byte-order mark is dropped |
|
|
259
|
-
| `tags` | string[] | No | Returned-only metadata — **NOT written to Notes.app**. Apple Notes tags can't be set via AppleScript, so values passed here are echoed back in the response but do not appear on the created note.
|
|
278
|
+
| `tags` | string[] | No | Returned-only metadata — **NOT written to Notes.app**. Apple Notes tags can't be set via AppleScript, so values passed here are echoed back in the response but do not appear on the created note. Inline `#hashtags` in `content` stay searchable text and are returned as `hashtags`, but they do not become native Notes tags; add real tags afterwards with [`add-native-tags`](#add-native-tags). Refused with `format: "markdown"` |
|
|
260
279
|
| `folder` | string | No | Folder to create the note in. Supports nested paths like `"Work/Clients"`. **The folder must already exist** — create it first with [`create-folder`](#create-folder). A smart folder is refused (see [`move-note`](#move-note)). Defaults to account root |
|
|
261
280
|
| `account` | string | No | Account name (defaults to Notes.app's default account; matched exactly or by a *unique* prefix — an ambiguous prefix is refused). Must be an account Notes.app already has configured — see [`list-accounts`](#list-accounts) |
|
|
262
281
|
| `format` | string | No | Content format: `"plaintext"` (default), `"html"`, or `"markdown"`. In all formats, the title is automatically prepended as the note's title line. In plaintext mode, newlines become `<br>`, tabs become `<br>`, and backslashes are preserved as HTML entities. `"markdown"` produces real Title/Heading/Subheading styles through a Shortcut; see [Markdown notes](#markdown-notes) |
|
|
263
282
|
| `markdownRoute` | string | No | With `format: "markdown"` only: `"shortcut"` (default) or `"html"`. See [Markdown through HTML](#markdown-through-html) |
|
|
264
283
|
| `timeoutSeconds` | number | No | Whole seconds, 1–120, for each Notes.app automation step this call runs; overrides `APPLE_NOTES_MCP_TIMEOUT_MS` for this call only. A timed-out write is uncertain, not failed: read the note by id before any retry. Also accepted by `get-note-content`, `update-note`, `append-to-note`, `delete-note` and `move-note` |
|
|
265
284
|
|
|
266
|
-
**Example (
|
|
285
|
+
**Example (with inline textual hashtags):**
|
|
267
286
|
```json
|
|
268
287
|
{
|
|
269
288
|
"title": "Meeting Notes",
|
|
@@ -587,8 +606,9 @@ base64 images larger than `APPLE_NOTES_MCP_MAX_INLINE_IMAGE_BYTES` (default
|
|
|
587
606
|
image-heavy note cannot blow the MCP message limit. `structuredContent` reports
|
|
588
607
|
this as `strippedImages` (count) and `truncated` (boolean). When either is set,
|
|
589
608
|
passing this body to an unguarded full-body writer would replace the real images
|
|
590
|
-
with placeholder text. This server
|
|
591
|
-
|
|
609
|
+
with placeholder text. This server's `update-note` refuses attachment-bearing
|
|
610
|
+
notes, and `append-to-note` routes them to native end-append with `scopeText`,
|
|
611
|
+
which never rewrites the existing body; make any other edit in Notes.app.
|
|
592
612
|
|
|
593
613
|
---
|
|
594
614
|
|
|
@@ -600,6 +620,10 @@ stable row and column identifiers. `tableCellsComplete` is false when Notes
|
|
|
600
620
|
metadata cannot be decoded completely. This tool is read-only and requires Full
|
|
601
621
|
Disk Access.
|
|
602
622
|
|
|
623
|
+
| Parameter | Type | Required | Description |
|
|
624
|
+
|-----------|------|----------|-------------|
|
|
625
|
+
| `id` | string | Yes | Exact note ID, in any [identifier form](#identifier-forms) |
|
|
626
|
+
|
|
603
627
|
---
|
|
604
628
|
|
|
605
629
|
#### `get-note-tables`
|
|
@@ -860,6 +884,13 @@ Shortcut runs. It refuses ambiguous title-and-scope matches and never retries an
|
|
|
860
884
|
uncertain write. Install the signed workflow as described in
|
|
861
885
|
[`shortcuts/README.md`](shortcuts/README.md).
|
|
862
886
|
|
|
887
|
+
| Parameter | Type | Required | Description |
|
|
888
|
+
|-----------|------|----------|-------------|
|
|
889
|
+
| `id` | string | Yes | Exact note ID, in any [identifier form](#identifier-forms) |
|
|
890
|
+
| `expectedContentHash` | string | Yes | `contentHash` from a fresh read of the note |
|
|
891
|
+
| `scopeText` | string | Yes | Distinctive phrase already in the note, 12–500 characters |
|
|
892
|
+
| `tags` | string[] | Yes | 1–100 tag names to add |
|
|
893
|
+
|
|
863
894
|
---
|
|
864
895
|
|
|
865
896
|
#### `get-note-plaintext`
|
|
@@ -947,6 +978,7 @@ Updates an existing note's content and/or title.
|
|
|
947
978
|
| `format` | string | No | Content format: `"plaintext"` (default) or `"html"`. When `"html"`, content replaces the entire note body as raw HTML and `newTitle` is ignored (the first HTML element serves as the title) |
|
|
948
979
|
| `allowLinkChanges` | boolean | No | Set to `true` only when intentionally changing or removing existing links |
|
|
949
980
|
| `ifFolderId`, `ifAncestorFolderId`, `forbiddenAncestorFolderIds` | string, string, string[] | No | Folder preconditions; see [Folder scope guards](#folder-scope-guards) |
|
|
981
|
+
| `timeoutSeconds` | number | No | Per-call timeout, 1–120 seconds, as for [`create-note`](#create-note). A timed-out write is uncertain: read the note by id before any retry |
|
|
950
982
|
|
|
951
983
|
Title-only updates are rejected because Apple Notes titles are not unique.
|
|
952
984
|
|
|
@@ -992,6 +1024,7 @@ Deletes a note (moves to Recently Deleted in Notes.app).
|
|
|
992
1024
|
| `id` | string | Yes | Exact CoreData note ID returned by a read or search |
|
|
993
1025
|
| `expectedContentHash` | string | Yes | `contentHash` from the exact note version being deleted |
|
|
994
1026
|
| `ifFolderId`, `ifAncestorFolderId`, `forbiddenAncestorFolderIds` | string, string, string[] | No | Folder preconditions; see [Folder scope guards](#folder-scope-guards) |
|
|
1027
|
+
| `timeoutSeconds` | number | No | Per-call timeout, 1–120 seconds, as for [`create-note`](#create-note). A timed-out write is uncertain: read the note by id before any retry |
|
|
995
1028
|
| `guardNoteId` | string | No | A second note (usually a verified copy) that must still be intact; needs Full Disk Access |
|
|
996
1029
|
| `expectedGuardContentHash` | string | With `guardNoteId` | `contentHash` of the guard note from `get-note-content` |
|
|
997
1030
|
| `requireActiveNoteId` | string | No | A second note that must still exist, be unlocked, stay outside Recently Deleted, and not be a Quick Note; its content is not fingerprinted. Needs Full Disk Access |
|
|
@@ -1055,7 +1088,9 @@ A smart folder is never a destination: it only gathers notes by its rules, and N
|
|
|
1055
1088
|
|-----------|------|----------|-------------|
|
|
1056
1089
|
| `id` | string | Yes | Exact CoreData note ID returned by a read or search |
|
|
1057
1090
|
| `folder` | string | Yes | Destination folder name or nested path (e.g., `"Work/Clients"`) |
|
|
1091
|
+
| `account` | string | No | Account whose `folder` is the destination (default: the default account) |
|
|
1058
1092
|
| `ifFolderId`, `ifAncestorFolderId`, `forbiddenAncestorFolderIds` | string, string, string[] | No | Folder preconditions; see [Folder scope guards](#folder-scope-guards) |
|
|
1093
|
+
| `timeoutSeconds` | number | No | Per-call timeout, 1–120 seconds, as for [`create-note`](#create-note). A timed-out write is uncertain: read the note by id before any retry |
|
|
1059
1094
|
|
|
1060
1095
|
Title-only moves are rejected.
|
|
1061
1096
|
|
|
@@ -1113,7 +1148,9 @@ Appends or prepends content to an existing note without replacing it. Always rea
|
|
|
1113
1148
|
| `position` | string | No | `"after"` (default) appends to the end; `"before"` inserts directly below the note's title line, so the title stays first |
|
|
1114
1149
|
| `separator` | string | No | String placed between existing content and new content (default: two newlines → `<div><br></div>` in HTML) |
|
|
1115
1150
|
| `format` | string | No | Format of the content being appended: `"plaintext"` (default) or `"html"` |
|
|
1151
|
+
| `scopeText` | string | Native-object notes only | Unique existing phrase, as for [`append-native`](#append-native) |
|
|
1116
1152
|
| `ifFolderId`, `ifAncestorFolderId`, `forbiddenAncestorFolderIds` | string, string, string[] | No | Folder preconditions; see [Folder scope guards](#folder-scope-guards) |
|
|
1153
|
+
| `timeoutSeconds` | number | No | Per-call timeout, 1–120 seconds, as for [`create-note`](#create-note). A timed-out write is uncertain: read the note by id before any retry |
|
|
1117
1154
|
|
|
1118
1155
|
Title-only appends are rejected.
|
|
1119
1156
|
|
|
@@ -2354,6 +2391,15 @@ distinctive existing `scopeText` so the Shortcut and server can independently
|
|
|
2354
2391
|
resolve the same note. Creating a note from Markdown is
|
|
2355
2392
|
[`create-note`](#create-note) with `format: "markdown"`.
|
|
2356
2393
|
|
|
2394
|
+
Every tool below that edits one note takes these parameters, plus the ones
|
|
2395
|
+
listed under the tool itself:
|
|
2396
|
+
|
|
2397
|
+
| Parameter | Type | Required | Description |
|
|
2398
|
+
|-----------|------|----------|-------------|
|
|
2399
|
+
| `id` | string | Yes | Exact note ID: x-coredata id, Notes UUID, or numeric key (see [Identifier forms](#identifier-forms)) |
|
|
2400
|
+
| `expectedContentHash` | string | Yes | `contentHash` (`sha256:…`) from a fresh read of the note |
|
|
2401
|
+
| `scopeText` | string | Yes | Distinctive phrase already in the note, 12–500 characters, that Notes search can find. Prefer plain words without punctuation, hashtags, or paths |
|
|
2402
|
+
|
|
2357
2403
|
When the Shortcut refuses a request (its Find Notes step did not return
|
|
2358
2404
|
exactly one note with that exact title and `scopeText`) or stops with its own
|
|
2359
2405
|
action error, and the note reads back unchanged, the tool reports the
|
|
@@ -2418,11 +2464,20 @@ unapproved bridge is identified rather than guessed at; a timeout also says it
|
|
|
2418
2464
|
may be an unanswered first-run consent prompt and names the Shortcut to run once
|
|
2419
2465
|
in the foreground.
|
|
2420
2466
|
|
|
2467
|
+
| Parameter | Type | Required | Description |
|
|
2468
|
+
|-----------|------|----------|-------------|
|
|
2469
|
+
| `content` | string | Yes | Content to append, up to 1,048,576 characters |
|
|
2470
|
+
| `format` | string | No | `"plaintext"` (default), `"html"`, or `"markdown"` |
|
|
2471
|
+
|
|
2421
2472
|
#### `create-checklist-item`
|
|
2422
2473
|
|
|
2423
2474
|
Appends one real unchecked Notes checklist item and verifies its native identity
|
|
2424
2475
|
and text.
|
|
2425
2476
|
|
|
2477
|
+
| Parameter | Type | Required | Description |
|
|
2478
|
+
|-----------|------|----------|-------------|
|
|
2479
|
+
| `text` | string | Yes | The item's text |
|
|
2480
|
+
|
|
2426
2481
|
#### `create-checklist-items`
|
|
2427
2482
|
|
|
2428
2483
|
Appends several real unchecked checklist items, 1 to 20, in the order given.
|
|
@@ -2462,27 +2517,54 @@ cell. It never substitutes a text table. Omit `rows` for an empty 2 × 2 table,
|
|
|
2462
2517
|
the size Notes itself inserts from Format > Table; its four empty cells are
|
|
2463
2518
|
verified the same way.
|
|
2464
2519
|
|
|
2520
|
+
| Parameter | Type | Required | Description |
|
|
2521
|
+
|-----------|------|----------|-------------|
|
|
2522
|
+
| `rows` | string[][] | No | Cell text, row by row: 1–1,000 rows of 1–100 cells, every row the same length. Omit for an empty 2 × 2 table |
|
|
2523
|
+
|
|
2465
2524
|
#### `set-note-pinned`
|
|
2466
2525
|
|
|
2467
2526
|
Sets an explicit pinned state after checking both the expected current state and
|
|
2468
2527
|
the note revision. It does not rewrite the body.
|
|
2469
2528
|
|
|
2529
|
+
| Parameter | Type | Required | Description |
|
|
2530
|
+
|-----------|------|----------|-------------|
|
|
2531
|
+
| `expectedPinned` | boolean | Yes | The pinned state you last read; the call is refused if it differs |
|
|
2532
|
+
| `pinned` | boolean | Yes | The pinned state to set |
|
|
2533
|
+
|
|
2470
2534
|
#### `remove-native-tags`
|
|
2471
2535
|
|
|
2472
2536
|
Removes specified tags from one exact note while preserving unrelated tags and
|
|
2473
2537
|
native objects. It does not delete global tag definitions.
|
|
2474
2538
|
|
|
2539
|
+
| Parameter | Type | Required | Description |
|
|
2540
|
+
|-----------|------|----------|-------------|
|
|
2541
|
+
| `tags` | string[] | Yes | 1–100 tag names to remove |
|
|
2542
|
+
|
|
2475
2543
|
#### `replace-native-tag`
|
|
2476
2544
|
|
|
2477
2545
|
Adds and verifies the new tag before removing the old tag on an explicit list of
|
|
2478
2546
|
freshly read notes. Stops on the first uncertain result. Smart Folder rules are
|
|
2479
2547
|
not changed.
|
|
2480
2548
|
|
|
2549
|
+
Unlike the other tools in this section, it takes a list of notes instead of one
|
|
2550
|
+
`id`:
|
|
2551
|
+
|
|
2552
|
+
| Parameter | Type | Required | Description |
|
|
2553
|
+
|-----------|------|----------|-------------|
|
|
2554
|
+
| `notes` | object[] | Yes | 1–100 entries, each with the note's `id`, `expectedContentHash`, and `scopeText` |
|
|
2555
|
+
| `oldTag` | string | Yes | Tag to remove after the new one is verified |
|
|
2556
|
+
| `newTag` | string | Yes | Tag to add |
|
|
2557
|
+
|
|
2481
2558
|
#### `insert-note-link`
|
|
2482
2559
|
|
|
2483
2560
|
Retrieves another note's real deep link and appends it with a static label while
|
|
2484
2561
|
preserving the target note's native objects.
|
|
2485
2562
|
|
|
2563
|
+
| Parameter | Type | Required | Description |
|
|
2564
|
+
|-----------|------|----------|-------------|
|
|
2565
|
+
| `linkedNoteId` | string | Yes | ID of the note to link to, in any [identifier form](#identifier-forms) |
|
|
2566
|
+
| `label` | string | No | Visible link text (default: the linked note's title) |
|
|
2567
|
+
|
|
2486
2568
|
### Private helper (opt-in, unsupported Apple API)
|
|
2487
2569
|
|
|
2488
2570
|
An optional, **read-only** native helper reads note state through Notes' own
|
|
@@ -2675,8 +2757,14 @@ All configuration is optional — the server works out of the box. Override beha
|
|
|
2675
2757
|
| `APPLE_NOTES_MCP_RETRY_DELAY_MS` | `1000` (1 s) | Base delay before the first retry; subsequent retries back off exponentially (1s, 2s, 4s, ...). |
|
|
2676
2758
|
| `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. |
|
|
2677
2759
|
| `APPLE_NOTES_MCP_PRIVATE_HELPER_DIR` | `~/Library/Application Support/apple-notes-mcp/private-helper` | Where `setup --native-helper` installs the helper and its checksum manifest. |
|
|
2678
|
-
| `APPLE_NOTES_MCP_PRIVATE_HELPER_TIMEOUT_MS` | `20000` (20 s) | Per-call helper
|
|
2760
|
+
| `APPLE_NOTES_MCP_PRIVATE_HELPER_TIMEOUT_MS` | `20000` (20 s) | Per-call timeout for the private helper. The helper is read-only, so a timeout changes nothing in Notes. |
|
|
2679
2761
|
| `APPLE_NOTES_MCP_PRIVATE_STORE` | unset | Testing only: points the helper at a **copy** of `NoteStore.sqlite`. The helper refuses a path that resolves to the live store. |
|
|
2762
|
+
| `APPLE_NOTES_MCP_PUBLIC_HELPER_DIR` | `~/Library/Application Support/apple-notes-mcp/public-helper` | Where `setup --public-helper` installs the [public native helper](#public-native-helper) and its checksum manifest. |
|
|
2763
|
+
| `APPLE_NOTES_MCP_PUBLIC_HELPER_TIMEOUT_MS` | `30000` (30 s) | Per-call timeout for the public native helper (`get-note-drawings`, `transcribe-note-audio`). |
|
|
2764
|
+
| `APPLE_NOTES_MCP_TAGS_SHORTCUT` | `Apple Notes MCP - Native Tags` | Name or UUID of the installed Native Tags bridge to run. `setup` still installs and checks the default name. |
|
|
2765
|
+
| `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. |
|
|
2766
|
+
| `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. |
|
|
2767
|
+
| `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. |
|
|
2680
2768
|
| `DEBUG` / `VERBOSE` | unset | Set either to enable verbose diagnostic logging to stderr. |
|
|
2681
2769
|
|
|
2682
2770
|
### Configuration file (when the host strips `env`)
|
|
@@ -2703,7 +2791,7 @@ MCP stores no secrets, but as a general rule keep only non-secret config here.
|
|
|
2703
2791
|
|
|
2704
2792
|
## Full Disk Access
|
|
2705
2793
|
|
|
2706
|
-
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`, `list-note-paragraphs`, `get-paragraph-link`, `get-note-structure`, `list-note-links`, `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`.
|
|
2794
|
+
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: `query-notes`, `get-native-objects`, `get-note-tables`, `list-smart-folders`, `delete-folder-by-id`, `get-note-drawings`, `transcribe-note-audio`, `native-note-state`, `get-checklist-state`, `get-note-metadata`, `get-note-blocks`, `list-note-paragraphs`, `get-paragraph-link`, `get-note-structure`, `list-note-links`, `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`.
|
|
2707
2795
|
|
|
2708
2796
|
> 📘 **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.
|
|
2709
2797
|
|
|
@@ -2723,6 +2811,8 @@ Several tools read directly from the Apple Notes SQLite database, which lives in
|
|
|
2723
2811
|
|
|
2724
2812
|
Every tool that does not read the Notes database works normally without Full Disk Access — that is the whole AppleScript surface (create, read, search, update, move, delete, folders, accounts, attachments, stats, export). The database-backed tools degrade like this:
|
|
2725
2813
|
- `get-checklist-state` returns an error explaining that database access is needed
|
|
2814
|
+
- `query-notes` returns the same kind of error; use `search-notes` instead
|
|
2815
|
+
- `delete-folder-by-id` refuses to delete anything (it fails closed)
|
|
2726
2816
|
- `get-note-metadata` returns the same kind of error — it has no non-database path
|
|
2727
2817
|
- `list-special-notes` and the `list-native-tags` inventory return the same kind of error
|
|
2728
2818
|
- `list-recent-notes` and `list-folder-tree` return the same kind of error
|
|
@@ -2750,7 +2840,7 @@ The helper never opens the Notes database and never writes under the Notes group
|
|
|
2750
2840
|
|
|
2751
2841
|
## Security and Privacy
|
|
2752
2842
|
|
|
2753
|
-
- **Local only** - All operations happen locally
|
|
2843
|
+
- **Local only** - All operations happen locally, through AppleScript, the packaged Shortcuts, read-only reads of the Notes database, and helpers you build on your own Mac. The server makes no network requests, and `transcribe-note-audio` uses on-device speech recognition only. Whatever your MCP client does with the results is governed by that client.
|
|
2754
2844
|
- **Permission required** - macOS will prompt for automation permission on first use.
|
|
2755
2845
|
- **Password-protected notes** - Notes with passwords cannot be read or modified via this server.
|
|
2756
2846
|
- **No credential storage** - The server doesn't store any passwords or authentication tokens.
|
|
@@ -2763,15 +2853,15 @@ The helper never opens the Notes database and never writes under the Notes group
|
|
|
2763
2853
|
|------------|--------|
|
|
2764
2854
|
| macOS only | Apple Notes and AppleScript are macOS-specific |
|
|
2765
2855
|
| Batch ops run per-note | `batch-delete-notes` / `batch-move-notes` apply each note individually rather than as one bulk operation — AppleScript has no bulk equivalent to IMAP's `UID STORE`/`MOVE`. This is deliberate: it preserves per-note success/failure reporting. ([#26](https://github.com/sweetrb/apple-notes-mcp/issues/26)) |
|
|
2766
|
-
|
|
|
2856
|
+
| Pinning needs a Shortcut | AppleScript exposes no `pinned` property. Pin state is readable via the BETA `get-note-metadata` tool (NoteStore database, needs Full Disk Access), and [`set-note-pinned`](#set-note-pinned) sets it through the Background Operations Shortcut rather than AppleScript ([#28](https://github.com/sweetrb/apple-notes-mcp/issues/28)) |
|
|
2767
2857
|
| Limited rich formatting | Use `format: "html"` on create/update for headings, lists, bold, code blocks; some complex formatting may not render |
|
|
2768
|
-
|
|
|
2858
|
+
| Exact IDs for writes | Writes take an exact note ID and a fresh `contentHash`, because Notes titles are not unique. Read tools that accept a `title` need an exact, case-sensitive match |
|
|
2769
2859
|
| Checklist state | Requires [Full Disk Access](https://github.com/sweetrb/apple-notes-mcp/blob/main/docs/FULL-DISK-ACCESS.md) to read done/undone state from the database |
|
|
2770
|
-
| Checklist **creation** | Not
|
|
2860
|
+
| Checklist **creation** | Not possible through AppleScript: its `body of note` setter strips `<input type="checkbox">` and ignores any checklist-styling CSS class, because Notes stores checklist items as a protobuf paragraph style (`style_type=103`). The server creates real checklist items through Shortcuts instead; see [Creating Checklists](#creating-checklists). Checking or unchecking an existing item is not supported. |
|
|
2771
2861
|
|
|
2772
2862
|
### Creating Checklists
|
|
2773
2863
|
|
|
2774
|
-
**There is no programmatic way to create a true Apple Notes checklist via AppleScript
|
|
2864
|
+
**There is no programmatic way to create a true Apple Notes checklist via AppleScript.** This is an Apple limitation, not a bug. Plaintext and HTML writes therefore cannot produce checklists, so this server creates them through Apple Shortcuts instead (workaround 2 below).
|
|
2775
2865
|
|
|
2776
2866
|
When a note is created or updated via AppleScript:
|
|
2777
2867
|
|
|
@@ -2786,7 +2876,7 @@ Apple Notes stores checklists as a paragraph style (`style_type=103`) inside a g
|
|
|
2786
2876
|
**Workarounds:**
|
|
2787
2877
|
|
|
2788
2878
|
1. **Create the note with bulleted list items, then convert manually in Notes.app.** Select the items and press <kbd>⇧⌘L</kbd> (or **Format → Checklist**). This converts the list in place and the resulting checklist will be readable by `get-checklist-state` and annotated by `get-note-markdown`.
|
|
2789
|
-
2. **Use the Apple Shortcuts app** to script the checklist creation, since Shortcuts can manipulate Notes content at a higher level than AppleScript. This server does that for you in two ways: [`create-checklist-item`](#create-checklist-item)
|
|
2879
|
+
2. **Use the Apple Shortcuts app** to script the checklist creation, since Shortcuts can manipulate Notes content at a higher level than AppleScript. This server does that for you in two ways: [`create-checklist-item`](#create-checklist-item) and [`create-checklist-items`](#create-checklist-items) append unchecked items to an existing note, and [`create-note`](#create-note) with `format: "markdown"` turns `- [ ]` / `- [x]` lines into checklist items with that done state through Notes' own Markdown importer (see [Markdown notes](#markdown-notes)).
|
|
2790
2880
|
3. **Read-only checklist support is fully implemented** — once a checklist exists (created manually or by another app), `get-checklist-state` and `get-note-markdown` will read its done/undone state correctly (with Full Disk Access).
|
|
2791
2881
|
|
|
2792
2882
|
If you need to *track* todos programmatically and don't strictly need them rendered as Apple Notes checklist UI, plain markdown-style `- [ ] item` / `- [x] item` lines in a `plaintext` note are a reasonable alternative — they are searchable, human-readable, and can be parsed by downstream tooling.
|
package/build/index.js
CHANGED
|
@@ -59329,7 +59329,7 @@ ${lines}${footer}`,
|
|
|
59329
59329
|
registerTool(
|
|
59330
59330
|
"get-note-content",
|
|
59331
59331
|
{
|
|
59332
|
-
description: "Use when: reading the full body text of one known note, by id (preferred) or title.\nReturns: the exact note id, content, contentHash revision token, parsed hashtags, nativeTags, restored links, richContentComplete/writable, and strippedImages/truncated when the body was capped. Read the warning when writable is false.\nDo not use when: you only need metadata (get-note-details) or Markdown with checklist state (get-note-markdown).\nNote: password-protected notes must be unlocked in Notes.app first.\nSafety: inline images larger than APPLE_NOTES_MCP_MAX_INLINE_IMAGE_BYTES (default 256 KB) are replaced with '[inline image omitted: ...]' text placeholders, so the returned body is lossy whenever truncated is true.
|
|
59332
|
+
description: "Use when: reading the full body text of one known note, by id (preferred) or title.\nReturns: the exact note id, content, contentHash revision token, parsed hashtags, nativeTags, restored links, richContentComplete/writable, and strippedImages/truncated when the body was capped. Read the warning when writable is false.\nDo not use when: you only need metadata (get-note-details) or Markdown with checklist state (get-note-markdown).\nNote: password-protected notes must be unlocked in Notes.app first.\nSafety: inline images larger than APPLE_NOTES_MCP_MAX_INLINE_IMAGE_BYTES (default 256 KB) are replaced with '[inline image omitted: ...]' text placeholders, so the returned body is lossy whenever truncated is true. For an attachment-bearing note, update-note refuses a full-body replacement; append-to-note with scopeText appends natively at the end and leaves attachments in place; add-attachment adds a file; move-note and delete-note work as usual. Make any other edit in Notes.app. Notes.app returns images inside the body as base64, so a note with a very large image can time out; the error then names the cause, and a larger timeoutSeconds gives the read more time.",
|
|
59333
59333
|
inputSchema: {
|
|
59334
59334
|
id: looseNoteId(external_exports.string()).optional().describe(`Note ID (preferred - more reliable than title): ${NOTE_ID_FORMS}`),
|
|
59335
59335
|
title: external_exports.string().max(MAX.TITLE).optional().describe("Note title (use id instead when available)"),
|
|
@@ -19,7 +19,7 @@ shared, body, id, name, plaintext
|
|
|
19
19
|
|
|
20
20
|
## Pinned notes (#28)
|
|
21
21
|
|
|
22
|
-
**Status: not feasible via AppleScript;
|
|
22
|
+
**Status: not feasible via AppleScript; read from the NoteStore database and set through a Shortcut.**
|
|
23
23
|
The Notes UI lets you pin a note to the top of a folder, but the `note` class
|
|
24
24
|
has no `pinned` property. Asking for it raises error `-1700`:
|
|
25
25
|
|
|
@@ -33,7 +33,7 @@ end tell
|
|
|
33
33
|
There is no alternative property, element, or command (`pin`, `pinned`,
|
|
34
34
|
`favorite`, …) in the dictionary. Pinned state lives only in Notes' private
|
|
35
35
|
Core Data store (`NoteStore.sqlite`), which is not part of the scriptable
|
|
36
|
-
surface, and
|
|
36
|
+
surface, and AppleScript offers no way to _set_ it.
|
|
37
37
|
|
|
38
38
|
Reading it, however, did turn out to be worth doing. Since 2.5.0 the BETA
|
|
39
39
|
`get-note-metadata` tool queries `ZISPINNED` on `ZICCLOUDSYNCINGOBJECT` in that
|
|
@@ -43,14 +43,17 @@ changes across macOS releases. It requires
|
|
|
43
43
|
[Full Disk Access](./FULL-DISK-ACCESS.md) and is marked BETA precisely because
|
|
44
44
|
the schema is version-dependent.
|
|
45
45
|
|
|
46
|
-
**Conclusion:** pin state is **
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
**Conclusion:** pin state is **not scriptable** through AppleScript in either
|
|
47
|
+
direction. It is **readable** (BETA, from the NoteStore database, Full Disk
|
|
48
|
+
Access required) and, since the native background operations were added,
|
|
49
|
+
**settable** through the packaged Background Operations Shortcut by
|
|
50
|
+
`set-note-pinned`, which checks the expected current state and the note
|
|
51
|
+
revision first. If a future macOS exposes a scriptable property, revisit by
|
|
52
|
+
re-running the probe above.
|
|
50
53
|
|
|
51
54
|
## Note-to-note links (#30)
|
|
52
55
|
|
|
53
|
-
**Status: link
|
|
56
|
+
**Status: link _relationships_ are not exposed to AppleScript; the server reads them from the database and inserts links by other routes.**
|
|
54
57
|
Apple Notes lets you insert a link from one note to another in the UI, but
|
|
55
58
|
AppleScript exposes no property or element for that relationship:
|
|
56
59
|
|
|
@@ -58,7 +61,7 @@ AppleScript exposes no property or element for that relationship:
|
|
|
58
61
|
(undefined). There is no element that enumerates outgoing/incoming links.
|
|
59
62
|
- Nothing in the dictionary inserts a link into a note's body.
|
|
60
63
|
|
|
61
|
-
A shareable deep link to a note
|
|
64
|
+
A shareable deep link to a note _is_ available, and has been since 2.6.0:
|
|
62
65
|
`get-note-link` returns a `notes://showNote?identifier=<uuid>` URL that opens
|
|
63
66
|
the note in Notes.app on macOS and iOS.
|
|
64
67
|
|
|
@@ -84,31 +87,39 @@ It **is** wrapped, as `show-note`, `show-folder`, `show-account`, and
|
|
|
84
87
|
something useful on a machine with an active desktop session; to read a note's
|
|
85
88
|
content, use `get-note-content` / `get-note-markdown` instead.
|
|
86
89
|
|
|
87
|
-
**Conclusion:** link relationships between notes
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
**Conclusion:** AppleScript can neither read link relationships between notes
|
|
91
|
+
nor insert a link into a body. The server does both by other routes:
|
|
92
|
+
`list-note-links` reads a note's or folder's links from the NoteStore database
|
|
93
|
+
(Full Disk Access required), `insert-link` appends a web, mail or Notes link,
|
|
94
|
+
and `insert-note-link` appends another note's real deep link through the
|
|
95
|
+
Background Operations Shortcut. To hand a note to a person or another app, use
|
|
96
|
+
`get-note-link`; to address a note in a follow-up tool call, use the `id`
|
|
97
|
+
returned by every read tool.
|
|
91
98
|
|
|
92
99
|
## Tags / hashtags (#29)
|
|
93
100
|
|
|
94
|
-
**Status:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
This server
|
|
101
|
-
|
|
102
|
-
rules match Notes' own
|
|
103
|
-
underscores containing **at least one letter**, so `#123` is not
|
|
104
|
-
are de-duplicated case-insensitively.
|
|
101
|
+
**Status: not scriptable; native tags go through Shortcuts.** A native Apple
|
|
102
|
+
Notes tag is an inline tag attachment backed by an `ICHashtag` object in Notes'
|
|
103
|
+
private Core Data store. It is **not** a scriptable property — the `note` class
|
|
104
|
+
exposes no `tags` element — and `#word` text written through AppleScript stays
|
|
105
|
+
plain text: Notes does not convert it into a native tag.
|
|
106
|
+
|
|
107
|
+
This server therefore separates two things. `get-note-content` parses textual
|
|
108
|
+
`#hashtag` tokens out of the body and returns them as `hashtags` (see
|
|
109
|
+
`src/utils/hashtags.ts`); the rules match Notes' own — `#` followed by
|
|
110
|
+
letters/digits/underscores containing **at least one letter**, so `#123` is not
|
|
111
|
+
a tag; tokens are de-duplicated case-insensitively. Actual native tags are read
|
|
112
|
+
from the database (`nativeTags`, `list-native-tags`, Full Disk Access) and
|
|
113
|
+
written with `add-native-tags` / `remove-native-tags` / `replace-native-tag`,
|
|
114
|
+
which drive the Notes Shortcuts action. A textual `hashtags` entry is not proof
|
|
115
|
+
that Notes registered a native tag.
|
|
105
116
|
|
|
106
117
|
Two related caveats:
|
|
107
118
|
|
|
108
119
|
- The `tags` parameter on `create-note` is an application-level pass-through. It
|
|
109
120
|
is stored on the returned object but Notes does **not** persist it, and it does
|
|
110
|
-
**not** create
|
|
111
|
-
|
|
121
|
+
**not** create tags. Typing `#tag` into the content does not either; use
|
|
122
|
+
`add-native-tags` on the created note.
|
|
112
123
|
- **Smart folders are not scriptable.** Notes' tag-driven Smart Folders cannot be
|
|
113
124
|
created, read, or enumerated via AppleScript; there is no `smart folder` class
|
|
114
125
|
in the dictionary. Only regular folders are scriptable.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apple-notes-mcp",
|
|
3
|
-
"version": "2.9.
|
|
4
|
-
"description": "MCP server for Apple Notes -
|
|
3
|
+
"version": "2.9.22",
|
|
4
|
+
"description": "MCP server for Apple Notes - read, search, create, edit, organize, and export notes on macOS via Claude and other AI assistants",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|
|
7
7
|
"types": "build/index.d.ts",
|
|
@@ -25,7 +25,16 @@
|
|
|
25
25
|
"applescript",
|
|
26
26
|
"macos",
|
|
27
27
|
"notes",
|
|
28
|
-
"model-context-protocol"
|
|
28
|
+
"model-context-protocol",
|
|
29
|
+
"mcp-server",
|
|
30
|
+
"apple",
|
|
31
|
+
"notes-app",
|
|
32
|
+
"claude-code",
|
|
33
|
+
"claude-desktop",
|
|
34
|
+
"shortcuts",
|
|
35
|
+
"markdown",
|
|
36
|
+
"note-taking",
|
|
37
|
+
"icloud"
|
|
29
38
|
],
|
|
30
39
|
"author": "Rob Sweet <rob@superiortech.io>",
|
|
31
40
|
"license": "MIT",
|