apple-notes-mcp 2.14.2 → 2.15.0
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 +67 -8
- package/build/index.js +1494 -298
- package/docs/FULL-DISK-ACCESS.md +62 -12
- package/docs/NODE-RUNTIME-AND-TCC-PERMISSIONS.md +101 -31
- package/native/broker/apple-notes-mcp-broker.swift +820 -0
- package/package.json +2 -1
package/docs/FULL-DISK-ACCESS.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Full Disk Access
|
|
2
2
|
|
|
3
3
|
Apple Notes MCP works almost entirely without any special disk permission. The
|
|
4
|
-
tools that need **Full Disk Access (FDA)** for the process
|
|
5
|
-
server are the ones that read Notes' own SQLite store:
|
|
4
|
+
tools that need **Full Disk Access (FDA)** for the process responsible for the MCP
|
|
5
|
+
server are the ones that read Notes' own SQLite store. Examples include:
|
|
6
6
|
|
|
7
7
|
- **`get-checklist-state`** — reads a note's checklist done/undone state.
|
|
8
8
|
- **Checklist annotations in `get-note-markdown`** — the `[x]` / `[ ]` prefixes on
|
|
@@ -17,9 +17,9 @@ server are the ones that read Notes' own SQLite store:
|
|
|
17
17
|
- **`get-sync-status`** — degrades rather than fails: without database access it
|
|
18
18
|
cannot see pending uploads or recent write activity.
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
The AppleScript tools (creating, reading, searching, updating, moving, and
|
|
21
|
+
deleting notes, for example) work **without** Full Disk Access. See the
|
|
22
|
+
[full tool list](../README.md#full-disk-access) for all database-backed features.
|
|
23
23
|
|
|
24
24
|
## Why it's needed
|
|
25
25
|
|
|
@@ -46,7 +46,10 @@ ever **reads** this database; it never writes to it.)
|
|
|
46
46
|
2. Go to **Privacy & Security → Full Disk Access**.
|
|
47
47
|
3. Click the **+** button (you may need to unlock with Touch ID / your password
|
|
48
48
|
first) and add the right entry for how you run the server:
|
|
49
|
-
- **
|
|
49
|
+
- **Permission broker** → `~/Applications/Apple Notes MCP Broker.app`, if you
|
|
50
|
+
opted in with `apple-notes-mcp setup --broker`. Read the
|
|
51
|
+
[trust trade-off below](#optional-permission-broker) before enabling it.
|
|
52
|
+
- **Claude Desktop without the broker** → the **Node binary** that runs the server, e.g.
|
|
50
53
|
`/usr/local/bin/node` or `~/.nvm/versions/node/v24.11.1/bin/node`. The
|
|
51
54
|
`doctor` tool prints the exact path. In the file picker, press **⌘⇧G** and
|
|
52
55
|
paste it (use **⌘⇧.** to show hidden folders such as `~/.nvm`). Adding
|
|
@@ -61,7 +64,7 @@ ever **reads** this database; it never writes to it.)
|
|
|
61
64
|
enough; quit the host application itself (⌘Q) and relaunch it. If `doctor`
|
|
62
65
|
still reports Full Disk Access as not granted after that, restart the Mac.
|
|
63
66
|
|
|
64
|
-
> **Why Claude Desktop needs the Node binary
|
|
67
|
+
> **Why Claude Desktop needs the Node binary without the broker.** macOS checks Full Disk
|
|
65
68
|
> Access against the *responsible process*, the app it holds accountable for a
|
|
66
69
|
> request. A terminal passes that role on to everything it launches, so a grant
|
|
67
70
|
> on Terminal or iTerm covers the server. Claude Desktop does not: it starts each
|
|
@@ -83,15 +86,61 @@ ever **reads** this database; it never writes to it.)
|
|
|
83
86
|
> }
|
|
84
87
|
> ```
|
|
85
88
|
>
|
|
86
|
-
> A Developer-ID-signed Node
|
|
87
|
-
>
|
|
89
|
+
> A Developer-ID-signed Node at a stable path avoids the identity changes of
|
|
90
|
+
> ad-hoc rebuilds. Permission continuity still depends on its designated code
|
|
91
|
+
> requirement and macOS permission state. See
|
|
88
92
|
> [Node runtime and TCC permissions](NODE-RUNTIME-AND-TCC-PERMISSIONS.md).
|
|
89
93
|
|
|
94
|
+
## Optional permission broker
|
|
95
|
+
|
|
96
|
+
`apple-notes-mcp setup --broker` installs a signed app at
|
|
97
|
+
`~/Applications/Apple Notes MCP Broker.app`. Grant Full Disk Access to that app
|
|
98
|
+
and allow it to control Notes when macOS asks. Brokered sessions use its grants
|
|
99
|
+
instead of those of the Node binary or MCP host that launched the client.
|
|
100
|
+
Setup requires a standalone Node runtime linked only to system libraries; see
|
|
101
|
+
the [runtime setup guide](NODE-RUNTIME-AND-TCC-PERMISSIONS.md).
|
|
102
|
+
|
|
103
|
+
**This trusts every process running as your macOS user.** While the broker is
|
|
104
|
+
running, any such process can connect and use the server's Notes capabilities
|
|
105
|
+
under the broker's Full Disk Access and Notes Automation grants. The socket's
|
|
106
|
+
permissions and same-UID check exclude other users; they do not authenticate
|
|
107
|
+
apps running as you. That is comparable trust exposure to granting Full Disk
|
|
108
|
+
Access to Node. Use the broker only if you accept this trade-off.
|
|
109
|
+
|
|
110
|
+
The broker runs a server sealed inside its signed app, verifies the bundle and
|
|
111
|
+
the pinned Node executable before spawning, and accepts only a short allowlist
|
|
112
|
+
of numeric limits and timeouts from clients. Code paths, helper paths, and
|
|
113
|
+
safety overrides cannot be selected through a socket request, and brokered
|
|
114
|
+
servers skip local JSON configuration files. External native
|
|
115
|
+
helpers are unavailable in broker sessions; tools that require them need an
|
|
116
|
+
in-process server. See [Permission broker](../README.md#permission-broker-opt-in)
|
|
117
|
+
for the security design and signing caveats.
|
|
118
|
+
|
|
119
|
+
The signature and hash checks reject changes detected at startup or before
|
|
120
|
+
spawn. They do not provide OS isolation against a hostile, unsandboxed
|
|
121
|
+
same-user process modifying the user-writable bundle or runtime after
|
|
122
|
+
validation. Installed Shortcuts are user-managed trusted integrations; the
|
|
123
|
+
broker does not authenticate their contents.
|
|
124
|
+
|
|
125
|
+
After updating the package or replacing the broker's Node runtime, run
|
|
126
|
+
`apple-notes-mcp setup --broker` again, restart your MCP clients, and check
|
|
127
|
+
`doctor`. Rebuilding with an ad-hoc signature or changing the signing identity
|
|
128
|
+
may require new macOS grants.
|
|
129
|
+
|
|
130
|
+
To bypass the broker for one client, set `APPLE_NOTES_MCP_BROKER=off` in that
|
|
131
|
+
client's environment. This does **not** stop the broker or prevent other
|
|
132
|
+
same-user processes from using it. To remove that access, run
|
|
133
|
+
`apple-notes-mcp setup --broker --uninstall`, then restart your clients. You can
|
|
134
|
+
also revoke the broker's Full Disk Access and Notes Automation grants in System
|
|
135
|
+
Settings.
|
|
136
|
+
|
|
90
137
|
## Verifying it worked
|
|
91
138
|
|
|
92
139
|
Run the **`doctor`** tool. It reports a dedicated **Full Disk Access** check as
|
|
93
140
|
`ok` / `warn` / `fail` with the reason, so you can confirm the grant took effect
|
|
94
|
-
without guessing.
|
|
141
|
+
without guessing. Its `broker` field identifies whether the session uses the
|
|
142
|
+
broker or has fallen back to an in-process server with its own permissions.
|
|
143
|
+
You can also just call `get-checklist-state` on a note that has
|
|
95
144
|
a checklist — if it returns items with `[x]`/`[ ]` state, FDA is working.
|
|
96
145
|
|
|
97
146
|
## Without Full Disk Access
|
|
@@ -108,8 +157,9 @@ The server degrades gracefully — nothing crashes:
|
|
|
108
157
|
appear as plain list items without the `[x]`/`[ ]` annotations.
|
|
109
158
|
- `get-sync-status` still answers, but with no database visibility it reports no
|
|
110
159
|
pending uploads and no active sync — treat that as "unknown", not "idle".
|
|
111
|
-
- **
|
|
112
|
-
|
|
160
|
+
- **AppleScript-only tools work normally.** See the
|
|
161
|
+
[full tool list](../README.md#full-disk-access) for other database-backed tools
|
|
162
|
+
that require FDA.
|
|
113
163
|
|
|
114
164
|
See also: [Known Limitations](../README.md#known-limitations) and
|
|
115
165
|
[Creating Checklists](../README.md#creating-checklists) in the README.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Node runtime & TCC permission stability
|
|
2
2
|
|
|
3
3
|
macOS gates this MCP server's access to your data behind **TCC** permissions —
|
|
4
|
-
**Full Disk Access** (to read
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
**Full Disk Access** (to read the Notes database) and **Automation / Apple
|
|
5
|
+
Events** (to drive Notes.app via AppleScript). See the
|
|
6
|
+
[Full Disk Access guide](FULL-DISK-ACCESS.md) for which operations need which
|
|
7
|
+
permission.
|
|
8
8
|
|
|
9
9
|
This page is about a **separate, recurring annoyance**: being asked to approve
|
|
10
10
|
those permissions **over and over**, often right after a routine `brew upgrade`.
|
|
@@ -13,19 +13,24 @@ those permissions **over and over**, often right after a routine `brew upgrade`.
|
|
|
13
13
|
|
|
14
14
|
- You granted Full Disk Access (and/or Automation) to "node", but days later
|
|
15
15
|
macOS prompts again — `"node" wants access to ...` or `"node" wants to control
|
|
16
|
-
"
|
|
16
|
+
"Notes"`.
|
|
17
17
|
- System Settings → Privacy & Security → Full Disk Access shows **several
|
|
18
18
|
identical "node" rows**, usually only one enabled.
|
|
19
19
|
- It tends to happen immediately after you update Node.
|
|
20
20
|
|
|
21
21
|
## Cause
|
|
22
22
|
|
|
23
|
-
TCC
|
|
24
|
-
the
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
TCC checks the **responsible process** for an access. Under Claude Desktop
|
|
24
|
+
without the broker, that is the `node` executable running the server; under a
|
|
25
|
+
terminal host it can be the terminal app. With the broker, it is
|
|
26
|
+
`~/Applications/Apple Notes MCP Broker.app`.
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
An **ad-hoc-signed** binary has no certificate-backed signing identity. Its
|
|
29
|
+
**cdhash** changes when its code changes, so a grant to one build may not apply
|
|
30
|
+
after an update. Moving the executable, including changing the resolved path
|
|
31
|
+
behind a version-manager symlink, can also require a new grant.
|
|
32
|
+
|
|
33
|
+
Check the Node binary you actually use. An ad-hoc signature looks like this:
|
|
29
34
|
|
|
30
35
|
```bash
|
|
31
36
|
$ codesign -dvvv "$(which node)" 2>&1 | grep -E 'Signature|TeamIdentifier'
|
|
@@ -33,21 +38,86 @@ Signature=adhoc
|
|
|
33
38
|
TeamIdentifier=not set
|
|
34
39
|
```
|
|
35
40
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
The `doctor` tool reports the runtime path and warns about ad-hoc signing.
|
|
42
|
+
Duplicate "node" rows in System Settings can be entries for previous binaries.
|
|
43
|
+
|
|
44
|
+
Certificate-signed code has a **designated requirement** that can identify it
|
|
45
|
+
across builds. Apple's documented Apple Development requirement includes the
|
|
46
|
+
leaf certificate's Common Name, while its Developer ID example uses certificate
|
|
47
|
+
type and Team ID constraints. A matching bundle identifier and Team ID alone
|
|
48
|
+
are therefore not a promise of permission continuity. See Apple's
|
|
49
|
+
[TN3127: Inside Code Signing: Requirements](https://developer.apple.com/documentation/technotes/tn3127-inside-code-signing-requirements).
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
across auto-updates because TCC matches them on a stable **Designated
|
|
42
|
-
Requirement** derived from their Developer ID, not on the cdhash.
|
|
51
|
+
## Option 1: opt in to the permission broker
|
|
43
52
|
|
|
44
|
-
|
|
53
|
+
The broker puts the grants on a signed app at a fixed path and runs a bundled
|
|
54
|
+
copy of the MCP server for connected clients. Run setup using a standalone Node
|
|
55
|
+
runtime whose dynamic library dependencies are all under `/usr/lib/` or
|
|
56
|
+
`/System/Library/`. Other dependencies, including the non-system libraries used
|
|
57
|
+
by common Homebrew Node builds, are rejected: pinning the Node executable alone
|
|
58
|
+
would not protect those libraries. The download steps under Option 2 below show
|
|
59
|
+
how to install an official Node runtime at a fixed path.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
apple-notes-mcp setup --broker
|
|
63
|
+
apple-notes-mcp setup --broker --check
|
|
64
|
+
# Or explicitly select your standalone runtime for setup:
|
|
65
|
+
/path/to/node /path/to/apple-notes-mcp/build/index.js setup --broker
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Add `~/Applications/Apple Notes MCP Broker.app` in **System Settings → Privacy
|
|
69
|
+
& Security → Full Disk Access**, and allow it to control Notes when prompted.
|
|
70
|
+
Restart your MCP client and run `doctor` to confirm that it is using the broker.
|
|
71
|
+
|
|
72
|
+
**Review the trust trade-off before installing:** every process running as your
|
|
73
|
+
macOS user can use the broker's Notes capabilities under its Full Disk Access
|
|
74
|
+
and Notes Automation grants. The socket's same-UID check excludes other users,
|
|
75
|
+
but does not authenticate same-user apps. This is comparable trust exposure to
|
|
76
|
+
granting Full Disk Access to a general-purpose Node binary. Socket requests
|
|
77
|
+
cannot select executable paths or safety overrides; this does not identify a
|
|
78
|
+
trusted MCP client. Brokered servers skip local JSON configuration files, and
|
|
79
|
+
external native helpers are unavailable in broker sessions.
|
|
80
|
+
See the [broker security design](../README.md#permission-broker-opt-in).
|
|
81
|
+
|
|
82
|
+
The signature and hash checks reject modifications detected at startup or
|
|
83
|
+
before spawn. They do not make later filesystem reads atomic or provide OS
|
|
84
|
+
isolation against a hostile, unsandboxed same-user process modifying the
|
|
85
|
+
user-writable bundle or runtime after validation. Installed Shortcuts remain
|
|
86
|
+
user-managed trusted integrations; the broker does not authenticate their
|
|
87
|
+
contents.
|
|
88
|
+
|
|
89
|
+
Setup automatically selects an identity only when exactly one Developer ID
|
|
90
|
+
Application or Apple Development identity qualifies. If more than one qualifies
|
|
91
|
+
across those types, specify `--sign-identity`. If none qualify, it signs ad hoc
|
|
92
|
+
and warns about re-granting permissions.
|
|
93
|
+
Keeping a compatible designated requirement can help preserve grants across
|
|
94
|
+
rebuilds, but **Apple Development signing is not a guarantee of continuity across
|
|
95
|
+
certificate renewal or signing identity changes**. Ad-hoc rebuilds may require
|
|
96
|
+
new grants. Always check `doctor` after reinstalling.
|
|
97
|
+
|
|
98
|
+
The signed configuration pins the Node executable's canonical path and digest.
|
|
99
|
+
After a package update, or after replacing or moving that runtime, run
|
|
100
|
+
`apple-notes-mcp setup --broker` again to refresh the bundled server and pin,
|
|
101
|
+
then restart your clients. A stale or unavailable broker causes clients to run
|
|
102
|
+
in-process with their own permissions; `doctor` reports that fallback.
|
|
103
|
+
|
|
104
|
+
Set `APPLE_NOTES_MCP_BROKER=off` to bypass it for one client. The broker continues
|
|
105
|
+
running and remains reachable by other same-user processes. To remove that
|
|
106
|
+
access, run `apple-notes-mcp setup --broker --uninstall` and restart your clients;
|
|
107
|
+
you can also revoke the broker's grants in System Settings.
|
|
108
|
+
|
|
109
|
+
## Option 2: run in-process under Developer-ID-signed Node
|
|
45
110
|
|
|
46
111
|
Node binaries distributed from **nodejs.org** are signed with a real Developer
|
|
47
112
|
ID (`Node.js Foundation`, Team `HX7739G8FX`), notarized, and self-contained.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
113
|
+
Keeping the executable at a stable path avoids the path changes of version
|
|
114
|
+
managers and the code-identity changes of ad-hoc rebuilds. Permission continuity
|
|
115
|
+
still depends on the designated requirement and macOS permission state. This
|
|
116
|
+
also decouples the MCP runtime from your Homebrew/dev Node.
|
|
117
|
+
|
|
118
|
+
If you installed the broker, set `APPLE_NOTES_MCP_BROKER=off` in this client's
|
|
119
|
+
environment or uninstall it before using this option. Otherwise the client
|
|
120
|
+
will hand off to the broker when it is available.
|
|
51
121
|
|
|
52
122
|
### Steps (Apple Silicon shown; use `darwin-x64` on Intel)
|
|
53
123
|
|
|
@@ -92,19 +162,18 @@ the MCP runtime from your Homebrew/dev Node, which can keep updating freely.
|
|
|
92
162
|
|
|
93
163
|
4. **Restart your MCP client** so the server relaunches under the new Node.
|
|
94
164
|
|
|
95
|
-
5. **Grant the permissions
|
|
165
|
+
5. **Grant the permissions** to the new binary:
|
|
96
166
|
- *Full Disk Access*: System Settings → Privacy & Security → Full Disk Access
|
|
97
167
|
→ **+** → ⌘⇧G → paste `~/mcp-runtime/node-current/bin/node`.
|
|
98
|
-
- *Automation*: the first time the server drives an app you'll get a
|
|
168
|
+
- *Automation*: the first time the server drives an app you'll get a
|
|
99
169
|
`"node" wants to control "<App>"` prompt — click **Allow**.
|
|
100
170
|
|
|
101
171
|
⚠️ **A TCC grant is keyed to the binary's resolved *path*, not only to its
|
|
102
172
|
signature.** Because the steps above unpack Node into a fixed directory
|
|
103
173
|
(`~/mcp-runtime/node-current`) rather than a versioned one, that path never
|
|
104
|
-
moves
|
|
174
|
+
moves — see "Updating" below. If you
|
|
105
175
|
instead point `node-current` at a `node-vX.Y.Z-…` directory, every update
|
|
106
|
-
changes the resolved path
|
|
107
|
-
will be re-prompted for all of it.
|
|
176
|
+
changes the resolved path and may require you to grant permissions again.
|
|
108
177
|
|
|
109
178
|
You can delete any stale "node" rows from the Full Disk Access list.
|
|
110
179
|
|
|
@@ -123,11 +192,12 @@ rm -rf node-current && mkdir -p node-current
|
|
|
123
192
|
tar -xzf node-$VER-$ARCH.tar.gz --strip-components=1 -C node-current
|
|
124
193
|
```
|
|
125
194
|
|
|
126
|
-
The path
|
|
127
|
-
|
|
128
|
-
|
|
195
|
+
The path stays unchanged. Check the replacement binary's signature as above,
|
|
196
|
+
then run `doctor` in your MCP client to verify that macOS retained its grants.
|
|
197
|
+
Do not assume a new signing identity or a changed designated requirement will
|
|
198
|
+
match an earlier grant.
|
|
129
199
|
|
|
130
200
|
⚠️ **Restart your MCP client afterwards.** Replacing the binary unlinks the one
|
|
131
|
-
any already-running server is executing;
|
|
132
|
-
|
|
133
|
-
|
|
201
|
+
any already-running server is executing; those processes can fail with
|
|
202
|
+
*"Permission denied"* until restarted. Recheck permissions from a fresh session
|
|
203
|
+
before changing grants.
|