apple-notes-mcp 2.6.16 → 2.7.1

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.
Files changed (3) hide show
  1. package/README.md +40 -16
  2. package/build/index.js +196 -85
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -181,7 +181,7 @@ Creates a new note in Apple Notes.
181
181
  | `content` | string | Yes | The body content of the note (do not repeat the title here) |
182
182
  | `tags` | string[] | No | Returned-only metadata — **NOT written to Notes.app**. Apple Notes tags can't be set via AppleScript, so values passed here are echoed back in the response but do not appear on the created note. Use inline `#hashtags` in `content` instead (Notes.app turns those into real tags) |
183
183
  | `folder` | string | No | Folder to create the note in. Supports nested paths like `"Work/Clients"`. **The folder must already exist** — create it first with [`create-folder`](#create-folder). Defaults to account root |
184
- | `account` | string | No | Account name (defaults to iCloud). Must be an account Notes.app already has configured — see [`list-accounts`](#list-accounts) |
184
+ | `account` | string | No | Account name (defaults to Notes.app's default account; matched exactly or by a *unique* prefix — an ambiguous prefix is refused). Must be an account Notes.app already has configured — see [`list-accounts`](#list-accounts) |
185
185
  | `format` | string | No | Content format: `"plaintext"` (default) or `"html"`. In both formats, the title is automatically prepended as `<h1>`. In plaintext mode, newlines become `<br>`, tabs become `<br>`, and backslashes are preserved as HTML entities |
186
186
 
187
187
  **Example (tagged with inline hashtags):**
@@ -224,7 +224,7 @@ Searches for notes by title or content.
224
224
  |-----------|------|----------|-------------|
225
225
  | `query` | string | Yes | Text to search for |
226
226
  | `searchContent` | boolean | No | If `true`, searches note body; if `false` (default), searches titles only |
227
- | `account` | string | No | Account to search in (defaults to iCloud) |
227
+ | `account` | string | No | Account to search in (defaults to Notes.app's default account; exact or unique-prefix match) |
228
228
  | `folder` | string | No | Limit search to a specific folder (supports nested paths like `"Work/Clients"`) |
229
229
  | `modifiedSince` | string | No | ISO 8601 date string to filter notes modified on or after this date (e.g., `"2025-01-01"`) |
230
230
  | `limit` | number | No | Maximum number of results to return. **Defaults to 50** — a broad query reads several properties per match via AppleScript (~200ms/note), so an unbounded search over hundreds of matches can exceed Notes' 30s timeout and return an error instead of results. Pass a higher value to see more; the applied limit (and whether it truncated the results) is disclosed in the response. |
@@ -266,7 +266,7 @@ Retrieves the full content of a specific note.
266
266
  |-----------|------|----------|-------------|
267
267
  | `id` | string | No | Note ID (preferred - more reliable than title) |
268
268
  | `title` | string | No | Note title (use `id` instead when available) |
269
- | `account` | string | No | Account containing the note (defaults to iCloud, ignored if `id` is provided) |
269
+ | `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match, ignored if `id` is provided) |
270
270
 
271
271
  **Note:** Either `id` or `title` must be provided. Using `id` is recommended as it's unique and avoids issues with duplicate titles.
272
272
 
@@ -309,7 +309,7 @@ Retrieves a note's body as plain text, with no HTML markup.
309
309
  |-----------|------|----------|-------------|
310
310
  | `id` | string | No | Note ID (preferred - more reliable than title) |
311
311
  | `title` | string | No | Note title (use `id` instead when available) |
312
- | `account` | string | No | Account containing the note (defaults to iCloud, ignored if `id` is provided) |
312
+ | `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match, ignored if `id` is provided) |
313
313
 
314
314
  **Note:** Either `id` or `title` must be provided. This reads the note's native `plaintext` property, so it skips the HTML-to-text conversion that `get-note-content` plus a Markdown pass would do. Use `get-note-content` when you need the HTML, or `get-note-markdown` when you want Markdown with checklist state.
315
315
 
@@ -324,7 +324,7 @@ Retrieves metadata about a note (without full content).
324
324
  | Parameter | Type | Required | Description |
325
325
  |-----------|------|----------|-------------|
326
326
  | `title` | string | Yes | Exact title of the note |
327
- | `account` | string | No | Account containing the note (defaults to iCloud) |
327
+ | `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match) |
328
328
 
329
329
  **Example:**
330
330
  ```json
@@ -383,7 +383,7 @@ Updates an existing note's content and/or title.
383
383
  | `title` | string | No | Current title of the note to update (use `id` instead when available) |
384
384
  | `newTitle` | string | No | New title (if changing the title; ignored when `format` is `"html"`) |
385
385
  | `newContent` | string | Yes | New content for the note body |
386
- | `account` | string | No | Account containing the note (defaults to iCloud, ignored if `id` is provided) |
386
+ | `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match, ignored if `id` is provided) |
387
387
  | `format` | string | No | Content format: `"plaintext"` (default) or `"html"`. When `"html"`, content replaces the entire note body as raw HTML and `newTitle` is ignored (the first HTML element serves as the title) |
388
388
 
389
389
  **Note:** Either `id` or `title` must be provided. Using `id` is recommended.
@@ -440,7 +440,7 @@ Deletes a note (moves to Recently Deleted in Notes.app).
440
440
  |-----------|------|----------|-------------|
441
441
  | `id` | string | No | Note ID (preferred - more reliable than title) |
442
442
  | `title` | string | No | Exact title of the note to delete (use `id` instead when available) |
443
- | `account` | string | No | Account containing the note (defaults to iCloud, ignored if `id` is provided) |
443
+ | `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match, ignored if `id` is provided) |
444
444
 
445
445
  **Note:** Either `id` or `title` must be provided. Using `id` is recommended.
446
446
 
@@ -473,7 +473,7 @@ Moves a note to a different folder. The note is relocated in place via Notes.app
473
473
  | `id` | string | No | Note ID (preferred - more reliable than title) |
474
474
  | `title` | string | No | Title of the note to move (use `id` instead when available) |
475
475
  | `folder` | string | Yes | Destination folder name or nested path (e.g., `"Work/Clients"`) |
476
- | `account` | string | No | Account containing the note (defaults to iCloud, ignored if `id` is provided) |
476
+ | `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match, ignored if `id` is provided) |
477
477
 
478
478
  **Note:** Either `id` or `title` must be provided. Using `id` is recommended.
479
479
 
@@ -509,7 +509,7 @@ Appends or prepends content to an existing note without replacing it. Always rea
509
509
  | `position` | string | No | `"after"` (default) appends to the end; `"before"` prepends to the start |
510
510
  | `separator` | string | No | String placed between existing content and new content (default: two newlines → `<div><br></div>` in HTML) |
511
511
  | `format` | string | No | Format of the content being appended: `"plaintext"` (default) or `"html"` |
512
- | `account` | string | No | Account containing the note (defaults to iCloud, ignored if `id` is provided) |
512
+ | `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match, ignored if `id` is provided) |
513
513
 
514
514
  **Note:** Either `id` or `title` must be provided. Using `id` is recommended.
515
515
 
@@ -545,7 +545,7 @@ Returns the `notes://showNote?identifier=<uuid>` deep-link URL for a note. The U
545
545
  |-----------|------|----------|-------------|
546
546
  | `id` | string | No | Note ID (preferred - more reliable than title) |
547
547
  | `title` | string | No | Note title (use `id` instead when available) |
548
- | `account` | string | No | Account containing the note (defaults to iCloud, ignored if `id` is provided) |
548
+ | `account` | string | No | Account containing the note (defaults to Notes.app's default account; exact or unique-prefix match, ignored if `id` is provided) |
549
549
 
550
550
  **Note:** Either `id` or `title` must be provided. Using `id` is recommended. Password-protected notes cannot be linked.
551
551
 
@@ -568,7 +568,7 @@ Lists all notes, optionally filtered by folder, date, and limit.
568
568
 
569
569
  | Parameter | Type | Required | Description |
570
570
  |-----------|------|----------|-------------|
571
- | `account` | string | No | Account to list notes from (defaults to iCloud) |
571
+ | `account` | string | No | Account to list notes from (defaults to Notes.app's default account; exact or unique-prefix match) |
572
572
  | `folder` | string | No | Filter to notes in this folder only (supports nested paths like `"Work/Clients"`) |
573
573
  | `modifiedSince` | string | No | ISO 8601 date string to filter notes modified on or after this date (e.g., `"2025-01-01"`) |
574
574
  | `limit` | number | No | Maximum number of notes to return |
@@ -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
 
@@ -615,7 +619,7 @@ Lists all folders in an account with full hierarchical paths.
615
619
 
616
620
  | Parameter | Type | Required | Description |
617
621
  |-----------|------|----------|-------------|
618
- | `account` | string | No | Account to list folders from (defaults to iCloud) |
622
+ | `account` | string | No | Account to list folders from (defaults to Notes.app's default account; exact or unique-prefix match) |
619
623
 
620
624
  **Example:**
621
625
  ```json
@@ -633,7 +637,7 @@ Creates a new folder, including a whole nested hierarchy in one call.
633
637
  | Parameter | Type | Required | Description |
634
638
  |-----------|------|----------|-------------|
635
639
  | `name` | string | Yes | Folder name, or a nested path separated by `/` (e.g. `"Retro Tech/PC/CPUs"`). Every intermediate folder is created; segments that already exist are skipped |
636
- | `account` | string | No | Account to create folder in (defaults to iCloud) |
640
+ | `account` | string | No | Account to create folder in (defaults to Notes.app's default account; exact or unique-prefix match) |
637
641
 
638
642
  **Example:**
639
643
  ```json
@@ -660,7 +664,7 @@ Deletes a folder.
660
664
  | Parameter | Type | Required | Description |
661
665
  |-----------|------|----------|-------------|
662
666
  | `name` | string | Yes | Name or path of the folder to delete (supports nested paths like `"Work/Old"`) |
663
- | `account` | string | No | Account containing the folder (defaults to iCloud) |
667
+ | `account` | string | No | Account containing the folder (defaults to Notes.app's default account; exact or unique-prefix match) |
664
668
 
665
669
  **Example:**
666
670
  ```json
@@ -959,7 +963,10 @@ AI: [calls get-note-content with title="Shopping List"]
959
963
 
960
964
  ### Working with Accounts
961
965
 
962
- By default, all operations use iCloud. To work with other accounts:
966
+ Omit `account` and an operation targets whichever account **Notes.app itself
967
+ reports as the default** — not a hardcoded "iCloud". That matters if your default
968
+ is a non-iCloud account, if the account name is localized, or if it carries a
969
+ trailing U+F8FF () character.
963
970
 
964
971
  ```
965
972
  User: "What accounts do I have?"
@@ -971,6 +978,23 @@ AI: [calls list-notes with account="Gmail"]
971
978
  "Your Gmail account has 5 notes..."
972
979
  ```
973
980
 
981
+ When you do pass `account`, it is resolved in this order:
982
+
983
+ 1. **Exact name match** wins outright.
984
+ 2. A **unique prefix match** resolves — `account="robert"` finds
985
+ `robert.b.sweet@gmail.com`.
986
+ 3. An **ambiguous prefix is refused**, with every candidate named:
987
+
988
+ ```
989
+ Account "rob" is ambiguous - it matches 2 accounts:
990
+ rob@superiortech.io, robert.b.sweet@gmail.com. Use the full account name.
991
+ ```
992
+
993
+ That third rule is deliberate. Silently taking the *first* prefix match would
994
+ make `delete-note` or `move-note` land in the wrong account and report success.
995
+ An unresolvable account is reported as such rather than as "note not found", so
996
+ you are not sent looking for the wrong problem.
997
+
974
998
  ### Organizing with Folders
975
999
 
976
1000
  ```
package/build/index.js CHANGED
@@ -39407,11 +39407,47 @@ function buildFolderReference(folderPath) {
39407
39407
  }
39408
39408
  return parts.reverse().map((part) => `folder "${escapePlainStringForAppleScript(part)}"`).join(" of ");
39409
39409
  }
39410
+ var AS_ACCOUNT_REF = "__acctRef";
39411
+ var ACCOUNT_RESOLUTION_ERROR = "AccountResolutionError:";
39412
+ function throwIfAccountResolutionFailed(error2) {
39413
+ if (!error2) return;
39414
+ const at = error2.indexOf(ACCOUNT_RESOLUTION_ERROR);
39415
+ if (at === -1) return;
39416
+ throw new Error(error2.slice(at + ACCOUNT_RESOLUTION_ERROR.length).trim());
39417
+ }
39418
+ function buildAccountResolution(account) {
39419
+ if (account === void 0) {
39420
+ return `set ${AS_ACCOUNT_REF} to default account`;
39421
+ }
39422
+ const safeAccount = sanitizeAccountName(account);
39423
+ return `
39424
+ set ${AS_ACCOUNT_REF} to missing value
39425
+ set _exactMatches to (every account whose name is "${safeAccount}")
39426
+ if (count of _exactMatches) is 1 then
39427
+ set ${AS_ACCOUNT_REF} to item 1 of _exactMatches
39428
+ else
39429
+ set _prefixMatches to (every account whose name starts with "${safeAccount}")
39430
+ if (count of _prefixMatches) is 1 then
39431
+ set ${AS_ACCOUNT_REF} to item 1 of _prefixMatches
39432
+ else if (count of _prefixMatches) > 1 then
39433
+ set _candidateNames to {}
39434
+ repeat with _candidate in _prefixMatches
39435
+ set end of _candidateNames to name of (contents of _candidate)
39436
+ end repeat
39437
+ set AppleScript's text item delimiters to ", "
39438
+ set _joinedNames to _candidateNames as text
39439
+ set AppleScript's text item delimiters to ""
39440
+ error "${ACCOUNT_RESOLUTION_ERROR} Account \\"${safeAccount}\\" is ambiguous - it matches " & (count of _prefixMatches) & " accounts: " & _joinedNames & ". Use the full account name."
39441
+ end if
39442
+ end if
39443
+ if ${AS_ACCOUNT_REF} is missing value then error "${ACCOUNT_RESOLUTION_ERROR} Account \\"${safeAccount}\\" not found"
39444
+ `;
39445
+ }
39410
39446
  function buildAccountScopedScript(scope, command) {
39411
- const safeAccount = sanitizeAccountName(scope.account);
39412
39447
  return `
39413
39448
  tell application "Notes"
39414
- tell account "${safeAccount}"
39449
+ ${buildAccountResolution(scope.account)}
39450
+ tell ${AS_ACCOUNT_REF}
39415
39451
  ${command}
39416
39452
  end tell
39417
39453
  end tell
@@ -39452,16 +39488,48 @@ function extractCoreDataId(output, prefix) {
39452
39488
  }
39453
39489
  var AppleNotesManager = class {
39454
39490
  /**
39455
- * Default account used when no account is specified.
39456
- * iCloud is the primary account for most Apple Notes users.
39491
+ * Normalizes a caller-supplied account name for the script builders.
39492
+ *
39493
+ * Returns `undefined` when no account was requested, which
39494
+ * {@link buildAccountResolution} turns into Notes.app's own
39495
+ * `default account`. It deliberately no longer substitutes a hardcoded
39496
+ * `"iCloud"` — that name is wrong for anyone whose default account differs,
39497
+ * is localized, or carries a U+F8FF suffix (#128).
39457
39498
  */
39458
- defaultAccount = "iCloud";
39499
+ resolveAccount(account) {
39500
+ const trimmed = account?.trim();
39501
+ return trimmed ? trimmed : void 0;
39502
+ }
39459
39503
  /**
39460
- * Resolves the account to use for an operation.
39461
- * Falls back to default if not specified.
39504
+ * Cached name of Notes.app's default account, for payload reporting only.
39505
+ * `null` = not yet queried; `""` = queried and unavailable (don't retry).
39462
39506
  */
39463
- resolveAccount(account) {
39464
- return account || this.defaultAccount;
39507
+ defaultAccountName = null;
39508
+ /**
39509
+ * The account name to report back in a returned payload.
39510
+ *
39511
+ * Returns the caller's account verbatim when they named one. When they did
39512
+ * not, it reports the *real* default account rather than the hardcoded
39513
+ * "iCloud" the payloads used to claim (#128).
39514
+ *
39515
+ * Most scripts resolve the account inline via {@link buildAccountResolution}
39516
+ * and cost nothing extra; this exists for the handful of methods whose script
39517
+ * output can't carry the name back — notably `createNote`, whose nested-folder
39518
+ * branch depends on the implicit result of `make new note` and must not have
39519
+ * its return value extended (the -1728 workaround above).
39520
+ *
39521
+ * The lookup runs at most once per manager instance and is cached, including
39522
+ * the failure case, so a Notes.app that can't answer is not re-asked on every
39523
+ * call. Returns `undefined` when unknown — `account` is an optional field, and
39524
+ * omitting it is honest where guessing was not.
39525
+ */
39526
+ reportedAccount(targetAccount) {
39527
+ if (targetAccount !== void 0) return targetAccount;
39528
+ if (this.defaultAccountName === null) {
39529
+ const result = executeAppleScript(buildAppLevelScript("return name of default account"));
39530
+ this.defaultAccountName = result.success ? result.output.trim() : "";
39531
+ }
39532
+ return this.defaultAccountName || void 0;
39465
39533
  }
39466
39534
  /**
39467
39535
  * Checks if a note is password-protected by its ID.
@@ -39481,7 +39549,7 @@ var AppleNotesManager = class {
39481
39549
  * Checks if a note is password-protected by its title.
39482
39550
  *
39483
39551
  * @param title - Exact title of the note
39484
- * @param account - Account to search in (defaults to iCloud)
39552
+ * @param account - Account to search in (defaults to Notes.app's default account)
39485
39553
  * @returns true if the note is password-protected, false otherwise
39486
39554
  */
39487
39555
  isNotePasswordProtected(title, account) {
@@ -39502,7 +39570,7 @@ var AppleNotesManager = class {
39502
39570
  * @param content - Body content (plain text that will be HTML-escaped, or raw HTML when format is "html")
39503
39571
  * @param tags - Optional tags (stored in returned object, not used by Notes.app)
39504
39572
  * @param folder - Optional folder name to create the note in
39505
- * @param account - Account to use (defaults to iCloud)
39573
+ * @param account - Account to use (defaults to Notes.app's default account)
39506
39574
  * @param format - Content format: "plaintext" escapes and wraps in div tags (default), "html" uses content as-is
39507
39575
  * @returns Created Note object with metadata, or null on failure
39508
39576
  *
@@ -39542,6 +39610,7 @@ var AppleNotesManager = class {
39542
39610
  const script = buildAccountScopedScript({ account: targetAccount }, createCommand);
39543
39611
  const result = executeMutationAppleScript(script);
39544
39612
  if (!result.success) {
39613
+ throwIfAccountResolutionFailed(result.error);
39545
39614
  console.error(`Failed to create note "${title}":`, result.error);
39546
39615
  return null;
39547
39616
  }
@@ -39557,7 +39626,7 @@ var AppleNotesManager = class {
39557
39626
  created: now,
39558
39627
  modified: now,
39559
39628
  folder,
39560
- account: targetAccount
39629
+ account: this.reportedAccount(targetAccount)
39561
39630
  };
39562
39631
  }
39563
39632
  /**
@@ -39568,7 +39637,7 @@ var AppleNotesManager = class {
39568
39637
  *
39569
39638
  * @param query - Text to search for
39570
39639
  * @param searchContent - If true, search note bodies; if false, search titles
39571
- * @param account - Account to search in (defaults to iCloud)
39640
+ * @param account - Account to search in (defaults to Notes.app's default account)
39572
39641
  * @param folder - Optional folder to limit search to
39573
39642
  * @param modifiedSince - Optional ISO 8601 date string to filter notes modified on or after this date
39574
39643
  * @param limit - Optional maximum number of results to return (default: no limit)
@@ -39660,6 +39729,7 @@ var AppleNotesManager = class {
39660
39729
  const items = result.output.split(RECORD_SEP);
39661
39730
  const notes = [];
39662
39731
  const seenIds = /* @__PURE__ */ new Set();
39732
+ const reportedAccount = this.reportedAccount(targetAccount);
39663
39733
  for (const item of items) {
39664
39734
  const [title, id, folder2, created, modified] = item.split(FIELD_SEP);
39665
39735
  if (!title?.trim()) continue;
@@ -39675,7 +39745,7 @@ var AppleNotesManager = class {
39675
39745
  created: parseAppleScriptDate(created ?? ""),
39676
39746
  modified: parseAppleScriptDate(modified ?? ""),
39677
39747
  folder: folder2?.trim(),
39678
- account: targetAccount
39748
+ account: reportedAccount
39679
39749
  });
39680
39750
  }
39681
39751
  return notes;
@@ -39688,7 +39758,7 @@ var AppleNotesManager = class {
39688
39758
  * getNoteDetails() or isNotePasswordProtected().
39689
39759
  *
39690
39760
  * @param title - Exact title of the note
39691
- * @param account - Account to search in (defaults to iCloud)
39761
+ * @param account - Account to search in (defaults to Notes.app's default account)
39692
39762
  * @returns HTML content of the note, or empty string if not found
39693
39763
  *
39694
39764
  * @example
@@ -39706,6 +39776,7 @@ var AppleNotesManager = class {
39706
39776
  const script = buildAccountScopedScript({ account: targetAccount }, getCommand);
39707
39777
  const result = executeAppleScript(script);
39708
39778
  if (!result.success) {
39779
+ throwIfAccountResolutionFailed(result.error);
39709
39780
  console.error(`Failed to get content of note "${title}":`, result.error);
39710
39781
  return "";
39711
39782
  }
@@ -39744,7 +39815,7 @@ var AppleNotesManager = class {
39744
39815
  * round-trip entirely.
39745
39816
  *
39746
39817
  * @param title - Exact title of the note
39747
- * @param account - Account to search in (defaults to iCloud)
39818
+ * @param account - Account to search in (defaults to Notes.app's default account)
39748
39819
  * @returns Plain-text content of the note, or empty string if not found
39749
39820
  */
39750
39821
  getNotePlaintext(title, account) {
@@ -39754,6 +39825,7 @@ var AppleNotesManager = class {
39754
39825
  const script = buildAccountScopedScript({ account: targetAccount }, getCommand);
39755
39826
  const result = executeAppleScript(script);
39756
39827
  if (!result.success) {
39828
+ throwIfAccountResolutionFailed(result.error);
39757
39829
  console.error(`Failed to get plaintext of note "${title}":`, result.error);
39758
39830
  return "";
39759
39831
  }
@@ -39832,7 +39904,7 @@ var AppleNotesManager = class {
39832
39904
  * including creation date, modification date, and sharing status.
39833
39905
  *
39834
39906
  * @param title - Exact title of the note
39835
- * @param account - Account to search in (defaults to iCloud)
39907
+ * @param account - Account to search in (defaults to Notes.app's default account)
39836
39908
  * @returns Note object with full metadata, or null if not found
39837
39909
  */
39838
39910
  getNoteDetails(title, account) {
@@ -39849,6 +39921,7 @@ var AppleNotesManager = class {
39849
39921
  const script = buildAccountScopedScript({ account: targetAccount }, getCommand);
39850
39922
  const result = executeAppleScript(script);
39851
39923
  if (!result.success) {
39924
+ throwIfAccountResolutionFailed(result.error);
39852
39925
  console.error(`Failed to get details for note "${title}":`, result.error);
39853
39926
  return null;
39854
39927
  }
@@ -39866,7 +39939,7 @@ var AppleNotesManager = class {
39866
39939
  modified: parsed.modified,
39867
39940
  shared: parsed.shared,
39868
39941
  passwordProtected: parsed.passwordProtected,
39869
- account: targetAccount
39942
+ account: this.reportedAccount(targetAccount)
39870
39943
  };
39871
39944
  }
39872
39945
  /**
@@ -39876,7 +39949,7 @@ var AppleNotesManager = class {
39876
39949
  * from the "Recently Deleted" folder in Notes.app.
39877
39950
  *
39878
39951
  * @param title - Exact title of the note to delete
39879
- * @param account - Account containing the note (defaults to iCloud)
39952
+ * @param account - Account containing the note (defaults to Notes.app's default account)
39880
39953
  * @returns true if deletion succeeded, false otherwise
39881
39954
  */
39882
39955
  deleteNote(title, account) {
@@ -39886,6 +39959,7 @@ var AppleNotesManager = class {
39886
39959
  const script = buildAccountScopedScript({ account: targetAccount }, deleteCommand);
39887
39960
  const result = executeMutationAppleScript(script);
39888
39961
  if (!result.success) {
39962
+ throwIfAccountResolutionFailed(result.error);
39889
39963
  console.error(`Failed to delete note "${title}":`, result.error);
39890
39964
  return false;
39891
39965
  }
@@ -39928,7 +40002,7 @@ var AppleNotesManager = class {
39928
40002
  * @param title - Current title of the note to update
39929
40003
  * @param newTitle - New title (optional, keeps existing if not provided; ignored in html format)
39930
40004
  * @param newContent - New content for the note body
39931
- * @param account - Account containing the note (defaults to iCloud)
40005
+ * @param account - Account containing the note (defaults to Notes.app's default account)
39932
40006
  * @param format - Content format: "plaintext" wraps in div tags (default), "html" uses content as-is
39933
40007
  * @returns true if update succeeded, false otherwise
39934
40008
  */
@@ -39950,6 +40024,7 @@ var AppleNotesManager = class {
39950
40024
  const script = buildAccountScopedScript({ account: targetAccount }, updateCommand);
39951
40025
  const result = executeMutationAppleScript(script);
39952
40026
  if (!result.success) {
40027
+ throwIfAccountResolutionFailed(result.error);
39953
40028
  console.error(`Failed to update note "${title}":`, result.error);
39954
40029
  return false;
39955
40030
  }
@@ -40100,29 +40175,12 @@ var AppleNotesManager = class {
40100
40175
  return refs;
40101
40176
  }
40102
40177
  /**
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.
40178
+ * Core listing path shared by `listNotes()` and `listNoteRefs()`: lists
40179
+ * notes in an account, optionally filtered by folder, date, and limit,
40180
+ * returning (title, id) pairs. Kept private because both public callers
40181
+ * need to apply their own return shape.
40106
40182
  */
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) {
40183
+ listNotesCore(account, folder, modifiedSince, limit) {
40126
40184
  const targetAccount = this.resolveAccount(account);
40127
40185
  const safeLimit = limit !== void 0 && limit > 0 ? Math.floor(limit) : void 0;
40128
40186
  const folderRef = folder ? buildFolderReference(folder) : void 0;
@@ -40148,7 +40206,7 @@ var AppleNotesManager = class {
40148
40206
  const records = sepIdx === -1 ? "" : result2.output.slice(sepIdx + 1);
40149
40207
  const refs = this.parseBulkListOutput(records, safeLimit);
40150
40208
  if (!Number.isNaN(totalCount) && (refs.length >= safeLimit || totalCount <= safeLimit)) {
40151
- return refs.map((ref) => ref.title);
40209
+ return refs;
40152
40210
  }
40153
40211
  }
40154
40212
  const script = buildAccountScopedScript(
@@ -40159,7 +40217,33 @@ var AppleNotesManager = class {
40159
40217
  if (!result.success) {
40160
40218
  throw new Error(`Failed to list notes: ${result.error ?? "unknown error"}`);
40161
40219
  }
40162
- return this.parseBulkListOutput(result.output, safeLimit).map((ref) => ref.title);
40220
+ return this.parseBulkListOutput(result.output, safeLimit);
40221
+ }
40222
+ /**
40223
+ * Lists all notes in an account, optionally filtered by folder, date, and limit.
40224
+ *
40225
+ * @param account - Account to list notes from (defaults to Notes.app's default account)
40226
+ * @param folder - Optional folder to filter by
40227
+ * @param modifiedSince - Optional ISO 8601 date string to filter notes modified on or after this date
40228
+ * @param limit - Optional maximum number of results to return (default: no limit)
40229
+ * @returns Array of note titles
40230
+ */
40231
+ listNotes(account, folder, modifiedSince, limit) {
40232
+ return this.listNotesCore(account, folder, modifiedSince, limit).map((ref) => ref.title);
40233
+ }
40234
+ /**
40235
+ * Lists all notes in an account, optionally filtered by folder, date, and
40236
+ * limit — same filtering semantics as `listNotes()`, but returns each
40237
+ * note's id alongside its title. Prefer this over `listNotes()` when the
40238
+ * caller needs to resolve notes by identity afterward: re-resolving by
40239
+ * title is unsafe when titles are duplicated (AppleScript's `note "<name>"`
40240
+ * specifier resolves ambiguously to the same one note every time — see
40241
+ * the fix in exportNotesAsJson for the failure mode this avoids).
40242
+ *
40243
+ * @returns Array of { title, id } pairs, deduplicated by id
40244
+ */
40245
+ listNoteRefs(account, folder, modifiedSince, limit) {
40246
+ return this.listNotesCore(account, folder, modifiedSince, limit);
40163
40247
  }
40164
40248
  /**
40165
40249
  * Lists all shared (collaborative) notes across all accounts.
@@ -40239,12 +40323,13 @@ var AppleNotesManager = class {
40239
40323
  * so that duplicate folder names (e.g., multiple "Archive" folders) are
40240
40324
  * distinguishable and can be used directly in other operations.
40241
40325
  *
40242
- * @param account - Account to list folders from (defaults to iCloud)
40326
+ * @param account - Account to list folders from (defaults to Notes.app's default account)
40243
40327
  * @returns Array of Folder objects with path-based names
40244
40328
  */
40245
40329
  listFolders(account) {
40246
40330
  const targetAccount = this.resolveAccount(account);
40247
40331
  const listCommand = `
40332
+ set acctName to name of it
40248
40333
  set folderList to {}
40249
40334
  set allFolders to every folder
40250
40335
  repeat with f in allFolders
@@ -40255,7 +40340,7 @@ var AppleNotesManager = class {
40255
40340
  set parentId to id of cRef
40256
40341
  end if
40257
40342
  set sharedFlag to shared of fRef as text
40258
- set end of folderList to (id of fRef) & ${AS_FIELD_SEP} & (name of fRef) & ${AS_FIELD_SEP} & parentId & ${AS_FIELD_SEP} & sharedFlag
40343
+ set end of folderList to (id of fRef) & ${AS_FIELD_SEP} & (name of fRef) & ${AS_FIELD_SEP} & parentId & ${AS_FIELD_SEP} & sharedFlag & ${AS_FIELD_SEP} & acctName
40259
40344
  end repeat
40260
40345
  set AppleScript's text item delimiters to ${AS_RECORD_SEP}
40261
40346
  return folderList as text
@@ -40275,7 +40360,11 @@ var AppleNotesManager = class {
40275
40360
  id: (parts[0] || "").trim(),
40276
40361
  name: (parts[1] || "").trim(),
40277
40362
  parentId: (parts[2] || "").trim(),
40278
- shared: (parts[3] || "").trim().toLowerCase() === "true"
40363
+ shared: (parts[3] || "").trim().toLowerCase() === "true",
40364
+ // The account name as Notes.app actually reports it. When the caller
40365
+ // omitted `account` this is the resolved default, which is the whole
40366
+ // point — reporting a hardcoded "iCloud" here was the #128 bug.
40367
+ account: (parts[4] || "").trim()
40279
40368
  };
40280
40369
  });
40281
40370
  const byId = new Map(entries.map((e) => [e.id, e]));
@@ -40291,7 +40380,7 @@ var AppleNotesManager = class {
40291
40380
  return entries.map((entry) => ({
40292
40381
  id: entry.id,
40293
40382
  name: buildPath(entry),
40294
- account: targetAccount,
40383
+ account: entry.account || targetAccount || "",
40295
40384
  shared: entry.shared
40296
40385
  }));
40297
40386
  }
@@ -40299,7 +40388,7 @@ var AppleNotesManager = class {
40299
40388
  * Creates a new folder in an account.
40300
40389
  *
40301
40390
  * @param name - Name for the new folder
40302
- * @param account - Account to create folder in (defaults to iCloud)
40391
+ * @param account - Account to create folder in (defaults to Notes.app's default account)
40303
40392
  * @returns Created Folder object, or null on failure
40304
40393
  */
40305
40394
  createFolder(name, account) {
@@ -40332,6 +40421,7 @@ var AppleNotesManager = class {
40332
40421
  const script = buildAccountScopedScript({ account: targetAccount }, createCommand);
40333
40422
  const result = executeMutationAppleScript(script);
40334
40423
  if (!result.success) {
40424
+ throwIfAccountResolutionFailed(result.error);
40335
40425
  console.error(`Failed to create folder "${name}":`, result.error);
40336
40426
  return null;
40337
40427
  }
@@ -40339,14 +40429,15 @@ var AppleNotesManager = class {
40339
40429
  const fullRef = buildFolderReference(name);
40340
40430
  const idScript = buildAccountScopedScript(
40341
40431
  { account: targetAccount },
40342
- `return id of ${fullRef}`
40432
+ `return (id of ${fullRef}) & ${AS_FIELD_SEP} & (name of it)`
40343
40433
  );
40344
40434
  const idResult = executeAppleScript(idScript);
40345
- const folderId = idResult.success ? extractCoreDataId(idResult.output, "folder") : "";
40435
+ const [rawId = "", rawAccount = ""] = idResult.success ? idResult.output.split(FIELD_SEP) : [];
40436
+ const folderId = idResult.success ? extractCoreDataId(rawId, "folder") : "";
40346
40437
  return {
40347
40438
  id: folderId,
40348
40439
  name,
40349
- account: targetAccount
40440
+ account: rawAccount.trim() || targetAccount || ""
40350
40441
  };
40351
40442
  }
40352
40443
  /**
@@ -40355,7 +40446,7 @@ var AppleNotesManager = class {
40355
40446
  * Note: This may fail if the folder contains notes.
40356
40447
  *
40357
40448
  * @param name - Name of the folder to delete
40358
- * @param account - Account containing the folder (defaults to iCloud)
40449
+ * @param account - Account containing the folder (defaults to Notes.app's default account)
40359
40450
  * @returns true if deletion succeeded, false otherwise
40360
40451
  */
40361
40452
  deleteFolder(name, account) {
@@ -40364,6 +40455,7 @@ var AppleNotesManager = class {
40364
40455
  const script = buildAccountScopedScript({ account: targetAccount }, deleteCommand);
40365
40456
  const result = executeMutationAppleScript(script);
40366
40457
  if (!result.success) {
40458
+ throwIfAccountResolutionFailed(result.error);
40367
40459
  console.error(`Failed to delete folder "${name}":`, result.error);
40368
40460
  return false;
40369
40461
  }
@@ -40383,7 +40475,7 @@ var AppleNotesManager = class {
40383
40475
  *
40384
40476
  * @param title - Title of the note to move
40385
40477
  * @param destinationFolder - Name of the folder to move to (must already exist)
40386
- * @param account - Account containing the note (defaults to iCloud)
40478
+ * @param account - Account containing the note (defaults to Notes.app's default account)
40387
40479
  * @returns true if the move succeeded, false otherwise
40388
40480
  */
40389
40481
  moveNote(title, destinationFolder, account) {
@@ -40405,15 +40497,15 @@ var AppleNotesManager = class {
40405
40497
  *
40406
40498
  * @param id - CoreData URL identifier for the note
40407
40499
  * @param destinationFolder - Name of the folder to move to (must already exist)
40408
- * @param account - Account containing the destination folder (defaults to iCloud)
40500
+ * @param account - Account containing the destination folder (defaults to Notes.app's default account)
40409
40501
  * @returns true if the move succeeded, false otherwise
40410
40502
  */
40411
40503
  moveNoteById(id, destinationFolder, account) {
40412
40504
  const targetAccount = this.resolveAccount(account);
40413
40505
  const safeId = sanitizeId(id);
40414
- const safeAccount = sanitizeAccountName(targetAccount);
40415
- const destFolderRef = `${buildFolderReference(destinationFolder)} of account "${safeAccount}"`;
40506
+ const destFolderRef = `${buildFolderReference(destinationFolder)} of ${AS_ACCOUNT_REF}`;
40416
40507
  const moveCommand = `
40508
+ ${buildAccountResolution(targetAccount)}
40417
40509
  set destFolder to ${destFolderRef}
40418
40510
  set noteRef to note id "${safeId}"
40419
40511
  move noteRef to destFolder
@@ -40421,6 +40513,7 @@ var AppleNotesManager = class {
40421
40513
  const script = buildAppLevelScript(moveCommand);
40422
40514
  const result = executeMutationAppleScript(script);
40423
40515
  if (!result.success) {
40516
+ throwIfAccountResolutionFailed(result.error);
40424
40517
  console.error(
40425
40518
  `Cannot move note to "${destinationFolder}" (folder may not exist):`,
40426
40519
  result.error
@@ -40616,7 +40709,7 @@ var AppleNotesManager = class {
40616
40709
  * Returns the notes:// deep-link URL for a note by title.
40617
40710
  *
40618
40711
  * @param title - Exact note title
40619
- * @param account - Account to search in (defaults to iCloud)
40712
+ * @param account - Account to search in (defaults to Notes.app's default account)
40620
40713
  * @returns notes://showNote?identifier=<uuid> string, or null on failure
40621
40714
  */
40622
40715
  getNoteLink(title, account) {
@@ -40790,12 +40883,11 @@ var AppleNotesManager = class {
40790
40883
  });
40791
40884
  return { healthy: false, checks };
40792
40885
  }
40793
- const defaultAccount = accounts[0]?.name || "iCloud";
40794
- const notes = this.listNotes(defaultAccount);
40886
+ const notes = this.listNotes();
40795
40887
  checks.push({
40796
40888
  name: "operations",
40797
40889
  passed: true,
40798
- message: `Basic operations working (${notes.length} note(s) in ${defaultAccount})`
40890
+ message: `Basic operations working (${notes.length} note(s) in the default account)`
40799
40891
  });
40800
40892
  const allPassed = checks.every((c) => c.passed);
40801
40893
  return { healthy: allPassed, checks };
@@ -41017,18 +41109,18 @@ var AppleNotesManager = class {
41017
41109
  * Lists attachments for a note by its title.
41018
41110
  *
41019
41111
  * @param title - Title of the note
41020
- * @param account - Account containing the note (defaults to iCloud)
41112
+ * @param account - Account containing the note (defaults to Notes.app's default account)
41021
41113
  * @returns Array of Attachment objects, or empty array if the note genuinely has none
41022
41114
  * @throws If the AppleScript call fails, so a lookup failure is never mistaken for
41023
41115
  * an attachment-free note (callers gate destructive full-body updates on this)
41024
41116
  */
41025
41117
  listAttachments(title, account) {
41026
41118
  const targetAccount = this.resolveAccount(account);
41027
- const safeAccount = escapePlainStringForAppleScript(targetAccount);
41028
41119
  const safeTitle = escapePlainStringForAppleScript(title);
41029
41120
  const script = `
41030
41121
  tell application "Notes"
41031
- tell account "${safeAccount}"
41122
+ ${buildAccountResolution(targetAccount)}
41123
+ tell ${AS_ACCOUNT_REF}
41032
41124
  set theNote to note "${safeTitle}"
41033
41125
  set attachmentList to {}
41034
41126
  set attachmentIds to id of every attachment of theNote
@@ -41328,7 +41420,7 @@ var AppleNotesManager = class {
41328
41420
  *
41329
41421
  * @param ids - Array of CoreData URL identifiers for notes to move
41330
41422
  * @param folder - Destination folder name
41331
- * @param account - Account containing the folder (defaults to iCloud)
41423
+ * @param account - Account containing the folder (defaults to Notes.app's default account)
41332
41424
  * @returns Array of results with id, success status, and optional error message
41333
41425
  *
41334
41426
  * @example
@@ -41342,8 +41434,7 @@ var AppleNotesManager = class {
41342
41434
  batchMoveNotes(ids, folder, account) {
41343
41435
  if (ids.length === 0) return [];
41344
41436
  const targetAccount = this.resolveAccount(account);
41345
- const safeAccount = sanitizeAccountName(targetAccount);
41346
- const destFolderRef = `${buildFolderReference(folder)} of account "${safeAccount}"`;
41437
+ const destFolderRef = `${buildFolderReference(folder)} of ${AS_ACCOUNT_REF}`;
41347
41438
  const results = new Array(ids.length);
41348
41439
  const runnable = [];
41349
41440
  ids.forEach((id, i) => {
@@ -41360,6 +41451,7 @@ var AppleNotesManager = class {
41360
41451
  if (runnable.length > 0) {
41361
41452
  const idList = runnable.map((r) => `"${r.safe}"`).join(", ");
41362
41453
  const script = buildAppLevelScript(`
41454
+ ${buildAccountResolution(targetAccount)}
41363
41455
  set destFolder to ${destFolderRef}
41364
41456
  set out to ""
41365
41457
  repeat with rawId in {${idList}}
@@ -41391,6 +41483,7 @@ var AppleNotesManager = class {
41391
41483
  `);
41392
41484
  const res = executeMutationAppleScript(script);
41393
41485
  if (!res.success) {
41486
+ throwIfAccountResolutionFailed(res.error);
41394
41487
  for (const r of runnable) {
41395
41488
  results[r.index] = this.createBatchResult(
41396
41489
  ids[r.index],
@@ -41571,7 +41664,7 @@ var AppleNotesManager = class {
41571
41664
  * [x] (done) or [ ] (undone) prefixes.
41572
41665
  *
41573
41666
  * @param title - Exact title of the note
41574
- * @param account - Account containing the note (defaults to iCloud)
41667
+ * @param account - Account containing the note (defaults to Notes.app's default account)
41575
41668
  * @returns Markdown content, or empty string if not found
41576
41669
  *
41577
41670
  * @example
@@ -42162,11 +42255,15 @@ var MAX = {
42162
42255
  };
42163
42256
  var noteTitleSchema = {
42164
42257
  title: external_exports.string().min(1, "Note title is required").max(MAX.TITLE),
42165
- account: external_exports.string().max(MAX.ACCOUNT).optional().describe("Account name (defaults to iCloud)")
42258
+ account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
42259
+ "Account name (defaults to Notes.app's default account; exact or unique-prefix match)"
42260
+ )
42166
42261
  };
42167
42262
  var folderNameSchema = {
42168
42263
  name: external_exports.string().min(1, "Folder name is required").max(MAX.FOLDER),
42169
- account: external_exports.string().max(MAX.ACCOUNT).optional().describe("Account name (defaults to iCloud)")
42264
+ account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
42265
+ "Account name (defaults to Notes.app's default account; exact or unique-prefix match)"
42266
+ )
42170
42267
  };
42171
42268
  function registerTool(name, config2, cb) {
42172
42269
  const { outputSchema, ...rest } = config2;
@@ -42193,7 +42290,7 @@ registerTool(
42193
42290
  "Folder to create the note in (supports nested paths like 'Work/Clients'). The folder must already exist \u2014 this tool does not create it; call create-folder first, which is idempotent and creates intermediate segments."
42194
42291
  ),
42195
42292
  account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
42196
- "Account name (defaults to iCloud). Must be an account Notes.app already has configured \u2014 see list-accounts."
42293
+ "Account name (defaults to the account Notes.app itself reports as default). Matched exactly, or by a unique prefix; an ambiguous prefix is refused. Must be an account Notes.app already has configured \u2014 see list-accounts."
42197
42294
  )
42198
42295
  },
42199
42296
  outputSchema: {
@@ -42302,7 +42399,9 @@ registerTool(
42302
42399
  inputSchema: {
42303
42400
  id: external_exports.string().max(MAX.ID).optional().describe("Note ID (preferred - more reliable than title)"),
42304
42401
  title: external_exports.string().max(MAX.TITLE).optional().describe("Note title (use id instead when available)"),
42305
- account: external_exports.string().max(MAX.ACCOUNT).optional().describe("Account name (defaults to iCloud, ignored if id is provided)")
42402
+ account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
42403
+ "Account name (defaults to Notes.app's default account; exact or unique-prefix match, ignored if id is provided)"
42404
+ )
42306
42405
  },
42307
42406
  outputSchema: {
42308
42407
  title: external_exports.string().optional(),
@@ -42377,7 +42476,9 @@ registerTool(
42377
42476
  inputSchema: {
42378
42477
  id: external_exports.string().max(MAX.ID).optional().describe("Note ID (preferred - more reliable than title)"),
42379
42478
  title: external_exports.string().max(MAX.TITLE).optional().describe("Note title (use id instead when available)"),
42380
- account: external_exports.string().max(MAX.ACCOUNT).optional().describe("Account name (defaults to iCloud, ignored if id is provided)")
42479
+ account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
42480
+ "Account name (defaults to Notes.app's default account; exact or unique-prefix match, ignored if id is provided)"
42481
+ )
42381
42482
  },
42382
42483
  outputSchema: {
42383
42484
  title: external_exports.string().optional(),
@@ -42800,7 +42901,9 @@ registerTool(
42800
42901
  inputSchema: {
42801
42902
  id: external_exports.string().max(MAX.ID).optional().describe("Note ID (preferred - more reliable than title)"),
42802
42903
  title: external_exports.string().max(MAX.TITLE).optional().describe("Note title (use id instead when available)"),
42803
- account: external_exports.string().max(MAX.ACCOUNT).optional().describe("Account name (defaults to iCloud, ignored if id is provided)")
42904
+ account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
42905
+ "Account name (defaults to Notes.app's default account; exact or unique-prefix match, ignored if id is provided)"
42906
+ )
42804
42907
  },
42805
42908
  outputSchema: {
42806
42909
  ok: external_exports.boolean().optional(),
@@ -42909,7 +43012,7 @@ registerTool(
42909
43012
  registerTool(
42910
43013
  "list-notes",
42911
43014
  {
42912
- 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.",
43015
+ 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.",
42913
43016
  inputSchema: {
42914
43017
  account: external_exports.string().max(MAX.ACCOUNT).optional().describe("Account to list notes from"),
42915
43018
  folder: external_exports.string().max(MAX.FOLDER).optional().describe("Filter to specific folder"),
@@ -42919,7 +43022,7 @@ registerTool(
42919
43022
  limit: external_exports.number().int().positive().optional().describe("Maximum number of notes to return")
42920
43023
  },
42921
43024
  outputSchema: {
42922
- notes: external_exports.array(external_exports.string()).optional(),
43025
+ notes: external_exports.array(external_exports.object({ title: external_exports.string(), id: external_exports.string() })).optional(),
42923
43026
  count: external_exports.number().optional()
42924
43027
  }
42925
43028
  },
@@ -42930,7 +43033,7 @@ registerTool(
42930
43033
  syncInterference
42931
43034
  } = withSyncAwarenessSync(
42932
43035
  "list-notes",
42933
- () => notesManager.listNotes(account, folder, modifiedSince, limit)
43036
+ () => notesManager.listNoteRefs(account, folder, modifiedSince, limit)
42934
43037
  );
42935
43038
  const location = folder ? ` in folder "${folder}"` : "";
42936
43039
  const acct = account ? ` (${account})` : "";
@@ -42952,7 +43055,7 @@ ${syncWarnings.join(" ")}` : "";
42952
43055
  count: 0
42953
43056
  });
42954
43057
  }
42955
- const noteList = notes.map((t) => ` - ${t}`).join("\n");
43058
+ const noteList = notes.map((n) => ` - ${n.title} [id: ${n.id}]`).join("\n");
42956
43059
  return successResponse(
42957
43060
  `Found ${notes.length} notes${location}${acct}${dateInfo}${limitInfo}:
42958
43061
  ${noteList}${syncNote}`,
@@ -43015,12 +43118,16 @@ ${syncWarnings.join(" ")}` : "";
43015
43118
  if (folders.length === 0) {
43016
43119
  return successResponse(`No folders found${acct}${syncNote}`, { folders: [], count: 0 });
43017
43120
  }
43121
+ const resolvedAcct = folders[0]?.account ? ` (${folders[0].account})` : acct;
43018
43122
  const folderList = folders.map((f) => ` - ${f.name}`).join("\n");
43019
- return successResponse(`Found ${folders.length} folders${acct}:
43020
- ${folderList}${syncNote}`, {
43021
- folders,
43022
- count: folders.length
43023
- });
43123
+ return successResponse(
43124
+ `Found ${folders.length} folders${resolvedAcct}:
43125
+ ${folderList}${syncNote}`,
43126
+ {
43127
+ folders,
43128
+ count: folders.length
43129
+ }
43130
+ );
43024
43131
  }, "Error listing folders")
43025
43132
  );
43026
43133
  registerTool(
@@ -43031,7 +43138,9 @@ registerTool(
43031
43138
  name: external_exports.string().min(1, "Folder name is required").max(MAX.FOLDER).describe(
43032
43139
  'Folder name or nested path separated by "/". E.g., "Retro Tech/PC/CPUs" creates all intermediate folders. Existing segments are skipped.'
43033
43140
  ),
43034
- account: external_exports.string().max(MAX.ACCOUNT).optional().describe("Account name (defaults to iCloud)")
43141
+ account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
43142
+ "Account name (defaults to Notes.app's default account; exact or unique-prefix match)"
43143
+ )
43035
43144
  },
43036
43145
  outputSchema: {
43037
43146
  ok: external_exports.boolean().optional(),
@@ -43374,7 +43483,9 @@ registerTool(
43374
43483
  folder: external_exports.string().max(MAX.FOLDER).describe(
43375
43484
  'Destination folder name or nested path (e.g. "Work/Clients"). Must already exist \u2014 create-folder first.'
43376
43485
  ),
43377
- account: external_exports.string().max(MAX.ACCOUNT).optional().describe("Account containing the destination folder (defaults to iCloud)")
43486
+ account: external_exports.string().max(MAX.ACCOUNT).optional().describe(
43487
+ "Account containing the destination folder (defaults to Notes.app's default account; exact or unique-prefix match)"
43488
+ )
43378
43489
  },
43379
43490
  outputSchema: {
43380
43491
  ok: external_exports.boolean().optional(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-notes-mcp",
3
- "version": "2.6.16",
3
+ "version": "2.7.1",
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",