apple-notes-mcp 2.9.20 → 2.9.21

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
@@ -256,14 +256,14 @@ Creates a new note in Apple Notes.
256
256
  | `title` | string | Yes | The title of the note. Automatically prepended as `<h1>` — do NOT include the title in `content` |
257
257
  | `content` | string | One of `content`/`contentPath` | The body content of the note (do not repeat the title here) |
258
258
  | `contentPath` | string | One of `content`/`contentPath` | Absolute path of a local UTF-8 file to use as the body instead of `content`. Allowed in the same places [`save-attachment`](#save-attachment) may write (home, temp, `/Volumes`); symbolic links, non-regular files, invalid UTF-8 and files over 1 MiB are refused before anything is written. A leading byte-order mark is dropped |
259
- | `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). Refused with `format: "markdown"` |
259
+ | `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. Inline `#hashtags` in `content` stay searchable text and are returned as `hashtags`, but they do not become native Notes tags; add real tags afterwards with [`add-native-tags`](#add-native-tags). Refused with `format: "markdown"` |
260
260
  | `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). A smart folder is refused (see [`move-note`](#move-note)). Defaults to account root |
261
261
  | `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) |
262
262
  | `format` | string | No | Content format: `"plaintext"` (default), `"html"`, or `"markdown"`. In all formats, the title is automatically prepended as the note's title line. In plaintext mode, newlines become `<br>`, tabs become `<br>`, and backslashes are preserved as HTML entities. `"markdown"` produces real Title/Heading/Subheading styles through a Shortcut; see [Markdown notes](#markdown-notes) |
263
263
  | `markdownRoute` | string | No | With `format: "markdown"` only: `"shortcut"` (default) or `"html"`. See [Markdown through HTML](#markdown-through-html) |
264
264
  | `timeoutSeconds` | number | No | Whole seconds, 1–120, for each Notes.app automation step this call runs; overrides `APPLE_NOTES_MCP_TIMEOUT_MS` for this call only. A timed-out write is uncertain, not failed: read the note by id before any retry. Also accepted by `get-note-content`, `update-note`, `append-to-note`, `delete-note` and `move-note` |
265
265
 
266
- **Example (tagged with inline hashtags):**
266
+ **Example (with inline textual hashtags):**
267
267
  ```json
268
268
  {
269
269
  "title": "Meeting Notes",
@@ -587,8 +587,9 @@ base64 images larger than `APPLE_NOTES_MCP_MAX_INLINE_IMAGE_BYTES` (default
587
587
  image-heavy note cannot blow the MCP message limit. `structuredContent` reports
588
588
  this as `strippedImages` (count) and `truncated` (boolean). When either is set,
589
589
  passing this body to an unguarded full-body writer would replace the real images
590
- with placeholder text. This server refuses update and append operations on
591
- attachment-bearing notes; edit them in Notes.app.
590
+ with placeholder text. This server's `update-note` refuses attachment-bearing
591
+ notes, and `append-to-note` routes them to native end-append with `scopeText`,
592
+ which never rewrites the existing body; make any other edit in Notes.app.
592
593
 
593
594
  ---
594
595
 
package/build/index.js CHANGED
@@ -59329,7 +59329,7 @@ ${lines}${footer}`,
59329
59329
  registerTool(
59330
59330
  "get-note-content",
59331
59331
  {
59332
- description: "Use when: reading the full body text of one known note, by id (preferred) or title.\nReturns: the exact note id, content, contentHash revision token, parsed hashtags, nativeTags, restored links, richContentComplete/writable, and strippedImages/truncated when the body was capped. Read the warning when writable is false.\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. Mutations refuse attachment-bearing notes; edit those in Notes.app. Notes.app returns images inside the body as base64, so a note with a very large image can time out; the error then names the cause, and a larger timeoutSeconds gives the read more time.",
59332
+ description: "Use when: reading the full body text of one known note, by id (preferred) or title.\nReturns: the exact note id, content, contentHash revision token, parsed hashtags, nativeTags, restored links, richContentComplete/writable, and strippedImages/truncated when the body was capped. Read the warning when writable is false.\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. For an attachment-bearing note, update-note refuses a full-body replacement; append-to-note with scopeText appends natively at the end and leaves attachments in place; add-attachment adds a file; move-note and delete-note work as usual. Make any other edit in Notes.app. Notes.app returns images inside the body as base64, so a note with a very large image can time out; the error then names the cause, and a larger timeoutSeconds gives the read more time.",
59333
59333
  inputSchema: {
59334
59334
  id: looseNoteId(external_exports.string()).optional().describe(`Note ID (preferred - more reliable than title): ${NOTE_ID_FORMS}`),
59335
59335
  title: external_exports.string().max(MAX.TITLE).optional().describe("Note title (use id instead when available)"),
@@ -91,24 +91,28 @@ a note in a follow-up tool call, use the `id` returned by every read tool.
91
91
 
92
92
  ## Tags / hashtags (#29)
93
93
 
94
- **Status: parsed from the body, not first-class.** Apple Notes "tags" are inline
95
- `#hashtag` tokens you type into a note's text. They are **not** a scriptable
96
- property — the `note` class exposes no `tags` element, and the tag relationship
97
- lives only in Notes' private Core Data store. So the only way to surface a
98
- note's tags via AppleScript is to read them back out of the body text.
99
-
100
- This server does that: `get-note-content` parses the body and returns the tags
101
- as `hashtags` in its `structuredContent` (see `src/utils/hashtags.ts`). The
102
- rules match Notes' own behaviour — a token is `#` followed by letters/digits/
103
- underscores containing **at least one letter**, so `#123` is not a tag; tokens
104
- are de-duplicated case-insensitively.
94
+ **Status: not scriptable; native tags go through Shortcuts.** A native Apple
95
+ Notes tag is an inline tag attachment backed by an `ICHashtag` object in Notes'
96
+ private Core Data store. It is **not** a scriptable property — the `note` class
97
+ exposes no `tags` element — and `#word` text written through AppleScript stays
98
+ plain text: Notes does not convert it into a native tag.
99
+
100
+ This server therefore separates two things. `get-note-content` parses textual
101
+ `#hashtag` tokens out of the body and returns them as `hashtags` (see
102
+ `src/utils/hashtags.ts`); the rules match Notes' own — `#` followed by
103
+ letters/digits/underscores containing **at least one letter**, so `#123` is not
104
+ a tag; tokens are de-duplicated case-insensitively. Actual native tags are read
105
+ from the database (`nativeTags`, `list-native-tags`, Full Disk Access) and
106
+ written with `add-native-tags` / `remove-native-tags` / `replace-native-tag`,
107
+ which drive the Notes Shortcuts action. A textual `hashtags` entry is not proof
108
+ that Notes registered a native tag.
105
109
 
106
110
  Two related caveats:
107
111
 
108
112
  - The `tags` parameter on `create-note` is an application-level pass-through. It
109
113
  is stored on the returned object but Notes does **not** persist it, and it does
110
- **not** create real `#hashtags` in the body. To make a real tag, put `#tag`
111
- in the note content.
114
+ **not** create tags. Typing `#tag` into the content does not either; use
115
+ `add-native-tags` on the created note.
112
116
  - **Smart folders are not scriptable.** Notes' tag-driven Smart Folders cannot be
113
117
  created, read, or enumerated via AppleScript; there is no `smart folder` class
114
118
  in the dictionary. Only regular folders are scriptable.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-notes-mcp",
3
- "version": "2.9.20",
3
+ "version": "2.9.21",
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",