A macOS tool that exposes Apple Reminders and Calendars via a local HTTP API, web UI, and MCP server — using EventKit. Zero third-party dependencies for the core server.
- HTTP API — REST endpoints for Reminders, Reminder Lists, Calendar Events, and Calendars
- Web UI — Apple Reminders-style web app at
/appfor managing reminders in the browser - MCP Server — Model Context Protocol server for AI agent integration (Claude Code, OpenClaw, etc.)
- API Docs — Interactive Swagger UI at
/docs - API Key Auth — Read/write and read-only keys with SHA-256 hashing
- Status Bar — Optional macOS menu bar icon
- launchd — Run as a persistent background service
- macOS 14 (Sonoma) or later
- Swift 6.0+ / Xcode 16+
- Node.js 18+ (for MCP server only)
task release # build release binary
task sign # ad-hoc sign (no developer account needed, no expiry)
task install # copy to /usr/local/binapple-bridge keys create --label "my-key"
apple-bridge keys create --label "viewer" --readonly # read-only keySave the key that's printed — it can't be retrieved again.
Run the server once interactively:
apple-bridge servemacOS will prompt you to grant access to Reminders and Calendars. Approve both.
Note: The TCC permission prompt comes from your terminal app, not the binary itself. If it doesn't appear, try resetting permissions first:
tccutil reset Reminders
tccutil reset CalendarThen run the server again.
apple-bridge serve # defaults: 127.0.0.1:23487
apple-bridge serve --host 0.0.0.0 --port 8080 # custom bind
apple-bridge serve --status-bar # show menu bar iconapple-bridge serve --status-bar &
disownFor a persistent background service that starts on login and restarts on crash:
task install # builds release, signs, copies to /usr/local/bin
task setup-launchd # installs and starts the launchd agentThis is the recommended approach for headless servers (e.g. a Mac Mini). No terminal or GUI needed.
task remove-launchd # stop and uninstallEdit com.apple-bridge.agent.plist to change the host/port before installing. Logs go to /tmp/apple-bridge.{stdout,stderr}.log.
apple-bridge keys create [--label <name>] [--readonly]
apple-bridge keys list
apple-bridge keys revoke <id>Keys can be read/write (default) or read-only (--readonly). Read-only keys can only make GET requests — write operations return 403.
Open http://127.0.0.1:23487/app in your browser. Enter your API token to connect. The web UI supports:
- Viewing and switching between reminder lists
- Creating, editing, completing, and deleting reminders
- Due dates, priorities, notes, and URLs
- Search across reminders
- Creating, editing, and deleting reminder lists
Read-only tokens hide all write UI elements.
Open http://127.0.0.1:23487/docs for interactive API documentation. The OpenAPI spec is also available at /openapi.yaml and in docs/openapi.yaml.
The MCP server allows AI agents to manage your Reminders and Calendars as tools.
npm install -g @evoio/apple-bridge-mcpOr use directly with npx (no install needed).
claude mcp add apple-bridge \
-e APPLE_BRIDGE_TOKEN=mb_YOUR_KEY \
-- npx @evoio/apple-bridge-mcptask mcp:build # install deps and compile TypeScript| Variable | Default | Description |
|---|---|---|
APPLE_BRIDGE_TOKEN |
(required) | API key for authentication |
APPLE_BRIDGE_URL |
http://127.0.0.1:23487 |
API server URL |
| Tool | Description |
|---|---|
list_reminder_lists |
List all reminder lists |
create_reminder_list |
Create a reminder list |
update_reminder_list |
Update a reminder list |
delete_reminder_list |
Delete a reminder list |
list_reminders |
List reminders (with filters) |
get_reminder |
Get a single reminder |
create_reminder |
Create a reminder |
update_reminder |
Update a reminder |
delete_reminder |
Delete a reminder |
complete_reminder |
Mark reminder complete |
uncomplete_reminder |
Mark reminder incomplete |
list_calendars |
List all calendars |
create_calendar |
Create a calendar |
update_calendar |
Update a calendar |
delete_calendar |
Delete a calendar |
list_events |
List events in a date range |
get_event |
Get a single event |
create_event |
Create an event |
update_event |
Update an event |
delete_event |
Delete an event |
All endpoints require Authorization: Bearer <key> except GET /health.
All dates are ISO 8601 format. All responses are JSON. Reminders default to showing only incomplete — pass completed=all to include completed.
GET /health
Returns {"status": "ok", "version": "1.0.0"}. No authentication required.
GET /auth/me
Returns {"permission": "readwrite"} or {"permission": "read"}.
GET /reminders
Query parameters (all optional):
listId— filter by reminder listcompleted—false(default),true, oralldueBefore— ISO 8601 datedueAfter— ISO 8601 datepriority— integer (0 = none, 1 = high, 5 = medium, 9 = low)
GET /reminders/:id
POST /reminders # body: {title, notes?, listId?, dueDate?, priority?, url?, alarms?, recurrenceRules?, location?}
PUT /reminders/:id # full update — missing fields reset to defaults
PATCH /reminders/:id # partial update — only provided fields change
DELETE /reminders/:id # returns 204
POST /reminders/:id/complete
POST /reminders/:id/uncomplete
GET /reminder-lists
GET /reminder-lists/:id
POST /reminder-lists # body: {title, color?}
PUT /reminder-lists/:id
DELETE /reminder-lists/:id
GET /events?startDate=2026-04-01T00:00:00Z&endDate=2026-04-30T23:59:59Z
Required: startDate, endDate. Optional: calendarId.
GET /events/:id
POST /events # body: {title, startDate, endDate, calendarId?, notes?, location?, isAllDay?, url?, availability?, alarms?, recurrenceRules?}
PUT /events/:id
PATCH /events/:id
DELETE /events/:id?span=this # span: "this" (default) or "future" for recurring
GET /calendars
GET /calendars/:id
POST /calendars # body: {title, color?}
PUT /calendars/:id
DELETE /calendars/:id
List endpoints return {"items": [...], "count": N}.
Errors return {"error": "snake_case_code", "message": "Human readable"}.
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 204 | Deleted (no body) |
| 400 | Bad request |
| 401 | Unauthorized |
| 403 | Forbidden (read-only key) |
| 404 | Not found |
| 405 | Method not allowed |
| 413 | Request body too large (>1MB) |
| 500 | Server error |
task testUnit tests cover the HTTP parser, router, API key store, Codable models, and CLI parser.
- HTTP server: Apple
Networkframework (NWListener), zero third-party dependencies - EventKit: Shared
EKEventStorewith synchronous service layer - Auth: Bearer token API keys with read/write and read-only permissions, SHA-256 hashed, stored in
~/.config/apple-bridge/keys.json - Web UI: Single HTML page with embedded CSS/JS served at
/app - MCP server: TypeScript, wraps the HTTP API as MCP tools over stdio
- Dual mode: Headless daemon (default) or menu bar icon (
--status-bar)