Native Apple apps for AI agents — Calendar, Reminders, Mail, Notes,
Contacts and Messages over MCP. Rust control plane, native Swift helper
(EventKit + ScriptingBridge), plus a detached Swift crawl worker that
compiles AppleScript through NSAppleScript (OSA) to index Mail. No
osascript processes, no Python.
Disclaimer: bite is an independent open-source project. It is not affiliated with, sponsored, or endorsed by Apple Inc. macOS, iMessage, iCloud, Calendar, Mail, Notes, Messages, Contacts and other Apple marks are trademarks of Apple Inc.
cargo install bite-mcp
bite setupThen in Claude Code or ZCode:
/plugin marketplace add ktesio/bite-mcp
/plugin install bite@bite-mcp
…or let bite setup write MCP config directly into Codex, OpenCode, Cursor,
VS Code, Gemini CLI (whichever it detects).
45 MCP tools + mirrored CLI verbs:
| App | Engine | Tools |
|---|---|---|
| Calendar | EventKit (native) | list, search, get, create, update, delete, availability/free-busy |
| Reminders | EventKit (native) | lists, search, create (alarms), update/complete, delete |
| ScriptingBridge | accounts, mailboxes, search, get, send, reply, forward, move, mark, delete, attachment save | |
| Notes | ScriptingBridge | folders, search, get (markdown+HTML), create, update (append), delete |
| Contacts | Contacts.framework (native) | search, get, create, update, delete, groups |
| Messages | ScriptingBridge + chat.db | send, recent chats, history |
| Index | LanceDB + bite-crawl worker |
index_rebuild, index_status, index_crawl_cancel, search, mail_bulk_* — plus index_wipe (callable via CLI/tools/call, not advertised in tools/list) |
Plus MCP resources (bite://calendars, bite://mail/mailboxes, …) and
prompts (plan-my-week, triage-inbox, daily-brief).
Every tool is also a human CLI verb:
bite reminders lists
bite reminders create "Water the plants" --due "tomorrow 9am"
bite calendar availability --from "today 9am" --to "today 6pm"
bite calendar create-event --title "Standup" --start "tomorrow 10am" --duration-minutes 15
bite mail search --mailbox INBOX --unread --limit 10
bite notes create --title "Ideas" --body "# Idea\n- **thing**"Bite indexes your mail into its own LanceDB database (in bite's data dir, mode 0700) and answers searches locally — no Apple Events on the query path.
| Operation (124k-message mailbox) | bite | Typical per-message AppleScript MCPs |
|---|---|---|
| Index/ingest 100k messages | 7.1 s one-time | n/a (never completes) |
| Full-text search | 8–10 ms | 120 s+ timeout at 100 messages |
| Exact count (66k unread) | 8.9 ms | times out |
| Bulk mark-unread-read | a handful of Apple Events total | 1,834+ events |
Reproduce: cargo run -p bite-index --example bench_100k --release.
Bulk ops (mark/move/delete over a filtered selection — unfiltered
whole-mailbox runs are refused) likewise run as a whose-clause script per
operation plus verification counts — a handful of
Apple Events total, still O(1) vs per-message: Mail iterates internally
while bite waits.
Mail crawl throughput depends on Mail's own Apple Event latency; the index-side numbers above are the LanceDB bench.
Agent / human
│
bite (Rust): MCP stdio server · CLI · setup · doctor · config writers
│ line-delimited JSON (docs/protocol.md)
bite-helper (Swift, installed once at a stable path):
├─ EventKit → Calendar, Reminders (full CRUD)
├─ Contacts.framework → Contacts (full CRUD)
└─ ScriptingBridge → Mail, Notes, Messages (Apple Events, no osascript)
bite (Rust) also spawns a background worker for the Mail index:
bite-crawl (Swift, detached worker): Mail crawl → staged JSONL batches
│ batches/*.jsonl
▼
bite (Rust) ingests them into the entity index (LanceDB) — instant local search
- Native, not
osascript. Every call goes through Apple's own APIs (EventKit, Contacts.framework, ScriptingBridge — and NSAppleScript for the Mail crawl worker). - OSA-mediated Apple Events. From macOS 27, raw (non-OSA) Apple Event senders get silent empty replies. Every bite component that sends Apple Events goes through OSA — the helper via ScriptingBridge, the Mail crawl worker via NSAppleScript — so events are answered normally; TCC behavior is unchanged.
- Stable helper path (
~/Library/Application Support/bite/bin/) keeps macOS TCC permission grants valid across upgrades. - One registry, two faces. MCP
tools/listschemas and CLI verbs are generated from the same table (crates/bite-core/src/registry.rs); a CI conformance test fails if Swift handlers and the Rust registry drift apart. - Agent-friendly errors. Permission denials return an exact
fix— a command or a System Settings deep link the agent relays verbatim. - Confirm-before-destruct. Deletes/moves return a preview until the caller
passes
confirm: true.
| Path | Command | Needs |
|---|---|---|
| crates.io (source) | cargo install bite-mcp |
Xcode Command Line Tools (compiles both Swift binaries — helper + crawl worker) |
| marketplace (Claude/ZCode) | /plugin marketplace add ktesio/bite-mcp |
bite on PATH first |
| other agent CLIs | bite setup (writes their MCP config) |
bite on PATH |
bite setup— installs the helper, runsbite doctor, configures detected agent CLIs, prints marketplace commands. The full walkthrough, including exactly what gets written where and how to recover from anything unusual: docs/setup.md.- First call per app shows macOS's own permission prompt once (Calendar, Reminders, Contacts, and one "wants to control Mail" prompt per SB app). The crawl worker is a separate binary with its own TCC identity, so Mail indexing raises one more "wants to control Mail" prompt of its own — see docs/permissions.md.
- Denied something?
bite doctor --fixopens the right System Settings panes (bite doctor --jsonfor scripts — same report, same exit codes).
A note on disk usage: target/ growing into many GB over weeks of cargo build/cargo test is normal Cargo behavior — every rebuild leaves a new
hashed copy of each binary/rlib (the Lance/DataFusion debug tree is heavy).
When it hurts, cargo clean and rebuild. The workspace pins
[profile.dev] debug = "line-tables-only", which keeps backtraces with
file/line while cutting the debug-info weight of dependencies roughly by a
third. Test scratch dirs are Drop-guarded (tempfile), so even panicking
test runs leave nothing behind in $TMPDIR — and bite doctor now sweeps
stale bite-* scratch there itself (the same 24h window it uses for
swift-build leftovers; fresh entries that might belong to a running test
binary are left alone) and shows a
storage overview (index size, batch backlog, leftover scratch) if you
suspect litter. When you run bite straight from a checkout
(target/debug, target/release), doctor also reports the build tree's
current size — the number that tells you when cargo clean is worth it.
- Local-only. bite runs entirely on your Mac. It makes no network calls beyond what macOS itself requires, collects no telemetry, and has no accounts or servers — your mail, messages, contacts, calendar events and notes never leave the device.
- Your data, your grants. Access happens only through macOS's own permission system (TCC), with visible, one-time prompts. Every grant is visible and revocable in System Settings → Privacy & Security — see docs/permissions.md.
- Own-device tool. bite is designed to operate on the data of the person running it, on their own machine, with their knowledge. Acceptable use: do not use bite to access another person's device or accounts, or to monitor anyone without their consent — that is unlawful in most jurisdictions and outside the purpose of this project.
- Full statement: PRIVACY.md.
- PRIVACY.md — privacy statement and intended use
- NOTICE.md — attribution and trademark notices
- SECURITY.md — how to report security issues
- CHANGELOG.md — notable changes per release; tags are gated on a matching section
- docs/setup.md — first-time setup, end to end
- docs/PLAN.md — the full implementation plan
- docs/protocol.md — the Rust↔Swift helper protocol and the crawl batch handoff
- docs/permissions.md — every TCC prompt and how to recover
- docs/adding-an-app.md — add Music/Finder/anything
- docs/ROADMAP.md — Phase 2 surface