コードを書かないSE日誌

SE歴26年。コードを書かずにClaude Codeで8体のAIエージェントチームを動かしています。AIエージェント・自動化・GTDの実験日誌。

MCP なしで Claude Code から Apple アプリを操作する — Calendar・Notes・Mail スキルを自作した

Claude Code のカスタムスキルは、MCP サーバーなしで macOS ネイティブアプリを操作できる拡張機能だ。

Claude Code を使い始めてしばらくは「外部サービスと連携するには MCP が必要」だと思い込んでいた。しかし macOS には AppleScript があり、Calendar・Notes・Mail はいずれも AppleScript で操作できる。MCP サーバーを立てなくても、Bash スクリプトから osascript を呼ぶだけで Claude Code に Apple アプリを操作させられる。

この記事では私が実際に自作した 4 つのスキルを紹介する。

  • /open 拡張 — ディレクトリを Finder で開く機能を追加
  • /cal — Apple Calendar の確認・追加
  • /notes — Apple Notes の読み取り・書き込み
  • /mail — Apple Mail のトリアージ

構成の全体像

Claude Code のカスタムスキルは .claude/commands/<name>.md に定義する。ファイルの中でスクリプトを直接実行するか、外部スクリプトへ委譲する。今回はロジックをシェルスクリプトに分離して .claude/commands/ からは委譲するだけにした。

.claude/commands/
  cal.md       ← /cal コマンド定義(委譲)
  notes.md     ← /notes コマンド定義(委譲)
  mail.md      ← /mail コマンド定義(委譲)
  open.md      ← /open コマンド定義(インライン実装)

scripts/util/
  cal.sh       ← 213 行(Calendar 操作の実装)
  notes.sh     ← 206 行(Notes 操作の実装)
  mail.sh      ← 198 行(Mail 操作の実装)

osascript で AppleScript をインラインで書き、結果を標準出力に返す。Claude Code 側はその出力をそのままユーザーに返す。MCP サーバーも API キーも不要。


/open 拡張 — Finder でフォルダを開く

最初に手をつけたのは /open の改修だ。元々の /open はファイルをデフォルトアプリで開くだけだったが、ディレクトリを渡しても Finder が開かなかった。

拡張後の実装:

if [ -d "$ARGUMENTS" ]; then
  open "$ARGUMENTS"   # Finder でフォルダを開く
elif case "$ARGUMENTS" in *.md|*.txt|*.log|*.csv|*.json|*.yaml|*.yml) true;; *) false;; esac; then
  # VSCode で開く(code コマンドにフォールバック)
  CODE_CMD="/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code"
  ...
else
  open "$ARGUMENTS"   # その他はデフォルトアプリ
fi

-d 判定を入口に置くだけで対応できた。これにより「/open ~/Documents/project」でプロジェクトフォルダを即座に Finder で開けるようになった。

この修正以降、「フォルダを開くために Finder を手動で起動する」という手順が完全に消えた。Claude Code に指示しながらそのまま Finder が開く、という流れが自然になっている。


/cal — Apple Calendar を CLI から操作する

背景と動機

Google Calendar を iCloud 経由で Apple Calendar に同期している。Apple Calendar に書き込むと Google Calendar にも反映される。ならば AppleScript で Apple Calendar を叩けば、Google Calendar の MCP を使わずに予定管理ができる。

主なコマンド

コマンド 動作
/cal または /cal today 今日の予定を時刻順で表示
/cal tomorrow 明日の予定を表示
/cal week 今日から 7 日間の予定を表示
/cal add "MTG" 14:00-15:00 今日に 1 時間のイベントを追加
/cal add "ランチ" 2026-05-30 12:00-13:00 指定日にイベントを追加

実行例(/cal week の出力イメージ):

📅 今週の予定(2026-05-24 〜)
──────────────────────────────
【5/24(土)】
  終日              子ども運動会
【5/26(月)】
  09:30-10:00       週次ミーティング
  14:00-15:00       1on1
【5/27(火)】
  予定なし

実装の要点

osascript に年・月・日を引数で渡し、AppleScript 側で current date を組み立てて対象日の範囲でイベントを取得する。終日イベントと時刻指定イベントを allday event プロパティで分岐し、ソートキーを付けて出力する。ソート自体は Bash 側の sort に任せた。

このスキルを使い始めてから、Google Calendar の Web 画面を開いて予定を確認するという動作がほぼなくなった。「今日何時に何があるか」を Claude Code に問いかけるだけで足りる。


/notes — iPhone のメモを CLI に引き込む

