apple-notes-mcp 2.6.3 → 2.6.4

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
@@ -362,6 +362,8 @@ Updates an existing note's content and/or title.
362
362
 
363
363
  **Note:** Either `id` or `title` must be provided. Using `id` is recommended.
364
364
 
365
+ **Returns:** Confirmation with the note's visible title and, for ID-based updates, its ID. For HTML updates, the title comes from the first rendered line of `newContent`, matching Notes.app. The response also warns if the note is shared.
366
+
365
367
  **Example - Using ID (recommended):**
366
368
  ```json
367
369
  {
package/build/index.js CHANGED
@@ -41766,6 +41766,40 @@ function strippedImagesWarning(stripped) {
41766
41766
  )} decoded) exceeded the per-image inline cap and ${stripped.strippedCount === 1 ? "was" : "were"} replaced with placeholders so the response stays within MCP message limits. The images are still in the note: use list-attachments with save-attachment or fetch-attachment to export them, or raise APPLE_NOTES_MCP_MAX_INLINE_IMAGE_BYTES.`;
41767
41767
  }
41768
41768
 
41769
+ // src/utils/updateResponseTitle.ts
41770
+ var BLOCK_END_RE = /<\/(?:div|h[1-6]|p|li)>/gi;
41771
+ var BREAK_RE = /<br\s*\/?\s*>/gi;
41772
+ var TAG_RE = /<[^>]*>/g;
41773
+ var NON_RENDERED_BLOCK_RE = /<(script|style)\b[^>]*>[\s\S]*?(?:<\/\1>|$)/gi;
41774
+ function decodeHtmlEntities(text) {
41775
+ const decodeCodePoint = (match, value, radix) => {
41776
+ const codePoint = Number.parseInt(value, radix);
41777
+ if (!Number.isInteger(codePoint) || codePoint < 0 || codePoint > 1114111 || codePoint >= 55296 && codePoint <= 57343) {
41778
+ return match;
41779
+ }
41780
+ return String.fromCodePoint(codePoint);
41781
+ };
41782
+ return text.replace(/&#x([0-9a-f]+);?/gi, (match, hex) => decodeCodePoint(match, hex, 16)).replace(/&#([0-9]+);?/g, (match, decimal) => decodeCodePoint(match, decimal, 10)).replace(/&nbsp(?:;|(?![0-9a-z]))/gi, " ").replace(/&quot(?:;|(?![0-9a-z]))/gi, '"').replace(/&apos(?:;|(?![0-9a-z]))/gi, "'").replace(/&lt(?:;|(?![0-9a-z]))/gi, "<").replace(/&gt(?:;|(?![0-9a-z]))/gi, ">").replace(/&amp(?:;|(?![0-9a-z]))/gi, "&");
41783
+ }
41784
+ function firstVisibleHtmlLine(html) {
41785
+ let text = html;
41786
+ let previous;
41787
+ do {
41788
+ previous = text;
41789
+ text = text.replace(NON_RENDERED_BLOCK_RE, "");
41790
+ } while (text !== previous);
41791
+ text = text.replace(BREAK_RE, "\n").replace(BLOCK_END_RE, "\n");
41792
+ do {
41793
+ previous = text;
41794
+ text = text.replace(TAG_RE, "");
41795
+ } while (text !== previous);
41796
+ return decodeHtmlEntities(text).split(/[\r\n\u2028\u2029]+/).map((line) => line.replace(/\s+/g, " ").trim()).find(Boolean);
41797
+ }
41798
+ function resolveUpdateResponseTitle(currentTitle, newTitle, format, newContent) {
41799
+ if (format === "html") return firstVisibleHtmlLine(newContent) ?? currentTitle;
41800
+ return newTitle || currentTitle;
41801
+ }
41802
+
41769
41803
  // src/tools/doctor.ts
41770
41804
  import { spawnSync } from "child_process";
41771
41805
  function runDoctor(manager) {
@@ -42401,7 +42435,9 @@ server.registerTool(
42401
42435
  inputSchema: {
42402
42436
  id: external_exports.string().max(MAX.ID).optional().describe("Note ID (preferred - more reliable than title)"),
42403
42437
  title: external_exports.string().max(MAX.TITLE).optional().describe("Current note title (use id instead when available)"),
42404
- newTitle: external_exports.string().max(MAX.TITLE).optional().describe("New title for the note"),
42438
+ newTitle: external_exports.string().max(MAX.TITLE).optional().describe(
42439
+ "New title for plaintext updates. Ignored when format is 'html'; include the visible title as the first line of newContent instead."
42440
+ ),
42405
42441
  newContent: external_exports.string().min(1, "New content is required").max(MAX.CONTENT).describe(
42406
42442
  "New note body. AppleScript cannot produce true Apple Notes checklists; checkbox inputs and `- [ ]` markdown do not render as checkable items. Use a plain list and convert in Notes.app with \u21E7\u2318L."
42407
42443
  ),
@@ -42430,7 +42466,7 @@ server.registerTool(
42430
42466
  if (!success2) {
42431
42467
  return errorResponse(`Failed to update note "${note2.title}"`);
42432
42468
  }
42433
- const displayTitle = newTitle || note2.title;
42469
+ const displayTitle = resolveUpdateResponseTitle(note2.title, newTitle, format, newContent);
42434
42470
  const sharedWarning2 = note2.shared ? "\n\n\u26A0\uFE0F This note is shared with collaborators. Your changes will be visible to them." : "";
42435
42471
  const checklistWarning2 = detectChecklistAttempt(newContent) ?? "";
42436
42472
  return successResponse(`Note updated: "${displayTitle}"${sharedWarning2}${checklistWarning2}`, {
@@ -42458,7 +42494,7 @@ server.registerTool(
42458
42494
  if (!success) {
42459
42495
  return errorResponse(`Failed to update note "${title}"`);
42460
42496
  }
42461
- const finalTitle = newTitle || title;
42497
+ const finalTitle = resolveUpdateResponseTitle(note.title, newTitle, format, newContent);
42462
42498
  const sharedWarning = note.shared ? "\n\n\u26A0\uFE0F This note is shared with collaborators. Your changes will be visible to them." : "";
42463
42499
  const checklistWarning = detectChecklistAttempt(newContent) ?? "";
42464
42500
  return successResponse(`Note updated: "${finalTitle}"${sharedWarning}${checklistWarning}`, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-notes-mcp",
3
- "version": "2.6.3",
3
+ "version": "2.6.4",
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",