apple-notes-mcp 2.6.15 → 2.7.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 CHANGED
@@ -593,7 +593,11 @@ Lists all notes, optionally filtered by folder, date, and limit.
593
593
  }
594
594
  ```
595
595
 
596
- **Returns:** List of note titles.
596
+ **Returns:** List of notes as `{title, id}` pairs — `notes: Array<{title, id}>`, plus `count`. The human-readable line is ` - <title> [id: <id>]`.
597
+
598
+ Use the returned `id` for any follow-up read/update/move/delete rather than re-resolving the title: titles are not unique, and a by-title lookup resolves a duplicated title to the same one note every time, silently skipping the others.
599
+
600
+ > **Changed in 2.7.0:** `notes` was previously `string[]` (titles only). Callers that treated the array as strings must now read `.title`.
597
601
 
598
602
  ---
599
603
 
package/build/index.js CHANGED
@@ -40100,29 +40100,12 @@ var AppleNotesManager = class {
40100
40100
  return refs;
40101
40101
  }
40102
40102
  /**
40103
- * Lists all notes in an account/folder as (title, id) pairs, unfiltered
40104
- * and unlimited. Used internally where the id is needed to avoid
40105
- * re-resolving identity by (possibly duplicated) title see exportNotesAsJson.
40103
+ * Core listing path shared by `listNotes()` and `listNoteRefs()`: lists
40104
+ * notes in an account, optionally filtered by folder, date, and limit,
40105
+ * returning (title, id) pairs. Kept private because both public callers
40106
+ * need to apply their own return shape.
40106
40107
  */
40107
- listNoteRefs(account, folder) {
40108
- const folderRef = folder ? buildFolderReference(folder) : void 0;
40109
- const script = buildAccountScopedScript({ account }, this.buildBulkListCommand({ folderRef }));
40110
- const result = executeAppleScript(script);
40111
- if (!result.success) {
40112
- throw new Error(`Failed to list notes: ${result.error ?? "unknown error"}`);
40113
- }
40114
- return this.parseBulkListOutput(result.output);
40115
- }
40116
- /**
40117
- * Lists all notes in an account, optionally filtered by folder, date, and limit.
40118
- *
40119
- * @param account - Account to list notes from (defaults to iCloud)
40120
- * @param folder - Optional folder to filter by
40121
- * @param modifiedSince - Optional ISO 8601 date string to filter notes modified on or after this date
40122
- * @param limit - Optional maximum number of results to return (default: no limit)
40123
- * @returns Array of note titles
40124
- */
40125
- listNotes(account, folder, modifiedSince, limit) {
40108
+ listNotesCore(account, folder, modifiedSince, limit) {
40126
40109
  const targetAccount = this.resolveAccount(account);
40127
40110
  const safeLimit = limit !== void 0 && limit > 0 ? Math.floor(limit) : void 0;
40128
40111
  const folderRef = folder ? buildFolderReference(folder) : void 0;
@@ -40148,7 +40131,7 @@ var AppleNotesManager = class {
40148
40131
  const records = sepIdx === -1 ? "" : result2.output.slice(sepIdx + 1);
40149
40132
  const refs = this.parseBulkListOutput(records, safeLimit);
40150
40133
  if (!Number.isNaN(totalCount) && (refs.length >= safeLimit || totalCount <= safeLimit)) {
40151
- return refs.map((ref) => ref.title);
40134
+ return refs;
40152
40135
  }
40153
40136
  }
40154
40137
  const script = buildAccountScopedScript(
@@ -40159,7 +40142,33 @@ var AppleNotesManager = class {
40159
40142
  if (!result.success) {
40160
40143
  throw new Error(`Failed to list notes: ${result.error ?? "unknown error"}`);
40161
40144
  }
40162
- return this.parseBulkListOutput(result.output, safeLimit).map((ref) => ref.title);
40145
+ return this.parseBulkListOutput(result.output, safeLimit);
40146
+ }
40147
+ /**
40148
+ * Lists all notes in an account, optionally filtered by folder, date, and limit.
40149
+ *
40150
+ * @param account - Account to list notes from (defaults to iCloud)
40151
+ * @param folder - Optional folder to filter by
40152
+ * @param modifiedSince - Optional ISO 8601 date string to filter notes modified on or after this date
40153
+ * @param limit - Optional maximum number of results to return (default: no limit)
40154
+ * @returns Array of note titles
40155
+ */
40156
+ listNotes(account, folder, modifiedSince, limit) {
40157
+ return this.listNotesCore(account, folder, modifiedSince, limit).map((ref) => ref.title);
40158
+ }
40159
+ /**
40160
+ * Lists all notes in an account, optionally filtered by folder, date, and
40161
+ * limit — same filtering semantics as `listNotes()`, but returns each
40162
+ * note's id alongside its title. Prefer this over `listNotes()` when the
40163
+ * caller needs to resolve notes by identity afterward: re-resolving by
40164
+ * title is unsafe when titles are duplicated (AppleScript's `note "<name>"`
40165
+ * specifier resolves ambiguously to the same one note every time — see
40166
+ * the fix in exportNotesAsJson for the failure mode this avoids).
40167
+ *
40168
+ * @returns Array of { title, id } pairs, deduplicated by id
40169
+ */
40170
+ listNoteRefs(account, folder, modifiedSince, limit) {
40171
+ return this.listNotesCore(account, folder, modifiedSince, limit);
40163
40172
  }
40164
40173
  /**
40165
40174
  * Lists all shared (collaborative) notes across all accounts.
@@ -42168,7 +42177,15 @@ var folderNameSchema = {
42168
42177
  name: external_exports.string().min(1, "Folder name is required").max(MAX.FOLDER),
42169
42178
  account: external_exports.string().max(MAX.ACCOUNT).optional().describe("Account name (defaults to iCloud)")
42170
42179
  };
42171
- server.registerTool(
42180
+ function registerTool(name, config2, cb) {
42181
+ const { outputSchema, ...rest } = config2;
42182
+ return server.registerTool(
42183
+ name,
42184
+ outputSchema ? { ...rest, outputSchema: external_exports.object(outputSchema).passthrough() } : rest,
42185
+ cb
42186
+ );
42187
+ }
42188
+ registerTool(
42172
42189
  "create-note",
42173
42190
  {
42174
42191
  description: "Use when: the user wants to create a brand-new Apple Note.\nReturns: the new note's title and id \u2014 reuse the id for follow-up reads/edits.\nDo not use when: editing an existing note (use update-note).\nNote: the title is prepended as an <h1>; true Apple Notes checklists cannot be created via AppleScript (see the content field). A 'folder' must already exist \u2014 create-folder first (it is idempotent), since this tool does not create it.",
@@ -42214,7 +42231,7 @@ server.registerTool(
42214
42231
  });
42215
42232
  }, "Error creating note")
42216
42233
  );
42217
- server.registerTool(
42234
+ registerTool(
42218
42235
  "search-notes",
42219
42236
  {
42220
42237
  description: "Use when: finding notes by a keyword in the title (or body with searchContent=true) and you need their ids.\nReturns: matching notes with title, folder, and id.\nDo not use when: you already have a note id (use get-note-content) or want every note (use list-notes).\nPrefer this first to obtain ids for subsequent read/update/delete/move calls.",
@@ -42287,7 +42304,7 @@ ${noteList}${truncationNote}${syncNote}`,
42287
42304
  );
