--- name: apple-notes description: Use this skill when the user wants to interact with Apple Notes on macOS - creating, searching, reading, updating, deleting, organizing, or formatting notes and folders. This skill provides access to Apple Notes through MCP tools and includes safe formatting guidance. --- # Apple Notes Skill This skill enables you to manage Apple Notes on macOS through natural language. Use it whenever the user mentions notes, wants to save information to Notes, or needs to retrieve, update, or organize their notes. ## When to Use This Skill Use this skill when the user: - Wants to create a new note or save information - Asks to find, search, or look up notes - Wants to read the contents of a note - Needs to update or edit an existing note - Wants to delete or remove a note - Asks to move or organize notes into folders - Wants to list their notes or folders - Mentions Apple Notes, Notes app, or "my notes" ## Available Tools ### Note Operations | Tool | Purpose | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `create-note` | Create a new note with title and content | | `search-notes` | Find notes by title or content | | `query-notes` | Find notes with a boolean expression over text, folders, tags, attachments, checklists, flags, word counts, and dates (reads the database; needs Full Disk Access) | | `get-note-content` | Read the full content of a note | | `get-note-plaintext` | Read a note's body as plain text (no HTML) | | `get-note-markdown` | Read note content as Markdown | | `get-note-by-id` | Get note metadata by ID | | `get-note-details` | Get metadata (created, modified, account) | | `get-note-link` | Get the shareable `notes://showNote?identifier=…` deep link for a note | | `update-note` | Replace a note's whole body; refused when the note holds attachments, tables, checklists, or native tags, or formatting HTML cannot carry | | `append-to-note` | Add content to a note without replacing it (`position: "after"` / `"before"`, which inserts below the title) | | `append-native` | Append plaintext, the native HTML subset, or Markdown to a note that holds native objects, without replacing its body (needs `scopeText`) | | `insert-link` | Add one URL to a note as its raw text or as a labeled hyperlink, verified from the stored link | | `insert-note-link` | Append a real link to another note (by id) with a static label, verified after the write | | `delete-note` | Remove a note (moves to Recently Deleted; refuses a note already there, where delete is permanent); like `update-note`, `append-to-note`, and `move-note` it accepts `ifFolderId`, `ifAncestorFolderId`, and `forbiddenAncestorFolderIds` folder preconditions. For copy-then-retire, pass `guardNoteId` and `expectedGuardContentHash` (the verified copy's `contentHash`) so the original is deleted only while the copy is intact; needs Full Disk Access | | `batch-delete-notes` | Delete multiple notes by ID (max 500 per call; refuses notes already in Recently Deleted) | | `move-note` | Move a note to a different folder | | `batch-move-notes` | Move multiple notes by ID (max 500 per call) | | `list-notes` | List all notes or notes in a folder (excludes Recently Deleted unless `includeRecentlyDeleted`) | | `list-special-notes` | List pinned notes, Quick Notes, Recently Deleted, or locked notes (`kind`; metadata only, needs Full Disk Access) | | `set-note-pinned` | Pin or unpin one exact note (checks `expectedPinned` and `expectedContentHash`; never rewrites the body) | | `list-recent-notes` | Changes since a cursor, oldest first, for incremental sync: pass `since`, then keep calling with `nextSince` until `saturated` is false (needs Full Disk Access) | | `show-note` | Reveal a note in the Notes.app UI by ID | | `get-selected-notes` | Read the notes currently selected in Notes.app | | `export-notes-json` | Export notes as JSON one page at a time (`offset`/`limit`/`modifiedSince`); repeat with `page.nextOffset` while `page.hasMore` | | `export-notes-markdown` | Export one note or a folder as one Markdown document from the decoded body; optional create-only `outputPath` and `assetsDir` for attachment copies; `template`/`templateFile` render through a JSON Markdown template such as `obsidian` front matter (presentation format, not a backup) | | `export-notes-html` | Export one note or a folder as one standalone HTML file (semantic tables, attachments in body order); `outputPath` required and create-only; assets embedded (10 MiB each) or in a sidecar directory with `embedAssets: false`; `vectorDrawings: true` renders classic drawings as SVG through the public helper (default `false` keeps Notes' PNG; Paper keeps its PNG; failures fall back to PNG) | | `list-markdown-templates` | List built-in and saved Markdown export templates | | `show-markdown-template` | Show a template's JSON (portable form; `expanded` for every rule) | | `validate-markdown-template` | Check a template; returns every problem with a JSON path | | `save-markdown-template` | Save a template to the library by slug name (create-only unless `force`) | | `delete-markdown-template` | Delete a saved template (built-ins cannot be deleted) | To edit a template visually, the user can run `apple-notes-mcp templates edit [name]` in a terminal: a local, token-gated web editor with live validation and a preview on sample notes. It is a command-line tool, not an MCP tool, so suggest it rather than trying to start it. ### Folder Operations | Tool | Purpose | | --------------------- | --------------------------------------------------------------------------------------------------- | | `list-folders` | List all folders in an account; with Full Disk Access, smart folders are marked `smartFolder: true` | | `list-smart-folders` | List Smart Folders with their decoded rules; optionally the notes each one shows | | `get-folder-by-id` | Read one folder's name, parent, account, and `isRoot` before a guarded rename or delete | | `rename-folder` | Rename one folder in place; requires its expected current name and parent | | `list-folder-tree` | Folder hierarchy with direct and cumulative note counts per account | | `create-folder` | Create a new folder | | `delete-folder` | Delete an empty folder | | `delete-folder-by-id` | Guarded delete of one exact empty folder: dry run returns a revision, apply requires it | | `show-folder` | Reveal a folder in the Notes.app UI by ID | ### Account Operations | Tool | Purpose | | ---------------------- | ------------------------------------------------------ | | `list-accounts` | List configured accounts (iCloud, Gmail, etc.) | | `get-default-location` | Read the default account and folder used for new notes | | `show-account` | Reveal an account in the Notes.app UI by ID | ### Native Tags | Tool | Purpose | | -------------------- | ------------------------------------------------------------------------------------------------------ | | `native-tags-status` | Check that the Native Tags Shortcut is installed before a tag write | | `list-native-tags` | Native tags in one folder, or omit `folder` for an account-wide inventory with note counts | | `add-native-tags` | Add real, clickable tags to one exact note (needs `expectedContentHash` and a distinctive `scopeText`) | | `remove-native-tags` | Remove named tags from one exact note, keeping its other tags | | `replace-native-tag` | Swap one tag for another across a list of freshly read notes; stops at the first uncertain result | ### Attachments, Checklists, Collaboration, and Diagnostics | Tool | Purpose | | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `list-attachments` | List attachments in a note; `includePaths` adds on-disk `assetPaths`/`previewPath`, `firstImage` returns the lead visual in body order | | `add-attachment` | Attach one local file (home, temp or /Volumes; no hidden paths or ~/Library) to an exact note (`filename` renames it); a macOS 27 PDF "outcome uncertain": read the note first | | `create-note-with-attachment` | Create a note and attach one local file in one call; on a failed attach, reuse the named note id with `add-attachment` | | `add-attachment-from-pasteboard` | Attach the copied image, PDF, or one file to an exact note (note checked first, pasteboard frozen, never modified); `pasteboard_access_denied`: ask before `allowPasteAlert: true` | | `save-attachment` | Save an attachment to disk | | `list-paper-attachments` | List Paper and classic drawings in a note, with Notes' rendered image size and any recognized handwriting text | | `export-paper-image` | Save Notes' rendered PNG (or JPEG) of one drawing to a new file | | `analyze-svg` | Read-only SVG preflight: can a local SVG become editable strokes, which losses it needs, and a digest of the result | | `export-attachments` | Copy a note\'s attachment files (or only its lead visual) into a directory; `exportedKind` says asset, fallback, or preview | | `fetch-attachment` | Fetch attachment bytes as base64 | | `show-attachment` | Reveal an attachment in the Notes.app UI | | `get-checklist-state` | Read checked/unchecked state for existing checklists | | `create-checklist-item` | Append one unchecked native checklist item (needs the Background Operations bridge) | | `get-note-tables` | Read a note's native tables as Markdown and JSON rows, in body order | | `create-table` | Append one native table from rectangular rows (omit `rows` for an empty 2 × 2 table); verified by reading the cells back | | `create-checklist-items` | Append several unchecked native checklist items in order (needs the Background Operations bridge; on `ok: false`, only `landed` items are verified) | | `get-note-metadata` | [BETA] Read pinned/trash/snippet metadata from the NoteStore DB | | `get-note-drawings` | Decode classic PencilKit drawings to strokes or SVG (needs `apple-notes-mcp setup --public-helper` once) | | `transcribe-note-audio` | Transcribe a note's voice recordings on-device (same helper; pass `locale`, and `attachmentId` for long recordings) | | `get-note-blocks` | Read a note's paragraph styles, inline formatting, and attachment positions as typed blocks | | `get-native-objects` | Read a note's native object ids, checklist ids and state, native tags, and decoded tables, with the current revision | | `list-note-paragraphs` | List a note's paragraphs with style, stored paragraph ID, and a direct link when the ID is unique | | `get-paragraph-link` | Get a link that opens Notes at one paragraph, refused when its ID is shared | | `create-paragraph-anchor` | Record an anchor for one paragraph so it can be found again after edits or ID changes (local registry only) | | `resolve-paragraph-anchor` | Find an anchored paragraph again; `url` only when `status` is `resolved`, fails closed on ambiguity | | `list-paragraph-anchors` | List recorded paragraph anchors, all or for one note | | `get-paragraph-anchor` | Show one stored paragraph anchor | | `prune-paragraph-anchors` | Remove anchors that no longer resolve (dry run unless `dryRun: false`) | | `get-note-structure` | Read a note's links by kind, tags, attachments (as list-attachments reports them), counts, and view/lock/share/trash state in one call | | `list-note-links` | List links (inline, card, note, section) in a note, folder (with subfolders), account, or the whole library | | `get-audio-transcripts` | Read the transcripts and summaries Notes stored for a note's audio recordings | | `list-shared-notes` | List notes shared with collaborators | | `get-sync-status` | Check whether iCloud sync is active | | `health-check` | Quickly verify Notes.app access | | `doctor` | Run detailed setup diagnostics, including the feature matrix | | `get-capabilities` | Check native-write operations and the OS-aware feature matrix (`features..available` / `reason`) before calling a tool that depends on them | | `get-notes-stats` | Summarize note counts and recent activity | ### Private Helper (opt-in, read-only, unsupported Apple API) Off unless the user built it (`apple-notes-mcp setup --native-helper`) and set `APPLE_NOTES_MCP_ENABLE_PRIVATE=1`. Call `native-helper-status` first; use `native-note-state` only when it reports the feature `available`. The helper is read-only: write support was deliberately deferred by the maintainer. | Tool | Purpose | | ---------------------- | ------------------------------------------------------------------------- | | `native-helper-status` | Report opt-in, build, and live-probe state with a reason code (read-only) | | `native-note-state` | Read a note's native state and `revision` change token (read-only) | ## Usage Patterns ### Creating Notes When the user wants to save information: ``` User: "Save this meeting summary as a note" Action: Use create-note with an appropriate title and the content ``` ``` User: "Create a shopping list note" Action: Use create-note with title="Shopping List" and formatted content ``` For structured notes, pass `format="html"` and use simple Apple Notes-friendly HTML. The server automatically prepends the `title` as an `

