Skip to main content

inotes — Apple Notes CLI

inotes is a Typer command line for Apple Notes — list, search, read, create, edit, delete, pin, unpin, attach local files, and inventory note links. Part of the imsg / imail / inotes / wa local-first tool family.

inotes list --limit 20
inotes search "standup" --json
inotes show "Project Plan"
inotes create --title "Idea" --body "…"
inotes edit --title "Idea" --body "Revised text"
inotes pin "Project Plan"
inotes unpin "Project Plan"
inotes attach "Project Plan" --file ./demo.wav
inotes attachments "Project Plan" --json
inotes links --output ./inotes-links.md
inotes update

macOS only

inotes drives Notes.app through AppleScript (osascript), which only exists on macOS. There is no Linux or Windows build, and none is planned — the tool has nothing to talk to without Notes.app.


Install

# Homebrew
brew install ml-lubich/tap/inotes

# pip
pip install inotes-mcp

# from a clone
git clone https://github.com/ml-lubich/inotes-mcp.git
cd inotes-mcp
uv tool install .

The PyPI/Homebrew package is inotes-mcp; the installed command is always inotes.

Permissions

inotes needs Automation access to Notes.app. The first time it runs a command, macOS will prompt you to allow it — or grant it up front in System Settings → Privacy & Security → Automation (allow your terminal app to control Notes). Verify it's working with:

inotes doctor

Quick start

inotes doctor                                        # verify Notes.app access
inotes list --limit 20                               # recent note titles
inotes list -j                                        # {"notes": [...]}
inotes search "standup" --limit 10 --json             # search titles + bodies
inotes show "My Note"                                 # exact-title lookup
inotes create --title "Idea" --body "…"               # new note
inotes create --title "Work" --body "…" --folder "Projects"
inotes edit --title "Idea" --body "Revised text"      # replace body
inotes edit --title "Idea" --new-title "New Idea"    # rename only
inotes edit --title "Shared" --body "Revised" --folder "Work" # disambiguate duplicate title
inotes delete --title "Old Note" --yes                # permanent; explicit confirmation required
inotes pin "Important Note" --folder "Work"         # pin exact title in folder
inotes unpin "Important Note"                       # unpin; safe to repeat
inotes attach "Project Plan" --file ./demo.wav      # attach a local media file
inotes attachments "Project Plan" --json             # inspect file attachments
inotes links --output ./inotes-links.md              # inventory links across notes
inotes update                                           # upgrade the installed CLI
inotes version
inotes -h                                             # help at every level

show, edit, and delete require one exact title match. If a title is missing or ambiguous, inotes reports an error instead of choosing a note silently. When editing, omitted fields stay as they are; --body replaces the whole body, and --body "" intentionally clears it. Use --folder on show, edit, or delete to scope an exact-title match when duplicate titles exist; it does not move the note. A successful edit is read back and verified. delete requires --yes and removes only a uniquely matched note. Reads and searches never write to Notes. create --folder targets a named folder; omit it to use the default account. inotes update upgrades a uv-managed installation with uv tool upgrade inotes-mcp; Homebrew/pip installations should use their package manager's upgrade command.

pin and unpin use the same exact-title matching and optional --folder disambiguation as show. They are idempotent: repeating the requested state does not toggle it back. AppleScript does not expose a pin property, so these commands select the note and use Notes.app's File → Pin Note menu through System Events. This requires UI scripting access: allow the terminal to control Notes and System Events in Automation settings, and enable the terminal under System Settings → Privacy & Security → Accessibility. Pinning is supported for upgraded iCloud notes and notes stored on the Mac; Recently Deleted notes cannot be pinned. A missing permission or unavailable menu action is an error, not a success. See Apple's pinning guide.

attach takes one local file per invocation and verifies it appears on the uniquely matched note. Notes accepts common files and media; support depends on the account type. Apple documents that Exchange notes cannot attach files. See Apple's attachment guide. Use attachments to list attachment names and IDs for one note.

