mstodo
# mstodo — Microsoft To Do for Claude
Connect **Microsoft To Do** to **Claude Code** and **Claude Desktop**. Claude can fetch tasks
from a specific list (disambiguated by your To Do **group folders**), plan the work with you,
mark tasks done, append timestamped notes, and manage checklists — all in conversation.
Ships as a **Claude Code plugin** (bundling a self-contained MCP server *and* a `/mstodo`
planning command), as a one-click **Claude Desktop extension** (`.mcpb`), or installable
**from source**. Pick whichever fits — all three are covered below.
Because Microsoft Graph does **not** expose To Do's group folders, this server keeps its own
group→list mapping on disk (`~/.mstodo-mcp/groups.json`) that mirrors how you organize lists in
the To Do app. You teach Claude your groups once, in conversation.
## How it works
- **Auth:** MSAL device-code flow using Microsoft's first-party "Graph Command Line Tools" client
ID — no Azure app registration required. You sign in once in a browser; the token is cached to
`~/.mstodo-mcp/token-cache.json` (chmod 600) and silently refreshed forever after.
- **Scope:** `Tasks.ReadWrite` (delegated). Works with personal Microsoft accounts.
- **State:** `~/.mstodo-mcp/` holds the token cache and the group mapping. Delete
`token-cache.json` to force a fresh sign-in; delete `groups.json` to reset group assignments.
- **Privacy:** each person signs into **their own** Microsoft account and gets their own
locally-cached token. Nothing of yours is shared — only the code.
---
## Install
### Option A — Claude Code plugin (recommended)
Inside Claude Code, add this repo as a plugin marketplace and install it:
```
/plugin marketplace add furkanzt/claude-mstodo
/plugin install mstodo@mstodo
```
That's it — one step wires up **both** the MCP tools and the `/mstodo` command. The plugin
bundles a self-contained server (`server/mstodo.mjs`, all dependencies inlined), so there's no
build step and no `npm install`.
> **Requirement:** Node.js **≥ 18** on your `PATH` — the plugin launches the server with `node`.
> Check with `node --version`.
Then, in any conversation, run the command (plugin commands are namespaced by plugin name):
```
/mstodo:mstodo
/mstodo:mstodo Grad School
```
…or just talk naturally: *"what lists do I have in Microsoft To Do?"* The first tool call
triggers a browser sign-in (see [First-time use](#first-time-use)).
To update later: `/plugin marketplace update mstodo`. To remove: `/plugin uninstall mstodo@mstodo`.
### Option B — Claude Desktop extension (one-click)
The whole server is packaged as a Claude Desktop Extension. From the
**[latest release](https://github.com/furkanzt/claude-mstodo/releases/latest)**, download
`mstodo-0.1.0.mcpb`, then:
1. Open **Claude Desktop → Settings → Extensions**.
2. Drag in `mstodo-0.1.0.mcpb` (or click *Install* and pick the file) and confirm.
3. Ask Claude *"what lists do I have in Microsoft To Do?"* — a browser sign-in prompt appears.
No terminal and no Azure setup. (The `/mstodo` slash command is a Claude Code plugin feature;
in Claude Desktop you drive the same tools with the everyday phrases below.)
### Option C — from source (manual / development)
```bash
git clone https://github.com/furkanzt/claude-mstodo.git
cd claude-mstodo
npm install
npm run build # compiles TypeScript → dist/
```
**Claude Code** — register the built server at user scope:
```bash
claude mcp add --scope user mstodo -- node "$(pwd)/dist/index.js"
```
**Claude Desktop** — add to `~/Library/Application Support/Claude/claude_desktop_config.json`
(use the absolute path to your `node` and to `dist/index.js`), then fully quit and reopen:
```json
"mcpServers": {
"mstodo": {
"command": "/opt/homebrew/bin/node",
"args": ["/absolute/path/to/claude-mstodo/dist/index.js"]
}
}
```
To rebuild the shareable `.mcpb` after changing the code: `npm run bundle`. To regenerate the
plugin's self-contained server bundle: `npm run bundle:plugin`.
---
## First-time use
1. Ask Claude: *"What lists do I have in Microsoft To Do?"* → it calls `todo_get_lists`.
The first call triggers sign-in: Claude gives you a URL (`https://www.microsoft.com/link`)
and a code. Enter them in a browser, approve, then tell Claude you're done.
2. **Teach it your groups** (one time). The To Do API can't see your group folders, so tell Claude
how your lists are grouped, e.g.:
> "In To Do, my *School* group has Calculus, Grad School and Ultralearning; my *Work* group has
> DenkSoru, KC Üretimi and Project Eddy."
Claude calls `todo_set_groups` and stores it. From then on, *"fetch the DenkSoru list from Work"*
resolves correctly, and same-named lists in different groups are disambiguated.
## Everyday phrases
- "Fetch the **Grad School** list from my To Do" → tasks with notes + checklist subtasks.
- "Let's plan these." → normal conversation; Claude reads the tasks.
- "Mark tasks 1, 3 and 4 as done." → `todo_complete_tasks` (batch).
- "Add a note to the report task explaining what we decided." → `todo_add_note`
(timestamped, appended — never overwrites).
- "Create a task 'Email the client' due next Monday with subtasks draft/review/send."
- "Check off the 'outline' subtask." / "Reopen that task."
## Tools
| Tool | Purpose |
|---|---|
| `todo_login` | Start/check Microsoft sign-in (device code). |
| `todo_get_lists` | All lists by group; reconciles mapping; reports renames/deletions. |
| `todo_get_tasks` | Tasks from a named list (+group), with notes & checklist. Open-only by default. |
| `todo_create_task` | New task with notes, due date, importance, checklist. |
| `todo_complete_tasks` | Batch-complete tasks. Detects recurring tasks (advance vs. complete). |
| `todo_update_task` | Change title / due date / importance / status (reopen = `notStarted`). |
| `todo_add_note` | Append a timestamped note without erasing existing content. |
| `todo_checklist` | Add / check / uncheck subtasks. |
| `todo_set_groups` | Assign lists to group folders (mirrors your To Do organization). |
## Behavior notes (verified against the live API)
- **Recurring tasks:** completing one advances it to the next occurrence rather than closing it;
`todo_complete_tasks` reports this as `recurring_advanced` so it isn't mistaken for a failure.
- **Due dates** are stored at UTC midnight so the calendar date round-trips (no off-by-one).
- **Notes** are stored as HTML (a To Do requirement) and shown back to Claude as plain text.
- **List renames** are handled automatically — the mapping is keyed by the stable list id.
- Groups, "My Day", and moving a task between lists are **not** in the Graph API; only groups are
emulated here (via the mapping).
## Development
```bash
npm run build # compile to dist/
npm test # unit tests (resolve + shape)
tsx test/smoke.ts # end-to-end against a throwaway list (needs a cached token)
npm run inspect # MCP Inspector against the built server
npm run bundle # build the Claude Desktop .mcpb (production deps only)
npm run bundle:plugin # rebuild the plugin's self-contained server/mstodo.mjs
```
The repo serves three distribution paths from one source tree:
- `dist/` — plain `tsc` output, used by the from-source and `.mcpb` paths.
- `server/mstodo.mjs` — a single-file esbuild bundle (deps inlined) committed for the **plugin**
path, so `/plugin install` runs it with no build step. Regenerate with `npm run bundle:plugin`
whenever `src/` changes.
- `mstodo-<version>.mcpb` — the Claude Desktop extension, shipped as a GitHub Release asset.
## Troubleshooting
- **Not signed in / expired:** ask Claude to sign in again, or run `npm run spike login-and-list`.
- **Plugin server won't start:** confirm `node --version` is ≥ 18 and `node` is on your `PATH`
(the plugin runs `node ${CLAUDE_PLUGIN_ROOT}/server/mstodo.mjs`). Run `/mcp` in Claude Code to
see whether the `mstodo` server registered and which tools it exposes.
- **Server won't start in Claude Desktop:** check `~/Library/Logs/Claude/mcp-server-mstodo.log`.
Ensure `dist/index.js` exists (`npm run build`) and the `command` path matches `which node`.
- **Wrong list picked:** run "show my To Do lists" to see the mapping; re-run `todo_set_groups`.
- **Use your own Azure app instead of the first-party client ID:** register a public client app
("Personal Microsoft accounts only", enable *Allow public client flows*, add delegated
`Tasks.ReadWrite`), then set `MSTODO_CLIENT_ID` (and optionally `MSTODO_AUTHORITY`) in the
server's `env` block. No client secret needed.
## License
MIT — see [LICENSE](LICENSE).
TDQS
Scored across 9 tools
Each tool has a clear, distinct purpose covering authentication, listing, CRUD on tasks, notes, and subtasks. There is a slight overlap between update_task and add_note for modifying task content, but the tools are well-described to avoid confusion.
All tool names follow a consistent verb_noun pattern (todo_login, todo_get_lists, todo_create_task, etc.), making it easy for an agent to predict tool existence and purpose. The prefix 'todo_' is uniformly applied.
9 tools is a reasonable number for a to-do management server, covering core operations without being overwhelming. It's slightly on the higher side for a focused domain but each tool addresses a distinct need.
The tool surface covers login, list management, CRUD on tasks, notes, and subtasks well. Missing operations like deleting a task or list are minor gaps that an agent can work around with existing tools (e.g., update to mark completion).