42288
42305
  }, "Error searching notes")
42289
42306
  );
42290
- server.registerTool(
42307
+ registerTool(
42291
42308
  "get-note-content",
42292
42309
  {
42293
42310
  description: "Use when: reading the full body text of one known note, by id (preferred) or title.\nReturns: the note's content plus parsed hashtags, and strippedImages/truncated when the body was capped.\nDo not use when: you only need metadata (get-note-details) or Markdown with checklist state (get-note-markdown).\nNote: password-protected notes must be unlocked in Notes.app first.\nSafety: inline images larger than APPLE_NOTES_MCP_MAX_INLINE_IMAGE_BYTES (default 256 KB) are replaced with '[inline image omitted: ...]' text placeholders, so the returned body is lossy whenever truncated is true \u2014 do NOT write it back with update-note or the real images are replaced by that text. Use append-to-note to add content, or export the images with save-attachment / fetch-attachment first.",
@@ -42362,7 +42379,7 @@ server.registerTool(
42362
42379
  });
42363
42380
  }, "Error retrieving note content")
42364
42381
  );
42365
- server.registerTool(
42382
+ registerTool(
42366
42383
  "get-note-plaintext",
42367
42384
  {
42368
42385
  description: "Use when: reading one note's body as plain text with no HTML, by id (preferred) or title.\nReturns: the note's plaintext exactly as Notes exposes it.\nDo not use when: you need the HTML body (get-note-content) or Markdown with checklist state (get-note-markdown).\nNote: this reads the note's native plaintext property, so it skips the HTML-to-text conversion; password-protected notes must be unlocked in Notes.app first.",
@@ -42412,7 +42429,7 @@ server.registerTool(
42412
42429
  return successResponse(plaintext, { title, plaintext });
42413
42430
  }, "Error retrieving note plaintext")
42414
42431
  );
42415
- server.registerTool(
42432
+ registerTool(
42416
42433
  "get-note-by-id",
42417
42434
  {
42418
42435
  description: "Use when: you have a note id and need its metadata only.\nReturns: id, title, created, modified, shared, passwordProtected.\nDo not use when: you need the body text (get-note-content) or only have a title (get-note-details).",
@@ -42444,7 +42461,7 @@ server.registerTool(
42444
42461
  return successResponse(JSON.stringify(metadata, null, 2), metadata);
42445
42462
  }, "Error retrieving note")
42446
42463
  );
42447
- server.registerTool(
42464
+ registerTool(
42448
42465
  "get-note-details",
42449
42466
  {
42450
42467
  description: "Use when: you have a note title (not an id) and need its metadata.\nReturns: id, title, created, modified, shared, passwordProtected, account.\nDo not use when: you have an id (get-note-by-id) or need the body text (get-note-content).\nUse the returned id for reliable follow-up operations.",
@@ -42476,7 +42493,7 @@ server.registerTool(
42476
42493
  return successResponse(JSON.stringify(metadata, null, 2), metadata);
42477
42494
  }, "Error retrieving note details")
42478
42495
  );
42479
- server.registerTool(
42496
+ registerTool(
42480
42497
  "show-note",
42481
42498
  {
42482
42499
  description: "Use when: the user wants to reveal a known note in Notes.app by id.\nReturns: confirmation that Notes.app accepted the show command.\nDo not use when: you only need note content (get-note-content) or metadata (get-note-by-id).\nNote: this opens or focuses the Notes UI.",
@@ -42497,7 +42514,7 @@ server.registerTool(
42497
42514
  return successResponse(`Shown note with ID "${id}" in Notes.app`, { id, separately });
42498
42515
  }, "Error showing note")
42499
42516
  );
42500
- server.registerTool(
42517
+ registerTool(
42501
42518
  "get-note-link",
42502
42519
  {
42503
42520
  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.",
@@ -42552,7 +42569,7 @@ server.registerTool(
42552
42569
  return successResponse(`Note link: ${url}`, { title, url });
42553
42570
  }, "Error getting note link")
42554
42571
  );
42555
- server.registerTool(
42572
+ registerTool(
42556
42573
  "show-folder",
42557
42574
  {
42558
42575
  description: "Use when: the user wants to reveal a known folder in Notes.app by id.\nReturns: confirmation that Notes.app accepted the show command.\nDo not use when: you only need the folder list (list-folders).\nNote: this opens or focuses the Notes UI. Get the id from list-folders.",
@@ -42573,7 +42590,7 @@ server.registerTool(
42573
42590
  return successResponse(`Shown folder with ID "${id}" in Notes.app`, { id, separately });
42574
42591
  }, "Error showing folder")
42575
42592
  );
42576
- server.registerTool(
42593
+ registerTool(
42577
42594
  "show-account",
42578
42595
  {
42579
42596
  description: "Use when: the user wants to reveal a known account in Notes.app by id.\nReturns: confirmation that Notes.app accepted the show command.\nDo not use when: you only need the account list (list-accounts).\nNote: this opens or focuses the Notes UI. Get the id from list-accounts.",
@@ -42594,7 +42611,7 @@ server.registerTool(
42594
42611
  return successResponse(`Shown account with ID "${id}" in Notes.app`, { id, separately });
42595
42612
  }, "Error showing account")
42596
42613
  );
42597
- server.registerTool(
42614
+ registerTool(
42598
42615
  "update-note",
42599
42616
  {
42600
42617
  description: "Use when: changing the title and/or replacing the body of an existing note, by id (preferred) or title.\nReturns: confirmation; warns when the note is shared.\nDo not use when: creating a new note (create-note).\nSafety: newContent REPLACES the entire body \u2014 it does not append. Read the note first if you need to preserve existing text, and run list-attachments first when the note may hold files, images, scans, PDFs, or audio, since a full-body replace can drop embedded attachments. Edits to shared notes are immediately visible to all collaborators.",
@@ -42670,7 +42687,7 @@ server.registerTool(
42670
42687
  });
42671
42688
  }, "Error updating note")
42672
42689
  );
42673
- server.registerTool(
42690
+ registerTool(
42674
42691
  "append-to-note",
42675
42692
  {
42676
42693
  description: "Use when: adding content to an existing note without replacing it, by id (preferred) or title.\nReturns: confirmation with the note id and title.\nDo not use when: creating a new note (create-note) or replacing the entire body (update-note).\nSafety: reads the existing body first, concatenates, then writes back. Run list-attachments first if the note may hold embedded files \u2014 a full-body rewrite can drop attachments.",
@@ -42785,7 +42802,7 @@ server.registerTool(
42785
42802
  "Error appending to note"
42786
42803
  )
42787
42804
  );
42788
- server.registerTool(
42805
+ registerTool(
42789
42806
  "delete-note",
42790
42807
  {
42791
42808
  description: "Use when: permanently deleting a single note, by id (preferred) or title.\nReturns: confirmation; warns when the note was shared.\nDo not use when: deleting many notes (batch-delete-notes) or just relocating one (move-note).\nSafety: requires explicit user confirmation before deleting. Prefer search-notes/list-notes first to show the affected note id and title. Deleting a shared note removes collaborator access.",
@@ -42840,7 +42857,7 @@ server.registerTool(
42840
42857
  });
42841
42858
  }, "Error deleting note")
42842
42859
  );
42843
- server.registerTool(
42860
+ registerTool(
42844
42861
  "move-note",
42845
42862
  {
42846
42863
  description: "Use when: moving one note to a different folder, by id (preferred) or title.\nReturns: confirmation of the note and destination folder.\nDo not use when: moving many notes (batch-move-notes).\nNote: the note is relocated in place via Notes.app's native move, preserving its id, creation date, and all attachments. The destination folder must already exist (create-folder).",
@@ -42898,10 +42915,10 @@ server.registerTool(
42898
42915
  });
42899
42916
  }, "Error moving note")
42900
42917
  );
42901
- server.registerTool(
42918
+ registerTool(
42902
42919
  "list-notes",
42903
42920
  {
42904
- description: "Use when: enumerating notes in an account or folder; supports modifiedSince and limit for large collections.\nReturns: note titles only (no content or ids).\nDo not use when: you need content (get-note-content) or ids for follow-up edits (use search-notes).\nNote: warns if iCloud sync is active and results may be partial.",
42921
+ description: "Use when: enumerating notes in an account or folder; supports modifiedSince and limit for large collections.\nReturns: each note's title and id (ids are safe to use for follow-up reads/edits even when titles are duplicated \u2014 see search-notes for keyword-based lookup instead).\nDo not use when: you need content (get-note-content).\nNote: warns if iCloud sync is active and results may be partial.",
42905
42922
  inputSchema: {
42906
42923
  account: external_exports.string().max(MAX.ACCOUNT).optional().describe("Account to list notes from"),
42907
42924
  folder: external_exports.string().max(MAX.FOLDER).optional().describe("Filter to specific folder"),
@@ -42911,7 +42928,7 @@ server.registerTool(
42911
42928
  limit: external_exports.number().int().positive().optional().describe("Maximum number of notes to return")
42912
42929
  },
42913
42930
  outputSchema: {
42914
- notes: external_exports.array(external_exports.string()).optional(),
42931
+ notes: external_exports.array(external_exports.object({ title: external_exports.string(), id: external_exports.string() })).optional(),
42915
42932
  count: external_exports.number().optional()
42916
42933
  }
42917
42934
  },
@@ -42922,7 +42939,7 @@ server.registerTool(
42922
42939
  syncInterference
42923
42940
  } = withSyncAwarenessSync(
42924
42941
  "list-notes",
42925
- () => notesManager.listNotes(account, folder, modifiedSince, limit)
42942
+ () => notesManager.listNoteRefs(account, folder, modifiedSince, limit)
42926
42943
  );
42927
42944
  const location = folder ? ` in folder "${folder}"` : "";
42928
42945
  const acct = account ? ` (${account})` : "";
@@ -42944,7 +42961,7 @@ ${syncWarnings.join(" ")}` : "";
42944
42961
  count: 0
42945
42962
  });
42946
42963
  }
42947
- const noteList = notes.map((t) => ` - ${t}`).join("\n");
42964
+ const noteList = notes.map((n) => ` - ${n.title} [id: ${n.id}]`).join("\n");
42948
42965
  return successResponse(
42949
42966
  `Found ${notes.length} notes${location}${acct}${dateInfo}${limitInfo}:
42950
42967
  ${noteList}${syncNote}`,
@@ -42952,7 +42969,7 @@ ${noteList}${syncNote}`,
42952
42969
  );
42953
42970
  }, "Error listing notes")
42954
42971
  );
42955
- server.registerTool(
42972
+ registerTool(
42956
42973
  "get-selected-notes",
42957
42974
  {
42958
42975
  description: "Use when: the user asks what note(s) are currently selected in Notes.app.\nReturns: selected note metadata with ids for follow-up operations.\nDo not use when: searching all notes (search-notes) or listing a folder (list-notes).\nNote: reads Notes.app UI selection; it may be empty if Notes is closed or no note is selected.",
@@ -42975,7 +42992,7 @@ server.registerTool(
42975
42992
  ${noteList}`, { notes, count: notes.length });
42976
42993
  }, "Error getting selected notes")
42977
42994
  );
42978
- server.registerTool(
42995
+ registerTool(
42979
42996
  "list-folders",
42980
42997
  {
42981
42998
  description: "Use when: listing all folders, with full nested paths, for an account.\nReturns: folder names/paths.\nDo not use when: listing notes (list-notes).\nNote: warns if iCloud sync is active.",
@@ -43015,7 +43032,7 @@ ${folderList}${syncNote}`, {
43015
43032
  });
43016
43033
  }, "Error listing folders")
43017
43034
  );
43018
- server.registerTool(
43035
+ registerTool(
43019
43036
  "create-folder",
43020
43037
  {
43021
43038
  description: "Use when: creating a folder, including nested paths like 'Work/Clients' (intermediate folders are created, existing ones skipped).\nReturns: confirmation.\nDo not use when: creating a note (create-note).",
@@ -43041,7 +43058,7 @@ server.registerTool(
43041
43058
  });
43042
43059
  }, "Error creating folder")
43043
43060
  );
43044
- server.registerTool(
43061
+ registerTool(
43045
43062
  "delete-folder",
43046
43063
  {
43047
43064
  description: "Use when: deleting an existing folder by name or nested path.\nReturns: confirmation.\nDo not use when: deleting a note (delete-note).\nSafety: requires explicit user confirmation. Deletion fails if the folder still contains notes \u2014 list or move those notes first.",
@@ -43061,7 +43078,7 @@ server.registerTool(
43061
43078
  return successResponse(`Folder deleted: "${name}"`, { ok: true, folder: name });
43062
43079
  }, "Error deleting folder")
43063
43080
  );
43064
- server.registerTool(
43081
+ registerTool(
43065
43082
  "list-accounts",
43066
43083
  {
43067
43084
  description: "Use when: discovering which Notes accounts exist (iCloud, Gmail, Exchange, etc.) before targeting one.\nReturns: account names.\nDo not use when: you already know the account, or are working by note id (ids are account-independent).",
@@ -43088,7 +43105,7 @@ ${accountList}`, {
43088
43105
  });
43089
43106
  }, "Error listing accounts")
43090
43107
  );
43091
- server.registerTool(
43108
+ registerTool(
43092
43109
  "get-default-location",
43093
43110
  {
43094
43111
  description: "Use when: discovering where Notes.app will create new notes by default.\nReturns: default account and default folder metadata.\nDo not use when: you already have an explicit account/folder target.",
@@ -43105,7 +43122,7 @@ Default folder: ${location.folder.name} [id: ${location.folder.id}]`;
43105
43122
  return successResponse(message, { ...location });
43106
43123
  }, "Error getting default Notes location")
43107
43124
  );
43108
- server.registerTool(
43125
+ registerTool(
43109
43126
  "list-shared-notes",
43110
43127
  {
43111
43128
  description: "Use when: finding notes shared with collaborators.\nReturns: shared notes with title, account, and id.\nDo not use when: searching all notes (search-notes).\nNote: edits or deletes to these notes affect all collaborators.",
@@ -43136,7 +43153,7 @@ ${noteList}
43136
43153
  );
43137
43154
  }, "Error listing shared notes")
43138
43155
  );
43139
- server.registerTool(
43156
+ registerTool(
43140
43157
  "get-sync-status",
43141
43158
  {
43142
43159
  description: "Use when: checking whether iCloud sync is in progress before trusting read results.\nReturns: sync active/idle, pending upload count, and seconds since last change.\nDo not use when: you need note data \u2014 this is a read-only diagnostics tool.",
@@ -43175,7 +43192,7 @@ server.registerTool(
43175
43192
  return successResponse(lines.join("\n"), { ...status });
43176
43193
  }, "Error checking sync status")
43177
43194
  );
43178
- server.registerTool(
43195
+ registerTool(
43179
43196
  "health-check",
43180
43197
  {
43181
43198
  description: "Use when: a quick check that Notes.app is reachable and (optionally) Full Disk Access is granted for checklist features.\nReturns: pass/fail per check.\nDo not use when: you need detailed, actionable setup diagnostics (use doctor).\nRead-only.",
@@ -43206,7 +43223,7 @@ ${fdaLine}`, {
43206
43223
  });
43207
43224
  }, "Error running health check")
43208
43225
  );
43209
- server.registerTool(
43226
+ registerTool(
43210
43227
  "doctor",
43211
43228
  {
43212
43229
  description: "Use when: diagnosing setup problems (Notes.app automation permission, account state, Full Disk Access) with actionable guidance.\nReturns: a detailed report plus structured fields.\nDo not use when: you just need a quick pass/fail (health-check).\nRead-only.",
@@ -43221,7 +43238,7 @@ server.registerTool(
43221
43238
  return successResponse(formatDoctorReport(report), { ...report });
43222
43239
  }, "Error running doctor")
43223
43240
  );
43224
- server.registerTool(
43241
+ registerTool(
43225
43242
  "get-notes-stats",
43226
43243
  {
43227
43244
  description: "Use when: summarizing the library \u2014 total notes, per-account/folder counts, and recent activity.\nReturns: aggregate statistics; flags partial coverage when some scopes were unreadable.\nDo not use when: you need individual notes (list-notes/search-notes).\nRead-only.",
@@ -43266,7 +43283,7 @@ server.registerTool(
43266
43283
  return successResponse(lines.join("\n"), { ...stats });
43267
43284
  }, "Error getting notes statistics")
43268
43285
  );
43269
- server.registerTool(
43286
+ registerTool(
43270
43287
  "list-attachments",
43271
43288
  {
43272
43289
  description: "Use when: listing the attachments of one note, by id (preferred) or title.\nReturns: each attachment's name, content type, and id (use with save-attachment/fetch-attachment).\nDo not use when: you want the attachment bytes (fetch-attachment) or a file on disk (save-attachment).",
@@ -43321,7 +43338,7 @@ ${attachmentList}`,
43321
43338
  );
43322
43339
  }, "Error listing attachments")
43323
43340
  );
43324
- server.registerTool(
43341
+ registerTool(
43325
43342
  "batch-delete-notes",
43326
43343
  {
43327
43344
  description: "Use when: permanently deleting multiple notes by id in one call.\nReturns: per-id success/failure counts.\nDo not use when: deleting a single note (delete-note).\nSafety: requires explicit user confirmation; this is destructive and not undoable. Prefer search-notes/list-notes first to confirm the exact ids being deleted.",
@@ -43357,7 +43374,7 @@ server.registerTool(
43357
43374
  }) : errorResponse(lines.join("\n"));
43358
43375
  }, "Error performing batch delete")
43359
43376
  );
43360
- server.registerTool(
43377
+ registerTool(
43361
43378
  "batch-move-notes",
43362
43379
  {
43363
43380
  description: "Use when: moving multiple notes by id into one destination folder.\nReturns: per-id success/failure counts.\nDo not use when: moving a single note (move-note).\nNote: the destination folder must already exist (create-folder).",
@@ -43399,7 +43416,7 @@ server.registerTool(
43399
43416
  }) : errorResponse(lines.join("\n"));
43400
43417
  }, "Error performing batch move")
43401
43418
  );
43402
- server.registerTool(
43419
+ registerTool(
43403
43420
  "save-attachment",
43404
43421
  {
43405
43422
  description: "Use when: writing one note attachment to a file on disk.\nReturns: the saved path.\nDo not use when: you want the bytes in-memory as base64 (fetch-attachment).\nSafety: writes a file; savePath must be absolute and under the home directory, a temp dir, or /Volumes. Get the ids from list-attachments first.",
@@ -43426,7 +43443,7 @@ server.registerTool(
43426
43443
  });
43427
43444
  }, "Error saving attachment")
43428
43445
  );
43429
- server.registerTool(
43446
+ registerTool(
43430
43447
  "fetch-attachment",
43431
43448
  {
43432
43449
  description: "Use when: retrieving one note attachment's bytes inline as base64 (no file written).\nReturns: name, content type, byte count, and base64 data.\nDo not use when: you want it saved to disk (save-attachment).\nNote: get the ids from list-attachments first.",
@@ -43452,7 +43469,7 @@ server.registerTool(
43452
43469
  );
43453
43470
  }, "Error fetching attachment")
43454
43471
  );
43455
- server.registerTool(
43472
+ registerTool(
43456
43473
  "show-attachment",
43457
43474
  {
43458
43475
  description: "Use when: the user wants to reveal one note attachment in Notes.app.\nReturns: confirmation that Notes.app revealed the attachment.\nDo not use when: you want the bytes (fetch-attachment) or a file on disk (save-attachment).\nNote: this opens or focuses the Notes UI. Get the ids from list-attachments first.",
@@ -43479,7 +43496,7 @@ server.registerTool(
43479
43496
  });
43480
43497
  }, "Error showing attachment")
43481
43498
  );