背景と動機

出先で iPhone にメモを書き、帰宅後にそれをネタ帳やタスクに変換したい。Apple Notes は iCloud 同期しているため、iPhone で書いたメモがそのまま Mac 側の AppleScript から読める。

主なコマンド

読み取り系

コマンド 動作
/notes または /notes list 直近 7 日のノート一覧(更新日降順)
/notes list 14 直近 14 日分
/notes read "タイトル" ノートの内容を全文表示
/notes harvest 直近 3 日のノートをまとめて表示しネタ帳化を提案
/notes harvest 7 直近 7 日分で harvest

書き込み系

コマンド 動作
/notes new "タイトル" 新規ノート作成
/notes new "タイトル" "本文" 本文つきで作成
/notes append "タイトル" "追記内容" 既存ノートの末尾に追記

harvest ワークフロー

私が最も頻繁に使うのが harvest だ。

1. /notes harvest
   → 直近 3 日のノートが一覧表示される
2. 「このノートをネタ帳に入れて」と伝える
3. /notes read "タイトル" で全文取得
4. writer エージェントがネタ帳エントリを作成

iPhone で「◯◯について書こう」とメモし、帰宅後に /notes harvest を実行すれば、その内容がそのままネタ帳候補として並ぶ。スマートフォンとデスクトップの間でコピペが不要になった。

ハマりポイント: $TODAY の直後に全角括弧

AppleScript のヒアドキュメントに Bash 変数を埋め込む際、$TODAY(月) のように変数の直後に全角括弧が来ると文字化けした。${TODAY}(月) と波括弧で囲むと回避できた。AppleScript ではなく Bash 側のクォート処理の問題だ。

harvest を導入してから、出先で iPhone に書いたメモが「埋もれて消える」パターンがなくなった。帰宅後に /notes harvest を実行するだけで、iPhone 側でのメモの書き方を変えずにそのまま Claude Code に渡せる。


/mail — Apple Mail のトリアージ

背景と動機

Gmail MCP の代替として Apple Mail を CLI から操作できないか試みた。未読メールを番号付きで一覧表示し、「#2 を読む」「#3 を既読にする」という操作を Claude Code 経由で完結させたい。

コマンド

コマンド 動作
/mail または /mail check 未読メール一覧(最大 30 件・直近 1 日)
/mail check 50 3 最大 50 件・直近 3 日で取得
/mail read N #N のメールを全文表示
/mail done N #N を既読にする
/mail trash N #N をゴミ箱へ移動

自動トリアージ

/mail check を実行すると Claude が各メールの内容を見て優先度を判定する。

  • 要対応: 固有名詞・締め切り・依頼・質問が含まれる
  • 参考: ニュースレター・通知・確認メール
  • 不要: 広告・spam 的なもの

「#2 と #5 が要対応です。読みますか?」のように候補を絞って提示するため、一覧を自分で全件読む必要がない。

実装上の制約と対処

未読 4000 件超でのタイムアウト問題

当初は every message of mailbox whose read status is false という AppleScript でメールボックス全件を走査しようとした。Gmail アカウントの INBOX には未読が 4000 件を超えており、これは完全にタイムアウトした。

対処として「インデックスアクセス + 日付フィルタ」方式に切り替えた。

repeat with i from 1 to checkCount  -- 最大 50 件を先頭からチェック
  set m to message i of targetMb
  set recv to date received of m
  if recv < cutoff then exit repeat   -- cutoff より古ければ打ち切り
  if read status of m is false then
    -- 対象メールとして収集
  end if
end repeat

先頭 50 件を降順(受信日が新しい順)でチェックし、cutoff(直近 N 日)より古ければ即打ち切る。全件走査を避けることでタイムアウトを回避した。ただしこの方式では「直近 N 日より前の未読メール」は取得できない。これは意図的な割り切りだ。

id プロパティの型問題

メールを id で検索する際、(id as string) = targetId で比較すると一致しなかった。id は整数型なので id = (targetId as integer) に変えたところ正常に動いた。AppleScript では id のようなプロパティで型が暗黙変換されない場合がある。

Mail.app のハング

実装中に Mail.app が AppleScript の実行中にハングし、強制終了が必要になった。with timeout of 30 seconds を主要操作に入れることで対処した。タイムアウト後は空の結果を返すだけで、プロセスが詰まることはなくなった。

現時点の限界

正直に書く。/mail は「動く」が「完全ではない」状態だ。

  • 直近 1〜3 日分しか取得できない(古いメールは対象外)
  • 複数アカウントを跨ぐ検索は未実装
  • 添付ファイルの取得は未対応
  • mail.sh の実行に数秒かかる(IMAP 通信を含むため)

