apple-notes-mcp 2.0.0 → 2.0.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.
@@ -634,7 +634,7 @@ export class AppleNotesManager {
634
634
  */
635
635
  searchNotes(query, searchContent = false, account, folder, modifiedSince, limit) {
636
636
  const targetAccount = this.resolveAccount(account);
637
- const safeQuery = escapeForAppleScript(query);
637
+ const safeQuery = escapePlainStringForAppleScript(query);
638
638
  const safeLimit = limit !== undefined && limit > 0 ? Math.floor(limit) : undefined;
639
639
  // Build the where clause based on search type
640
640
  // AppleScript uses 'name' for title and 'body' for content
@@ -738,7 +738,7 @@ export class AppleNotesManager {
738
738
  */
739
739
  getNoteContent(title, account) {
740
740
  const targetAccount = this.resolveAccount(account);
741
- const safeTitle = escapeForAppleScript(title);
741
+ const safeTitle = escapePlainStringForAppleScript(title);
742
742
  // Retrieve the body property of the note
743
743
  const getCommand = `get body of note "${safeTitle}"`;
744
744
  const script = buildAccountScopedScript({ account: targetAccount }, getCommand);
@@ -830,7 +830,7 @@ export class AppleNotesManager {
830
830
  */
831
831
  getNoteDetails(title, account) {
832
832
  const targetAccount = this.resolveAccount(account);
833
- const safeTitle = escapeForAppleScript(title);
833
+ const safeTitle = escapePlainStringForAppleScript(title);
834
834
  // Fetch multiple properties at once
835
835
  const getCommand = `
836
836
  set n to note "${safeTitle}"
@@ -875,7 +875,7 @@ export class AppleNotesManager {
875
875
  */
876
876
  deleteNote(title, account) {
877
877
  const targetAccount = this.resolveAccount(account);
878
- const safeTitle = escapeForAppleScript(title);
878
+ const safeTitle = escapePlainStringForAppleScript(title);
879
879
  const deleteCommand = `delete note "${safeTitle}"`;
880
880
  const script = buildAccountScopedScript({ account: targetAccount }, deleteCommand);
881
881
  const result = executeAppleScript(script);
@@ -931,7 +931,7 @@ export class AppleNotesManager {
931
931
  validateLength(newTitle, MAX_TITLE_LENGTH, "Note title");
932
932
  validateLength(newContent, MAX_CONTENT_LENGTH, "Note content");
933
933
  const targetAccount = this.resolveAccount(account);
934
- const safeCurrentTitle = escapeForAppleScript(title);
934
+ const safeCurrentTitle = escapePlainStringForAppleScript(title);
935
935
  let fullBody;
936
936
  if (format === "html") {
937
937
  // HTML mode: content is the complete body, escaped only for AppleScript string
@@ -1251,7 +1251,7 @@ export class AppleNotesManager {
1251
1251
  continue;
1252
1252
  }
1253
1253
  // Folder doesn't exist — create it
1254
- const segmentName = escapeForAppleScript(parts[i]);
1254
+ const segmentName = escapePlainStringForAppleScript(parts[i]);
1255
1255
  let createCommand;
1256
1256
  if (i === 0) {
1257
1257
  createCommand = `make new folder with properties {name:"${segmentName}"}`;
@@ -1699,7 +1699,7 @@ export class AppleNotesManager {
1699
1699
  */
1700
1700
  listAttachments(title, account) {
1701
1701
  const targetAccount = this.resolveAccount(account);
1702
- const safeTitle = escapeForAppleScript(title);
1702
+ const safeTitle = escapePlainStringForAppleScript(title);
1703
1703
  const script = `
1704
1704
  tell application "Notes"
1705
1705
  tell account "${targetAccount}"
@@ -1759,8 +1759,8 @@ export class AppleNotesManager {
1759
1759
  return { success: false, error: e instanceof Error ? e.message : String(e) };
1760
1760
  }
1761
1761
  const safeNoteId = sanitizeId(noteId);
1762
- const safeAttId = escapeForAppleScript(attachmentId);
1763
- const safePath = escapeForAppleScript(abs);
1762
+ const safeAttId = escapePlainStringForAppleScript(attachmentId);
1763
+ const safePath = escapePlainStringForAppleScript(abs);
1764
1764
  const script = `
1765
1765
  tell application "Notes"
1766
1766
  set theNote to note id "${safeNoteId}"
@@ -633,6 +633,15 @@ describe("AppleNotesManager", () => {
633
633
  const content = manager.getNoteContent("Missing Note");
634
634
  expect(content).toBe("");
635
635
  });
636
+ it("looks up titles containing & literally, not HTML-escaped (regression)", () => {
637
+ // Bug found in live testing: titles with "&" were HTML-escaped to "&"
638
+ // in the `note "..."` lookup, so the note could never be found.
639
+ mockExecuteAppleScript.mockReturnValue({ success: true, output: "<div>x</div>" });
640
+ manager.getNoteContent("Tom & Jerry", "iCloud");
641
+ const script = mockExecuteAppleScript.mock.calls[0][0];
642
+ expect(script).toContain("Tom & Jerry");
643
+ expect(script).not.toContain("Tom &amp; Jerry");
644
+ });
636
645
  it("uses specified account", () => {
637
646
  mockExecuteAppleScript.mockReturnValue({
638
647
  success: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-notes-mcp",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "MCP server for Apple Notes - create, search, update, and manage notes via Claude",
5
5
  "type": "module",
6
6
  "main": "build/index.js",