io.github.MAG-Cie/mcp-microsoft-todo
MCP server for Microsoft To Do via Microsoft Graph. MSAL device code flow, no client secret needed.
Open source Open in the app JSON README (API)
About
MCP server for Microsoft To Do via Microsoft Graph. MSAL device code flow, no client secret needed.
Details
- Kind
- MCP servers
- Topic
- No topic detected
- Publisher
- mag-cie
- Origin
- official
- Category
- ferramentas
- Transport
- local
- Version
- 1.2.2
- Stars
- 10
- Forks
- 1
- Last push
- 2026-05-11T20:26:18Z
- Repository state
- ativo
- Language
- TypeScript
- License
- MIT
- Added
- 2026-08-29 03:02:01
- Updated
- 2026-08-29 03:02:01
- Origin id
io.github.MAG-Cie/mcp-microsoft-todo
README
# mcp-microsoft-todo
> π«π· Version franΓ§aise : [README.fr.md](README.fr.md)
MCP server to drive **Microsoft To Do** from Claude Code, Claude Desktop, or any MCP-compatible client.
Works with **any Microsoft account**: personal (outlook.com, hotmail.com, live.com), Office 365 personal or business, Microsoft 365. **Zero Azure setup** required on the user side β just sign in via device code flow.
[](https://www.npmjs.com/package/@mag-cie/mcp-microsoft-todo)
[](LICENSE)
---
## π Built and maintained by MAG&Cie
This MCP server is open-source and free to use. It's also a showcase of our **CrΓ©ation de MCP** offering at [MAG&Cie](https://www.mag-cie.com) β we build custom MCP connectors for businesses that want to plug AI into their internal tools (CRM, ERP, custom APIs, internal databases).
If you'd like the same kind of connector for **your** tools β drop us a line at [www.mag-cie.com/creation-mcp](https://www.mag-cie.com/creation-mcp).
---
## π End-user installation
### Prerequisites (all clients)
- **Node.js 20+** ([nodejs.org](https://nodejs.org))
- A Microsoft account (free or paid)
No Azure account required, no App Registration to create, nothing to compile.
---
### π¦ Claude Code (CLI)
**Install (one command):**
```bash
claude mcp add --transport stdio microsoft-todo -- npx -y @mag-cie/mcp-microsoft-todo
```
If you have a **personal Microsoft account** (outlook.com, hotmail.com, live.com, msn.com, Office 365 personal), add `MS_TENANT=consumers`:
```bash
claude mcp add --transport stdio microsoft-todo --env MS_TENANT=consumers -- npx -y @mag-cie/mcp-microsoft-todo
```
**Verify it's wired up:**
```bash
claude mcp list
```
**First use β recommended: pre-auth in a terminal first** to avoid the "stuck on first MCP call" issue (where the device code is printed to MCP stderr but Claude Code doesn't surface it):
```bash
# macOS / Linux
MS_TENANT=consumers npx -y @mag-cie/mcp-microsoft-todo@latest --auth
```
```powershell
# Windows PowerShell
$env:MS_TENANT="consumers"; npx -y @mag-cie/mcp-microsoft-todo@latest --auth
```
You'll see:
```
To sign in, use a web browser to open the page https://www.microsoft.com/link and enter the code XXXXXXXXX
```
Visit the URL, enter the code, sign in. The token is cached in `~/.mcp-microsoft-todo/token-cache.json` and refreshed automatically β you'll never have to do this again. Now go to Claude Code and any prompt that calls a tool will work instantly.
> Skip the pre-auth step if you're feeling lucky β the MCP will trigger the device code flow on first call too. The code goes to the Claude Code MCP log file (look in `%USERPROFILE%\.claude\logs\` on Windows or `~/.claude/logs/` elsewhere).
**Update to the latest version:**
```bash
claude mcp remove microsoft-todo
claude mcp add --transport stdio microsoft-todo -- npx -y @mag-cie/mcp-microsoft-todo@latest
```
The `-y` flag of npx auto-accepts the download. Without `@latest`, npx may serve a stale cached version.
**Uninstall:**
```bash
claude mcp remove microsoft-todo
# Purge the token cache:
rm -rf ~/.mcp-microsoft-todo
```
---
### πͺ Claude Desktop (app)
**1. Locate the config file:**
| OS | Path |
|---|---|
| **Windows** | `%APPDATA%\Claude\claude_desktop_config.json` |
| **macOS** | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| **Linux** | `~/.config/Claude/claude_desktop_config.json` |
On Windows, you can open it directly with:
```powershell
notepad $env:APPDATA\Claude\claude_desktop_config.json
```
If the file doesn't exist, create it with an empty JSON object `{}` then edit.
**2. Add the config:**
```json
{
"mcpServers": {
"microsoft-todo": {
"command": "npx",
"args": ["-y", "@mag-cie/mcp-microsoft-todo"]
}
}
}
```
For a personal Microsoft account, add `env`:
```json
{
"mcpServers": {
"microsoft-todo": {
"command": "npx",
"args": ["-y", "@mag-cie/mcp-microsoft-todo"],
"env": { "MS_TENANT": "consumers" }
}
}
}
```
To localize the compact-format strings (optional, see [Localization](#-localization)):
```json
{
"env": { "MS_TENANT": "consumers", "MCP_LOCALE": "fr" }
}
```
**3. Restart Claude Desktop COMPLETELY** (not just close the window):
- **Windows**: right-click systray icon β Quit, then relaunch
- **macOS**: β+Q then relaunch
**4. Verify it's wired up:**
In Claude Desktop, look at the **π plug** or **π§ tools** icon at the bottom right of the input area β you should see `microsoft-todo` listed.
**5. First auth β recommended pre-auth in a terminal:**
```bash
# macOS / Linux
MS_TENANT=consumers npx -y @mag-cie/mcp-microsoft-todo@latest --auth
```
```powershell
# Windows PowerShell
$env:MS_TENANT="consumers"; npx -y @mag-cie/mcp-microsoft-todo@latest --auth
```
You'll see the device code immediately in the terminal. Visit the URL, enter the code, sign in. Token cached. Now Claude Desktop will reuse this cache β no need to fish in the logs.
Without `--auth`, the device code goes to the Claude Desktop MCP log file:
- **Windows**: `%APPDATA%\Claude\logs\mcp-server-microsoft-todo.log`
- **macOS**: `~/Library/Logs/Claude/mcp-server-microsoft-todo.log`
**Update:** edit the version in args (`@mag-cie/mcp-microsoft-todo@latest`), restart Claude Desktop. Or let npx do its thing (npx cache ~24h).
---
### π§ Cursor / Continue / other stdio MCP clients
Any MCP client that supports the **stdio** transport works the same way. Generic format:
```
command: npx
args: -y @mag-cie/mcp-microsoft-todo
env: MS_TENANT=consumers (if personal account)
```
Adapt to the client's config format (often JSON or TOML similar to Claude Desktop).
---
## π‘ Example prompts
Once installed, just ask Claude in natural language. Sample prompts that exercise the main tools:
| Prompt | Tool(s) |
|---|---|
| *"Show me all my To Do lists"* | `list_task_lists` |
| *"What do I have to do today?"* | `summarize_today` |
| *"Show me my overdue tasks"* | `list_overdue_tasks` |
| *"List tasks tagged 'work'"* | `list_tasks_by_category` |
| *"Find any task containing 'invoice'"* | `search_tasks` |
| *"Add a daily recurring 'Workout' task"* | `create_task` (with recurrence) |
| *"Mark these 5 tasks as done"* | `batch_complete_tasks` |
| *"Move 'Buy bread' from Personal to Shopping"* | `move_task` |
| *"Add a 'recipe' subtask to the cake task"* | `create_checklist_item` |
| *"Tag all my Magaria tasks as 'urgent'"* | `bulk_update_categories` |
| *"Export my work tasks as iCalendar"* | `export_tasks_ics` |
| *"Attach a project_id metadata to this task"* | `set_extension` |
---
## π Auth troubleshooting
| Symptom | Solution |
|---|---|
| "This page isn't right" page after sign-in | Add `MS_TENANT=consumers` (personal accounts only) |
| Browser opens with the wrong Microsoft account | Use an **InPrivate/Incognito** window for the sign-in |
| `invalid_scope` or `Tasks.ReadWrite.Shared` error | Purge the token cache and re-auth: `rm -rf ~/.mcp-microsoft-todo` |
| `Node.js not found` or `npx not found` | Install Node 20+ from [nodejs.org](https://nodejs.org). On Windows, verify it's in PATH (relaunch your terminal after install) |
| Token expired, refresh fails | Purge the cache and re-auth |
| Device code never appears | Verify the server is spawning β Claude Code: `claude mcp list`; Claude Desktop: tools icon at the bottom. If absent, check the `npx` PATH in the config |
| `MS_CLIENT_ID not configured` | You're using a dev fork β export `MS_CLIENT_ID` or use the official npm version |
---
## π Available tools (28)
Safety column legend: `read` = read-only, `write` = mutates state (non-idempotent create), `update` = idempotent mutation (safe to retry), `delete` = destructive (data loss). See [Safety annotations](#-safety-annotations) below for details.
### Lists & tasks
| Tool | Safety | Description |
|---|---|---|
| `list_task_lists` | read | All your To Do lists |
| `list_tasks` | read | Tasks of a list (OData filter, `$orderby`, `paginate`) |
| `get_task` | read | Detail of a task by ID |
| `create_task` | write | Create a task (title, body, importance, due date, categories, **recurrence, reminder**) |
| `update_task` | update | Update title, status, due date, recurrence, reminder⦠|
| `complete_task` | update | Mark as completed |
| `delete_task` | delete | Delete permanently |
| `move_task` | delete | Move a task from one list to another (source task is deleted) |
| `search_tasks` | read | Cross-list search by title |
| `summarize_today` | read | Summary of tasks due today + overdue |
| `list_all_tasks` | read | Every task across every list in one round-trip (uses Graph `$batch`) |
### Batch operations (saves API calls)
| Tool | Safety | Description |
|---|---|---|
| `batch_create_tasks` | write | Create up to 100 tasks in a single Graph `$batch` HTTP call |
| `batch_complete_tasks` | update | Mark up to 100 tasks as completed in one call |
| `batch_delete_tasks` | delete | Delete up to 100 tasks in one call |
### Sub-tasks (checklist items)
| Tool | Safety | Description |
|---|---|---|
| `list_checklist_items` | read | Sub-items of a task |
| `create_checklist_item` | write | Add a sub-item |
| `update_checklist_item` | update | Rename / check / uncheck |
| `delete_checklist_item` | delete | Delete a sub-item |
### Linked resources (external URLs attached to a task)
| Tool | Safety | Description |
|---|---|---|
| `list_linked_resources` | read | List the linked resources of a task |
| `create_linked_resource` | write | Attach a URL or external reference |
| `delete_linked_resource` | delete | Delete a linked resource |
### Open extensions (custom JSON metadata)
| Tool | Safety | Description |
|---|---|---|
| `list_extensions` | read | List the open extensions of a task |
| `set_extension` | update | Upsert: create or update an extension (project_id, external_ref, etc.) |
| `delete_extension` | delete | Delete an extension |
### Cross-list helpers
| Tool | Safety | Description |
|---|---|---|
| `list_overdue_tasks` | read | All overdue tasks, aggregated across all lists |
| `list_tasks_by_category` | read | All tasks with a given category, cross-lists |
| `bulk_update_categories` | update | Add/remove categories on many tasks in 2 batch phases |
### Export
| Tool | Safety | Description |
|---|---|---|
| `export_tasks_ics` | read | iCalendar export (VTODO + RRULE + VALARM) for import into Google Cal / Apple Cal / Outlook / Thunderbird |
### Output format
By default, tools return a **compact text format** (one line per item) to save LLM tokens. Legend:
- `[!]` high importance, `[?]` low (nothing if normal)
- `[v]` completed, `[>]` in progress, `[w]` waiting, `[d]` deferred (nothing if not started)
- `due:`, `rem:`, `rec:`, `cat:`, `body:` fields shown only when populated
To get the **full Graph JSON**, pass `verbose: true` to any read tool.
---
## π Safety annotations
Every tool exposed by this server carries the [MCP tool annotations](https://modelcontextprotocol.io/specification/2025-06-18/server/tools#tool-annotations) defined by the Model Context Protocol spec (2025-06-18):
| Annotation | Meaning |
|---|---|
| `readOnlyHint` | The tool only fetches data; running it has no side effects on Microsoft Graph |
| `destructiveHint` | The tool deletes data or otherwise causes data loss that cannot be undone |
| `idempotentHint` | Running the tool repeatedly with the same arguments yields the same end state (safe to retry) |
| `openWorldHint` | The tool talks to an external system (Microsoft Graph) β always `true` here |
| `title` | Human-readable display name for MCP clients |
These hints are **advisory** β the server itself enforces nothing β but MCP clients (Claude Code, Claude Desktop, Cursor, β¦) can use them to:
- Auto-approve `readOnlyHint: true` calls without prompting (faster UX for read-heavy workflows)
- Show a confirmation dialog before `destructiveHint: true` calls (e.g. `delete_task`, `batch_delete_tasks`, `move_task`)
- Retry on transient failures only when `idempotentHint: true`
- Display the friendly `title` instead of the snake_case `name`
The full mapping is in [`src/index.ts`](src/index.ts) (`ANNOTATIONS` constant). Summary by safety class (see also the per-tool **Safety** column above):
- **read** (15 tools): all `list_*`, `get_*`, `search_*`, `summarize_*`, `export_*` β `readOnlyHint: true`
- **write** (4 tools): `create_*`, `batch_create_tasks` β `destructiveHint: false, idempotentHint: false`
- **update** (5 tools): `update_*`, `complete_*`, `set_extension`, `bulk_update_categories`, `batch_complete_tasks` β `destructiveHint: false, idempotentHint: true`
- **delete** (5 tools): `delete_*`, `batch_delete_tasks`, `move_task` β `destructiveHint: true, idempotentHint: true`
`move_task` is classified as `delete` because it deletes the source task (a new task is created in the target list with a different id).
---
## π Localization
The MCP works in **any language out of the box** β Claude reads the data the server returns and replies to the user in whatever language they prompted in. Try `"List my tasks"`, `"Liste mes tΓ’ches"`, `"Zeig meine Aufgaben"`, `"ζηδ»»ε‘"` β all work.
Optionally, you can localize the compact-format short labels returned by the server itself (`No tasks.`, `Due today:`, `Overdue:`, `Task X deleted.`, etc.) β this is a marginal improvement (saves a few tokens, slightly cleaner LLM context). Set `MCP_LOCALE` in your env:
| Locale | Code |
|---|---|
| English (default) | `en` |
| FranΓ§ais | `fr` |
| EspaΓ±ol | `es` |
| Deutsch | `de` |
Resolution order: `MCP_LOCALE` β `LC_ALL` β `LANG` β fallback `en`. Only the first 2 chars are inspected (so `fr_FR.UTF-8` works). Unsupported locale β falls back to `en`.
```json
{
"mcpServers": {
"microsoft-todo": {
"command": "npx",
"args": ["-y", "@mag-cie/mcp-microsoft-todo"],
"env": { "MCP_LOCALE": "fr" }
}
}
}
```
---
## π Security & privacy
- The Microsoft token is stored **only on your machine** in `~/.mcp-microsoft-todo/token-cache.json`
- No data transits through MAG&Cie servers
- Revoke access at any time at https://account.live.com/consent/Manage
- To purge the local token: `rm -rf ~/.mcp-microsoft-todo`
Graph permissions requested: `Tasks.ReadWrite`, `Tasks.ReadWrite.Shared`, `offline_access`.
---
## π§βπ» Developer setup (fork / contribution)
If you fork or want to develop locally with your own Azure AD App Registration:
### 1. Azure AD App Registration (maintainer/fork side only)
1. https://portal.azure.com β **Microsoft Entra ID** β **App registrations** β **New registration**
2. Name: `mcp-microsoft-todo` (free choice)
3. Supported account types: **Accounts in any organizational directory and personal Microsoft accounts**
4. Redirect URI: leave empty
5. Register
6. Note the **Application (client) ID**
7. **Authentication** tab β **Allow public client flows**: **Yes**
8. **Authentication** tab β **Add a platform** β **Mobile and desktop applications** β check `https://login.microsoftonline.com/common/oauth2/nativeclient`
9. **API permissions** tab β **Add a permission** β **Microsoft Graph** β **Delegated** β add `Tasks.ReadWrite`, `Tasks.ReadWrite.Shared`, and `offline_access`. **Grant admin consent** if on a corporate tenant.
### 2. Build and local auth
```bash
git clone https://github.com/MAG-Cie/mcp-microsoft-todo
cd mcp-microsoft-todo
npm install
npm run build
export MS_CLIENT_ID="<your-client-id>" # PowerShell: $env:MS_CLIENT_ID="..."
export MS_TENANT="common"
npm run auth
```
The token cache will be written to `~/.mcp-microsoft-todo/token-cache.json`.
### 3. Wire up Claude Code (local build)
```powershell
# Windows PowerShell
$env:MS_CLIENT_ID="<your-client-id>"
claude mcp add --transport stdio microsoft-todo -- node "C:\path\to\mcp-microsoft-todo\dist\index.js"
```
```bash
# macOS / Linux
export MS_CLIENT_ID="<your-client-id>"
claude mcp add --transport stdio microsoft-todo -- node /path/to/mcp-microsoft-todo/dist/index.js
```
> β οΈ Env vars must be visible at spawn time. On Windows with fnm, verify the PowerShell session that launches `claude` has `MS_CLIENT_ID` exported.
### 4. Run tests
```bash
npm test # one-shot
npm run test:watch # watch mode
```
---
## β¬οΈ Upgrading from earlier versions
| From | To | Action required |
|---|---|---|
| `0.x` | `0.4.0+` | Re-auth required: token cache lacks the new `Tasks.ReadWrite.Shared` scope. Run `rm -rf ~/.mcp-microsoft-todo` then trigger any tool to re-auth via device code. |
| `0.x` | `0.5.0+` | No breaking change β new tools added. Token compatible. |
| any | `1.0.0+` | Stable API marker. Future minor versions guarantee no breaking change to tool names, args, or return formats (compact + verbose). |
---
## πΊ Roadmap
- [x] v0.1 β stdio + 6 CRUD tools
- [x] v0.2 β distributable npm package, baked-in client ID
- [x] v0.3 β recurrence + reminders + checklists + linkedResources + search + move + summarize_today + retry/error robustness + vitest tests + compact format (verbose opt-in)
- [x] v0.4 β auto pagination + `$batch` operations + `Tasks.ReadWrite.Shared` scope (read shared lists)
- [x] v0.5 β open extensions + cross-list helpers (overdue, by category, bulk update) + iCalendar export
- [x] v1.0 β stable milestone: GitHub Actions CI + extended tests + snapshot tests + README polish
Possible future versions:
- v1.1 β file attachments (Graph beta)
- v1.2 β auto-pagination follow-on for `summarize_today` / `search_tasks` / `list_overdue_tasks`
- v2.0 β remote HTTP/SSE transport for Claude.ai custom connectors (multi-user OAuth)
---
## π License
[MIT](LICENSE) β Β© MAG&Cie