Unofficial Any.do MCP
Unofficial MCP (Model Context Protocol) server that connects AI assistants to your Any.do tasks. Supports accounts with 2FA.
Disclaimer: This is an unofficial, community-built project. It is not affiliated with, endorsed by, or connected to Any.do Inc. in any way. "Any.do" is a trademark of Any.do Inc., used here only nominatively to identify the third-party service this software interoperates with. The API endpoints used are reverse-engineered from the Any.do web application and are not officially documented or supported. This work is provided for interoperability purposes pursuant to Article 6 of Directive 2009/24/EC of the European Parliament. Use at your own risk — the API may change without notice, and your account could be affected. Users are responsible for ensuring their use complies with Any.do's Terms of Service.
Privacy & no telemetry: This tool processes your Any.do data locally on your machine. No data, telemetry, or analytics is transmitted to the package author or any third party. Task content — including notes and any location data stored in Any.do — passes directly between your device and Any.do's servers. This is a hard guarantee: if telemetry is ever introduced, it will require a major version bump and explicit opt-in.
Features
- Full task CRUD (create, read, update, delete)
- Subtask support (create, update, delete)
- Category/list management
- Mark tasks done/undone, archive/unarchive
- Due dates, priorities, notes, labels
- Filter tasks by category
Installation
# Global install (recommended)
npm install -g unofficial-anydo-mcp
# Or run without installing
npx unofficial-anydo-mcp
Authentication (with 2FA support)
The server uses an X-Anydo-Auth token. Run the included helper to capture it:
Requirements:
- Node.js ≥ 18 and a graphical environment (does not work over headless SSH).
- Puppeteer is needed by the token-capture helper. It is listed as an optional npm dependency because the MCP server itself does not need it — only
mcp-anydo-tokendoes. Ifnpm install -g unofficial-anydo-mcpskipped puppeteer (e.g. behind a firewall or due to the ~170 MB Chromium download), install it explicitly:npm install -g puppeteer.- On Linux, install Chromium system dependencies first:
sudo apt-get install -y libgbm1 libnss3 libatk-bridge2.0-0
mcp-anydo-token
- A browser window opens — log in to Any.do (including 2FA if prompted)
- The token is automatically captured and saved to
.envasANYDO_AUTH_TOKEN
Note: Tokens expire periodically. When expired the server returns:
Authentication failed. Your token may have expired.Re-runmcp-anydo-token, then updateANYDO_AUTH_TOKENin your MCP client config and restart the client.
Security & threat model: The token is saved as plaintext in
.env. Anyone with read access to that file can act as you in Any.do until the token is rotated. On a shared system, restrict permissions:chmod 600 .env. If you suspect leakage, change your Any.do password — that invalidates issued tokens.
Troubleshooting
| Problem | Solution |
|---|---|
Authentication failed | Token expired — run mcp-anydo-token |
Missing ANYDO_AUTH_TOKEN | .env file missing — run mcp-anydo-token |
Configuration
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"anydo": {
"command": "unofficial-anydo-mcp",
"env": {
"ANYDO_AUTH_TOKEN": "<your-token>"
}
}
}
}
OpenCode
Add to opencode.json in your project root or ~/.config/opencode/opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"anydo": {
"type": "local",
"command": ["unofficial-anydo-mcp"],
"enabled": true,
"env": {
"ANYDO_AUTH_TOKEN": "<your-token>"
}
}
}
}
Cursor
Add to ~/.cursor/mcp.json:
{
"mcpServers": {
"anydo": {
"command": "unofficial-anydo-mcp",
"env": {
"ANYDO_AUTH_TOKEN": "<your-token>"
}
}
}
}
Continue.dev
Add to ~/.continue/config.json:
{
"mcpServers": [
{
"name": "anydo",
"command": "unofficial-anydo-mcp",
"env": {
"ANYDO_AUTH_TOKEN": "<your-token>"
}
}
]
}
Other MCP clients
Any client that supports MCP stdio servers works with unofficial-anydo-mcp (global install) or npx unofficial-anydo-mcp as the command, with ANYDO_AUTH_TOKEN passed as an environment variable.
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
ANYDO_AUTH_TOKEN | Yes | — | Auth token from Any.do (obtain via mcp-anydo-token) |
ANYDO_TIMEZONE | No | Europe/Bratislava | Timezone for reminder calculations — set to your local zone (e.g. America/New_York, Europe/London) to ensure reminders fire at the correct local time |
ANYDO_DEFAULT_REMINDER_HOUR | No | 9 | Default hour (0–23) used for reminders when alert=true and no reminderTime is specified |
Contributing / Development
git clone https://github.com/branislav-remen/unofficial-anydo-mcp
cd unofficial-anydo-mcp
npm install
npm run build
| Command | Description |
|---|---|
npm run build | Compile TypeScript to dist/ |
npm start | Run compiled server |
npm run dev | Run directly via ts-node |
npm test | Run tests |
npm run test:watch | Run tests in watch mode |
npm run test:coverage | Run tests with coverage |
npm run typecheck | TypeScript type checking |
npm run lint / lint:fix | ESLint check / auto-fix |
Available Tools (16 total)
Tasks
| Tool | Description |
|---|---|
list_tasks | List tasks (includeDone, includeDeleted, categoryId filter) |
get_task | Get task details by ID |
create_task | Create a task (title, priority, note, categoryId, dueDate, labels) |
update_task | Update a task (title, priority, note, categoryId, dueDate, labels) |
delete_task | Delete a task by ID |
mark_task_done | Mark a task as completed (CHECKED) |
mark_task_undone | Mark a task as not completed (UNCHECKED) |
archive_task | Archive a task (DONE — hidden from active list) |
unarchive_task | Unarchive a task (restores to UNCHECKED) |
Subtasks
| Tool | Description |
|---|---|
create_subtask | Create a subtask under a parent task |
update_subtask | Update a subtask |
delete_subtask | Delete a subtask |
Categories / Lists
| Tool | Description |
|---|---|
get_categories | List all categories/lists |
create_category | Create a new category/list |
update_category | Rename a category/list |
delete_category | Delete a category/list |
Usage Examples
- "Show me my todos"
- "Create a task 'Buy groceries' in the Personal list"
- "Mark task xyz as done"
- "Change priority of task abc to High"
- "Show me all my lists"
- "Create a new list called 'Work'"
- "Move task to the Work category"
- "Show me tasks only from the Work category"
How It Works
The server intercepts Any.do web app API calls to understand their endpoints. No official API documentation exists — all endpoints are reverse-engineered from the web application.
- Base URL:
https://sm-prod2.any.do - Auth:
X-Anydo-Authheader (extracted via Puppeteer after browser login) - Endpoints:
/me/tasks,/me/categories,/me/tasks/:id,/me/categories/:id
Known Limitations
- Category rename is destructive:
update_categorycreates a new category, migrates all tasks, then deletes the old one. If interrupted mid-operation, both categories may exist with tasks partially migrated. - Recurring task deletion: Deleting a recurring task causes Any.do to automatically create the next occurrence. Always call
update_taskwithrepeatingMethod: "TASK_REPEAT_OFF"before deleting a recurring task. - No rate-limit handling: Bulk operations such as renaming a large category fire multiple API requests. Very large task lists may trigger Any.do's API rate limits.
- Unofficial API: All endpoints are reverse-engineered from the web app. Any.do may change them without notice.
License
ISC © Branislav Remen