notes-mcp

notes-mcp

An MCP server for Apple Notes that can read and write checklist state, enabling agents to manage checklists in notes.

Category
Visit Server

README

notes-mcp

An MCP server for Apple Notes that can read and write checklist state — so an agent can do things like "reset my workout checklist" or "tell me what I didn't finish today".

That sounds simple. It isn't: AppleScript cannot see checklists at all. A note full of checkboxes arrives over the scripting bridge as plain bullets with no state, and writing back through AppleScript silently converts every checklist into permanent plain bullets. Most Apple Notes automations quietly have this bug.

This server routes around it using Notes' App Intents API, reached through generated Shortcuts. Full reverse-engineering notes are in docs/spike-findings.md.

Requirements

  • macOS 13 or later (developed on macOS 26)
  • Node.js 20+
  • Permission for your terminal to control Notes (macOS prompts on first use)

No Full Disk Access, no Accessibility, no SQLite parsing.

Install

git clone https://github.com/eliotshea/notes-mcp.git
cd notes-mcp
npm install
npm run build
npm run setup

setup generates, signs, and installs three helper shortcuts, then verifies the whole pipeline end to end by creating a scratch note, reading its checklist state back, clearing it, and deleting it.

You will get three "Add Shortcut" prompts. Approve each one. macOS has no command-line path to install a shortcut, so this step cannot be automated. It only happens once.

Then register the server with your MCP client:

{
  "mcpServers": {
    "notes": { "command": "node", "args": ["/absolute/path/to/notes-mcp/dist/index.js"] }
  }
}

Verify at any time with npm run setup -- --check, or by calling the check_setup tool.

Tools

Discovery — fast, AppleScript-backed, never touches note content.

Tool Purpose
list_notes All notes with folder and timestamps
list_folders Folders with note counts
search_notes Full-text search across titles and bodies

Content — routed through App Intents so checklist state is accurate.

Tool Purpose
read_note Full content, with checklist state
read_checklist Just the checklist items: [{index, text, checked}]
create_note Create from Markdown
append_to_note Append Markdown, leaving existing content alone
replace_note_content Replace the body, keeping the note's identity

Checklists

Tool Purpose
clear_checklist Uncheck everything, keeping the items
check_all_items Check everything
set_checklist_items Check/uncheck/toggle items by index or text match

Organizationcreate_folder, move_note, delete_note (needs confirm: true; goes to Recently Deleted and is recoverable).

Healthcheck_setup.

Markdown

Notes does the Markdown conversion itself, so it round-trips cleanly:

- [ ] Barbell squat     →  ○ Barbell squat     (unchecked checklist item)
- [x] Hip thrust        →  ◉ Hip thrust        (checked checklist item)
- Warm up first         →  • Warm up first     (ordinary bullet)

Reading a note back yields tab-delimited markers — unchecked, checked, ordinary bullet — which the server parses into structured items for you.

Nested lists are preserved. Apple's two APIs each tell half the story: the App Intents text carries checked state but flattens indentation, while the AppleScript HTML preserves indentation but has no state. The server reads both and merges them, so each item reports a depth and rebuilds reproduce the original nesting exactly. If the two sources ever disagree, tools report nestingResolved: false and refuse to rewrite rather than silently flattening your note.

Example

> Reset my Leg day checklist for tomorrow

  read_checklist  { note: "Leg day" }
    → [{0,"Barbell squat",true}, {1,"Hip thrust",true}, {2,"Hamstring curl",false}]
  clear_checklist { note: "Leg day" }
    → 2 items changed, all now unchecked

How it works

discovery / metadata ──→ AppleScript (JXA)      ~0.17s for 177 notes
content + checklists ──→ Shortcuts → App Intents ~0.4s warm

AppleScript is used only where it is fast and truthful — listing, search, folders, moving, deleting, and clearing a body. Anything involving checklist structure goes through the bridge, because AppleScript's view of a checklist is actively misleading rather than merely incomplete.

Three shortcuts are installed: notes-mcp-read-body, notes-mcp-append-markdown, and notes-mcp-create-note. They take JSON on stdin and return text, so all arguments are passed at run time and nothing is regenerated per call.

Changing checked state works by rebuild: read the note, clear its body, and re-append every line as Markdown with the desired state. There is no per-item toggle action in Notes' API, so this is the only route. The note keeps its id, folder, and creation date.

Limitations

  • Notes are addressed by name, so names must be unique. Duplicates raise an error rather than guessing.
  • Rebuild is lossy for rich content. Images, tables, and inline styling in the same note are not reconstructed. Tools that rebuild refuse when they detect attachments or tables; pass force: true to override. List nesting is preserved.
  • Password-protected notes are unreadable.
  • Setup needs manual clicks — three, once.
  • Bridge dispatch is ~0.4s warm, a few seconds cold. Discovery tools are much faster because they skip the bridge.

Development

npm run build      # compile
npm test           # build + run the parser test suite
npm run setup -- --check   # verify the installation

The parsing and rendering logic in src/checklist.ts is pure and covered by tests using fixtures captured verbatim from real Notes output.

License

MIT

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured