Apple Calendar

io.github.JonathanRReed由 GitHub 帳號 JonathanRReed 發布v1.1.6更新於 Nov 7, 2026

List, create, update, and delete events in Apple Calendar on macOS.

已驗證STDIO僅桌面效率與工作流檔案與儲存

概覽

AI 產生的概覽

本機 macOS MCP 伺服器,讓助理透過 EventKit 列出、建立、修改與刪除 Apple 行事曆事件,並提供安全模式與行事曆允許清單。

可以做什麼
  • 列出行事曆與指定時間範圍內的事件,並取得事件完整詳情
  • 建立、修改與刪除事件,支援提醒與重複事件的作用範圍
  • 檢查伺服器健康狀態、存取權限狀態,提供授權指引並在權限變更後重新檢查
  • 依關鍵字搜尋工具,並為上下文受限的用戶端載入某個工具的完整結構
適用情境
適合希望助理在 Mac 上檢視行程、確認空檔,或新增與修改 Apple 行事曆約會的情境,同時讓行事曆本身繼續作為記錄來源。也適合只需要行事曆功能、不想使用一體成型伺服器的使用者。
執行需求
僅能在 macOS 上本機執行,以 stdio 方式透過 uvx 從 PyPI 套件啟動(或使用複製倉庫中的啟動腳本,需 Python 3.11+),也可使用 .mcpb 安裝包。需要授予 macOS 行事曆存取權限。選用環境變數可設定安全模式與行事曆允許清單。
安裝前請注意
它會建立、修改與刪除真實行事曆事件,建議設定安全模式與允許清單;safe_readonly 會阻擋所有寫入。允許清單是伺服器端政策而非 macOS 沙箱,且名稱須完全相符,同名行事曆會擴大作用範圍。回傳的行事曆資料可能被 MCP 用戶端傳送給其模型供應商。部分寫入失敗或逾時後結果未知,重試前應先檢查事件。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Apple Calendar,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

Apple Calendar

MCP server for Apple Calendar on macOS.

Provides access to calendars and events through EventKit. Keep Calendar as the system of record while enabling agents to read, create, update, and delete events.

When to use

  • Calendar-only workflows
  • EventKit-backed calendar access without the all-in-one server
  • Tighter app-level separation for scheduling

What It Does

  • Discover and list calendars
  • Create, read, update, and delete events
  • Tool discovery helpers search_tools and get_tool_info for context-constrained clients
  • Today resources and planning prompts
  • Health checks that distinguish empty results from blocked access
  • Read fallback through Calendar.app automation when native EventKit reads are blocked on supported local setups
  • Permission recovery: calendar_permission_guide, calendar_recheck_permissions

Install On This Mac

Quick start (uvx, from PyPI)

With uv installed:

bash
uvx apple-calendar-mcp

No clone, no venv management.

From a clone
bash
git clone https://github.com/JonathanRReed/Apple-MCPs.gitcd Apple-MCPsuv sync --all-packages

This builds one workspace environment with every server's entry point in .venv/bin (for example .venv/bin/apple-calendar-mcp). You can also point an MCP client at Apple-Calendar-MCP/start.sh, which prefers uv run and falls back to a plain venv bootstrap (Python 3.11+ required).

Install In AI Agents

Generic MCP client config
json
{  "mcpServers": {    "apple-calendar": {      "command": "uvx",      "args": ["apple-calendar-mcp"],      "env": {        "APPLE_CALENDAR_MCP_SAFETY_MODE": "safe_manage"      }    }  }}

Running from a clone instead? Use /path/to/Apple-MCPs/Apple-Calendar-MCP/start.sh as the command with empty args.

Claude Code example
bash
claude mcp add --transport stdio --scope user apple-calendar -- uvx apple-calendar-mcp

--scope user makes the server available in every project. To share it with one repository through its .mcp.json instead, use --scope project.

Selecting calendar and event identifiers

Call calendar_list_calendars, select the intended calendar by its displayed name and source, and pass its returned calendar_id unchanged to calendar_list_events, calendar_create_event or the destination of calendar_update_event. Native EventKit listings return native identifiers; automation listings use calendar names as identifiers. When EventKit can read calendars, a calendar name passed to calendar_create_event or calendar_update_event is resolved to its native calendar, ignoring case and extra whitespace, so the write keeps full alarm support. A name shared by several calendars returns AMBIGUOUS_CALENDAR with the candidates; pass the intended calendar_id instead. Unknown names return CALENDAR_NOT_FOUND and read-only calendars return CALENDAR_READ_ONLY. Without native calendar read access, names still use automation.

