apple-notes-mcp 2.1.3 → 2.2.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
@@ -62,7 +62,10 @@ The Codex plugin runs the published `apple-notes-mcp` server through `npx` and s
62
62
 
63
63
  ### Other Hosts (Hermes, Antigravity)
64
64
 
65
- Plugin packaging for the Hermes and Antigravity hosts is also included (`.hermes-plugin/` and `.antigravity-plugin/`). Each registers the same `apple-notes` MCP server (launched via `npx -y apple-notes-mcp`) and bundles the Apple Notes skill, so behavior matches the Claude Code and Codex plugins. Install them through each host's plugin/marketplace mechanism pointed at this repository.
65
+ Configuration for two more hosts is included each registers the same `apple-notes` MCP server (`npx -y apple-notes-mcp`):
66
+
67
+ - **[Hermes Agent](https://hermes-agent.nousresearch.com/)** (NousResearch) — Hermes has no plugin/marketplace drop-in. Add the server with `hermes mcp add apple-notes --command npx --args -y apple-notes-mcp`, or merge [`.hermes-plugin/config.yaml`](.hermes-plugin/config.yaml) into `~/.hermes/config.yaml`. Details: [`.hermes-plugin/README.md`](.hermes-plugin/README.md).
68
+ - **[Antigravity](https://antigravity.google/)** (Google) — add the server entry from [`.antigravity-plugin/mcp_config.json`](.antigravity-plugin/mcp_config.json) to `~/.gemini/config/mcp_config.json` (or via Antigravity's MCP settings).
66
69
 
67
70
  ### Manual Installation
68
71
 
package/build/index.js CHANGED
@@ -131,7 +131,13 @@ server.tool("create-note", "Use when: the user wants to create a brand-new Apple
131
131
  return errorResponse(`Failed to create note "${title}". Check that Notes.app is configured and accessible.`);
132
132
  }
133
133
  const checklistWarning = detectChecklistAttempt(content) ?? "";
134
- return successResponse(`Note created: "${note.title}" [id: ${note.id}]${checklistWarning}`);
134
+ return successResponse(`Note created: "${note.title}" [id: ${note.id}]${checklistWarning}`, {
135
+ ok: true,
136
+ id: note.id,
137
+ title: note.title,
138
+ folder,
139
+ account,
140
+ });
135
141
  }, "Error creating note"));
136
142
  // --- search-notes ---
