mcpField
M
MustDo

MustDo

リモート
ltng.jp生産性02 週間前に更新
リポジトリ公式サイト

MustDo について

MustDoは、ClaudeなどのMCPクライアントからMustDoのiOSアラーム付きTo-Doを管理するMCPサーバーです。ユーザー自身のiCloudプライベートCloudKitデータベースにアクセスし、ホスト型OAuthリレーと開発者向けローカルstdioを提供します。

主な機能

  1. 01日付とステータスによるTo-Do一覧
  2. 02To-Doの追加、更新、完了、スヌーズ、削除
  3. 03繰り返しスケジュールと期限の設定
  4. 04ユーザーのiCloud CloudKitデータベースへの保存
  5. 05ホスト型リレーとローカルstdio

活用シーン

  1. 01期間内の未完了または完了済みTo-Doを確認
  2. 02期限付きのアラームTo-Doを作成
  3. 03繰り返しタスクを更新、または特定回を完了
  4. 04MCPクライアントからTo-Doをスヌーズまたは削除

MCP 対応

MustDoは、アカウントとTo-Doの操作をMCPツールとして提供します。ホスト型リレーはOAuthによるリモートMCPを使い、開発者はローカルでstdio経由のサーバーを実行できます。

設定

リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。

エンドポイントhttps://ltng.jp/api/mustdo/mcp
インストールコマンドをコピー
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。

ツール

詳細

mustdo-mcp

日本語版はこちら (README.ja.md)

MustDo 用の MCP サーバー — 実行するまで鳴り続ける iOS の To-Do アラームです。

Claude(Claude Code、Claude Desktop、claude.ai、Claude iPhone アプリ)や、その他の Model Context Protocol クライアントから、MustDo の To-Do を読み書きできます。

  • データは iCloud に保管されます。 MustDo は To-Do 用のデータベースを独自に持っていません。データは Apple ID の CloudKit プライベートデータベース(コンテナ iCloud.jp.lightning.mustdo、ゾーン MustDo)に保存されます。 このサーバーは Apple の CloudKit Web Services と通信し、iPhone アプリと同じレコードを読み書きします。
  • 開発者が To-Do を保存することはありません。 このリポジトリのローカルサーバーも、ホスト型リレー(以下を参照)も、Lightning LLC のサーバーに To-Do の内容を保存しません。
  • 書き込み後、CloudKit が iPhone にサイレント通知を送信するため、アプリはすぐに更新されます。

2 つの利用方法

A. ホスト型リレー(推奨)B. このリポジトリをローカルで実行(開発者向け)
利用できる場所claude.ai、Claude iPhone アプリ、リモート MCP + OAuth に対応するすべてのクライアントMac 上の Claude Code / Claude Desktop(stdio)
セットアップカスタムコネクターを追加し、Apple ID でサインインNode 24、ビルド、設定、サインインが必要です。一般公開されていない CloudKit API Token が必要です(以下を参照)
Lightning LLC が保存するものCloudKit サインイントークンのみ(AWS KMS で暗号化。以下を参照)なし
A. ホスト型リレー — https://ltng.jp/api/mustdo/mcp
  1. claude.ai → Settings → Connectors → Add custom connector → URL https://ltng.jp/api/mustdo/mcp(名前を「MustDo」にします)。
  2. Connect をクリックします。保存される情報について説明する ltng.jp の同意ページが表示され、その後 Apple のサインインページが表示されます。 MustDo アプリで使用しているものと同じ Apple ID でサインインしてください。
  3. これで完了です。同じコネクターを Claude iPhone アプリでも利用できます。

リレーが保存する情報について、正直に説明します:

  • サインインすると、Apple が CloudKit サインイントークン(ckWebAuthToken)を発行します。リレーは、このトークンを AWS KMS(AWS 東京リージョン)で暗号化して保存し、各リクエストでユーザーに代わって CloudKit を呼び出せるようにします。
  • また、コネクター自体の OAuth アクセストークン/リフレッシュトークンのハッシュも保存します。
  • To-Do の内容、Apple ID のメールアドレス、パスワード、生の iCloud ユーザー ID を保存または記録することはありません。
  • 接続解除: claude.ai でコネクターを削除し、さらに https://ltng.jp/api/mustdo/disconnect にアクセスします。 Apple ID で確認すると、保存されているトークンはすぐに削除されます。Apple がサインインを無効にした場合も自動的に削除されます(その場合、ツールは RECONNECT_REQUIRED を返すため、再接続してください)。

詳細な説明:https://ltng.jp/mustdo/mcp。

B. ローカルで実行(stdio)

必要なもの:

  • Node.js 24 以降を搭載した macOS
  • MustDo アプリがインストールされ、少なくとも一度 iCloud と同期されていること(アプリがゾーンと Account レコードを作成します)
  • MustDo コンテナ用の CloudKit API Token。現在、一般公開されていません —「CloudKit API Token について」を参照してください。トークンがない場合は、ホスト型リレー(A)を使用してください
