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 alwaysinotes.
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)
| 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)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| 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.