137
143
  server.tool("search-notes", "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.", {
@@ -313,7 +319,12 @@ server.tool("update-note", "Use when: changing the title and/or replacing the bo
313
319
  ? "\n\n⚠️ This note is shared with collaborators. Your changes will be visible to them."
314
320
  : "";
315
321
  const checklistWarning = detectChecklistAttempt(newContent) ?? "";
316
- return successResponse(`Note updated: "${displayTitle}"${sharedWarning}${checklistWarning}`);
322
+ return successResponse(`Note updated: "${displayTitle}"${sharedWarning}${checklistWarning}`, {
323
+ ok: true,
324
+ id,
325
+ title: displayTitle,
326
+ shared: note.shared ?? false,
327
+ });
317
328
  }
318
329
  // Fall back to title-based update
319
330
  if (!title) {
@@ -337,7 +348,11 @@ server.tool("update-note", "Use when: changing the title and/or replacing the bo
337
348
  ? "\n\n⚠️ This note is shared with collaborators. Your changes will be visible to them."
338
349
  : "";
339
350
  const checklistWarning = detectChecklistAttempt(newContent) ?? "";
340
- return successResponse(`Note updated: "${finalTitle}"${sharedWarning}${checklistWarning}`);
351
+ return successResponse(`Note updated: "${finalTitle}"${sharedWarning}${checklistWarning}`, {
352
+ ok: true,
353
+ title: finalTitle,
354
+ shared: note.shared ?? false,
355
+ });
341
356
  }, "Error updating note"));
342
357
  // --- delete-note ---
343
358
  server.tool("delete-note", "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.", {
@@ -363,7 +378,12 @@ server.tool("delete-note", "Use when: permanently deleting a single note, by id
363
378
  const sharedWarning = note.shared
364
379
  ? "\n\n⚠️ This note was shared with collaborators. They will no longer have access."
365
380
  : "";
366
- return successResponse(`Note deleted: "${note.title}"${sharedWarning}`);
381
+ return successResponse(`Note deleted: "${note.title}"${sharedWarning}`, {
382
+ ok: true,
383
+ id,
384
+ title: note.title,
385
+ wasShared: note.shared ?? false,
386
+ });
367
387
  }
368
388
  // Fall back to title-based deletion
369
389
  if (!title) {
@@ -382,7 +402,11 @@ server.tool("delete-note", "Use when: permanently deleting a single note, by id
382
402
  const sharedWarning = note.shared
383
403
  ? "\n\n⚠️ This note was shared with collaborators. They will no longer have access."
384
404
  : "";
385
- return successResponse(`Note deleted: "${title}"${sharedWarning}`);
405
+ return successResponse(`Note deleted: "${title}"${sharedWarning}`, {
406
+ ok: true,
407
+ title,
408
+ wasShared: note.shared ?? false,
409
+ });
386
410
  }, "Error deleting note"));
387
411
  // --- move-note ---
388
412
  server.tool("move-note", "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: implemented as copy-then-delete; the destination folder must already exist (create-folder).", {
@@ -402,7 +426,12 @@ server.tool("move-note", "Use when: moving one note to a different folder, by id
402
426
  if (!success) {
403
427
  return errorResponse(`Failed to move note "${note.title}" to folder "${folder}". Folder may not exist.`);
404
428
  }
405
- return successResponse(`Note moved: "${note.title}" -> "${folder}"`);
429
+ return successResponse(`Note moved: "${note.title}" -> "${folder}"`, {
430
+ ok: true,
431
+ id,
432
+ title: note.title,
433
+ folder,
434
+ });
406
435
  }
407
436
  // Fall back to title-based move
408
437
  if (!title) {
@@ -417,7 +446,11 @@ server.tool("move-note", "Use when: moving one note to a different folder, by id
417
446
  if (!success) {
418
447
  return errorResponse(`Failed to move note "${title}" to folder "${folder}". Folder may not exist.`);
419
448
  }
420
- return successResponse(`Note moved: "${title}" -> "${folder}"`);
449
+ return successResponse(`Note moved: "${title}" -> "${folder}"`, {
450
+ ok: true,
451
+ title,
452
+ folder,
453
+ });
421
454
  }, "Error moving note"));
422
455
  // --- list-notes ---
423
456
  server.tool("list-notes", "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.", {
@@ -506,7 +539,10 @@ server.tool("create-folder", "Use when: creating a folder, including nested path
506
539
  if (!folder) {
507
540
  return errorResponse(`Failed to create folder "${name}".`);
508
541
  }
509
- return successResponse(`Folder created: "${folder.name}"`);
542
+ return successResponse(`Folder created: "${folder.name}"`, {
543
+ ok: true,
544
+ folder: folder.name,
545
+ });
510
546
  }, "Error creating folder"));
511
547
  // --- delete-folder ---
512
548
  server.tool("delete-folder", "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 — list or move those notes first.", folderNameSchema, withErrorHandling(({ name, account }) => {
@@ -514,7 +550,7 @@ server.tool("delete-folder", "Use when: deleting an existing folder by name or n
514
550
  if (!success) {
515
551
  return errorResponse(`Failed to delete folder "${name}". Folder may not exist or may contain notes.`);
516
552
  }
517
- return successResponse(`Folder deleted: "${name}"`);
553
+ return successResponse(`Folder deleted: "${name}"`, { ok: true, folder: name });
518
554
  }, "Error deleting folder"));
519
555
  // =============================================================================
520
556
  // Account Tools
@@ -607,7 +643,11 @@ server.tool("health-check", "Use when: a quick check that Notes.app is reachable
607
643
  const fdaLine = fdaAvailable
608
644
  ? " ✓ full_disk_access: Granted (checklist features available)"
609
645
  : " ⓘ full_disk_access: Not granted (optional — needed for get-checklist-state and checklist annotations in get-note-markdown). Grant in System Settings > Privacy & Security > Full Disk Access.";
610
- return successResponse(`${statusIcon} ${statusText}\n\n${checkLines}\n${fdaLine}`);
646
+ return successResponse(`${statusIcon} ${statusText}\n\n${checkLines}\n${fdaLine}`, {
647
+ healthy: result.healthy,
648
+ checks: result.checks,
649
+ fullDiskAccess: fdaAvailable,
650
+ });
611
651
  }, "Error running health check"));
612
652
  // --- doctor ---
613
653
  server.tool("doctor", "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.", {}, withErrorHandling(() => {
@@ -709,7 +749,14 @@ server.tool("batch-delete-notes", "Use when: permanently deleting multiple notes
709
749
  lines.push(` - ${result.id}: ${result.error}`);
710
750
  }
711
751
  }
712
- return succeeded > 0 ? successResponse(lines.join("\n")) : errorResponse(lines.join("\n"));
752
+ return succeeded > 0
753
+ ? successResponse(lines.join("\n"), {
754
+ ok: failed === 0,
755
+ succeeded,
756
+ failed,
757
+ results,
758
+ })
759
+ : errorResponse(lines.join("\n"));
713
760
  }, "Error performing batch delete"));
714
761
  // --- batch-move-notes ---
715
762
  server.tool("batch-move-notes", "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).", {
@@ -733,7 +780,15 @@ server.tool("batch-move-notes", "Use when: moving multiple notes by id into one
733
780
  lines.push(` - ${result.id}: ${result.error}`);
734
781
  }
735
782
  }
736
- return succeeded > 0 ? successResponse(lines.join("\n")) : errorResponse(lines.join("\n"));
783
+ return succeeded > 0
784
+ ? successResponse(lines.join("\n"), {
785
+ ok: failed === 0,
786
+ folder,
787
+ succeeded,
788
+ failed,
789
+ results,
790
+ })
791
+ : errorResponse(lines.join("\n"));
737
792
  }, "Error performing batch move"));
738
793
  // --- save-attachment ---
739
794
  server.tool("save-attachment", "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.", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-notes-mcp",
3
- "version": "2.1.3",
3
+ "version": "2.2.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",
@@ -59,7 +59,7 @@
59
59
  "darwin"
60
60
  ],
61
61
  "dependencies": {
62
- "@modelcontextprotocol/sdk": "1.4.1",
62
+ "@modelcontextprotocol/sdk": "^1.29.0",
63
63
  "turndown": "^7.2.2",
64
64
  "zod": "^3.22.4"
65
65
  },