git clone https://github.com/lightning-llc-jpn/mustdo-mcp mustdo-mcp
cd mustdo-mcp
npm install
npm run build        # -> dist/index.js
npm test             # vitest; CloudKit is mocked

Claude Code に登録します:

claude mcp add mustdo \
  -e MUSTDO_CK_API_TOKEN=<MUSTDO_CK_API_TOKEN> \
  -e MUSTDO_CK_ENV=production \
  -- node /path/to/mustdo-mcp/dist/index.js

または、設定を ~/.mustdo/config.json に記述し、-e を付けずに登録します:

{
  "apiToken": "<MUSTDO_CK_API_TOKEN>",
  "environment": "production"
}

次に、Claude に sign_in ツールを一度実行するよう依頼してください。サーバーがブラウザーで Apple のサインインページを開き、 http://localhost:51234/callback で待ち受け、返されたトークンを ~/.mustdo/auth.json に保存します(モード 0600)。

CloudKit API Token について

CloudKit Web Services では、すべてのリクエストに 2 つのトークンが必要です。

トークン内容所有者
ckAPITokenコンテナ(iCloud.jp.lightning.mustdo)を識別します。コンテナの所有者が CloudKit Dashboard で作成します。Apple はこれを「Web サイトまたは埋め込み Web ビューから」使用するように設計しており、固定のサインインコールバック URL を持つクライアント側トークンです。Lightning LLC(コンテナは MustDo の開発者チームに属します)。自分で作成することはできません。CloudKit Dashboard では、チームが自分のコンテナ用のトークンしか作成できません。
ckWebAuthTokenApple ID でサインインしたときに Apple が発行する、個人用 CloudKit セッションです。プライベートデータベースへのアクセスを実際に許可する認証情報です。あなたのみ。~/.mustdo/auth.json に保存されます。本番用トークンでは、サインイン時に Apple が ltng.jp 経由のリダイレクトでこのトークンを返します(詳細は以下を参照。そこでは何も保存もログ記録もされません)。その後は Apple にのみ送信されます。

API Token はコンテナ全体に適用され、エンドユーザーが作成することはできません。Lightning LLC は現在、これを一般公開していないため、このサーバーをローカルで実行する方法は一般ユーザーには提供されていません。ホスト型リレー(A)を使用してください。 このコードは、MCP サーバーがデータをどのように扱うかを正確に確認できるよう公開されています。

参考までに、本番環境用トークンのサインインコールバックは https://ltng.jp/api/mustdo/oauth/local-callback に設定されています。これは、何も保存もログ記録もせずに http://localhost:51234/callback へリダイレクトするだけです。

設定

環境変数は ~/.mustdo/config.json より優先されます。

envconfig.json のキーデフォルト意味
MUSTDO_CK_API_TOKENapiToken(必須)MustDo コンテナ用 CloudKit API Token
MUSTDO_CK_ENVenvironmentdevelopmentApp Store のデータには production を指定します。development は MustDo の開発者のみが使用します
MUSTDO_CK_CONTAINERcontaineriCloud.jp.lightning.mustdo変更しないでください
MUSTDO_CK_ZONEzoneNameMustDo変更しないでください
MUSTDO_CALLBACK_PORTcallbackPort51234サインインコールバックが待ち受けるポート
MUSTDO_HOME—~/.mustdoconfig.json と auth.json の保存場所
MUSTDO_LOG_LEVEL—INFODEBUG / INFO / WARN / ERROR(stderr に JSON Lines 形式で出力)

auth.json は環境ごとに用意されます。MUSTDO_CK_ENV を切り替える場合は、別途 sign_in を実行する必要があります。 Apple は一定時間が経過するとセッションを無効にします(CloudKit は HTTP 421 を返します)。その場合、ツールは NOT_SIGNED_IN を返すため、もう一度 sign_in を実行してください。

ツール

すべてのツールは JSON を返します。出力の日付は ISO 8601(UTC)形式です。入力の日付には次の形式を使用できます。

  • YYYY-MM-DD — その日のアカウントのデフォルト時刻(下記参照)
  • YYYY-MM-DDTHH:mm — アカウントのタイムゾーンでの現地時刻
  • オフセット付きの完全な ISO 8601 形式
