notes-mcp
An MCP server for Apple Notes that can read and write checklist state, enabling agents to manage checklists in notes.
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 |
Organization — create_folder, move_note, delete_note (needs
confirm: true; goes to Recently Deleted and is recoverable).
Health — check_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: trueto 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
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
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.
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.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
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.
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.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
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.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.