macOS Apps について
macOS Apps は、Mail、Calendar、Reminders、Notes などの macOS アプリに一つのインターフェースからアクセスするローカル MCP サーバーです。ポインターを先に返し、内容は上限付きで別途取得します。書き込みは段階化・監査され、削除などは事前確認できます。
主な機能
- 01複数の macOS アプリにアクセス
- 02検索結果をポインターで返却
- 03上限付きコンテンツの個別取得
- 04書き込みの段階化と監査ログ記録
- 05削除・移動・送信の事前プレビュー
活用シーン
- 01カレンダーの予定と空き時間を確認
- 02返信が必要なメールを探して下書きを開く
- 03メール移動を事前確認して取り消す
MCP 対応
macOS アプリを検索・読み取り・書き込みするツールをローカル MCP サーバーとして提供します。アプリごとにアダプターを無効化でき、読み取り専用モードでは書き込みが停止します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
macos-apps-mcp
macOS 上の Mail、Calendar、Reminders、Notes、Messages、Contacts、Photos、Safari、Music、Shortcuts を扱う、ローカルで動作する MCP サーバーです。検索や一覧表示では、ID、1 行の概要、アプリで項目を開くリンクが返されます。本文は別途取得し、取得量には上限があります。書き込みは段階的に制御され、監査ログに記録されます。削除、移動、送信は、まずプレビューを表示します。macOS 専用です。Python + FastMCP + uv を使用します。DESIGN.md と CHANGELOG.md をご覧ください。
できること
- 「今週の予定は何ですか? 木曜日の午後はいつ空いていますか?」
events、free_busy - 「返信が必要なメールはどれですか? 最初のメールへの返信を下書きしてください。」
mail_needs_response、mail_reply。返信は Mail で下書きとして開きます。送信はされません。 - 「受信トレイにあるニュースレターを Archive に移動してください。まず内容を見せてください。」
mail_search、move_mail、mail_undo。移動はデフォルトでプレビューされます。以下の既知の制限内で、mail_undoによって移動を元に戻せます。
安全性とプライバシー
- ローカルで動作します。 テレメトリーや独自のネットワークリクエストはありません。使用するのはローカルの unix ソケット(デーモンへのシム)と 127.0.0.1 上のダッシュボードのみです。呼び出されたときにアプリを介して Mac の外部と通信するツールは 3 つあります。送信ツール(デフォルトでは無効)は Mail 経由で送信し、
safari_openはページを開き、run_shortcutは Web を呼び出す可能性のある Shortcut を実行します。 - 3 つの段階があります。 読み取り、書き込み、外部への送信です。アプリごとに有効化するまで、送信ツールは利用できません。デーモンでは
macos-apps-mcp allow-send mail、stdio ではMACOS_APPS_ALLOW_SEND=mailを指定します。MACOS_APPS_READ_ONLY=1を指定すると読み取りツールのみが登録され、ほかの設定より優先されます。 - まずドライランを行います。
delete_draft、move_mail、trash_mail、mail_undo、send_mail、reply_all、forward_mail、delete_reminder、delete_event、delete_note、update_noteでは、dry_runのデフォルト値はtrueです。そのほかの書き込みは、呼び出すと実行されます。mail_replyは下書きを開くだけです。 - 監査ログ。 すべての書き込みは
~/.local/state/macos-apps-mcp/audit.jsonlに記録されます($XDG_STATE_HOMEが設定されている場合はその下に記録されます)。ID を指定した更新や削除では、変更前の項目も記録されます。auditツールでログを読み返せます。 - メールの復元。 Mail でメールを移動または削除する前に、各メッセージが
.emlとして~/.local/state/macos-apps-mcp/backup/mail/にコピーされます。mail_undoで一括操作を元に戻せます。ゴミ箱を空にするツールはありません。 - 既知の制限。 Mail が一部しかダウンロードしていないメッセージは、添付ファイルなしでバックアップされます。Gmail のラベルフォルダ経由の移動やゴミ箱への移動は、約 2 分後に Gmail に取り消されるため拒否されます。
sent: trueは Mail がメッセージを受け付けたことを意味し、配信されたことを意味するものではありません。メールに関するすべての情報。 - ダッシュボード。 署名済みの
.appデーモンでは、ローカルページ(127.0.0.1 からのみアクセス可能)に、すべての書き込み、変更内容、各 Mail 一括操作のバックアップが表示されます。以下は架空のデータです。

