Skip to main content

One consolidated MCP server for native macOS apps (Calendar, Reminders, Mail, ...).

Project description

macos-apps-mcp

One consolidated MCP server for native macOS apps — Calendar & Reminders read/write, Messages & Notes content search over the native stores, id-first Mail with draft-and-open replies, plus read-only context and a few actions across Contacts, Photos, Safari, and Shortcuts. Python + FastMCP 2.0, managed with uv.

Replaces the pile of Apple MCP servers a life-cockpit otherwise juggles with a single modular adapter layer you own. Every read returns pointers (id + one-line summary + open-in-app deeplink), never full bodies — so it structurally avoids the context-bloat bug of the archived flagship server; bodies are a separate, bounded, opt-in fetch.

macOS only. See DESIGN.md for the rationale and CHANGELOG.md for what's landed.

Install

Requires macOS and Python ≥ 3.11.

From source (works today):

git clone https://github.com/elfensky/macos-apps-mcp && cd macos-apps-mcp
uv sync

Then point your MCP client at the project's own venv python — deterministic, and it carries the locked PyObjC wheels:

{
  "mcpServers": {
    "macos-apps": {
      "command": "/absolute/path/to/macos-apps-mcp/.venv/bin/python",
      "args": ["-m", "macos_apps_mcp"]
    }
  }
}

From PyPI (once published — see the CHANGELOG): uvx macos-apps-mcp runs the server with no clone, and the MCP config becomes "command": "uvx", "args": ["macos-apps-mcp"] (same "macos-apps" key).

Permissions (macOS TCC)

Grant access when macOS prompts — the first call to each app triggers its dialog:

  • EventKit — Calendar + Reminders (read/write).
  • Automation (per app) — Mail, Notes, Contacts, Photos, Safari, Messages actions/reads.
  • Full Disk Access — required for Messages content (chat.db) and the fast Notes path (NoteStore.sqlite). Notes degrades to Automation without it; Messages content raises a clear, typed error telling you to grant it. Run the doctor tool to see what's granted.

Tools

Reads return pointers; results are capped per adapter. Bodies/content are a separate bounded fetch. Writes/actions are skipped entirely when MACOS_APPS_READ_ONLY is set (see below).

Calendar & Reminders — read/write (EventKit)

Tool Args Notes
events when = today | week | YYYY-MM-DD list events as pointers
free_busy start, end (ISO), optional calendars ids merged busy intervals + free gaps in the window; no event details
reminders due = today | overdue | this-week | a list name list reminders as pointers
calendars / reminder_lists containers (id + name) to target writes
create_event / update_event title, start, end (ISO), calendar, location, notes, all_day, recurrence update is a full replace by id
delete_event id, span, dry_run dry_run previews without deleting
create_reminder / update_reminder title, due, list_name, notes, priority (0–9), start, recurrence update is a full replace by id
complete_reminder id marks complete

A write targets its container by name or Pointer.id; an ambiguous name raises rather than guessing. Recurrence is an RFC 5545 RRULE (FREQ/INTERVAL/COUNT/UNTIL subset, e.g. FREQ=WEEKLY;INTERVAL=2;COUNT=10); a recurring reminder needs a due date; unsupported parts (BYDAY, …) are rejected, not ignored.

Mail — id-first read + draft-and-open (Automation)

Nothing here ever sends — replies and drafts open a compose window for you to review.

Tool Args Notes
mail subject-OR-sender substring inbox matches; id = stable RFC822 message-id, message:// deeplink
mail_body id one message's plaintext, bounded + truncation-marked
mail_attachments mailbox (inbox/sent/drafts/trash/junk), optional query attachment name/size/downloaded per message; works on Drafts
create_draft to, subject, body opens a draft for review — never sends; returns a locator
mail_reply message_id, reply_body, include_quote native threaded reply (sets In-Reply-To/References), quoted original, opens for review — never sends

Messages — content via chat.db (read-only; Full Disk Access)

Tool Args Notes
messages_chats conversation list (id + name); no content, no FDA needed
messages_search query, limit search message text (decodes attributedBody), newest first
messages_with contact (phone/email), country, limit recent messages with one person; country = calling code or 2-letter region (locale default, never +1)
message_body id full text of one message by guid

Notes — NoteStore.sqlite reads + opt-in bodies

Tool Args Notes
notes title/snippet substring matching notes (id + snippet); diacritic- & smart-punctuation-insensitive
notes_all every live note (id + "Account / Folder" + snippet), Recently Deleted excluded
note_bodies ids (≤ 50) opt-in plaintext hydration → [{id, body}]
delete_note id, expect_title, dry_run moves to Recently Deleted; dry_run previews

Other read-only context

Tool Args Returns
contacts name substring cards (name, org, first phone + email)
photos search string media (filename); matches the Photos search field
safari_tabs every open tab (url + title)
shortcuts name substring (empty = all) the user's Shortcuts; id = stable UUID, shortcuts:// deeplink
ping / now / doctor health check / time / permission diagnostics

Actions (writes)

Tool Args Notes
create_contact given_name, family_name, organization
run_shortcut name or id, optional input_text runs a Shortcut; returns a bounded output snippet
safari_open url opens in a new tab; bare host → https://; only http/https allowed

Read-only mode

Set MACOS_APPS_READ_ONLY=1 (or true / yes) to register reads only — every write and action tool is skipped, a safe-deploy guard. (Reads may still open apps / read local stores.)

Develop

uv sync
uv run pytest                   # unit tests (mock at the adapter boundary)
uv run pytest -m integration    # real macOS / EventKit / TCC — run manually, never in CI
uv run ruff check .             # lint (config in pyproject.toml)
uv run ruff format .            # format
uv run macos-apps-mcp                  # run the server (stdio)

ruff (lint + format, line-length 88) and pytest gate CI — full workflow in CONTRIBUTING.md.

Prior art & credits

macos-apps-mcp builds on prior work — the Apple Mail MCP it draws from, the EventKit/Photos servers it references, the project that pioneered the unified-Apple-MCP pattern, and FastMCP / PyObjC / the MCP spec it depends on. See CREDITS.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

macos_apps_mcp-0.7.0.tar.gz (346.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

macos_apps_mcp-0.7.0-py3-none-any.whl (92.5 kB view details)

Uploaded Python 3

File details

Details for the file macos_apps_mcp-0.7.0.tar.gz.

File metadata

  • Download URL: macos_apps_mcp-0.7.0.tar.gz
  • Upload date:
  • Size: 346.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.31 {"installer":{"name":"uv","version":"0.11.31","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for macos_apps_mcp-0.7.0.tar.gz
Algorithm Hash digest
SHA256 a3ba4b2213ea7ca993199a8ab11dc4e7b98e5e769d6d36e8af82721198da9cd7
MD5 4c26fd1ad70135d77dfe673a41c8e674
BLAKE2b-256 cb860a0abe43163097783e25e0dbed4b80d98be932e23be4e7d263c74a2791cf

See more details on using hashes here.

File details

Details for the file macos_apps_mcp-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: macos_apps_mcp-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 92.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.31 {"installer":{"name":"uv","version":"0.11.31","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for macos_apps_mcp-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c5847b37bb19be7c55c1aa8647620419baccee8c1526bccc797494d66c9eafce
MD5 ca78d83d4a93b2b4327b4856e0648659
BLAKE2b-256 6c2b297799d6aab62009dede4dcf5735aa06e3938588e40cf3c7a600ac8636e9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page