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で「AIチーム」を作るまで(¥900 / 序章・第1部無料)
- コードを書けない私がClaude Codeで「AIチーム」を回すまで(¥900 / 序章無料)
この記事のテーマを深掘りした本
Claude Codeで作る1人エージェントチーム エンジニア向け。writer + reviewer の2体から始めるサブエージェント設計(序章無料)
シリーズ全6冊: Vol.1 作るまで / Vol.2 回すまで / Vol.3 書き続けるまで / Vol.4 仕組みを渡すまで / Vol.5 仕事を任せるまで / Vol.6 1人エージェントチーム