` in both plaintext and HTML modes, so do not include the same `

` title in `content` when creating a note. ### Finding Notes When the user wants to find notes: ``` User: "Find my notes about the project" Action: Use search-notes with query="project" ``` ``` User: "Search for notes containing budget information" Action: Use search-notes with query="budget" and searchContent=true ``` With Full Disk Access, a `searchContent` search reads the Notes database and returns quickly even for a common word; without it, a broad body search can time out, so narrow it with `folder` or `modifiedSince`. When Full Disk Access is available, prefer `query-notes` for anything beyond a single keyword. It matches title or body in one call, runs in well under a second, and combines conditions: ``` User: "Which work notes still have open to-dos?" Action: Use query-notes with query='folder:Work checklist:open' User: "Find invoices or anything tagged finance since July" Action: Use query-notes with query='(title:invoice OR tag:finance) modified:>=2026-07-01' User: "Long notes with a PDF that aren't in Archive" Action: Use query-notes with query='words:>250 has:pdf -folder:Archive' ``` Bare words and "quoted phrases" match title or body. Fields are `title:`, `body:`, `text:`, `folder:`, `account:`, and `tag:`; facets are `has:link|attachment|checklist|drawing|image|video|audio|pdf|table|scan|url|map|tag` (`has:url` is a link preview card, `has:map` a map); `checklist:open|done`; flags `pinned`, `locked`, `shared`, `quicknote`; and `words:`, `created:`, `modified:` take `=`, `>`, `>=`, `<`, `<=` with `YYYY-MM-DD` local dates. AND is implicit; use `OR`, `NOT` or a leading `-`, and parentheses. Quote an operator word (`"and"`) to search it literally. It scans the 500 most recently modified notes unless `scanLimit` is raised (max 10000), and the response says when older notes were left out. Recently Deleted is excluded unless `includeDeleted` is true. Locked notes match on title and metadata only. The returned ids work with every id-based tool. Both search tools can say where a note matched and how long it is. Results whose text came from the database carry `matchedIn` (`title`, `body`, or both); `query-notes` always has it for readable notes, and `search-notes` has it for a database body search. Pass `includeWordCount: true` to either tool for a `wordCount` per result (null for locked notes). On a `search-notes` title search it reads the bodies in one database query and adds `matchedIn` too, which answers "does this note also mention it in the body?" without opening each note. ``` User: "Which of my budget notes are long, and do they mention it in the body?" Action: Use query-notes with query='budget' and includeWordCount=true ``` ### Reading Notes When the user wants to see note contents: ``` User: "Show me my shopping list" Action: Search by title if needed, then use get-note-content with the exact ID ``` For a note's tables, use `get-note-tables` with the note ID. It returns each table as Markdown and as JSON rows. When `tableCellsComplete` is false, some cells could not be decoded: they are `null` in `rows` and shown as `[undecoded cell]` in Markdown. Report that to the user rather than filling them in. Use titles for discovery only. Mutations require the exact note ID; update, append, and delete also require the `contentHash` returned by `get-note-content`. This prevents duplicate-title mistakes and stale saves. For a note with audio recordings, `get-audio-transcripts` returns the transcript Notes already computed for each recording (it never transcribes). Check each attachment's `status`: `none` means Notes stored no transcript, not that the read failed. Ask for `includeSegments` only when word timings or speakers per word matter, because segments make the response much larger. ### Updating Notes **Adding to a note — use `append-to-note`.** It takes the new `content` plus an optional `position` (`"after"` is the default and appends; `"before"` prepends), `separator`, and `format` (`"plaintext"` / `"html"`), and does the read-and-splice itself, always round-tripping the body as HTML so existing rich formatting survives. Do not hand-roll read-then-`update-note` for an addition. A note that already contains native objects (a table, a checklist, native tags) cannot be spliced, so `append-to-note` routes it to the native end-append bridge instead. That path additionally needs `scopeText` (a unique existing phrase from below the title line; a title-only phrase is refused), keeps the default blank-line `separator` and `position: "after"`, and accepts a fixed HTML subset: `