apple-notes-mcp 2.8.46 → 2.8.48

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
@@ -56,7 +56,7 @@ Install as a Claude Code plugin for automatic configuration and enhanced AI beha
56
56
 
57
57
  This method also installs a **skill** that teaches Claude when and how to use Apple Notes effectively.
58
58
 
59
- On the first tool call, macOS shows an Automation permission prompt ("Claude" wants access to control "Notes") — click **OK**. Optionally, grant **Full Disk Access** to the app that launches the server to enable the database-backed tools (`get-checklist-state`, `get-note-metadata`, `get-audio-transcripts`, `list-special-notes`, `list-native-tags`, `get-note-link`, checklist annotations in `get-note-markdown`, and full `get-sync-status` detail); see the [Full Disk Access Setup Guide](https://github.com/sweetrb/apple-notes-mcp/blob/main/docs/FULL-DISK-ACCESS.md). The rest of the server is pure AppleScript and works without it.
59
+ On the first tool call, macOS shows an Automation permission prompt ("Claude" wants access to control "Notes") — click **OK**. Optionally, grant **Full Disk Access** (under Claude Desktop, to the Node binary that runs the server; from a terminal, to the terminal app) to enable the database-backed tools (`get-checklist-state`, `get-note-metadata`, `get-audio-transcripts`, `list-special-notes`, `list-native-tags`, `get-note-link`, checklist annotations in `get-note-markdown`, and full `get-sync-status` detail); see the [Full Disk Access Setup Guide](https://github.com/sweetrb/apple-notes-mcp/blob/main/docs/FULL-DISK-ACCESS.md). The rest of the server is pure AppleScript and works without it.
60
60
 
61
61
  Native tag, checklist, table, pin, and rich append operations use two packaged
62
62
  Apple Shortcuts. A third, `Apple Notes MCP - Create Markdown Note`, is optional:
@@ -1035,7 +1035,7 @@ Returns the `notes://showNote?identifier=<uuid>` deep-link URL for a note. The U
1035
1035
 
1036
1036
  **Returns:** `notes://showNote?identifier=<uuid>` URL string, plus the note id and title.
1037
1037
 
1038
- **Note:** Requires Full Disk Access for the app that launches the server so the Notes SQLite database is readable. On macOS 12–15 the tool also falls back to the AppleScript `note link` property. Run the `doctor` tool to verify access.
1038
+ **Note:** Requires Full Disk Access for the process that runs the server so the Notes SQLite database is readable. On macOS 12–15 the tool also falls back to the AppleScript `note link` property. Run the `doctor` tool to verify access.
1039
1039
 
1040
1040
  ---
1041
1041
 
@@ -2127,12 +2127,12 @@ Several tools read directly from the Apple Notes SQLite database, which lives in
2127
2127
  1. Open **System Settings** (or System Preferences on older macOS)
2128
2128
  2. Go to **Privacy & Security > Full Disk Access**
2129
2129
  3. Click the **+** button
2130
- 4. Add the application that hosts the MCP server:
2131
- - **Claude Desktop**: Add `/Applications/Claude.app`
2130
+ 4. Add the entry that matches how the server runs:
2131
+ - **Claude Desktop**: 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)).
2132
2132
  - **Terminal**: Add `/Applications/Utilities/Terminal.app`
2133
2133
  - **VS Code**: Add `/Applications/Visual Studio Code.app`
2134
2134
  - **iTerm**: Add `/Applications/iTerm.app`
2135
- 5. Restart the application after granting access
2135
+ 5. Fully quit (⌘Q) and relaunch the host app after granting access; if `doctor` still reports it missing, restart the Mac
2136
2136
 
2137
2137
  ### Without Full Disk Access
2138
2138
 
package/build/index.js CHANGED
@@ -39536,7 +39536,7 @@ function getChecklistItems(noteId3) {
39536
39536
  return {
39537
39537
  items: null,
39538
39538
  error: "no_fda",
39539
- message: `Full Disk Access is required to read checklist state. In System Settings > Privacy & Security > Full Disk Access, grant access to the app that launches this server (Claude Desktop / Terminal / iTerm2), then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`
39539
+ message: `Full Disk Access is required to read checklist state. In System Settings > Privacy & Security > Full Disk Access, grant access to the Node binary running this server (required under Claude Desktop) or the terminal that launches it, then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`
39540
39540
  };
39541
39541
  }