ツール引数機能
sign_inwaitSeconds?(5~300、デフォルトは 90)ローカルのみ。 Apple のサインインページを開き、ckWebAuthToken を保存します。リレーにはありません。
get_me—アカウント情報:timeZone、today、weekday、defaultTime、defaultDueNext、トライアル/サブスクリプションの日付、canAddTodo。日付の計算を行う前に呼び出してください。
list_todosdate?、from?、to?(YYYY-MM-DD、両端を含む)、status?(デフォルトは pending / done / skipped / all)、includeRepeating?(デフォルトは true)To-Do を一覧表示します。削除済みの To-Do は除外されます。繰り返しの To-Do は repeating の下にテンプレートとして返され(展開されません)、期間内の各日の occurrences も含まれます。
add_todotitle(1~200)、due?、repeat?、notes?(≤2000)、sound?source = "mcp" を設定して To-Do を作成します。due を省略した場合、デフォルト時刻の翌日になります。
update_todoid、title?、due?、repeat?(オブジェクトまたは null)、notes?(文字列または null)、sound?、status?渡されたフィールドのみを変更します。repeat はルール全体を置き換えます。null または { "kind": "none" } を指定すると、ルールが削除されます。
complete_todoid、occurrenceDate?1 回限りの To-Do:status = done。繰り返しの To-Do:その日の発生分を完了として記録します(デフォルトは今日)。
snooze_todoid、until、occurrenceDate?until までスヌーズします。繰り返しの To-Do では、その日の発生分のみが対象です。
delete_todoid論理削除(deletedAt)。アプリは 14 日後に完全削除します。

注: AI クライアントは、指示に従って To-Do を追加、変更、削除します。削除された To-Do は 14 日後に iCloud から削除され、復元できません。AI の操作結果はご自身で確認してください。 delete_todo には破壊的操作の注釈(destructiveHint)、get_me / list_todos には読み取り専用の注釈(readOnlyHint)が付いているため、注釈に対応するクライアントは削除前に確認を求めます。

デフォルト時刻と due の省略

各アカウントにはデフォルトのアラーム時刻(Account.defaultTime、HH:mm 形式)が設定されています。アプリの設定で変更でき、未設定の場合は 09:00 です。

  • due を指定せずに add_todo を実行 → アカウントのタイムゾーンで翌日のデフォルト時刻になります。 月/年の境界や DST の切り替えは、現地時刻に従います。
  • due: "2026-10-10" → その日のデフォルト時刻になります。
  • get_me は defaultTime と defaultDueNext を返すため、クライアントはアラームが鳴る時刻をユーザーに伝えられます。

例:

// "Remind me to buy milk" → tomorrow at the default time
{ "title": "Buy milk" }

// "Call the dentist on the 10th" → that day at the default time
{ "title": "Call the dentist", "due": "2026-10-10" }

// "Today at 3pm"
{ "title": "Submit report", "due": "2026-10-06T15:00" }
繰り返しルール

iOS カレンダーアプリと同じ用語です。add_todo / update_todo の入力として使用され、list_todos が返します。

{
  "kind": "none | daily | weekly | monthly | yearly",
  "interval": 1,                                   // 1 = every, 2 = every other … (1–99)
  "weekdays": [2, 4],                              // weekly only. 1 = Sun … 7 = Sat. Empty → weekday of `due`
  "monthly": { "mode": "dayOfMonth | weekdayOrdinal", "ordinal": 1, "weekday": 2 },
  "end": { "kind": "never | until | count", "until": "2026-12-31", "count": 10 }
}
内容repeat
毎日{ "kind": "daily" }
毎週月曜日と水曜日{ "kind": "weekly", "weekdays": [2, 4] }
1 週間おき{ "kind": "weekly", "interval": 2 }
3 日ごと{ "kind": "daily", "interval": 3 }
毎月 5 日due を 5 日にして { "kind": "monthly" }(29~31 日は月末に繰り下げられます)
毎月第 1 月曜日{ "kind": "monthly", "monthly": { "mode": "weekdayOrdinal", "ordinal": 1, "weekday": 2 } }
毎月最終金曜日{ "kind": "monthly", "monthly": { "mode": "weekdayOrdinal", "ordinal": -1, "weekday": 6 } }
毎年{ "kind": "yearly" }(due の月日。うるう年でない年の 2 月 29 日は 2 月 28 日になります)
10 回繰り返したら停止{ "kind": "daily", "end": { "kind": "count", "count": 10 } }
12 月 31 日まで{ "kind": "weekly", "weekdays": [2], "end": { "kind": "until", "until": "2026-12-31" } }

省略したフィールドにはデフォルト値が適用されます(interval は 1、weekdays は []、monthly.mode は dayOfMonth、end.kind は never)。 範囲:interval は 1~99、ordinal は 1~5 または -1、weekday は 1~7、count は 1~999 です。それ以外の場合は INVALID_ARGUMENT になります。 従来の形式 { "kind", "weekdays", "until" } も引き続き受け付けます。

展開はこのアプリ内で行われます。ここでは行われません。 list_todos はテンプレートと、日ごとの done / skipped / スヌーズを含む occurrences を返します。 範囲フィルタリングでは、範囲内に実行される可能性がないことが確実なテンプレート(最初の発生日が範囲の後、until が範囲の前、該当する曜日がない週次ルール)のみが除外されます。