After changing Calendar permissions, restart the MCP server and call calendar_list_calendars again to refresh identifiers. For full alarm replacement or clearing, list events with the native calendar_id and pass the returned native event_id to calendar_update_event. Existing applescript:: event IDs still use automation after permissions change. Treat event IDs as opaque: re-list to obtain native IDs instead of rewriting an existing token. Calendar writability, safety modes and allowlists still apply.

Bridge Batch Lookup

The internal Python CalendarBridge.get_events(event_ids) method batches native lookups without adding an MCP tool. Pass a sequence of non-empty strings, at most 10000 input IDs. Duplicate input IDs are resolved once. Requests are chunked to an exact 32768-byte UTF-8 JSON argv budget, including JSON escaping; an individual oversized ID is rejected before any lookup.

The returned mapping distinguishes:

  • An event value: a validated response for the requested ID
  • None: an explicit native miss confirmed through the existing single-get/JXA fallback, or a definitive miss on that fallback path
  • An absent key: unknown, including unanswered, malformed, contradictory, duplicate-response, mismatched, or unsupported entries

JXA-issued IDs are opaque versioned tokens that identify the Automation backend, calendar scope, and exact UID or id() namespace/value. Do not parse or construct them. UID-less events keep their actual typed id() value; distinct events with identical metadata no longer collapse. Rows without usable identifiers, or duplicate provider identities, receive display-only weak tokens. Weak tokens cannot prove absence or authorize writes.

Versioned tokens resolve directly through verified, server-filtered JXA lookups. A single matching calendar and event are required; ambiguous, unavailable, malformed, or mismatched lookups remain unknown. No unfiltered event-directory scan is used. Lookup snapshots are capped at 1000 calendars and 1000 returned matches per query, and identifiers at 32768 characters. Legacy bare UID/id values still resolve when their namespaces unambiguously identify the same event. Legacy calendar/start/title composites remain readable when unique, but cannot authorize mutations or definitive batch absence. Legacy values that resemble versioned tokens are rejected if their meanings conflict.

Legacy fallback identifiers, including encoded identifiers that could also be literal provider UIDs, require collision checks across calendars. Those exact queries can exceed the 30-second fallback deadline on large calendar stores. A timeout is an explicit error and does not establish absence or permit a mutation. Full native EventKit access avoids that fallback lookup for native identifiers: grant the host app full Calendar access, list events again to obtain native IDs, then retry. Existing fallback identifiers retain their strict collision checks.

Native misses retry the single-get/JXA path. If the whole native batch cannot answer, a fallback miss for an opaque native ID remains unknown because JXA may use a different identifier format. A verified versioned JXA miss can establish absence. Permission or per-ID confirmation failures remain unknown; non-fallback whole-helper transport failures remain explicit errors. A valid native reply with a different canonical ID requires a separate single-get lookup confirming that canonical ID. Conflicting or unconfirmed aliases remain unknown. Unsupported legacy uid: IDs remain unknown without a lookup. Callers must not delete mappings for absent keys.

JXA in-place updates and deletion require a strong, unique identity and reject stale calendar names before writing. Calendar moves through the JXA fallback are explicitly unsupported because cloning cannot safely preserve every event field. Native Calendar moves remain available. Recurrence updates through versioned JXA IDs are also unsupported.

The native batch command itself reports EventKit-only lookup outcomes. Synthetic IDs produce UNSUPPORTED_IDENTIFIER; native EVENT_NOT_FOUND alone is not a confirmed absence across both backends.

Safety Modes

  • safe_readonly
  • safe_manage
  • full_access

Calendar allowlists

Set these environment variables in your MCP client's configuration, then restart the server:

VariableEffect
APPLE_CALENDAR_MCP_ALLOWED_CALENDARSComma-separated calendar names the server may read or modify. Calendar listings, event listings, event details, and Calendar resources respect this scope.
APPLE_CALENDAR_MCP_WRITE_ALLOWED_CALENDARSAdditional comma-separated calendar names the server may create, update, or delete events in. It does not hide other readable calendars.

For an assistant that may read your schedule but only write to a dedicated calendar:

json
{  "APPLE_CALENDAR_MCP_SAFETY_MODE": "safe_manage",  "APPLE_CALENDAR_MCP_WRITE_ALLOWED_CALENDARS": "AI Planning"}