39542
39542
  if (!hexData) {
@@ -40199,7 +40199,7 @@ function readAudioTranscripts(noteId3, options = {}) {
40199
40199
  if (/authorization denied|unable to open database/i.test(message))
40200
40200
  throw new AudioTranscriptError(
40201
40201
  "no_fda",
40202
- `Full Disk Access is required to read stored transcripts. Grant it to the app that launches this server, then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL}`
40202
+ `Full Disk Access is required to read stored transcripts. Grant it to the Node binary running this server (or the terminal that launches it), then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL}`
40203
40203
  );
40204
40204
  throw new AudioTranscriptError("query_error", "Failed to read the Notes database.");
40205
40205
  }
@@ -40516,7 +40516,7 @@ var NOTES_DB_PATH3 = path2.join(
40516
40516
  os2.homedir(),
40517
40517
  "Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
40518
40518
  );
40519
- var FDA_MESSAGE = `Full Disk Access is required to read smart folders. In System Settings > Privacy & Security > Full Disk Access, grant access to the app that launches this server (Claude Desktop / Terminal / iTerm2), then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`;
40519
+ var FDA_MESSAGE = `Full Disk Access is required to read smart folders. In System Settings > Privacy & Security > Full Disk Access, grant access to the Node binary running this server (required under Claude Desktop) or the terminal that launches it, then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`;
40520
40520
  var COCOA_EPOCH_OFFSET = 978307200;
40521
40521
  var MAX_DEPTH = 32;
40522
40522
  var RELATIVE_RANGES = {
@@ -41275,7 +41275,7 @@ function runSqlite3(dbPath2, sql) {
41275
41275
  const message = error2 instanceof Error ? error2.message : String(error2);
41276
41276
  if (/authorization denied|unable to open database/i.test(message)) {
41277
41277
  throw new AttachmentStoreError(
41278
- "Full Disk Access is required to read attachment paths. Grant it to the app that launches this server, then relaunch it (run the doctor tool to verify).",
41278
+ "Full Disk Access is required to read attachment paths. Grant it to the Node binary running this server (or the terminal that launches it), then relaunch it (run the doctor tool to verify).",
41279
41279
  "no_fda"
41280
41280
  );
41281
41281
  }
@@ -41809,7 +41809,7 @@ function runSqlite4(dbPath2, sql) {
41809
41809
  const message = error2 instanceof Error ? error2.message : String(error2);
41810
41810
  if (/authorization denied|unable to open database/i.test(message)) {
41811
41811
  throw new AttachmentStoreError(
41812
- "Full Disk Access is required to read drawing attachments. Grant it to the app that launches this server, then relaunch it (run the doctor tool to verify).",
41812
+ "Full Disk Access is required to read drawing attachments. Grant it to the Node binary running this server (or the terminal that launches it), then relaunch it (run the doctor tool to verify).",
41813
41813
  "no_fda"
41814
41814
  );
41815
41815
  }
@@ -43036,7 +43036,10 @@ var AppleNotesManager = class {
43036
43036
  set originalFolder to container of noteRef
43037
43037
  end try
43038
43038
  if originalFolder is not missing value then
43039
- set __inTrash to false
43039
+ set __inTrash to true
43040
+ try
43041
+ if (class of originalFolder) is folder then set __inTrash to false
43042
+ end try
43040
43043
  try
43041
43044
  if ${trashFolderIdList()} contains (id of originalFolder) then set __inTrash to true
43042
43045
  end try
@@ -45180,7 +45183,7 @@ var NOTES_DB_PATH6 = path5.join(
45180
45183
  os5.homedir(),
45181
45184
  "Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
45182
45185
  );
45183
- var FDA_MESSAGE2 = `Full Disk Access is required to read note metadata. In System Settings > Privacy & Security > Full Disk Access, grant access to the app that launches this server (Claude Desktop / Terminal / iTerm2), then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`;
45186
+ var FDA_MESSAGE2 = `Full Disk Access is required to read note metadata. In System Settings > Privacy & Security > Full Disk Access, grant access to the Node binary running this server (required under Claude Desktop) or the terminal that launches it, then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`;
45184
45187
  var COLUMN_MAP = [
45185
45188
  { key: "pinned", column: "ZISPINNED", type: "bool" },
45186
45189
  { key: "hasChecklist", column: "ZHASCHECKLIST", type: "bool" },
@@ -45273,7 +45276,7 @@ var NOTES_DB_PATH7 = path6.join(
45273
45276
  "Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
45274
45277
  );
45275
45278
  var CORE_DATA_EPOCH_MS = Date.UTC(2001, 0, 1);
45276
- var STORE_FDA_MESSAGE = `Full Disk Access is required to read the Notes database. In System Settings > Privacy & Security > Full Disk Access, grant access to the app that launches this server (Claude Desktop / Terminal / iTerm2), then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`;
45279
+ var STORE_FDA_MESSAGE = `Full Disk Access is required to read the Notes database. In System Settings > Privacy & Security > Full Disk Access, grant access to the Node binary running this server (required under Claude Desktop) or the terminal that launches it, then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`;
45277
45280
  var NoteStoreError = class extends Error {
45278
45281
  constructor(message, kind) {
45279
45282
  super(message);
@@ -45697,7 +45700,7 @@ var ENTITY_LABEL = {
45697
45700
  ICFolder: "folder",
45698
45701
  ICAccount: "account"
45699
45702
  };
45700
- var NO_FDA_MESSAGE = `Resolving a Notes UUID or numeric key reads the Notes database, which needs Full Disk Access for the app that launches this server (System Settings > Privacy & Security > Full Disk Access, then fully quit and relaunch it). x-coredata ids from search-notes, list-notes, or list-folders work without it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL}`;
45703
+ var NO_FDA_MESSAGE = `Resolving a Notes UUID or numeric key reads the Notes database, which needs Full Disk Access for the Node binary running this server, or the terminal that launches it (System Settings > Privacy & Security > Full Disk Access, then fully quit and relaunch it). x-coredata ids from search-notes, list-notes, or list-folders work without it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL}`;
45701
45704
  function canonicalKey(value) {
45702
45705
  return BigInt(value).toString();
45703
45706
  }
@@ -46453,7 +46456,7 @@ var QUERY_RESULTS = { DEFAULT: 50, MAX: 500 };
46453
46456
  var CORE_DATA_EPOCH_MS2 = Date.UTC(2001, 0, 1);
46454
46457
  var SNIPPET_BEFORE = 60;
46455
46458
  var SNIPPET_LENGTH = 180;
46456
- var QUERY_FDA_MESSAGE = `Full Disk Access is required to query notes. In System Settings > Privacy & Security > Full Disk Access, grant access to the app that launches this server (Claude Desktop / Terminal / iTerm2), then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`;
46459
+ var QUERY_FDA_MESSAGE = `Full Disk Access is required to query notes. In System Settings > Privacy & Security > Full Disk Access, grant access to the Node binary running this server (required under Claude Desktop) or the terminal that launches it, then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`;
46457
46460
  var NoteQueryStoreError = class extends Error {
46458
46461
  constructor(message, kind) {
46459
46462
  super(message);
@@ -46838,7 +46841,7 @@ function describeContentScan(scan) {
46838
46841
  }
46839
46842
  function contentSearchFailureHint(message, dbUnavailable) {
46840
46843
  if (!/timed out/i.test(message)) return message;
46841
- const remedy = dbUnavailable === "no_fda" ? " Grant Full Disk Access to the app that launches this server (run the doctor tool) so search-notes can search note bodies through the Notes database instead, which takes well under a second." : "";
46844
+ const remedy = dbUnavailable === "no_fda" ? " Grant Full Disk Access to the Node binary running this server (run the doctor tool for its path) so search-notes can search note bodies through the Notes database instead, which takes well under a second." : "";
46842
46845
  return `${message} Body search through AppleScript scans every note body before the result limit applies, so a broad term can exceed the time budget on a large library.${remedy} Otherwise narrow the search with \`folder\` or \`modifiedSince\`, or use a more specific term.`;
46843
46846
  }
46844
46847
 
@@ -47930,7 +47933,7 @@ function runDoctor(manager, capabilityMatrix = getCapabilityMatrix) {
47930
47933
  checks.push({
47931
47934
  name: "Full Disk Access",
47932
47935
  status: fda ? "ok" : "warn",
47933
- detail: fda ? "granted \u2014 the Notes database is readable (checklist state, note metadata, note links, sync detail)" : `not granted \u2014 get-checklist-state, get-note-metadata, and the checklist annotations in get-note-markdown won't work; get-note-link fails on macOS 26+ (macOS 12-15 falls back to AppleScript); get-sync-status still answers but cannot see pending uploads. Everything else is pure AppleScript and is unaffected. In System Settings > Privacy & Security > Full Disk Access, grant access to the app that launches this server (Claude Desktop / Terminal / iTerm2), then fully quit and relaunch it and re-run doctor. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL}`
47936
+ detail: fda ? "granted \u2014 the Notes database is readable (checklist state, note metadata, note links, sync detail)" : "not granted \u2014 get-checklist-state, get-note-metadata, and the checklist annotations in get-note-markdown won't work; get-note-link fails on macOS 26+ (macOS 12-15 falls back to AppleScript); get-sync-status still answers but cannot see pending uploads. Everything else is pure AppleScript and is unaffected. " + fdaRemediation()
47934
47937
  });
47935
47938
  const consentReminder = "After install or upgrade, run each bridge Shortcut once in the foreground in Shortcuts.app and choose Always Allow: a background run cannot display a first-run consent prompt, so an unanswered one stalls that bridge's native writes until they time out while this check stays ok";
47936
47939
  try {
@@ -47961,6 +47964,10 @@ function runDoctor(manager, capabilityMatrix = getCapabilityMatrix) {
47961
47964
  }
47962
47965
  return matrix ? { healthy, checks, runtimeOS: matrix.runtimeOS, features: matrix.features } : { healthy, checks };
47963
47966
  }
47967
+ function fdaRemediation(execPath = process.execPath) {
47968
+ const versioned = /\/(\.nvm|\.fnm|\.volta|\.asdf|\.local\/share\/mise|\.nodenv|n\/versions)\//.test(execPath);
47969
+ return `In System Settings > Privacy & Security > Full Disk Access, click + and add the Node binary running this server: ${execPath} (press Cmd+Shift+G in the file picker to paste the path). Under Claude Desktop that entry is required: Claude Desktop launches servers as their own responsible process, so a grant on Claude.app does not reach them. When the server runs from a terminal (Terminal, iTerm2) or an editor, granting that app is enough. Then fully quit (Cmd+Q) and relaunch the host app and re-run doctor; if it still reports not granted, restart the Mac. ` + (versioned ? "This Node lives under a version manager, so the path changes with each Node version and the grant has to be added again after switching; pointing the MCP config at one fixed Node path avoids that. " : "") + `Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL}`;
47970
+ }
47964
47971
  function markdownBridgeDetail() {
47965
47972
  const purpose = 'needed only for create-note format: "markdown" on macOS 26+';
47966
47973
  try {
@@ -50584,7 +50591,7 @@ function classify(error2) {
50584
50591
  const message = error2 instanceof Error ? error2.message : String(error2);
50585
50592
  if (/authorization denied|unable to open database|not authorized/i.test(message)) {
50586
50593
  return new FolderStoreError(
50587
- "Full Disk Access is required to verify folder type and contents before deleting. Grant it to the app that launches this server, then relaunch it.",
50594
+ "Full Disk Access is required to verify folder type and contents before deleting. Grant it to the Node binary running this server (or the terminal that launches it), then relaunch it.",
50588
50595
  "no_fda"
50589
50596
  );
50590
50597
  }
@@ -52166,7 +52173,7 @@ registerTool(
52166
52173
  registerTool(
52167
52174
  "get-note-link",
52168
52175
  {
52169
- description: "Use when: you need the notes:// deep-link URL for a note so it can be stored in a Reminders task, shared, or opened directly.\nReturns: a notes://showNote?identifier=<uuid> URL that opens the note in Notes.app on iOS and macOS.\nDo not use when: you only need the note's CoreData id (get-note-by-id) or want to reveal the note on screen (show-note).\nNote: the primary path reads the note's identifier from the Notes database, so it needs Full Disk Access for the app that launches this server; macOS 12-15 can fall back to the AppleScript 'note link' property, which macOS 26+ no longer exposes. Password-protected notes cannot be linked.",
52176
+ description: "Use when: you need the notes:// deep-link URL for a note so it can be stored in a Reminders task, shared, or opened directly.\nReturns: a notes://showNote?identifier=<uuid> URL that opens the note in Notes.app on iOS and macOS.\nDo not use when: you only need the note's CoreData id (get-note-by-id) or want to reveal the note on screen (show-note).\nNote: the primary path reads the note's identifier from the Notes database, so it needs Full Disk Access for the Node binary running this server; macOS 12-15 can fall back to the AppleScript 'note link' property, which macOS 26+ no longer exposes. Password-protected notes cannot be linked.",
52170
52177
  inputSchema: {
52171
52178
  id: looseNoteId(external_exports.string()).optional().describe(`Note ID (preferred - more reliable than title): ${NOTE_ID_FORMS}`),
52172
52179
  title: external_exports.string().max(MAX.TITLE).optional().describe("Note title (use id instead when available)"),
@@ -52192,7 +52199,7 @@ registerTool(
52192
52199
  const url2 = notesManager.getNoteLinkById(id2);
52193
52200
  if (!url2) {
52194
52201
  return errorResponse(
52195
- `Failed to get note link for "${note2.title}". The Notes database may not be accessible \u2014 grant Full Disk Access to the app that launches the server, fully quit and relaunch, then run the doctor tool. See: ${FULL_DISK_ACCESS_GUIDE_URL}. (On macOS 12\u201315 this also falls back to the AppleScript note link property.)`
52202
+ `Failed to get note link for "${note2.title}". The Notes database may not be accessible \u2014 grant Full Disk Access to the Node binary running the server (or the terminal that launches it), fully quit and relaunch, then run the doctor tool. See: ${FULL_DISK_ACCESS_GUIDE_URL}. (On macOS 12\u201315 this also falls back to the AppleScript note link property.)`
52196
52203
  );
52197
52204
  }
52198
52205
  return successResponse(`Note link: ${url2}`, { id: id2, title: note2.title, url: url2 });
@@ -52212,7 +52219,7 @@ registerTool(
52212
52219
  const url = notesManager.getNoteLink(title, account);
52213
52220
  if (!url) {
52214
52221
  return errorResponse(
52215
- `Failed to get note link for "${title}". The Notes database may not be accessible \u2014 grant Full Disk Access to the app that launches the server, fully quit and relaunch, then run the doctor tool. See: ${FULL_DISK_ACCESS_GUIDE_URL}. (On macOS 12\u201315 this also falls back to the AppleScript note link property.)`
52222
+ `Failed to get note link for "${title}". The Notes database may not be accessible \u2014 grant Full Disk Access to the Node binary running the server (or the terminal that launches it), fully quit and relaunch, then run the doctor tool. See: ${FULL_DISK_ACCESS_GUIDE_URL}. (On macOS 12\u201315 this also falls back to the AppleScript note link property.)`
52216
52223
  );
52217
52224
  }
52218
52225
  return successResponse(`Note link: ${url}`, { title, url });
@@ -52385,7 +52392,7 @@ registerTool(
52385
52392
  page = pageNoteBlocks(readNoteBlocks(id2), { offset, limit });
52386
52393
  } catch (error2) {
52387
52394
  if (!(error2 instanceof NoteBlocksError)) throw error2;
52388
- const hint = error2.code === "no-full-disk-access" ? ` Grant Full Disk Access to the app that launches this server: ${FULL_DISK_ACCESS_GUIDE_URL}` : "";
52395
+ const hint = error2.code === "no-full-disk-access" ? ` Grant Full Disk Access to the Node binary running this server (run the doctor tool for its path): ${FULL_DISK_ACCESS_GUIDE_URL}` : "";
52389
52396
  return errorResponse(`Error reading note blocks [${error2.code}]: ${error2.message}${hint}`);
52390
52397
  }
52391
52398
  const { summary } = page;
@@ -53269,7 +53276,7 @@ registerTool(
53269
53276
  return ` ${icon} ${c.name}: ${c.message}`;
53270
53277
  }).join("\n");
53271
53278
  const fdaAvailable = hasFullDiskAccess();
53272
- const fdaLine = fdaAvailable ? " \u2713 full_disk_access: Granted (Notes database readable \u2014 checklist state, note metadata, note links, sync detail)" : ` \u24D8 full_disk_access: Not granted \u2014 get-checklist-state, get-note-metadata, and the checklist annotations in get-note-markdown won't work; get-note-link fails on macOS 26+ (macOS 12-15 falls back to AppleScript); get-sync-status cannot see pending uploads. The rest of the server is pure AppleScript and is unaffected. In System Settings > Privacy & Security > Full Disk Access, grant access to the app that launches this server (Claude Desktop / Terminal / iTerm2), then fully quit and relaunch it. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL} \u2014 run the doctor tool to verify.`;
53279
+ const fdaLine = fdaAvailable ? " \u2713 full_disk_access: Granted (Notes database readable \u2014 checklist state, note metadata, note links, sync detail)" : " \u24D8 full_disk_access: Not granted \u2014 get-checklist-state, get-note-metadata, and the checklist annotations in get-note-markdown won't work; get-note-link fails on macOS 26+ (macOS 12-15 falls back to AppleScript); get-sync-status cannot see pending uploads. The rest of the server is pure AppleScript and is unaffected. " + fdaRemediation();
53273
53280
  return successResponse(`${statusIcon} ${statusText}
53274
53281
 
53275
53282
  ${checkLines}
@@ -53949,7 +53956,7 @@ registerTool(
53949
53956
  });
53950
53957
  } catch (error2) {
53951
53958
  if (!(error2 instanceof NotesExportError || error2 instanceof NoteBlocksError)) throw error2;
53952
- const hint = error2.code === "no-full-disk-access" ? ` Grant Full Disk Access to the app that launches this server: ${FULL_DISK_ACCESS_GUIDE_URL}` : "";
53959
+ const hint = error2.code === "no-full-disk-access" ? ` Grant Full Disk Access to the Node binary running this server (run the doctor tool for its path): ${FULL_DISK_ACCESS_GUIDE_URL}` : "";
53953
53960
  return errorResponse(`Error exporting Markdown [${error2.code}]: ${error2.message}${hint}`);
53954
53961
  }
53955
53962
  const skipped = receipt.skipped.length ? `; skipped ${receipt.skipped.length}` : "";
@@ -54001,7 +54008,7 @@ registerTool(
54001
54008
  });
54002
54009
  } catch (error2) {
54003
54010
  if (!(error2 instanceof NotesExportError || error2 instanceof NoteBlocksError)) throw error2;
54004
- const hint = error2.code === "no-full-disk-access" ? ` Grant Full Disk Access to the app that launches this server: ${FULL_DISK_ACCESS_GUIDE_URL}` : "";
54011
+ const hint = error2.code === "no-full-disk-access" ? ` Grant Full Disk Access to the Node binary running this server (run the doctor tool for its path): ${FULL_DISK_ACCESS_GUIDE_URL}` : "";
54005
54012
  return errorResponse(`Error exporting HTML [${error2.code}]: ${error2.message}${hint}`);
54006
54013
  }
54007
54014
  const assets = receipt.assets ? `; copied ${receipt.assets.files} asset file(s) to ${receipt.assets.dir}` : `; embedded ${receipt.embedded ?? 0} asset(s)`;
@@ -37,7 +37,7 @@ That database lives in a macOS-protected directory:
37
37
  ```
38
38
 
39
39
  Reading anything under `~/Library/Group Containers/` requires **Full Disk
40
- Access** for the host process — without it, macOS denies the read. (The MCP only
40
+ Access** for the process that runs the server — without it, macOS denies the read. (The MCP only
41
41
  ever **reads** this database; it never writes to it.)
42
42
 
43
43
  ## How to grant Full Disk Access
@@ -45,21 +45,47 @@ ever **reads** this database; it never writes to it.)
45
45
  1. Open **System Settings** (or **System Preferences** on older macOS).
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
- first), and add the application that **hosts** the MCP server — i.e. the app
49
- that actually launches `node`:
50
- - **Claude Desktop** → `/Applications/Claude.app`
51
- - **Terminal** (if you run Claude Code from a shell) → `/Applications/Utilities/Terminal.app`
52
- - **iTerm** → `/Applications/iTerm.app`
48
+ first) and add the right entry for how you run the server:
49
+ - **Claude Desktop** → the **Node binary** that runs the server, e.g.
50
+ `/usr/local/bin/node` or `~/.nvm/versions/node/v24.11.1/bin/node`. The
51
+ `doctor` tool prints the exact path. In the file picker, press **⌘⇧G** and
52
+ paste it (use **⌘⇧.** to show hidden folders such as `~/.nvm`). Adding
53
+ `/Applications/Claude.app` as well does no harm, but on its own it is not
54
+ enough (see below).
55
+ - **Claude Code or another client in a terminal** → the terminal app:
56
+ `/Applications/Utilities/Terminal.app` or `/Applications/iTerm.app`
53
57
  - **VS Code** → `/Applications/Visual Studio Code.app`
54
- 4. Make sure the toggle next to the app is **on**.
58
+ 4. Make sure the toggle next to the entry is **on**.
55
59
  5. **Fully quit and reopen the host app.** macOS only applies the new permission
56
- to processes started *after* the change — a reload or restart-server is not
57
- enough; the host application itself must be quit (⌘Q) and relaunched.
58
-
59
- > **Grant FDA to the right app.** FDA applies to the process that spawns the
60
- > server, not to `node` or to Notes.app. If you launch Claude Code from iTerm,
61
- > grant it to iTerm; if you use Claude Desktop, grant it to Claude. Granting it to
62
- > the wrong app has no effect.
60
+ to processes started *after* the change. A reload or restart-server is not
61
+ enough; quit the host application itself (⌘Q) and relaunch it. If `doctor`
62
+ still reports Full Disk Access as not granted after that, restart the Mac.
63
+
64
+ > **Why Claude Desktop needs the Node binary itself.** macOS checks Full Disk
65
+ > Access against the *responsible process*, the app it holds accountable for a
66
+ > request. A terminal passes that role on to everything it launches, so a grant
67
+ > on Terminal or iTerm covers the server. Claude Desktop does not: it starts each
68
+ > MCP server through a helper that *disclaims* responsibility, which makes the
69
+ > `node` process its own responsible process. macOS then looks for a grant on the
70
+ > Node binary's path and ignores the one on Claude.app
71
+ > ([#220](https://github.com/sweetrb/apple-notes-mcp/issues/220)).
72
+ >
73
+ > The grant is tied to that exact path. With a version manager (nvm, fnm, Volta,
74
+ > asdf, mise) the path changes with every Node version, so switching versions
75
+ > drops the grant, and `npx` runs whichever `node` is first on the `PATH` Claude
76
+ > Desktop sees. Pointing the config at one fixed Node binary keeps the grant
77
+ > stable:
78
+ >
79
+ > ```json
80
+ > "apple-notes": {
81
+ > "command": "/Users/you/.nvm/versions/node/v24.11.1/bin/node",
82
+ > "args": ["/path/to/global/node_modules/apple-notes-mcp/build/index.js"]
83
+ > }
84
+ > ```
85
+ >
86
+ > A Developer-ID-signed Node keeps its grant across updates at the same path;
87
+ > an ad-hoc-signed one (typically Homebrew's) does not. See
88
+ > [Node runtime and TCC permissions](NODE-RUNTIME-AND-TCC-PERMISSIONS.md).
63
89
 
64
90
  ## Verifying it worked
65
91
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-notes-mcp",
3
- "version": "2.8.46",
3
+ "version": "2.8.48",
4
4
  "description": "MCP server for Apple Notes - create, search, update, and manage notes via Claude and other AI assistants",
5
5
  "type": "module",
6
6
  "main": "build/index.js",