Metadata-Version: 2.5
Name: mac-stickies-mcp
Version: 1.0.0
Summary: A local MCP server for Apple Stickies on macOS.
Project-URL: Homepage, https://github.com/wangwang0204/mac-stickies-mcp
Project-URL: Repository, https://github.com/wangwang0204/mac-stickies-mcp.git
Project-URL: Issues, https://github.com/wangwang0204/mac-stickies-mcp/issues
Author: Jui-Yang Wang
License: MIT License
        
        Copyright (c) 2026 wangwang0204
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: MacOS X
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Utilities
Requires-Python: >=3.11
Requires-Dist: mcp<3,>=2
Requires-Dist: pyobjc-framework-applicationservices>=11; sys_platform == 'darwin'
Description-Content-Type: text/markdown

# mac-stickies-mcp

A local MCP server for reading and safely editing Apple Stickies on macOS.

> **Status:** `1.0.0` is the stable contract for one currently open Stickies
> app on one screen. It is prepared for production PyPI release; the release
> itself occurs only after the maintainer publishes the matching GitHub Release.

## Scope

- Runs locally on macOS through MCP stdio.
- Is intended to be installed with `uvx mac-stickies-mcp` once published.
- Does not send note contents to a remote service.
- Does not use the Anthropic Python SDK or call an LLM.

Start with the [documentation guide](docs/README.md). The public tool contract
is in [docs/reference/mcp-tools.md](docs/reference/mcp-tools.md); internal
behaviour and safety rules are in [docs/specification.md](docs/specification.md).
The reproducible running-App write study is in
[docs/research/compatibility-study.md](docs/research/compatibility-study.md).
For local development rules, see [AGENTS.md](AGENTS.md) and
[docs/development.md](docs/development.md).

## Available tools

| Tool | Purpose |
| --- | --- |
| `list_notes` | List note titles, previews, versions, and modification times |
| `get_note` | Read one note and obtain its version |
| `search_notes` | Search current local text without uploading or indexing it |
| `list_screens` | Read current screen and Dock/menu-bar-safe rectangles without Accessibility |
| `suggest_note_position` | Suggest a fully visible origin for a known note size without moving it |
| `update_note` | Replace text after version check and backup |
| `append_to_note` | Add plain text while retaining the existing RTF body |
| `backup_note` | Save a complete local note package snapshot |
| `undo` | Revert an MCP edit if the note has not changed since |
| `create_note` | Create a new note only after Stickies exposes a new UUID |
| `get_note_layout` | Read exposed position, size, and window state without moving a note |
| `move_note` | Move a visible note only if its last-read position still matches |
| `delete_note` | Back up then delete a note with a recovery ID; requires `allow_foreground: true` |
| `list_deleted_notes` / `restore_note` | Inspect and recreate a deleted note |

Writes require the `expected_version` returned by `get_note`. With a running,
visible Stickies note that version starts with `ui-sha256:` and the mutation is
performed through Accessibility; Stickies, not this package, owns the later
disk save. A conflict or unsaved human UI edit is reported as a tool error; no
data is overwritten. Every completed write has an `operation_id` that can be
passed to `undo`.

The server keeps backups in
`~/Library/Application Support/mac-stickies-mcp/backups/`. Backups are local
and private to the current user, retained for up to 30 days and 100 per note.
The original Stickies files remain under the user's Stickies container.

### Stable visual-state boundary

The stable API deliberately does **not** set note color, size, or rich-text
styles. Stickies Accessibility exposes commands to change some of these values,
but it does not reliably expose a current note color. Those values therefore
cannot yet receive the same before/after backup and undo guarantees as text.
They are deferred to a read-first state compatibility study. `restore_note`
creates a new note with a new UUID; it restores backed-up text, not an
unverifiable visual state.