Leaving either allowlist unset or empty applies no restriction from that list. When both are set, writes must pass both; safe_readonly blocks all writes regardless of either list. Moving an event checks both the source and destination calendar. A write with an unresolved target is rejected when an allowlist is configured.

Names are exact, case-sensitive matches after trimming configuration whitespace. Every calendar with a matching name is included, so use unique calendar names for security-sensitive scopes. calendar_health reports the configured write allowlist.

These are policies enforced by the Python MCP server, not a macOS sandbox. Direct use of the native helper or bridge library does not enforce them. macOS permissions still apply, and your MCP client may send returned data to its model provider.

Transport

stdio is the default and recommended transport. Set APPLE_CALENDAR_MCP_TRANSPORT=streamable-http (with optional APPLE_CALENDAR_MCP_HOST and APPLE_CALENDAR_MCP_PORT) to serve Streamable HTTP instead.

macOS Permissions

  • Calendar access is required
  • calendar_health reports native access_status, read access, and write access without trying AppleScript fallback or requesting permissions. Explicit Calendar reads can still use the existing automation fallback.

Launch Checklist

  • Add uvx apple-calendar-mcp (or a clone's Apple-Calendar-MCP/start.sh) to your MCP client
  • Reload or reconnect the client so the Calendar tool surface is loaded into context
  • Call calendar_health first
  • If access is blocked or access_status is not_determined, call calendar_permission_guide
  • After changing macOS permissions, call calendar_recheck_permissions

Prompting Notes

  • tools/list returns the full Calendar tool surface. Context-constrained clients can use search_tools first, then get_tool_info for the Calendar tool they need.
  • Before creating events, confirm the date, time, duration, and title with the user
  • Use Calendar for scheduled time blocks, meetings, and appointments

Related

Event alerts

calendar_create_event and calendar_update_event accept alarms: an array of { "minutes_before": 15 } or { "absolute_iso": "2030-10-11T10:00:00Z" } objects. Absolute dates require an explicit Z or UTC offset; timezone-naive dates are rejected. Relative offsets must be whole minutes from 0 through 525600; each event accepts at most 100 alarms. Omit alarms to preserve existing alerts on update, or pass [] to clear them.

Event detail and list responses include alarm metadata. EventKit reports relative, absolute, and location alerts. Full alarm replacement and clearing require native EventKit access. The Calendar scripting fallback can create initial display alerts and read the alert types exposed by Calendar's scripting dictionary. If an alarm edit requires removing existing alerts, or the existing alert collections cannot be read, it returns ALARM_EDIT_REQUIRES_NATIVE before changing any event fields. Omit alarms to preserve existing alerts while updating other fields. Fallback updates that combine explicit alarms (including []) with any non-null title, time, location, notes or all-day field require native EventKit, even if that field already has the supplied value. An unchanged calendar_id is not a field write; moves remain unsupported. Alarm-only updates can add initial display alerts when all four alert collections are readable and empty; [] is then a no-op. Fallible event-record reads finish before insertion. If an insertion fails or a mutation times out, the outcome may be unknown: no individual alerts are deleted, and the event must be inspected before retrying. Fallback parity is still tracked in issue #41.

calendar_health reports alarm_edit_backend: "native_eventkit" and can_edit_existing_alarms, based on native read/write permission. Calendar writability and server safety rules still apply to each edit.

Thanks to LightSpeedSpirit for the original event-alarm contribution in PR #26.

Repeating events

Every occurrence of a repeating event shares one event_id, so calendar_update_event and calendar_delete_event take two optional arguments that say which occurrences a write covers. calendar_list_events marks these events with recurring: true.

  • scope: "occurrence" for one occurrence, "following" for that occurrence and every later one, or "series" for every occurrence.
  • occurrence_start_iso: for "occurrence" and "following", the occurrence's start exactly as calendar_list_events returned it.

A write to a repeating event without scope changes nothing. If the client supports MCP forms (elicitation) and the call names an occurrence, the server asks the user to choose: only this occurrence, this and all following, or the whole series. Otherwise it returns RECURRING_EVENT_SCOPE_REQUIRED, telling the agent to ask the user and call again. The user, not the model, makes the choice, so an agent can't delete a whole series by guessing. A user who declines the question gets CANCELLED_BY_USER. Events that don't repeat work exactly as before.

An occurrence edited on its own gets its own event_id; writes through it accept the same scope. With "series", a new start_iso/end_iso moves every occurrence by the same amount. deleted in the response reports whether the targeted occurrences are actually gone. Scopes need native EventKit access; Calendar automation returns UNSUPPORTED_OPERATION.

Thanks to vlasovpe-sg for the detailed report and root-cause analysis in issue #79.

來源:Apple-Calendar-MCP/README.md,提交 9acda09

工具

13

calendar_health

Calendar Health

Report the active Apple Calendar server configuration.

無需輸入參數。

calendar_permission_guide

Calendar Permission Guide

Explain how to grant Apple Calendar permission on macOS.

無需輸入參數。

calendar_recheck_permissions

Calendar Recheck Permissions

Recheck Calendar access after the user changes macOS permissions, and notify the client that Calendar resources changed.

無需輸入參數。

calendar_list_calendars

List Calendars

List available Apple Calendar calendars. Select by name and source, then pass the returned calendar_id unchanged. Re-list after Calendar access changes to refresh identifiers.

無需輸入參數。

calendar_list_events

List Events

List calendar events in a time window, optionally filtered to one calendar. Use calendar_id from calendar_list_calendars. Listing through native EventKit returns native event IDs for full alarm edits.

輸入參數limitend_iso必填start_iso必填calendar_id

calendar_get_event

Get Event

Fetch full details for a calendar event by event_id.

輸入參數event_id必填

calendar_create_event

Create Event

Create a new event in a specific Apple Calendar calendar. Use the exact calendar_id returned by calendar_list_calendars. With native access, a unique calendar name resolves to its native calendar; duplicate names return AMBIGUOUS_CALENDAR. Optional alarms: list of {minutes_before: N} or {absolute_iso: ISO datetime}. Automation can add initial display alerts only when no inherited alerts need removal; full alarm editing requires native EventKit access.

輸入參數notestitle必填alarmsall_dayend_iso必填locationstart_iso必填recurrencecalendar_id必填

calendar_update_event

Update Event

Update one or more fields on an existing calendar event. For full alarm edits, list events using a native calendar_id and pass the returned native event_id. Existing applescript:: IDs continue to use automation after access changes. Optional alarms: list of {minutes_before: N} or {absolute_iso: ISO datetime}; pass [] to clear alarms, omit to leave unchanged. Replacing or clearing existing alarms, or combining explicit alarms with other field edits, requires native EventKit access. Automation rejects combined requests before any mutation, including [] or unchanged field values. Omit alarms for ordinary field edits; alarm-only initial alerts or [] no-ops require all alert collections verified empty. For a repeating event (recurring: true in calendar_list_events), pass scope and, for one occurrence or those following it, occurrence_start_iso. Without scope, the user is asked to choose when the client supports forms; otherwise the call returns RECURRING_EVENT_SCOPE_REQUIRED and nothing changes.

輸入參數notesscopetitlealarmsall_dayend_isoevent_id必填locationstart_isorecurrencecalendar_idoccurrence_start_iso

calendar_delete_event

Delete Event

Delete a calendar event by event_id. For a repeating event (recurring: true in calendar_list_events), pass scope and, for one occurrence or those following it, occurrence_start_iso. Without scope, the user is asked to choose when the client supports forms; otherwise the call returns RECURRING_EVENT_SCOPE_REQUIRED and nothing changes.

輸入參數scopeevent_id必填occurrence_start_iso

calendar_list_prompts

Calendar List Prompts

Fallback prompt discovery tool for tool-only MCP clients.

無需輸入參數。

calendar_get_prompt

Calendar Get Prompt

Fallback prompt rendering tool for tool-only MCP clients.

輸入參數name必填arguments_json

search_tools

Search Tools

Search this server's tool catalog by keyword, alias, or domain tag.

輸入參數modelimitquery必填domain_tags

get_tool_info

Get Tool Info

Load the full schema, examples, and metadata for one tool from this server.

輸入參數name必填include_schemainclude_examples

版本歷史

8
  1. v1.1.6最新Nov 6, 2026
  2. v1.1.4Oct 29, 2026
  3. v1.1.3Oct 22, 2026
  4. v1.1.2Oct 14, 2026
  5. v1.1.1Oct 13, 2026
  6. v1.1.0Oct 10, 2026
  7. v1.0.5Sep 26, 2026
  8. v1.0.4Sep 16, 2026

評分

已滿足適用檢查項的 90%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分
  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分