43482
- server.registerTool(
43499
+ registerTool(
43483
43500
  "export-notes-json",
43484
43501
  {
43485
43502
  description: "Use when: exporting the entire notes library as structured JSON for backup or bulk processing.\nReturns: a summary plus the full JSON of all notes, folders, and accounts.\nDo not use when: you need a single note (get-note-content) \u2014 this reads everything and can be large.\nRead-only.",
@@ -43511,7 +43528,7 @@ Full JSON export:`
43511
43528
  };
43512
43529
  }, "Error exporting notes")
43513
43530
  );
43514
- server.registerTool(
43531
+ registerTool(
43515
43532
  "get-note-markdown",
43516
43533
  {
43517
43534
  description: "Use when: reading a note as Markdown, with checklist items annotated [x]/[ ] when Full Disk Access is granted.\nReturns: the note's Markdown.\nDo not use when: you need the raw HTML/plaintext body (get-note-content) or only metadata (get-note-details).\nNote: falls back to plain lists (no checkmarks) without Full Disk Access.",
@@ -43544,7 +43561,7 @@ server.registerTool(
43544
43561
  return successResponse(markdown, { markdown });
43545
43562
  }, "Error getting note as markdown")
43546
43563
  );
43547
- server.registerTool(
43564
+ registerTool(
43548
43565
  "get-checklist-state",
43549
43566
  {
43550
43567
  description: "Use when: reading the checked/unchecked state of a note's checklist items, by id.\nReturns: each item's text and done state plus checked/total counts.\nDo not use when: you only have a title (get the id via search-notes first) or want the full body text (get-note-content).\nNote: requires Full Disk Access; reads the NoteStore database directly.",
@@ -43580,7 +43597,7 @@ ${summary}`,
43580
43597
  );
43581
43598
  }, "Error reading checklist state")
43582
43599
  );
43583
- server.registerTool(
43600
+ registerTool(
43584
43601
  "get-note-metadata",
43585
43602
  {
43586
43603
  description: "[BETA] Use when: reading note metadata AppleScript cannot expose \u2014 pinned state, checklist flags, trash/recovery state, preview snippet, password hint \u2014 by id.\nReturns: a metadata object; fields vary by macOS version and are omitted when unavailable.\nDo not use when: you need the body (get-note-content) or per-item checklist state (get-checklist-state).\nNote: reads the NoteStore SQLite database read-only and requires Full Disk Access. BETA \u2014 the database schema changes between macOS releases, so some fields may be absent. Works on trashed notes that AppleScript can no longer resolve.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-notes-mcp",
3
- "version": "2.6.15",
3
+ "version": "2.7.0",
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",