最初の5分
macOS、Python ≥ 3.12、および uv が必要です。uv は uvx を提供します。パッケージは PyPI にあります。MCP クライアントで uvx を指定してください。パッケージを取得して実行するため、リポジトリのクローンも venv のパスも不要です。
{
"mcpServers": {
"macos-apps": {
"command": "uvx",
"args": ["macos-apps-mcp"]
}
}
}
Claude Desktop が uvx を見つけられない場合は、"command" にフルパスを設定してください。Terminal で which uvx を実行します(uv のデフォルトインストールでは /Users/you/.local/bin/uvx が表示されます)。
Claude Code の場合:
claude mcp add macos-apps --scope user -- uvx macos-apps-mcp
または、claude mcp add の代わりに Claude Code プラグインをインストールします。同じサーバーを起動し、ドライランのワークフローを説明するスキルを追加します。Claude Code で /plugin marketplace add elfensky/macos-apps-mcp を実行し、続けて
/plugin install macos-apps@macos-apps-mcp を実行してください。
後述の CLI コマンド(allow-send、dedupe-mail)も同じ方法で実行できます:uvx macos-apps-mcp allow-send。
まず doctor を実行してください。 doctor ツールは許可されている項目を報告し、ダイアログを開きません(各 Automation 権限はリアルタイムで読み取られ、実行中でないアプリは not_running と表示されます)。画面の前にいる状態で doctor(request=True) を実行すると、EventKit と Automation のダイアログが開きます。サーバーには次の権限が必要です:
- EventKit:Calendar と Reminders。
- Automation:アプリごとに1つのダイアログ。Mail、Notes、Contacts、Safari、Messages、Music。
- Full Disk Access(任意、ダイアログなし:サーバーを起動するアプリの System Settings → Privacy & Security → Full Disk Access で有効にします):Messages のコンテンツ、Photos、Mail のインデックス読み取り、リマインダーのタグとサブタスク、Notes の高速パス。これがない場合、Notes と一部の Mail の読み取りにはより遅いパスが使われます。それ以外ではエラーまたは
coverageの注記が返されます。
stdio では、macOS はサーバーを起動するアプリ(Claude Desktop、Terminal、VS Code)ごとに権限を付与するため、クライアントごとに権限が必要です。署名済みの .app デーモンは、すべてのアプリで共通の権限セットを保持します:docs/DAEMON.md。
使用するアプリだけを読み込んでください。MACOS_APPS_ADAPTERS_OFF=photos,music を設定すると、それらのアプリのツールは登録されず、クライアントのコンテキストに保持されるツールが少なくなります。デーモンの場合は、アダプターを無効にするを参照してください。
ソースから(開発用): サーバー自体を開発する場合は、この方法を使用してください。
git clone https://github.com/elfensky/macos-apps-mcp && cd macos-apps-mcp
uv sync
次に、MCP クライアントでプロジェクト専用の venv の python を指定します。動作が決定的で、固定された PyObjC ホイールが含まれています。
{
"mcpServers": {
"macos-apps": {
"command": "/absolute/path/to/macos-apps-mcp/.venv/bin/python",
"args": ["-m", "macos_apps_mcp"]
}
}
}
apple-mcp ではなく、こちらを使う理由
Dhravya Shah による apple-mcp は、すべての Apple アプリに対応する1つの MCP サーバーを先駆けて開発しました。現在はアーカイブされています。ノートとメールの本文全体をインラインで返していました。このサーバーはポインターを返し、リクエストがあった場合にのみ本文を取得し、すべての書き込みをティアごとに制限します。CREDITS.md を参照してください。
問題が発生しましたか?doctor を実行し、その出力を GitHub のイシューに貼り付けてください。レポートにはプロセスのパスが表示されるため、投稿する前に確認してください。
ツール
読み取りではポインターが返され、結果はアダプターごとに上限があります。本文やコンテンツは、別途、上限付きで取得します。MACOS_APPS_READ_ONLY が設定されている場合、書き込み/アクションはすべて完全にスキップされます(下記を参照)。
カレンダーとリマインダー — 読み取り/書き込み(EventKit)
| ツール | 引数 | 備考 |
|---|---|---|
events | when = today | week | YYYY-MM-DD | イベントをポインターとして一覧表示 |
free_busy | start、end(ISO)、省略可能な calendars の ID | 指定期間の統合された予定ありの時間帯と空き時間帯を返します。イベントの詳細は含まれません |
reminders | due = today | overdue | this-week | リスト名 | リマインダーを {results, coverage?} として一覧表示します。各結果には folder、tags、parent が含まれます(読み取り専用。EventKit とフルディスクアクセスが必要です) |
calendars / reminder_lists | — | 書き込み先となるコンテナー(id + name) |
create_event / update_event | title、start、end(ISO)、calendar、location、notes、all_day、recurrence、alarms(開始前の分数、最大 5 件。終日イベントの場合は現地時間の午前 0 時から計算し、-540 = 当日の 09:00) | update は ID による完全置換です。ただし alarms は省略するとイベントのアラームを維持し、[] を指定すると削除します |
delete_event | id、span、dry_run | dry_run は削除前にプレビューします。実際に削除すると、対象(シリーズではなく発生回)が削除されたことを検証します |
create_reminder / update_reminder | title、due、list_name、notes、priority(0~9)、start、recurrence | update は ID による完全置換です |
create_reminder_list | name | デフォルトアカウントに新しいリストを作成します。同じ名前が完全一致するリストがある場合は拒否されます |
complete_reminder | id | 完了としてマークします。親リマインダーを完了すると、未完了のまま残るサブタスクが subtasks に表示されます。リマインダーのストアを読み取れない場合は拒否され、何も変更されません(EventKit とフルディスクアクセスが必要です) |
delete_reminder | id、dry_run(デフォルトは true)、with_subtasks | ID で削除し、削除されたことを確認します。サブタスクを持つ親リマインダーは、削除するとサブタスクも削除されるため、with_subtasks=true でない限り拒否されます(EventKit とフルディスクアクセスが必要です) |
イベントとリマインダーのポインターには、カレンダーまたはリストの ID である folder が含まれます。これは free_busy(calendars=…) と書き込みツール(calendar=、list_name=)で指定できます。
リマインダーの タグ と サブタスク(tags、親の ID を示す parent)は、リマインダーのストアから読み取られ、読み取り専用であり、フルディスクアクセスが必要です。ストアを読み取れない場合でもリマインダーは返され、その理由が coverage に示されます。タグの書き込みやリマインダーのネストを行うパブリック API はないため、ここにもそのためのツールはありません。
書き込み先のコンテナーは、名前または Pointer.id で指定します。名前が曖昧な場合は推測せず、エラーになります。繰り返しには RFC 5545 の RRULE を使用します。指定できるのは FREQ、INTERVAL、COUNT、UNTIL、BYDAY(月次および年次ルールでは 2TU や -1FR などの序数を使用)、BYMONTHDAY、BYMONTH、BYYEARDAY、BYSETPOS です。例:FREQ=MONTHLY;BYDAY=2TU;COUNT=6。繰り返しリマインダーには期限日が必要です。BYWEEKNO、BYHOUR、BYMINUTE、BYSECOND、WKST は名前を示して拒否されます(EventKit は BYWEEKNO を保存しますが、展開するのは最初の日付のみです)。範囲外の値や RFC 5545 で禁止されている組み合わせも拒否されます。各パーツは書き込み後にも再検証されます。開始日がルールに一致しない場合も受け付けられます。RFC 5545 ではその日付を最初の発生回として数えるため、イベントの結果には最初の発生回が余分に含まれることが示されます。
メール — ID 優先の読み取り + 下書き作成と表示(Automation)
送信はデフォルトで無効です。読み取り、create_draft、mail_reply では送信されず、確認できるように作成ウィンドウが開きます。送信機能(send_mail、reply_all、forward_mail)もありますが、オペレーターが MACOS_APPS_ALLOW_SEND を通じて明示的に許可した場合にのみ実行されます。その場合も、dry_run のデフォルトは True です。
| ツール | 引数 | 備考 |
|---|---|---|
mail | 件名または送信者の部分文字列 | 受信トレイ内を検索します。id = 安定した RFC822 メッセージ ID、message:// ディープリンク |
mail_body | id, mailbox | 1 件のメッセージのプレーンテキストを、長さを制限し、切り詰めた箇所を明示して返します。mailbox は mail_search の結果に含まれる folder の値をそのまま(または正規名で)渡します。受信トレイに限らず、すべてのメールボックスが対象です |
mail_search | subject, from_, to, mailbox, account, since, until, unread, flagged, has_attachments, body, limit | Envelope Index を使ったインデックス検索(オフライン時)。account= が表示名の場合は Mail を起動して解決するため、その場合に限り Mail が起動します。UUID は純粋な sqlite 検索のままで、未知の名前はエラーになります。メッセージごとに 1 件を返します(INBOX を優先)。has_attachments はインライン画像を除外します。body はベストエフォート(インデックス登録済みの内容のみ)です |
mail_index_bodies | rebuild | オフライン時に .emlx からオプトインの FTS 本文インデックスを構築/更新します。再開可能で、サイズ制限があります。まだダウンロードされていないものはスキップします(仕様上、対象範囲は一部のみです) |
mail_thread | id, limit (default 100) | 会話全体を古い順に返します。送信済みメッセージも含みます。重複は除去され、limit を超えた場合は古いものから削除されます(返信用のスレッドを読むためのものです) |
mail_overview | — | すべてのメールボックスの合計数と未読数を、未読優先で表示します。迷惑メール/ゴミ箱/すべてのメールも含みます。件数はリアルタイムで、メッセージごとに重複を除いて数えます(保存済みカウンターは古くなることがあります)。アカウントの名前は Mail から取得します(Mail を起動します)。Mail に接続できない場合は UUID を代わりに表示します。「この Mac 内」は常に名前で表示されます |
mail_attachments | mailbox (検索結果の folder をそのまま — または inbox/sent/drafts/trash/junk), optional query | メッセージごとの添付ファイル名/サイズ/ダウンロード状況を表示します。下書きにも対応します |
mail_needs_response | — | 返信が必要と思われる受信トレイのメールを、reason(フラグ付き/未読の直接宛て/未返信の直接宛て)とともに優先度順で表示します。ヘッダーのみを対象とし、本文は読み取りません |
mail_awaiting_reply | days (1–365, default 3) | days 日以上前にあなたが送信し、返信がないメール(In-Reply-To/References による実際のスレッド判定)を古い順に表示します。理由は awaiting-reply です |
create_draft | to, subject, body | レビュー用の下書きを開きます。送信はしません。ロケーターを返します |
mail_reply | message_id, mailbox, reply_body, include_quote | スレッド形式の返信(In-Reply-To/References を設定)を作成し、元のメールを引用してレビュー用に開きます。送信はしません |
drafts | — | Mail の下書きをポインターとして一覧表示します(id + 件名 — 宛先) |
delete_draft | id, dry_run | メッセージ ID を指定して下書きを 1 件削除します。dry_run はプレビューです |
create_mailbox | name (/ nests), account | フォルダーを作成します。不足している親フォルダーは自動作成されます。削除に対応する機能はありません。delete <mailbox> はスクリプトから実行できないため、削除するには Mail.app で操作します。Gmail アカウントでは、新しいフォルダーはラベルとなり、move_mail はこれを拒否します |
move_mail | ids (≤25), from_mailbox, to_mailbox, dry_run | 移動/アーカイブ/再振り分けを行います。移動する前に、すべてのメッセージをバックアップして記録するため、mail_undo で元に戻せます。dry_run の既定値は True です。アカウントをまたぐ移動では、コピーは 1 つだけ残ります。Gmail のラベルフォルダーは、移動元でも移動先でも拒否されます(ラベルから移動するとコピーが残るためです)。統合名を移動元に指定した場合も拒否されます |
trash_mail | ids (≤25), mailbox, dry_run | ソフト削除であり、実行できる唯一の削除操作です。Mail の delete はアカウントのゴミ箱へ移動するだけで、スクリプト用辞書にはゴミ箱から消去する機能がありません。mail_undo で元に戻せます。ゴミ箱を空にする操作は Mail.app で行ってください。dry_run の既定値は True です |
mail_undo | receipt, dry_run | move_mail/trash_mail のレシートを逆順に再実行します。取り消し操作もバックアップされ、さらに取り消せます。Gmail のラベルまたは統合名へのレシートは拒否され、手動で復元する方法が示されます |
update_mail_status | ids (≤25), mailbox, read, flagged, flag_color | 既読/未読の設定、フラグの設定(色を含む)を行います。反対の値で再実行すれば元に戻せるため、dry_run の既定値は False です |
mail_duplicates | limit | レポート専用です。メールボックスごとの重複コピー数と、重複が最も多いものを表示します。整理には下記の dedupe-mail CLI を使います。このツールでは削除できません |
send_mail | to, subject, body, cc, bcc, html, from_address, dry_run | MACOS_APPS_ALLOW_SEND によるゲート制御があります。dry_run の既定値は True です |
reply_all | message_id, mailbox, body, include_quote, dry_run | ゲート制御あり。ネイティブのスレッドヘッダーを使用します |
forward_mail | message_id, mailbox, to, dry_run | ゲート制御あり。元のメールと添付ファイルをそのまま転送します。カバーノート用のパラメーターはありません(本文を書くと両方が失われることを、実機で確認済みです) |
Messages — chat.db 経由のコンテンツ(読み取り専用;フルディスクアクセス)
| ツール | 引数 | 備考 |
|---|---|---|
messages_chats | — | 会話一覧(id + 名前);コンテンツは含まれず、FDA は不要です |
messages_search | query, limit | メッセージのテキストを検索します(attributedBody をデコード)。新しい順です |
messages_with | contact (phone/email), country, limit | 1 人との最近のメッセージ;country = 国番号または 2 文字の地域コード(ロケールのデフォルト。+1 は使用しません) |
message_body | id | guid で指定した 1 件のメッセージの全文 |
Notes — NoteStore.sqlite の読み取り + オプトインによる本文取得
| ツール | 引数 | 備考 |
|---|---|---|
notes | title, snippet or body words | {results, truncated?, plane?, coverage?} — 一致したノート(id + スニペット)。タイトル/スニペットの一致が先で、その後に本文のみの一致が続きます。フルディスクアクセスのプレーンでは本文をメモリ上で検索します(ロックされたノートは対象外)。本文の単語はスペースと句読点のみで分割されるため、スペースのない中国語または日本語テキスト内の単語は、タイトルまたはスニペットでのみ検索できます。ダイアクリティカルマークとスマート句読点は区別しません |
notes_all | — | すべての現存するノート(id + 「アカウント / フォルダ」+ スニペット)。最近削除した項目は除外されます |
note_bodies | ids (≤ 50) | オプトインによるプレーンテキストの取得 → [{id, body}] |
create_note | title, body, optional folder name | 安定した x-coredata id を返します。不明または曖昧なフォルダは推測せず、拒否されます |
update_note | id, title, body | id でタイトルと本文を完全に置き換えます。安定した id は保持され、書き込み後に検証されます |
delete_note | id, expect_title, dry_run | 最近削除した項目に移動します。dry_run はプレビューを表示します |
その他の読み取り専用コンテキスト
| ツール | 引数 | 戻り値 |
|---|---|---|
contacts | name substring | カード(名前、組織、最初の電話番号 + メールアドレス) |
photos | search string | {results, truncated?} ポインター(タイトル · ファイル名 · 日付)。新しい順、最大 25 件です。ファイル名、タイトル、説明、キーワード、場所、人物、ラベルに一致します。id は Photos の uuid です。以前の <UUID>/L0/001 id も引き続き使用できます |
photo_albums | — | {results, truncated?} アルバムポインター(id、title (n photos)、フォルダパス)。最大 100 件です |
photo_info | photo id | 日付、位置情報、場所、人物、EXIF の一部、ピクセルサイズ、種類。画像データやサムネイルは取得しません |
safari_tabs | — | 開いているすべてのタブ(url + タイトル) |
shortcuts | name substring (empty = all) | ユーザーのショートカット。id = 安定した UUID、shortcuts:// ディープリンク |
ping / now / doctor | —(doctor はオプションの request=True を指定して権限プロンプトを表示できます) | ヘルスチェック / 時刻 / 権限の診断 |
audit | optional since (ISO datetime) | 最近の書き込み監査エントリ(新しい順)— macos-apps-mcp が変更した内容と、変更前/変更後のポインター(手動で元に戻すのに十分な情報) |
usage | — | ツールごとの呼び出し回数 + 未使用のツール一覧(使用頻度の低いツールの整理用) |
アクション(書き込み)
| ツール | 引数 | 備考 |
|---|---|---|
create_contact | given_name, family_name, organization | |
run_shortcut | name or id, optional input_text | ショートカットを実行し、長さを制限した出力スニペットを返します |
safari_open | url | 新しいタブで開きます。ホスト名のみの場合は https:// を使用します。許可されるのは http/https のみです |
export_photo | photo id, dest_dir inside the allowed root | 編集済みの静止画(編集がない場合はオリジナル)を新しいファイルとして書き込みます。ファイル名は <original stem>_<id prefix>.<ext> で、上書きは行いません。上限は 250 MiB です。iCloud のみにある写真は absent として扱われ(ダウンロードされません)、動画は拒否されます。Live Photo は静止画のみを書き出します。追加のみで、監査対象です |
読み取り専用モード
MACOS_APPS_READ_ONLY=1(または true/yes)を設定すると、読み取りのみが登録されます。安全なデプロイ用ガードとして、すべての書き込みツールとアクションツールがスキップされます。(読み取りによってアプリが開いたり、ローカルストアが読み取られたりする場合はあります。)
アダプターを無効にする
MACOS_APPS_ADAPTERS_OFF=photos,music(アダプター名をカンマ区切りで指定)を設定すると、指定したアプリのツールは登録されません。デーモンでは、ファイル ~/.local/state/macos-apps-mcp/adapters_off に同じリストを記述すると、再起動後に反映されます。詳細:docs/DAEMON.md。
ダッシュボード
デーモンでは、http://127.0.0.1:47632 に監査記録、ヘルス状態、アダプターの切り替え、使用状況、Mail のバックアップが表示されます。macos-apps-mcp dashboard を実行すると、ページキーを使って開けます。詳細:docs/DAEMON.md。どちらのスクリーンショットも架空のデータを使用しています。
重複したメールを整理する
Mail には、同じメッセージの冗長なコピーが蓄積されます。UI でドラッグすると移動ではなくコピーされる、Gmail でラベルと「すべてのメール」の両方に同じメッセージが表示される、移行によって2つのアカウントにコピーが残る、といったケースです。読み取りツールではすでに重複がまとめられているため、ここではサーバー上に実際に保存されているデータのみを扱います。セッションで mail_duplicates() を呼び出して状況を確認してから、ターミナルで整理します。
macos-apps-mcp dedupe-mail # preview every mailbox — changes nothing
macos-apps-mcp dedupe-mail --verbose # also list the sets it will NOT touch
macos-apps-mcp dedupe-mail --execute --mailbox=<folder-url> # do one mailbox for real
allow-send と同じ理由で、これはツールではなく CLI コマンドです。30秒でタイムアウトする直列処理のワーカーに対して数千件を削除する作業は、人が開始するには何時間もかかるためです。バイト単位で完全に同一(サイズと送信日時が一致)するコピーだけをまとめます。Mail では特定のコピーを指定できないため、残るのは Mail が残すコピーです。バイト単位で同一であることが、安全に処理できる根拠です。内容が異なるセットは件数に含めるだけで、変更せず --verbose の下に一覧表示されます。
冗長なコピーは、少量ずつゴミ箱に移され、それぞれに個別の mail_undo レシートが作成されます。ゴミ箱を空にする操作は Mail.app で行ってください。ここでメッセージが消去されることはありません。
処理には時間がかかります。 実際の IMAP アカウントでは、重複セット1件につき約1分かかります(Mail の whose 検索ではメールボックス全体をスキャンするため)。そのため、大きなフォルダーでは何時間もかかります。途中で終了しても問題のないターミナルで、メールボックスを1つずつ処理してください。処理は再開可能です。実行するたびに Mail のインデックスからプランが再計算されるため、中断しても無駄にはならず、再実行すれば残りだけが見つかります。Mail が削除できなかったセットは報告され、黙って再試行されることはありません。
送信モード
送信はデフォルトで無効です。サーバーは下書きを作成するだけで、送信は行いません。次のコマンドで有効にできます。
macos-apps-mcp allow-send mail # or: messages / mail,messages / all / off
macos-apps-mcp allow-send # print the current setting
この設定はオプトインとして保存され、デーモンが再起動して再登録されます(登録はインポート時に行われるため、再起動は避けられません。その後、MCP クライアントを再接続してください)。これはツールではなく CLI コマンドです。送信を許可するかどうかはユーザーの同意にかかっているため、モデルが自分で送信を許可したり、セッションを中断してサーバーを再起動したりすることはできません。
同じ設定は環境変数 MACOS_APPS_ALLOW_SEND でも指定できます。これは stdio サーバーが読み取る値です(変数が設定されている場合、保存済みの切り替え設定より常に優先されます)。
| 値 | 効果 |
|---|---|
| 未設定(デフォルト) | 送信ツールは一切登録されません |
mail | Mail の送信のみ(send_mail、reply_all、forward_mail) |
mail,messages | 名前を指定したアダプター(カンマ区切りのリスト) |
1 / true / yes / all | すべてのアダプターの送信 |
MACOS_APPS_READ_ONLY は常に優先されます。両方が設定されている場合、送信ツールは登録されません。
送信ツールには dry_run があり、デフォルトは True です。これは、ID を指定する削除操作とは意図的に逆の設定です。削除の対象は、読み取りで既に返された項目です。一方、送信では宛先を指定して構成するため、宛先を間違えることが重大な問題になります。ドライランでは Mail を一切呼び出さず、解決された送信情報を報告します。実際に送信するには dry_run=False を渡してください。例外は reply_all です。ドライランでは元のメッセージの実際の宛先(to/cc)を読み取ります(送信はしません)。これこそ、呼び出し元が予測できない宛先の集合だからです。
send_mail / reply_all / forward_mail が成功した結果(sent: True)は、Mail がメッセージを受け付けたことを意味し、配信されたことを意味するものではありません。実機で確認済みです。正しく作成されたメッセージでも、send の戻り後、Mail の送信ボックスに数分間配信されずに残ることがあります。また、宛先のないメッセージが送信ボックスに滞留すると、後続の正しい送信がその後ろに並び、送信されないことがあります。各結果には Mail の現在の送信ボックス件数 outbox_pending も含まれます。これがゼロより大きい場合、配信は確認されておらず、Mail ▸ 送信ボックスを確認するよう説明する note が結果に含まれます。
送信が実際に有効かどうかを確認するには、doctor ツールを実行してください。deployment.outbound には、現在送信が有効なアダプターがすべて表示されます(該当なしの場合は [])。これは上記と同じ登録ロジックから導出され、環境変数の生の値を再読み込みするものではないため、登録内容と食い違うことはありません。deployment.outbound_note には状態の説明が表示されます。
デーモンでのデプロイでは、MCP クライアントの設定で MACOS_APPS_ALLOW_SEND を設定しても何も起こりません。クライアントの env ブロックはシムには渡されますが、インポート時にこの変数を読み取る長時間稼働プロセスであるデーモンには渡されません。また、同梱の LaunchAgent plist に EnvironmentVariables キーはありません。そのために allow-send が用意されています。このコマンドは、デーモンが読み取れる状態を書き込みます(~/.local/state/macos-apps-mcp/allow_send。ホームディレクトリを基準にすることで、書き込みを行うシェルと読み取りを行う launchd プロセスが常に同じ場所を参照します)。また、再起動後も設定が保持されます。これは launchctl setenv とは異なります。docs/DAEMON.md(「デーモンでの送信モード」)を参照してください。
開発
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(リント+フォーマット、行の長さは 88)と pytest が CI の必須チェックです。ワークフロー全体についてはCONTRIBUTING.mdを参照してください。
先行事例と謝辞
macos-apps-mcp は先行する取り組みを基盤としています。参照元となった Apple Mail MCP、参照している EventKit/Photos サーバー、統合型 Apple MCP のパターンを先駆けたプロジェクト、そして依存している FastMCP / PyObjC / MCP 仕様です。詳しくは CREDITS.md を参照してください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。