links is the only command that scans every note body. It extracts external hyperlinks and plain HTTP(S) URLs, returning the source note title, link label, and URL without including note bodies or following links. A report can contain private URLs; --output writes it to a file with owner-only permissions. No report is created unless that option is supplied.


Commands

Command Description
doctor Verify Notes.app Automation access
list List recent note titles (--limit, --json)
search Search note titles and bodies (--limit, --json)
show Show a note by exact title
create Create a note (--title, --body, --folder)
edit Edit a uniquely matched note's title/body (--folder scopes the source match)
delete Permanently delete a uniquely matched note (--yes required)
pin Pin one uniquely matched note (--folder scopes duplicate titles)
unpin Unpin one uniquely matched note (--folder scopes duplicate titles)
attach Attach a local file to one uniquely matched note (--file, optional --folder)
attachments List file attachments on one note (--json, optional --folder)
links Inventory note hyperlinks and plain URLs; optionally write a private report (--output)
update Upgrade the installed CLI with uv
version Print the installed version
mcp Run the built-in MCP server over stdio
agent schema Print a JSON command contract (version, tool, params per command)
agent guide Print a markdown playbook for LLM agents

Help is available at every level: inotes -h, inotes <command> -h, inotes agent -h.


Using inotes from an agent

inotes is CLI-first by design — cheaper on tokens than a full MCP round trip for the common case of list/search/show/create/edit/delete/pin/unpin/attach/attachments. inotes agent schema gives an agent a machine-readable contract of every command and its parameters; inotes agent guide gives it a short playbook (the same rules documented above: run doctor first, --json on list/search, exit code 0 on success). Root and agent help only render command usage; they do not contact Notes.app. Notes automation runs only when a Notes command is invoked.

Built-in MCP server

inotes mcp runs a stdio MCP server exposing the CLI's Notes operations (doctor, list_notes, search_notes, show_note, create_note, edit_note, delete_note, pin_note, unpin_note, attach_file_to_note, list_note_attachments, list_note_links) as MCP tools — no separate package needed. inotes agent schema lists every CLI command and registered MCP tool. Point any MCP client at the installed inotes command:

{
  "mcpServers": {
    "inotes": {
      "command": "inotes",
      "args": ["mcp"]
    }
  }
}

Development

git clone https://github.com/ml-lubich/inotes-mcp.git
cd inotes-mcp
python3 -m pip install -e ".[dev]"
pytest -q
inotes -h

A legacy bash implementation is preserved as inotes.bash.bak for reference.


MIT License · Copyright (c) 2026 Misha Lubich (ml-lubich)

Metadata

Release files for inotes-mcp 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for inotes-mcp 0.3.0
File Size Uploaded Provenance Actions
inotes_mcp-0.3.0.tar.gz 106.8 kB Without provenance Details for inotes_mcp-0.3.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for inotes-mcp 0.3.0
File Interpreter ABI Platform Actions
inotes_mcp-0.3.0-py3-none-any.whl Python 3 none any Details for inotes_mcp-0.3.0-py3-none-any.whl

Total release size: 125.2 kB

Release files / inotes_mcp-0.3.0.tar.gz

Download URL inotes_mcp-0.3.0.tar.gz
Size 106.8 kB
Tags Source
SHA-256 checksum
How to use checksums
f86ee2a24825f28ad6208027a2fbcad84533c771a5332b7e99a914b1ebb2cfb6
BLAKE2b-256 checksum
How to use checksums
f997ad0cfb774fbff96a1fff973d9a023222758790fcdcae5366385b073c54ac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.9

Release files / inotes_mcp-0.3.0-py3-none-any.whl

Download URL inotes_mcp-0.3.0-py3-none-any.whl
Size 18.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
daf1fc3ba1cad5c5b0ef638c4d2705add8ca0c13cc3e48b0b7cbd1f21b08cab8
BLAKE2b-256 checksum
How to use checksums
e16a29481b2aafca0f47a44cf8b9268eee11c944e586f731edc88af3cb4ea7a2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.9

Security for inotes-mcp 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page