apple-notes-mcp 2.15.1 → 2.15.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 CHANGED
@@ -19,9 +19,9 @@ Beyond creating and editing notes, it manages folders and accounts, native tags,
19
19
 
20
20
  ## Contents
21
21
 
22
- - [What is This?](#what-is-this) · [Quick Start](#quick-start) · [Requirements](#requirements) · [Features](#features)
22
+ - [What is This?](#what-is-this) · [Setup on your Mac](#setup-on-your-mac) · [Requirements](#requirements) · [Features](#features)
23
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) · [Permission broker](#permission-broker-opt-in)
24
+ - [Usage Patterns](#usage-patterns) · [Installation choices and upgrades](#installation-choices-and-upgrades) · [Server settings](#server-settings) · [Full Disk Access](docs/FULL-DISK-ACCESS.md) · [Public native helper](#public-native-helper) · [Permission broker](#permission-broker-opt-in)
25
25
  - [Security and Privacy](#security-and-privacy) · [Known Limitations](#known-limitations) · [Troubleshooting](#troubleshooting) · [Recurring macOS permission prompts](#recurring-macos-permission-prompts) · [Development](#development)
26
26
 
27
27
  ## What is This?
@@ -34,138 +34,247 @@ This server acts as a bridge between AI assistants and Apple Notes. Once configu
34
34
  - "Move my draft notes to the Archive folder"
35
35
  - "What notes do I have in my Work folder?"
36
36
 
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.
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). Notes operations and speech recognition run locally. If you explicitly enable `downloadAssets: true`, the public helper may download speech models; what your MCP client does with tool results is up to that client.
38
38
 
39
- ## Quick Start
39
+ <a id="quick-start"></a>
40
40
 
41
- ### Using Claude Code (Easiest)
41
+ ## Setup on your Mac
42
42
 
43
- If you're using [Claude Code](https://claude.com/product/claude-code) (in Terminal or VS Code), just ask Claude to install it:
43
+ Apple Notes MCP runs on the Mac that holds your Notes library. Your assistant starts a local MCP server over **stdio**, and the server uses AppleScript, signed Apple Shortcuts, and read-only database access. Choose one client setup below, then complete the macOS permissions and optional feature setup you need.
44
44
 
45
+ **Version boundary:** these instructions describe v2.15.1, including the optional [permission broker](#permission-broker-opt-in). Normal client registration starts an in-process server unless a matching broker is already installed and answering. Broker installation is a separate opt-in step.
46
+
47
+ Manual client entries, setup commands, and the source checkout below select v2.15.1. Run setup from the same release as the server your client actually launches. The Claude Code plugin bundles its server; the Codex plugin manifest launches an unpinned npm package even when its marketplace is pinned. For reproducible Codex setup, use the manual registration below instead of the plugin. When upgrading, update the selected version consistently in the client and setup commands.
48
+
49
+ Run each setup target separately and use the exact options shown. Version 2.15.1 does not reject all unknown or mixed setup flags; a misspelled target can fall through to Shortcut setup and open import windows.
50
+
51
+ ### Requirements
52
+
53
+ - macOS with Notes.app and at least one configured Notes account. Features depend on the installed macOS version and account type; inspect `get-capabilities` before relying on optional features.
54
+ - Node.js 20 or newer. The `npx` examples also need npm, normally included with Node.js.
55
+ - A client that can launch a local stdio MCP server on this Mac. The configurations below cover Claude Code, Claude Desktop, Codex, Hermes, and Antigravity.
56
+ - Automation permission to control Notes.app for AppleScript operations. Database-backed operations also need Full Disk Access for the process macOS holds responsible for the server.
57
+ - Apple Shortcuts for native writes such as native tags, checklists, tables, pinning, and rich append. The optional native Markdown creation route needs macOS 26 or newer and an iCloud account.
58
+ - An Apple developer toolchain only if you choose to build an optional native helper or permissions window. The public helper needs a current Swift toolchain and macOS SDK that expose the macOS 26 speech APIs; older SDK compatibility is unverified.
59
+
60
+ Python is **not** an Apple Notes MCP runtime dependency. The package includes its compiled JavaScript server and signed Shortcut files. Python is used by developer scripts that regenerate those workflows, not by normal installation or MCP tool calls.
61
+
62
+ You do not need an Apple ID password, API key, or NotesCTL installation to configure this server. A client's own login and tool-approval policy are separate from macOS privacy permissions.
63
+
64
+ ### 1. Choose one client registration
65
+
66
+ Use either a plugin or a manual MCP entry for the same client. Registering both can load duplicate servers or leave you using a different package version than expected. Adding a client entry does not grant macOS permissions or import Shortcuts.
67
+
68
+ #### Claude Code
69
+
70
+ For the plugin, run these commands inside a Claude Code session:
71
+
72
+ ```text
73
+ /plugin marketplace add sweetrb/apple-notes-mcp#v2.15.1
74
+ /plugin install apple-notes@apple-notes-mcp
45
75
  ```
46
- Install the sweetrb/apple-notes-mcp MCP server so you can help me manage my Apple Notes
76
+
77
+ The plugin bundles the server and the Apple Notes skill. For a manual MCP registration instead, run this in your terminal:
78
+
79
+ ```bash
80
+ claude mcp add apple-notes -s user -- npx -y apple-notes-mcp@2.15.1
47
81
  ```
48
82
 
49
- Claude will handle the installation and configuration automatically.
83
+ Check the connection with `/mcp` in Claude Code. `claude mcp get apple-notes` inspects the manually registered server. Project-scoped `.mcp.json` entries require workspace/server approval and can override a user-scoped entry.
84
+
85
+ #### Claude Desktop
50
86
 
51
- Or register it yourself with one deterministic command:
87
+ Open **Settings → Developer → Edit Config**. Merge the following server entry into `~/Library/Application Support/Claude/claude_desktop_config.json`, preserving any existing servers:
88
+
89
+ ```json
90
+ {
91
+ "mcpServers": {
92
+ "apple-notes": {
93
+ "command": "npx",
94
+ "args": ["-y", "apple-notes-mcp@2.15.1"]
95
+ }
96
+ }
97
+ }
98
+ ```
99
+
100
+ Fully quit and reopen Claude Desktop. This `npx` route does not require a preceding global npm installation. If the desktop app cannot find `npx`, use an absolute executable path or the fixed Node configuration below. The desktop app may have a different `PATH` from your interactive shell.
101
+
102
+ #### Codex
103
+
104
+ For the plugin and its Apple Notes skill:
105
+
106
+ ```bash
107
+ codex plugin marketplace add sweetrb/apple-notes-mcp --ref v2.15.1
108
+ codex plugin add apple-notes@apple-notes-mcp
109
+ ```
110
+
111
+ For a manual MCP registration instead:
52
112
 
53
113
  ```bash
54
- claude mcp add apple-notes -s user -- npx -y apple-notes-mcp
114
+ codex mcp add apple-notes -- npx -y apple-notes-mcp@2.15.1
115
+ ```
116
+
117
+ The equivalent entry in `~/.codex/config.toml` is:
118
+
119
+ ```toml
120
+ [mcp_servers.apple-notes]
121
+ command = "npx"
122
+ args = ["-y", "apple-notes-mcp@2.15.1"]
55
123
  ```
56
124
 
57
- ### Using the Plugin Marketplace
125
+ If `codex` is not on your terminal's `PATH`, use the desktop client's **Settings → MCP servers → Add server**: choose **STDIO**, enter `npx` with arguments `-y` and `apple-notes-mcp@2.15.1`, save, and restart the server.
126
+
127
+ Restart the relevant local Codex session or client. Use `/mcp` in the CLI or the client's MCP settings to inspect the connection. `codex mcp list` lists manually configured servers. The desktop client, CLI, and IDE extension share the Codex configuration; select local execution on the Mac containing your Notes library.
128
+
129
+ The plugin's server entry runs the published npm package through unpinned `npx`, despite the marketplace ref above. Its server may therefore differ from v2.15.1. Use the manual entry to pin the runtime for these instructions, or run setup from the release matching the plugin's actual server. This is a different distribution path from the Claude Code plugin's bundled server.
58
130
 
59
- Install as a Claude Code plugin for automatic configuration and enhanced AI behavior:
131
+ #### Hermes
132
+
133
+ Register a local stdio server:
60
134
 
61
135
  ```bash
62
- /plugin marketplace add sweetrb/apple-notes-mcp
63
- /plugin install apple-notes
136
+ hermes mcp add apple-notes --command npx --args -y apple-notes-mcp@2.15.1
64
137
  ```
65
138
 
66
- This method also installs a **skill** that teaches Claude when and how to use Apple Notes effectively.
139
+ Or merge this entry into `~/.hermes/config.yaml`:
67
140
 
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.
141
+ ```yaml
142
+ mcp_servers:
143
+ apple-notes:
144
+ command: npx
145
+ args: ["-y", "apple-notes-mcp@2.15.1"]
146
+ ```
69
147
 
70
- Native tag, checklist, table, pin, and rich append operations use two packaged
71
- Apple Shortcuts. A third, `Apple Notes MCP - Create Markdown Note`, is optional:
72
- only `create-note`'s `format: "markdown"` needs it, and only on macOS 26 or
73
- later. Run the explicit setup once:
148
+ Restart the Hermes session. This repository supplies an MCP configuration route for Hermes; see its [CLI commands](https://hermes-agent.nousresearch.com/docs/reference/cli-commands#hermes-mcp) and [MCP configuration reference](https://hermes-agent.nousresearch.com/docs/reference/mcp-config-reference).
149
+
150
+ #### Antigravity
151
+
152
+ In the IDE, open **MCP Servers → Manage MCP Servers → View raw config**. Merge the same `mcpServers` JSON entry shown for Claude Desktop into the global `~/.gemini/config/mcp_config.json`, or use the workspace configuration at `.agents/mcp_config.json`. Refresh or restart the client so it loads the server. Google's [MCP guide](https://antigravity.google/docs/mcp) describes the current menu and configuration paths.
153
+
154
+ The repository's `.antigravity-plugin/mcp_config.json` supplies an unpinned stdio server entry; the JSON above pins the audited release. Use `command` and `args`; this package does not provide a remote `serverUrl`.
155
+
156
+ #### Other MCP clients and remote execution
157
+
158
+ A local MCP client can use the command `npx` with arguments `-y` and `apple-notes-mcp@2.15.1`. Follow that client's stdio configuration format: JSON `mcpServers`, TOML, and YAML are not interchangeable.
159
+
160
+ Apple Notes MCP has no built-in HTTP, SSE, WebSocket, or OAuth MCP endpoint. A cloud-only client cannot access your Mac's Notes library merely by installing the npm package in a Linux container or entering a URL. A separately managed transport bridge or client feature that delegates tool execution to your Mac needs its own configuration and security review; it is not part of this package's supported setup. GUI reveal and clipboard tools also need your logged-in desktop session.
161
+
162
+ The optional `anchors serve` command is a paragraph-link resolver, and `templates edit` is a template editor. Neither is a remote MCP server.
163
+
164
+ <a id="full-disk-access"></a>
165
+ <a id="permissions-check"></a>
166
+
167
+ ### 2. Verify the server and macOS access
168
+
169
+ In the configured client, ask it to run `get-capabilities` and then `doctor`. `get-capabilities` inspects feature availability without opening Notes or running the bridges. `doctor` also sends a read-only Apple event to Notes and may trigger the macOS Automation prompt. Run these from the actual client because a successful terminal check does not establish that a different desktop app has the same permissions.
170
+
171
+ | Access or component | What it enables | How to complete it |
172
+ |---|---|---|
173
+ | Automation of Notes.app | AppleScript reads and writes | Allow the macOS prompt for the responsible app to control Notes. Inspect **Privacy & Security → Automation** if access was denied. |
174
+ | Full Disk Access | Database reads, rich-content inspection and safety checks, query tools, native object reads, and database-backed exports | Add the responsible executable/app under **Privacy & Security → Full Disk Access**, fully quit and relaunch the host, then rerun `doctor`. |
175
+ | Shortcut installation and consent | Native tag, checklist, table, pin, link, and append routes | Import the bridges and complete their foreground consent steps below. |
176
+ | Public helper and, where required, Speech Recognition | Classic drawing decoding and on-device audio transcription | Build the optional helper; follow the permission result from `doctor` or the tool. |
177
+
178
+ **Which process needs Full Disk Access?** For a brokered session, grant the signed **Apple Notes MCP Broker.app** access; `doctor` reports whether that session uses it. Without the broker, Claude Desktop needs the exact **Node executable** printed by `doctor`; granting Claude.app alone does not reach the server in that launch path. For a terminal-launched client, the terminal app is normally the responsible app; for an editor-launched server, check that editor. Use the actual running client's diagnostics instead of assuming that all clients share grants.
179
+
180
+ Client sandbox access is a separate boundary. A sandboxed client must be able to launch the executable and reach its files; a brokered client also needs access to the broker's local Unix socket. Full Disk Access and Automation grants do not expand the client's sandbox. Diagnose a launch or socket-access refusal in the client before changing macOS privacy permissions.
181
+
182
+ To inspect setup from a terminal without opening permission panes or requesting Automation access:
74
183
 
75
184
  ```bash
76
- npx -y apple-notes-mcp setup
77
- ```
78
-
79
- The command checks existing installations and opens only missing signed
80
- workflows; it opens the optional Create Markdown Note bridge only on macOS 26 or
81
- later. Confirm **Add Shortcut** in each macOS window, then verify with
82
- `npx -y apple-notes-mcp setup --check` or the MCP `doctor` tool. `setup --check`
83
- reports ready and `doctor` reports ok once the two required bridges are
84
- installed; both list the optional bridge's status separately. macOS does not
85
- support silent Shortcut import, so merely connecting an MCP client never opens
86
- setup windows or bypasses these confirmations.
87
-
88
- After install **and after every upgrade**, open Shortcuts.app and run each
89
- installed bridge — `Apple Notes MCP - Native Tags`,
90
- `Apple Notes MCP - Background Operations v5` and, if you installed it, the
91
- optional `Apple Notes MCP - Create Markdown Note` — once in the foreground, choosing
92
- **Always Allow** when Shortcuts asks for permission. The Create Markdown Note
93
- bridge stops before reaching Notes when run with no input, so start its run
94
- with the request in [`shortcuts/README.md`](shortcuts/README.md). The server runs these
95
- Shortcuts in the background, where Shortcuts cannot display a first-run consent
96
- prompt: an unanswered one stalls every native write on that bridge until it
97
- times out, while `doctor` still reports the bridge installed. Quitting or
98
- relaunching Shortcuts.app or Notes.app does not clear it; the foreground run
99
- does, once per bridge.
100
-
101
- ### Using the Codex Marketplace
102
-
103
- The same plugin is available for Codex. Add the marketplace and install the plugin:
185
+ npx -y apple-notes-mcp@2.15.1 setup --permissions --check --json
186
+ ```
187
+
188
+ The Automation result is intentionally unknown in this mode. When you are at the Mac and want to check it, this command sends a read-only Apple event and may show the macOS consent prompt:
104
189
 
105
190
  ```bash
106
- codex plugin marketplace add sweetrb/apple-notes-mcp
107
- codex plugin add apple-notes@apple-notes-mcp
191
+ npx -y apple-notes-mcp@2.15.1 setup --permissions --once --probe-automation
108
192
  ```
109
193
 
110
- The Codex plugin runs the published `apple-notes-mcp` server through `npx` and ships the same Apple Notes skill, so behavior matches the Claude Code plugin.
194
+ For an interactive checklist that also opens the relevant settings panes:
195
+
196
+ ```bash
197
+ npx -y apple-notes-mcp@2.15.1 setup --permissions --open --probe-automation
198
+ ```
111
199
 
112
- ### Other Hosts (Hermes, Antigravity)
200
+ The command checks permissions; it does not grant them. `--check` and SSH sessions suppress the Automation probe even when `--probe-automation` is supplied. Without the probe, exit status 0 does not establish Automation access.
113
201
 
114
- Two more hosts can run the same `apple-notes` MCP server (`npx -y apple-notes-mcp`):
202
+ Full Disk Access is optional if you only need operations that can safely run through AppleScript, but many capabilities and safety checks depend on it. It can also be required by guards on existing-note writes, including rich-content and revision verification; it is not merely an enhancement for read tools. Do not interpret an unavailable database-backed feature as an empty result. In particular, sync results without database visibility do not prove that iCloud sync is idle. Use the tool reference and `get-capabilities` for individual requirements, and see the [Full Disk Access guide](docs/FULL-DISK-ACCESS.md).
115
203
 
116
- - **[Hermes Agent](https://hermes-agent.nousresearch.com/)** (NousResearch) — Hermes has no plugin/marketplace drop-in, so there is nothing in this repo to install from. Register the server with the CLI:
204
+ ### 3. Enable the native Shortcut features you need
117
205
 
118
- ```bash
119
- hermes mcp add apple-notes --command npx --args -y apple-notes-mcp
120
- ```
206
+ Run explicit setup on your Mac:
121
207
 
122
- Or add it to `~/.hermes/config.yaml` by hand:
208
+ ```bash
209
+ npx -y apple-notes-mcp@2.15.1 setup
210
+ ```
123
211
 
124
- ```yaml
125
- mcp_servers:
126
- apple-notes:
127
- command: npx
128
- args: ["-y", "apple-notes-mcp"]
129
- ```
212
+ Approve **Add Shortcut** for the missing signed workflows that macOS opens:
130
213
 
131
- Restart your Hermes session afterward so the tools load.
132
- - **[Antigravity](https://antigravity.google/)** (Google) — add the server entry from [`.antigravity-plugin/mcp_config.json`](https://github.com/sweetrb/apple-notes-mcp/blob/main/.antigravity-plugin/mcp_config.json) to `~/.gemini/config/mcp_config.json` (or via Antigravity's MCP settings).
214
+ - `Apple Notes MCP - Native Tags`
215
+ - `Apple Notes MCP - Background Operations v5`
216
+ - `Apple Notes MCP - Create Markdown Note`, offered only on macOS 26 or newer and optional for native Markdown creation
133
217
 
134
- ### Using Claude Desktop
218
+ Then check installation:
135
219
 
136
- **1. Install the server:**
137
220
  ```bash
138
- npm install -g apple-notes-mcp
221
+ npx -y apple-notes-mcp@2.15.1 setup --check
139
222
  ```
140
223
 
141
- **2. Add to Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json`):
142
- ```json
143
- {
144
- "mcpServers": {
145
- "apple-notes": {
146
- "command": "npx",
147
- "args": ["-y", "apple-notes-mcp"]
148
- }
149
- }
150
- }
224
+ The first two bridges determine this check's readiness; the optional Markdown bridge is reported separately. Keep only one installed copy of each named bridge. The server refuses duplicate bridge names.
225
+
226
+ After installation or upgrade, run each installed bridge once in the foreground in Shortcuts.app and answer its access prompts. Choose **Always Allow** if you want that bridge to run unattended. For the Markdown bridge, use the first-run request in [`shortcuts/README.md`](shortcuts/README.md); running it without input stops before it asks Notes for access. That request creates a disposable check note.
227
+
228
+ An installed bridge is not proof of consent: `shortcuts list`, `setup --check`, and `doctor` cannot observe the first-run consent state. A background native write can stall on an unanswered prompt. After a timeout or an indeterminate write result, read the exact note before retrying because the write may already have happened.
229
+
230
+ ### 4. Build optional helpers
231
+
232
+ These commands are separate from registering the MCP client. If `xcrun swiftc` or `clang` is unavailable, install Apple's Command Line Tools with `xcode-select --install` before building a helper. The public helper's source references `SpeechAnalyzer` and `SpeechTranscriber`, so its build needs a current Swift toolchain and macOS SDK exposing those macOS 26 APIs. Runtime availability checks do not establish compatibility with an older SDK; builds with older SDKs are unverified.
233
+
234
+ #### Public native helper
235
+
236
+ <a id="public-native-helper"></a>
237
+
238
+ Needed for `get-note-drawings` and `transcribe-note-audio`. Brokered sessions do not load external helpers; set `APPLE_NOTES_MCP_BROKER=off` for this client and restart it before using these tools:
239
+
240
+ ```bash
241
+ npx -y apple-notes-mcp@2.15.1 setup --public-helper
242
+ npx -y apple-notes-mcp@2.15.1 setup --public-helper --check
151
243
  ```
152
244
 
153
- **3. Restart Claude Desktop** and start using natural language:
245
+ It compiles locally, signs ad hoc, verifies its handshake, and records source and binary checksums. The server refuses stale or modified helpers; rerun setup after a relevant package upgrade. This helper uses public Apple frameworks and does not open or write the Notes database. The server still needs Full Disk Access to read the drawing/audio assets it passes to the helper.
246
+
247
+ On older macOS versions, speech transcription needs Speech Recognition access for the responsible host. The helper never requests this silently. On macOS 26 and newer, the SpeechAnalyzer route has been observed to work without a prior grant; explicit denial or restriction still blocks it. Inspect the returned capability/permission status on your Mac.
248
+
249
+ #### Private helper setup
250
+
251
+ Optional read-only NotesShared state inspection, disabled by default. Brokered sessions do not load this helper; set `APPLE_NOTES_MCP_BROKER=off` for this client and restart it first:
252
+
253
+ ```bash
254
+ npx -y apple-notes-mcp@2.15.1 setup --native-helper
255
+ npx -y apple-notes-mcp@2.15.1 setup --native-helper --check
154
256
  ```
155
- "Create a note called 'Ideas' with my brainstorming thoughts"
257
+
258
+ To enable it, set the string environment value `APPLE_NOTES_MCP_ENABLE_PRIVATE=1` for the server and restart the client. Inspect `native-helper-status` before using `native-note-state`. This released helper opens the store read-only and cannot provide deep native writes. Apple's private API may change with macOS updates; the remaining server features do not require this helper.
259
+
260
+ #### Optional checklist window
261
+
262
+ Optional graphical presentation of the checklist:
263
+
264
+ ```bash
265
+ npx -y apple-notes-mcp@2.15.1 setup --permissions-window
266
+ npx -y apple-notes-mcp@2.15.1 setup --permissions --window
156
267
  ```
157
268
 
158
- On first use, macOS will ask for permission to automate Notes.app. Click "OK" to allow.
269
+ It displays the command's checks and opens settings on request. It does not become the permission owner or replace the client process.
159
270
 
160
- ### Other MCP clients
271
+ ### 5. Confirm the capabilities you intend to use
161
272
 
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).
273
+ After restarting the client, run `doctor` and `get-capabilities` again. Confirm that the specific routes you need are available, not just that the server connected. Private helper status, public helper readiness, Markdown creation, and the native-write bridges are separate checks.
163
274
 
164
- ## Requirements
275
+ Use read-only operations first, such as listing accounts/folders and reading a note you select. If you want to exercise a write route, use a dedicated disposable note and verify the result by its exact ID. A successful plain note creation does not validate native tables, checklists, or Markdown creation; test the feature you plan to use.
165
276
 
166
- - **macOS** - Apple Notes and AppleScript are macOS-only
167
- - **Node.js 20+** - Required for the MCP server
168
- - **Apple Notes** - Must have at least one account configured (iCloud, Gmail, etc.)
277
+ Keep the server's revision and scope checks enabled. Updates, appends, and deletes use exact IDs and content hashes; native routes may also require a distinctive existing `scopeText`. Full-body updates refuse rich notes they cannot preserve. Follow the returned error and capability information instead of falling back to a lower-level write.
169
278
 
170
279
  ## Features
171
280
 
@@ -2771,28 +2880,7 @@ Private API can break on any macOS update; see
2771
2880
  [TECHNICAL_NOTES.md](TECHNICAL_NOTES.md#private-helper-notesshared) for the
2772
2881
  API surface, risks, and safety contract.
2773
2882
 
2774
- If you installed the [permission broker](#permission-broker-opt-in), set
2775
- `APPLE_NOTES_MCP_BROKER=off` for this client first. Broker sessions do not load
2776
- external native helpers.
2777
-
2778
- To use it:
2779
-
2780
- 1. Build it on your Mac from the packaged source (needs the Command Line
2781
- Tools, `xcode-select --install`). No prebuilt binary ships with the package.
2782
-
2783
- ```bash
2784
- apple-notes-mcp setup --native-helper # build, ad-hoc sign, install
2785
- apple-notes-mcp setup --native-helper --check # report only
2786
- ```
2787
-
2788
- 2. Set `APPLE_NOTES_MCP_ENABLE_PRIVATE=1` in the server's environment (or in
2789
- the [config file](#configuration-file-when-the-host-strips-env)).
2790
- 3. Give the app that launches the server Full Disk Access, the same grant the
2791
- database reads already need.
2792
-
2793
- The server checks the helper's recorded source and binary SHA-256 before every
2794
- call and refuses a missing, stale, or modified helper with a machine-readable
2795
- `code`. Rerun setup after upgrading apple-notes-mcp.
2883
+ Brokered sessions do not load external native helpers. Set `APPLE_NOTES_MCP_BROKER=off` for this client and restart it, then follow [Private helper setup](#private-helper-setup) to build and enable it. The server checks the helper's recorded source and binary SHA-256 before every call and refuses a missing, stale, or modified helper with a machine-readable `code`. Rerun matching-version setup after upgrading apple-notes-mcp.
2796
2884
 
2797
2885
  #### `native-helper-status`
2798
2886
 
@@ -2811,6 +2899,35 @@ title, modification date, folder identifier, lock/trash/shared/editable
2811
2899
  flags, iCloud version counters, and a `revision` change token (compare two
2812
2900
  reads to detect a change). Opens the store with Core Data's read-only option.
2813
2901
 
2902
+ #### `native-checklist-state`
2903
+
2904
+ Reads one note's native checklist by Notes UUID (`identifier`) or x-coredata
2905
+ `id`; pass exactly one. The `id` is resolved through an exact read-only database
2906
+ lookup after checking the opt-in and installed hashes. Requires the same opt-in, current helper, and Full Disk
2907
+ Access as `native-note-state`. Check `native-helper-status`'s `readChecklist`
2908
+ feature first: its probe checks the checklist getters separately. Locked notes
2909
+ or unavailable native bodies are refused. Ordinary `☐` glyphs and Markdown
2910
+ task text do not count as native checklist items.
2911
+
2912
+ Returns `identifier`, `revision`, `items`, `total`, `checked`, and
2913
+ `syncHostRunning`. Each item has its exact native `todoIdentifier` (32 lowercase
2914
+ hex digits), `uuid`, `index`, `done`, and `text`. Items follow the first occurrence
2915
+ of each native todo identity, which can cover multiple style runs. `text` is the
2916
+ line containing its first visible styled character, or the first styled line
2917
+ when it has only line terminators. `lineStart`, `lineLengthUTF16`, `styledStart`,
2918
+ and `styledLengthUTF16` are UTF-16 offsets and lengths; line text excludes the
2919
+ terminator. The styled range is an envelope, including intervening characters
2920
+ when the identity occurs in separated runs.
2921
+
2922
+ Read the ambiguity flags before treating an entry as a single checklist row:
2923
+ `contiguous: false` means separated runs share the identity; `consistent: false`
2924
+ means their done bits disagree; `spansLines: true` means its styled envelope
2925
+ contains multiple lines after leading/trailing terminators are removed. `done`
2926
+ comes from the first visible styled character, falling back to the first run.
2927
+ Totals count native identities, including ambiguous ones. The `revision` is an
2928
+ informational change token. This tool opens the store read-only and cannot
2929
+ toggle, create, or repair checklist items.
2930
+
2814
2931
  ## Usage Patterns
2815
2932
 
2816
2933
  ### Basic Workflow
@@ -2885,67 +3002,94 @@ AI: [calls create-note with title="Acme Corp", content="...", folder="Work/Clien
2885
3002
 
2886
3003
  ---
2887
3004
 
2888
- ## Installation Options
3005
+ <a id="installation-options"></a>
2889
3006
 
2890
- ### npm (Recommended)
3007
+ ## Installation choices and upgrades
3008
+
3009
+ ### Published package
3010
+
3011
+ The examples above use `npx -y apple-notes-mcp@2.15.1`, so a separate global install is optional. To install a persistent command instead:
2891
3012
 
2892
3013
  ```bash
2893
- npm install -g apple-notes-mcp
3014
+ npm install -g apple-notes-mcp@2.15.1
2894
3015
  ```
2895
3016
 
2896
- ### From Source
3017
+ You can then run `apple-notes-mcp setup --check` and the other setup commands directly. An npm package version can be pinned in an `npx` argument, for example `apple-notes-mcp@2.15.1`, when you need a reproducible version. Keep client and setup commands on the same package version.
3018
+
3019
+ After an upgrade, restart the client, check Shortcuts, complete any renewed foreground Shortcut consent, and rebuild a helper if its source checksum changed. Do not use a permission reset as a routine upgrade step.
3020
+
3021
+ ### Fixed Node executable for desktop clients
3022
+
3023
+ If a desktop client cannot resolve `npx`, or Node updates repeatedly invalidate macOS grants, use a persistent package location and an absolute Node executable path:
2897
3024
 
2898
3025
  ```bash
2899
- git clone https://github.com/sweetrb/apple-notes-mcp.git
2900
- cd apple-notes-mcp
3026
+ command -v node
3027
+ npm root -g
2901
3028
  ```
2902
3029
 
2903
- The repo ships a prebuilt, dependency-free `build/index.js`, so a bare clone runs with nothing but Node installed. `pnpm install` and `pnpm run build` are only needed when you change the source (development uses [pnpm](https://pnpm.io/), not npm).
2904
-
2905
- You can also install straight from the git repo with `npm install -g github:sweetrb/apple-notes-mcp` (building from source requires pnpm), but the published npm package above is the recommended path.
3030
+ Use the first result as `command` and append `/apple-notes-mcp/build/index.js` to the second result for `args`. Example placeholders:
2906
3031
 
2907
- If installed from source, use this configuration:
2908
3032
  ```json
2909
3033
  {
2910
3034
  "mcpServers": {
2911
3035
  "apple-notes": {
2912
- "command": "node",
2913
- "args": ["/path/to/apple-notes-mcp/build/index.js"]
3036
+ "command": "/absolute/path/to/node",
3037
+ "args": ["/absolute/npm/root/apple-notes-mcp/build/index.js"]
2914
3038
  }
2915
3039
  }
2916
3040
  }
2917
3041
  ```
2918
3042
 
2919
- #### Running from a clone in Claude Code (project-scope `.mcp.json`)
3043
+ Confirm those files exist on your Mac. A Developer-ID-signed Node at a stable resolved path is preferable when permission persistence matters. Ad-hoc signing or moving to a different version-manager path can require new grants. `doctor` checks the running Node's signature. See [`docs/NODE-RUNTIME-AND-TCC-PERMISSIONS.md`](docs/NODE-RUNTIME-AND-TCC-PERMISSIONS.md) for the dedicated-runtime procedure.
3044
+
3045
+ ### Source checkout
3046
+
3047
+ ```bash
3048
+ git clone --branch v2.15.1 https://github.com/sweetrb/apple-notes-mcp.git
3049
+ cd apple-notes-mcp
3050
+ ```
3051
+
3052
+ The repository includes the compiled `build/index.js`, so running that snapshot needs Node but no dependency installation. Configure the client with an absolute Node executable and the absolute path to `build/index.js`.
2920
3053
 
2921
- This repo ships a `.mcp.json` at its root so that, when you run `claude` from inside a clone, the server is registered automatically as a **project-scope** server — no manual config needed. Just launch Claude Code from the repo directory and approve the server when prompted (the bundled `build/index.js` is committed, so no build step is required).
3054
+ For Claude Code launched inside the clone, the root `.mcp.json` is a project-scope entry using `${CLAUDE_PROJECT_DIR:-.}/build/index.js`. Approve it when prompted. The plugin's `${CLAUDE_PLUGIN_ROOT}` entry belongs to the plugin installation and is not the clone configuration. Local scope takes precedence over project scope, which takes precedence over user scope; avoid accidentally selecting an older copy.
2922
3055
 
2923
- The entrypoint is written as (an excerpt of that file, not a whole config):
3056
+ Only when changing the source, install and build using the repository's pinned pnpm version. First ensure Corepack is installed: Node.js 25 and newer no longer bundle it, and other Node distributions may omit it. If `corepack` is unavailable, follow the [official Corepack installation instructions](https://github.com/nodejs/corepack#how-to-install), then run:
2924
3057
 
2925
- ```text
2926
- "args": ["${CLAUDE_PROJECT_DIR:-.}/build/index.js"]
3058
+ ```bash
3059
+ corepack enable
3060
+ pnpm install --frozen-lockfile
3061
+ pnpm run build
2927
3062
  ```
2928
3063
 
2929
- `CLAUDE_PROJECT_DIR` is the variable Claude Code injects into a project/user-scoped server's environment, and it resolves to the repo root. **You must launch `claude` from inside the repo** for this to work — the bare `.` fallback is only a last resort and is *not* reliable, because it resolves against the launching process's working directory, not the repo.
3064
+ These are developer commands, not prerequisites for the published package.
2930
3065
 
2931
- > **Why not `${CLAUDE_PLUGIN_ROOT}`?** `CLAUDE_PLUGIN_ROOT` is set **only** for marketplace plugin installs, never for a project-scope clone, so it can't drive the clone workflow. Conversely, a plugin install can't use `CLAUDE_PROJECT_DIR` (in a plugin, that points at the *user's* project, not the plugin's own directory). Claude Code does **not** support nested defaults like `${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR:-.}}`, so a single entrypoint string cannot serve both contexts. The two distribution paths are therefore decoupled: the **plugin** carries its own MCP config in `.claude-plugin/plugin.json` (using `${CLAUDE_PLUGIN_ROOT}`), while the root `.mcp.json` is dedicated to the **clone** workflow (using `${CLAUDE_PROJECT_DIR:-.}`). Because `plugin.json` declares its own `mcpServers`, the plugin does not also auto-load the root `.mcp.json`, so there is no double-registration.
3066
+ <a id="configuration"></a>
3067
+ <a id="configuration-file-when-the-host-strips-env"></a>
2932
3068
 
2933
- > **Heads-up on scope precedence:** project-scope (`.mcp.json`) outranks user-scope. If you *also* have an `apple-notes` entry registered at user scope (e.g. an absolute path in `~/.claude.json`), the project-scope entry wins and the user-scope one is ignored entirely. Pick one — for local development on this repo, the project-scope `.mcp.json` is the intended source. To pin a specific local build instead, register it at **local** scope (`claude mcp add apple-notes -s local -- node /abs/path/build/index.js`), which outranks project scope.
3069
+ ## Server settings
2934
3070
 
2935
- ---
3071
+ Use the client's server environment configuration for optional `APPLE_NOTES_MCP_*` settings. When a host does not propagate the values, the server can also read string values from `~/Library/Application Support/apple-notes-mcp/config.json`, or the path in `APPLE_NOTES_MCP_CONFIG_FILE`:
3072
+
3073
+ ```json
3074
+ {
3075
+ "APPLE_NOTES_MCP_TIMEOUT_MS": "60000"
3076
+ }
3077
+ ```
3078
+
3079
+ An explicit nonempty environment value takes precedence over the file. Restart the server after changing settings. Put only non-secret server settings in this file. A settings file can configure the server but cannot grant macOS permissions, import a Shortcut, or install a native helper.
2936
3080
 
2937
- ## Configuration
3081
+ For a brokered session, the client forwards only the broker's allowed numeric settings from this file. The brokered server skips JSON configuration files entirely; editing this file cannot enable helper paths or safety overrides in that server.
2938
3082
 
2939
3083
  ### Environment variables
2940
3084
 
2941
- All configuration is optional — the server works out of the box. Override behavior with these variables (set them in your MCP client's `env` block, or via the [config file](#configuration-file-when-the-host-strips-env) below). The opt-in [permission broker](#permission-broker-opt-in) accepts only a short, explicit allowlist of numeric limits and timeouts; code paths, helper paths, Shortcut overrides, and settings that relax safety checks do not carry over:
3085
+ These optional settings control server behavior. They do not replace the [macOS permissions and component setup](#setup-on-your-mac). Set them in the client environment or the [server settings file](#server-settings). The broker accepts only an explicit allowlist of numeric limits and timeouts; code paths, helper paths, Shortcut overrides, and settings that relax safety checks do not carry over.
2942
3086
 
2943
3087
  | Variable | Default | Description |
2944
3088
  |----------|---------|-------------|
2945
3089
  | `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. |
2946
3090
  | `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. |
2947
3091
  | `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. |
2948
- | `APPLE_NOTES_MCP_CONFIG_FILE` | `~/Library/Application Support/apple-notes-mcp/config.json` | Path to the JSON config file (see below). |
3092
+ | `APPLE_NOTES_MCP_CONFIG_FILE` | `~/Library/Application Support/apple-notes-mcp/config.json` | Path to the [JSON settings file](#server-settings). |
2949
3093
  | `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. |
2950
3094
  | `APPLE_NOTES_MCP_TEMPLATE_DIR` | `~/Library/Application Support/apple-notes-mcp/templates` | Absolute directory of the saved Markdown template library (`save-markdown-template` and friends). |
2951
3095
  | `APPLE_NOTES_MCP_ANCHOR_FILE` | `~/Library/Application Support/apple-notes-mcp/paragraph-anchors.json` | Absolute path of the [paragraph anchor](#paragraph-anchors) registry. |
@@ -2967,123 +3111,11 @@ All configuration is optional — the server works out of the box. Override beha
2967
3111
  | `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. |
2968
3112
  | `DEBUG` / `VERBOSE` | unset | Set either to enable verbose diagnostic logging to stderr. |
2969
3113
 
2970
- ### Configuration file (when the host strips `env`)
2971
-
2972
- Some host apps (e.g. Claude Desktop) launch the MCP server with a scrubbed
2973
- environment and ignore the `env` block in their server config, so there's no way
2974
- to pass `APPLE_NOTES_MCP_*` settings through it. In that case, put them in a JSON
2975
- file the host doesn't manage — `APPLE_NOTES_MCP_CONFIG_FILE`, or by default
2976
- `~/Library/Application Support/apple-notes-mcp/config.json`:
2977
-
2978
- ```json
2979
- {
2980
- "APPLE_NOTES_MCP_MAX_BUFFER": "134217728",
2981
- "DEBUG": "1"
2982
- }
2983
- ```
2984
-
2985
- The server reads it at startup and merges values into the environment **without
2986
- overriding** anything already set there (so an explicit `env` still wins). This
2987
- is the recommended way to configure the server under Claude Desktop. Apple Notes
2988
- MCP stores no secrets, but as a general rule keep only non-secret config here.
2989
-
2990
- For a brokered session, the client forwards only the broker's allowed numeric
2991
- settings from this file. The brokered server skips JSON configuration files
2992
- entirely; editing this file cannot enable helper paths or safety overrides in
2993
- that server.
2994
-
2995
- ---
2996
-
2997
- ## Full Disk Access
2998
-
2999
- 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`.
3000
-
3001
- > 📘 **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.
3002
-
3003
- ### How to Grant Full Disk Access
3004
-
3005
- 1. Open **System Settings** (or System Preferences on older macOS)
3006
- 2. Go to **Privacy & Security > Full Disk Access**
3007
- 3. Click the **+** button
3008
- 4. Add the entry that matches how the server runs:
3009
- - **Permission broker**: if you opted in with `setup --broker`, add `~/Applications/Apple Notes MCP Broker.app`. Read the [broker's trust trade-off](#permission-broker-opt-in) before enabling it.
3010
- - **Claude Desktop without the broker**: add the **Node binary** that runs the server (the `doctor` tool prints its path, e.g. `~/.nvm/versions/node/v24.11.1/bin/node`; press ⌘⇧G in the file picker to paste it). Claude Desktop launches MCP servers as their own responsible process, so a grant on `/Applications/Claude.app` alone does not reach them ([#220](https://github.com/sweetrb/apple-notes-mcp/issues/220)).
3011
- - **Terminal**: Add `/Applications/Utilities/Terminal.app`
3012
- - **VS Code**: Add `/Applications/Visual Studio Code.app`
3013
- - **iTerm**: Add `/Applications/iTerm.app`
3014
- 5. Fully quit (⌘Q) and relaunch the host app after granting access; if `doctor` still reports it missing, restart the Mac
3015
-
3016
- ### Without Full Disk Access
3017
-
3018
- 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:
3019
- - `get-checklist-state` returns an error explaining that database access is needed
3020
- - `query-notes` returns the same kind of error; use `search-notes` instead
3021
- - `delete-folder-by-id` refuses to delete anything (it fails closed)
3022
- - `get-note-metadata` returns the same kind of error — it has no non-database path
3023
- - `list-special-notes` and the `list-native-tags` inventory return the same kind of error
3024
- - `list-recent-notes` and `list-folder-tree` return the same kind of error
3025
- - `get-note-link` returns an error on macOS 26+; on macOS 12–15 it still works via the AppleScript `note link` fallback
3026
- - `get-note-markdown` returns plain list items without `[x]`/`[ ]` annotations (graceful fallback)
3027
- - `get-sync-status` still answers, but reports no pending uploads and no active sync — treat that as "unknown", not "idle"
3028
- - `get-note-drawings` and `transcribe-note-audio` return the same Full Disk Access error
3029
-
3030
- ---
3031
-
3032
- ## Permissions check
3033
-
3034
- `apple-notes-mcp setup --permissions` checks, in one report, the four grants that decide what the server can do on this Mac:
3035
-
3036
- | Item | How it is checked | Needed for |
3037
- |------|-------------------|------------|
3038
- | Full Disk Access | one read-only `SELECT 1` against `NoteStore.sqlite` | every database-backed tool (see [Full Disk Access](#full-disk-access)) |
3039
- | Automation of Notes.app | one read-only Apple event (the first account's name), sent only with `--probe-automation` | every AppleScript tool |
3040
- | Shortcut bridges (optional) | `shortcuts list`, like `setup --check` | the native-write tools |
3041
- | Speech Recognition (optional) | the public helper's `speech_status`, read without prompting | `transcribe-note-audio` before macOS 26 |
3042
-
3043
- ```bash
3044
- apple-notes-mcp setup --permissions # report, then press Enter to check again
3045
- apple-notes-mcp setup --permissions --open # also open the System Settings pane of each missing grant
3046
- apple-notes-mcp setup --permissions --once # report once and exit (also --json)
3047
- apple-notes-mcp setup --permissions --probe-automation # also check Automation (sends one Apple event)
3048
- ```
3049
-
3050
- For each missing grant the report names the System Settings pane and its URL, for example `x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Privacy_AllFiles` (the `com.apple.preference.security` form before macOS 13). Panes open only with `--open`, each once per run. The command never changes a setting or a grant: you make the change in System Settings, then press Enter to check again. Type `q` to stop. It exits 1 when a required grant is missing or could not be verified, and 0 otherwise, so a run that did not probe Automation exits 0 if Full Disk Access is granted.
3051
-
3052
- Automation is the one item that cannot be read without talking to Notes.app, so it is opt-in. By default the command sends no Apple event, and the Automation line reads `unknown` (not probed) with the command that checks it. Add `--probe-automation` to send one read-only event; the first time, macOS may ask whether the app may control Notes, and **Allow** is the only way to add an Automation grant. The probe never runs under `--check` (which reports state only) or when `SSH_CONNECTION` is set, because nobody at the remote shell can answer the prompt. In those cases the line reads `unknown` even if `--probe-automation` was passed. An unprobed Automation line does not change the exit code and the report says Automation was not checked, so run the probe from a terminal on the Mac itself when you need to know. A probe that runs and fails (denied, or no answer) does exit 1.
3053
-
3054
- macOS attributes these grants to the app that launched the process, so the report names it (for example `/Applications/iTerm.app`). Run the check from the app you use as the MCP host when you can. Under Claude Desktop, use the `doctor` tool inside the client: for a brokered session, grant Full Disk Access to `~/Applications/Apple Notes MCP Broker.app`; otherwise add the Node binary it names. The Speech item reads `unknown` until the [public native helper](#public-native-helper) is built.
3055
-
3056
- ### Optional checklist window
3057
-
3058
- The same checklist is also available in a small window with **Open Settings** and **Re-check** buttons. Like the public helper, it is built on your Mac from the packaged Swift source, never shipped as a binary:
3059
-
3060
- ```bash
3061
- apple-notes-mcp setup --permissions-window # compile, ad-hoc sign, verify, install
3062
- apple-notes-mcp setup --permissions-window --check # report the installed state only
3063
- apple-notes-mcp setup --permissions --window # open the window
3064
- apple-notes-mcp setup --permissions --window --probe-automation # the window's checks include Automation
3065
- ```
3066
-
3067
- Setup compiles `native/permissions-window/apple-notes-permissions-window.swift`, signs it ad hoc, runs its `hello` handshake (which shows no window), and installs it in `~/Library/Application Support/apple-notes-mcp/permissions-window/` with a manifest of source and binary SHA-256 digests; `APPLE_NOTES_MCP_PERMISSIONS_WINDOW_DIR` overrides the folder. The window probes nothing itself. The command runs every check and sends the results to it, and opens a pane only for an item it reported. The window shows an unprobed Automation item as "Not checked", with the command that checks it, and gives it no Open Settings button. If the window is not built, is stale after an upgrade, or was modified, `--window` says so and shows the checklist in the terminal instead. The server never uses the window.
3068
-
3069
- ---
3070
-
3071
- ## Public native helper
3072
-
3073
- `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.
3074
-
3075
- If you installed the [permission broker](#permission-broker-opt-in), set `APPLE_NOTES_MCP_BROKER=off` for this client to use these tools. Broker sessions do not load external native helpers.
3076
-
3077
- Build it once on your Mac:
3078
-
3079
- ```bash
3080
- apple-notes-mcp setup --public-helper # compile, sign, verify, install
3081
- apple-notes-mcp setup --public-helper --check # report the installed state only
3082
- ```
3114
+ ## Separate direct CLI setup
3083
3115
 
3084
- 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.
3116
+ NotesCTL is a separate direct CLI, not a dependency installed or launched by Apple Notes MCP. Its direct CLI requires Python 3.13 or newer; its installed signed Capability Host has its own protected runtime, signing, protocol, and macOS permission setup. If you separately use that tool, follow the documentation accompanying your authorized distribution. Its private/deep-write capabilities and permissions do not automatically become MCP tools or transfer to this server.
3085
3117
 
3086
- 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.
3118
+ The [Apple Notes MCP permission broker](#permission-broker-opt-in) is a separate optional component of this server. Its setup and grants do not install or validate the direct CLI's Capability Host, and a successful Capability Host check does not establish that the MCP client is ready.
3087
3119
 
3088
3120
  ---
3089
3121
 
@@ -3172,7 +3204,7 @@ paragraph or note.
3172
3204
 
3173
3205
  ## Security and Privacy
3174
3206
 
3175
- - **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.
3207
+ - **Local Notes operations** - AppleScript, the packaged Shortcuts, read-only database access, and helpers run on your Mac. `transcribe-note-audio` uses on-device speech recognition; `downloadAssets: true` explicitly permits downloading missing speech models. Whatever your MCP client does with tool results is governed by that client.
3176
3208
  - **Permission required** - macOS will prompt for automation permission on first use.
3177
3209
  - **Optional broker trusts all same-user processes** - With the [permission broker](#permission-broker-opt-in) running, every process under your macOS user can use its Notes capabilities with the broker's Full Disk Access and Notes Automation grants. The socket checks exclude other users, but do not authenticate same-user apps. This is comparable trust exposure to granting Full Disk Access to Node. `APPLE_NOTES_MCP_BROKER=off` bypasses it for one client; `apple-notes-mcp setup --broker --uninstall` stops and removes the shared service.
3178
3210
  - **Broker checks have limits** - Signature and hash checks detect tampering present before spawn; they do not isolate the user-writable bundle and runtime from a hostile, unsandboxed same-user process modifying them after validation. Installed Shortcuts are user-managed trusted integrations whose contents the broker does not authenticate.
@@ -3261,7 +3293,7 @@ In a JSON string literal the two characters `\\` denote **one** literal backslas
3261
3293
  - macOS needs automation permission
3262
3294
  - Go to System Settings > Privacy & Security > Automation
3263
3295
  - Ensure your terminal/Claude has permission to control Notes
3264
- - `apple-notes-mcp setup --permissions --open --probe-automation` checks every grant and opens the pane of each missing one ([Permissions check](#permissions-check))
3296
+ - Follow the [permissions check](#permissions-check) from the client that launches the server; an Automation probe can prompt, and a terminal result does not establish another client's grants.
3265
3297
 
3266
3298
  ### Native writes time out or report an uncertain outcome
3267
3299
  - Symptom: `add-native-tags`, `set-note-pinned`, `append-native` or another native write fails with "Shortcuts timed out waiting for …", "Operation outcome uncertain" or "readback was not verified", while `doctor` and `get-capabilities` report the bridges installed
@@ -3282,7 +3314,7 @@ In a JSON string literal the two characters `\\` denote **one** literal backslas
3282
3314
  ### Notes accumulate blank lines after repeated updates
3283
3315
  - Repeatedly updating a note (especially with HTML content) can accumulate whitespace artifacts — `<div><br></div>` tags that persist between sections even after you remove them from your content
3284
3316
  - Apple Notes' internal HTML processing preserves empty divs from previous edits, so the gaps are baked into the note's internal representation and cannot be fixed through further updates
3285
- - Fix: delete the note with `delete-note` and create a fresh one with `create-note`
3317
+ - Keep the original note. Inspect its native objects and stored content before choosing a repair; plain text cannot establish that rich content is preserved. For notes that cannot safely be rewritten, edit the spacing in Notes.app. Create a separate replacement only when the user wants one, verify it, and obtain explicit deletion intent before retiring the original.
3286
3318
 
3287
3319
  ### Every tool is refused: "invalid outputSchema … unsupported dialect"
3288
3320
 
@@ -3314,7 +3346,7 @@ library, permissions, or configuration is involved.
3314
3346
 
3315
3347
  ## Development
3316
3348
 
3317
- Development uses [pnpm](https://pnpm.io/) (see `packageManager` in `package.json`):
3349
+ Development uses [pnpm](https://pnpm.io/) (see `packageManager` in `package.json`). Complete the [source checkout prerequisites](#source-checkout), including Corepack, first:
3318
3350
 
3319
3351
  ```bash
3320
3352
  pnpm install # Install dependencies