エラー

失敗時は isError: true と、{ "code": "...", "message": "...", "details"?: {...} } の形式の本文が返されます。

code意味
NOT_SIGNED_IN有効な ckWebAuthToken がありません(ローカル)。sign_in を実行してください。
RECONNECT_REQUIREDホスト型リレーで同様の問題が発生しています。claude.ai でコネクターを再接続してください。
NOT_CONFIGUREDAPI Token がないか、CloudKit に拒否されました(HTTP 401/403)。
PAYMENT_REQUIREDアカウントのトライアル期間が終了しており、有効なサブスクリプションがありません。影響するのは add_todo のみです。
NOT_FOUND該当する To-Do がないか、削除されています。
INVALID_ARGUMENT日付が不正、繰り返しルールが範囲外、タイトルが空など。
CONFLICT別のデバイスによってレコードが連続して 2 回変更されました。再試行してください。
CLOUDKIT_ERRORその他の CloudKit エラー(例:アプリが一度も同期されていないためゾーンがない)。
SIGN_IN_TIMEOUT10 分間のサインインリスナーが期限切れになりました。
INTERNAL予期しないエラー。

セキュリティモデル

  • To-Do へのアクセスは、ご自身の Apple ID セッション(ckWebAuthToken)によって制限されています。このセッションは Apple のサインインページから発行されます。 開発者を含め、誰もこれなしでプライベートデータベースを読み取ることはできません。
  • API Token はコンテナを識別し、サインイン後に Apple がリダイレクトできる場所を指定するだけです。 Apple はこれをクライアント側トークンとして位置付けています(通常、CloudKit JS の Web ページに埋め込まれています)。それ自体では、ユーザーのプライベートデータへのアクセス権は付与されません。
  • ローカルでは、セッションは ~/.mustdo/auth.json(0600)に保存され、ログは JSON 形式で stderr に出力され、トークンは含まれません。また、サインインリスナーは 127.0.0.1 / ::1 のみにバインドされます。
  • リレーでは、セッションはユーザーごとに AWS KMS で暗号化され(暗号化コンテキストを使用したエンベロープ暗号化)、OAuth トークンは pepper を適用した SHA-256 ハッシュのみが保存され、PKCE S256 が必須となり、再利用検出機能付きでリフレッシュトークンがローテーションされます。また、To-Do の内容がストレージやログに書き込まれることはありません。
  • 書き込みでは CloudKit の recordChangeTag(楽観的ロック)を使用し、競合時に 1 回再試行します。削除は論理削除です。
  • 気になる点があれば、SECURITY.md をご覧ください。

開発

npm install
npm run build       # tsc → dist/
npm test            # vitest (CloudKit mocked in test/fakeCloudKit.ts)
npm run typecheck   # tsc --noEmit
MUSTDO_LOG_LEVEL=DEBUG node dist/index.js   # run the stdio server by hand

構成:

src/
  index.ts      entry point (stdio)
  server.ts     wiring for stdio: sign_in + the 7 To-Do tools
  tools.ts      tool definitions (zod schemas) shared by stdio and the relay
  core.ts       public entry for the shared core (no auth/config/stdio)
  service.ts    tool logic: filtering, upserts, conflict retry
  cloudkit.ts   thin CloudKit Web Services client (query / lookup / modify, 421 handling)
  records.ts    CloudKit record <-> model conversion
  dates.ts      time-zone-aware date math using Intl only
  auth.ts       auth.json and the sign-in callback listener
  config.ts     env / ~/.mustdo/config.json
  model.ts      enums, allowlists, RepeatRule types (mirrors the Swift app)
  errors.ts     ToolError / NotSignedInError
  log.ts        JSON logs to stderr (setLogSink to redirect)
test/           vitest

dist/core.js(パッケージの exports)は、ホスト型リレーが使用する共有コアです。auth.ts、config.ts、index.ts、server.ts 以外のすべてが含まれます。ローカルファイルシステムやブラウザーにアクセスするものは含めないでください。

ワークフロー:Issue から始める

変更はすべて GitHub Issue から始めます。コミットメッセージに Issue #N として Issue を記載してください (例:Fix the due-date default for repeating To-Dos (Issue #12)。マージコミットも対象です)。変更が main に反映されたら、Issue をクローズしてください。#12 だけの記載は受け付けられません。

bash tools/git-hooks/install.sh   # once per clone: installs the commit-msg hook that enforces this

プッシュされたコミットは .github/workflows/issue-number.yml によって再度チェックされます。

ライセンス

MIT — Copyright (c) 2026 Lightning LLC。LICENSE を参照してください。

MustDo は Lightning LLC の製品です。Apple、iCloud、CloudKit は Apple Inc. の商標です。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。