メール操作の完全な自動化を目指すなら Gmail MCP や Apple Mail の公式 API の方が適している。私のユースケース(毎朝の軽いトリアージ、未読の件数確認)には十分で使い続けているが、ヘビーユーズには向かないと思っている。

完全ではないが、毎朝「未読が何件あってどれが要対応か」をアプリを開かずに把握できる、という点は確実に変わった。


MCP vs AppleScript — どちらを選ぶか

Calendar・Notes・Mail 程度の操作なら、osascript を使ったスクリプトは数十〜200 行台に収まる。MCP サーバーを立てるよりも軽量で、ローカル完結・オフライン動作・デバッグのしやすさを優先したい場合には AppleScript の方が向いている。一方、複数サービスをまたぐ連携や、既存の MCP エコシステムに乗りたい場合は MCP が適している。私が今回 AppleScript を選んだのは、「まず動かす」という初期コストの低さと、スクリプト全体を自分で把握できる透明性を重視したためだ。


MCP なしで始める利点と限界

利点

セットアップがシンプル。MCP サーバーを立てる必要がなく、Node.js や Python のランタイムも不要だ。.claude/commands/<name>.md に数行書いて、Bash スクリプトを置けば動く。

ローカル完結。API キーもクラウドへのリクエストも不要。オフラインでも動く(ただし iCloud 同期は必要)。

挙動がわかりやすいosascript の出力をそのまま受け取るだけなので、デバッグが楽だ。

限界

macOS 専用。AppleScript は macOS にしかない。Windows・Linux では動かない。

AppleScript の表現力の制約。ループや条件分岐は書けるが、複雑なデータ変換は Bash 側に任せる設計になりやすい。

パフォーマンスosascript の呼び出しごとに起動コストがかかる。/cal week は 7 日分のイベントを 1 回の AppleScript 呼び出しで取得しているが、複数回呼び出す処理は遅くなりがちだ。


最初に試すなら /notes harvest から

4つのスキルのうち、最も低コストで始められるのが /notes harvest だ。iPhone でメモを書く習慣があれば、スクリプト側に追加の設定は不要。notes.sh を配置して /notes harvest を実行するだけで、手元のメモが Claude Code に取り込める。

/cal/open は次点でシンプルだ。Google Calendar を iCloud 経由で同期している場合は /cal がそのまま使える。/mail は動作するが、IMAP 環境によってタイムアウト挙動が異なるため、最初は /notes/cal で手応えを確かめてから試すのが現実的だ。


4つのスキルの比較と使いどころ

スキル 操作対象 主な使いどころ
/open 拡張 Finder・VSCode フォルダを即座に開く
/cal Apple Calendar 今日・今週の予定確認、イベント追加
/notes Apple Notes 出先メモの収穫、ネタ帳化
/mail Apple Mail 朝のトリアージ(未読の仕分け)

4 つのスキルはすべて「MCP サーバー不要・AppleScript + Bash」の構成だ。macOS ユーザーで「Claude Code から日常ツールを操作したいが MCP のセットアップが面倒」と感じている人には、この構成が手っ取り早い出発点になると思う。

AppleScript には限界もある(タイムアウト・型変換・ハング)。それでも、シンプルな用途なら十分に動く。まず動かして、足りない部分は後から補う、という進め方が現実的だ。

すでに Claude Code でエージェントを組んでいる場合も、これらのスキルは既存の構成に干渉しない。.claude/commands/ にファイルを追加するだけで、エージェントからも /cal/notes を呼び出せるようになる。


この記事の実施記録(2026年5月): Claude Code のカスタムスキルとして /cal/notes/mail の 3 本と /open の拡張を自作した。すべて AppleScript を Bash から呼び出す構成で、MCP サーバー不要。スクリプトの合計は 617 行(cal.sh 213 行・notes.sh 206 行・mail.sh 198 行、2026-05-24 時点の実測値)。


この記事でカバーしきれなかった設計・運用の全体像は、Zenn Books にまとめている。序章・第1部は無料で読める。

この記事のテーマを深掘りした本

Claude Codeで作る1人エージェントチーム エンジニア向け。writer + reviewer の2体から始めるサブエージェント設計(序章無料)

シリーズ全6冊: Vol.1 作るまでVol.2 回すまでVol.3 書き続けるまでVol.4 仕組みを渡すまでVol.5 仕事を任せるまでVol.6 1人エージェントチーム