`create_note` has a strict safety guard: if Stickies does not surface a new
window with a distinct document UUID, it returns `create_unidentified` without
writing into the currently active note. It waits up to three seconds for the package to
appear, then returns `persistence: "persisted"` or `"pending"`; clients must
wait for the latter before a file-dependent follow-up such as deletion. Successful
responses include `ui_exposure_ms` and `persistence_wait_ms` for diagnostics.

### Stable-scope limitations

- `delete_note` is recoverable, but the only verified Stickies deletion route
  brings Stickies and the target note to the foreground. It requires explicit
  `allow_foreground: true`, so clients must warn the user before it can
  interrupt work or leave the desktop visible after closing the last focused note.
- `move_note` changes only a UUID-matched window's
  `AXPosition`, verifies the result, and does not activate or raise Stickies.
  It requires `expected_position` from `get_note_layout`, so a human drag is a
  safe `layout_conflict` rather than an overwrite. Color, resizing, floating,
  collapsed state, multi-display placement, and layout commands remain
  unimplemented.
- Never remove or replace a `.rtfd` package while Stickies is running. The App
  can retain an in-memory copy and later overwrite or conflict with the file.

## Accessibility setup for writes

Reading and searching do not require Accessibility. Editing a note while
Stickies is open does: the server uses macOS Accessibility to update the exact
visible note rather than replacing its RTF file behind the app's back.

After installation, run this once in the same environment that will launch the
MCP server:

```zsh
mac-stickies-mcp doctor
```

It requests the macOS consent prompt and prints the executable that macOS must
trust. In **System Settings → Privacy & Security → Accessibility**, enable that
reported executable. If an update changes the executable identity, run `doctor`
again and repeat the one-time approval. A missing grant causes a safe
`accessibility_required` error; no note is changed.

## Install and connect

After `1.0.0` is published on production PyPI, install the stable CLI with:

```zsh
uv tool install mac-stickies-mcp==1.0.0
mac-stickies-mcp doctor
```

Before publication, use a locally supplied wheel or a source checkout. For a
local source checkout, use the project's installed CLI so the Accessibility
client has a stable executable:

```zsh
uv tool install mac-stickies-mcp
mac-stickies-mcp doctor
```

Then add it to a local Codex client:

```zsh
codex mcp add mac-stickies -- mac-stickies-mcp
codex mcp list
```

The equivalent `~/.codex/config.toml` entry is:

```toml
[mcp_servers.mac-stickies]
command = "mac-stickies-mcp"
default_tools_approval_mode = "writes"
```

`writes` keeps read tools convenient while asking before mutation tools. In the
ChatGPT desktop app, the same shared configuration can also be added from
**Settings → MCP servers → Add server**, selecting **STDIO** and entering
`mac-stickies-mcp` as the command.

## Uninstall and local data

```zsh
uv tool uninstall mac-stickies-mcp
```

Uninstalling the tool does not touch Apple Stickies or its backups. To remove
MCP-only recovery data, first inspect
`~/Library/Application Support/mac-stickies-mcp/backups/`, then move the
`mac-stickies-mcp` folder to Trash manually if it is no longer needed. Remove
the corresponding Accessibility entry in **System Settings → Privacy &
Security → Accessibility** if you no longer want the executable to control
Stickies.

## Development

```zsh
uv sync --all-groups
uv run python -m unittest discover -s tests -v
uv run ruff check .
uv run ruff format --check .
```

For a local development connection, use the project's installed CLI at
`.venv/bin/mac-stickies-mcp` as the MCP stdio command. The eventual PyPI
installation command will be `uvx mac-stickies-mcp`.

The prototype exporter lives at `scripts/export_stickies.py`. It reads local
Stickies and writes a Markdown snapshot under `work/`, which is ignored by Git.

## Project layout

```text
src/mac_stickies_mcp/  Package source
tests/                 Automated tests and non-private fixtures
scripts/               Development-only helper scripts
docs/                  Public reference, maintainer docs, and research evidence
work/                  Local generated files; never committed
```

## License

[MIT](LICENSE)
