toodledo-mcp
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
toodledo-mcp
A small, open-source remote MCP server that connects Claude (claude.ai web, desktop, mobile and scheduled tasks) to your Toodledo account through the official Toodledo API v3.
Runs on Cloudflare Workers (free tier is plenty for one person).
OAuth on both sides: Claude → this server (OAuth 2.1 + PKCE, dynamic client registration), and this server → Toodledo (OAuth2 authorization code). No authless mode.
Toodledo tokens are encrypted at rest (AES-256-GCM) in a per-user Durable Object that serialises refreshes, so Toodledo's single-use refresh tokens are never used twice.
Human-friendly I/O:
YYYY-MM-DDdates,HH:MMtimes, and folder/context/goal names instead of numeric IDs.Five small runtime dependencies (the Cloudflare
agentsMCP helpers need both MCP SDK packages), no UI framework. MIT licensed.
You deploy your own instance and connect your own Toodledo account. Nothing is shared with the author.
Architecture
┌──────────────┐ OAuth 2.1 (PKCE, DCR) ┌───────────────────────── Cloudflare Worker ─────────────────────────┐
│ claude.ai │ ───────────────────────► │ OAuthProvider (@cloudflare/workers-oauth-provider) │
│ web/desktop/ │ Bearer token │ /authorize /token /register ── grants & tokens ──► KV (OAUTH_KV) │
│ mobile/sched │ ───────────────────────► │ /mcp ──► ToodledoMCP (McpAgent Durable Object, Streamable HTTP) │
└──────────────┘ │ │ tools (zod) ─► ToodledoClient ── retries/backoff ──┐ │
│ │ name lookups cached 5 min │ │
browser (once) ──► consent page ──►│ /callback ◄─┘ │ │
│ │ │ exchange code │ │
▼ │ ▼ │ │
┌────────────────────┐ OAuth2 code │ ToodledoTokenStore (Durable Object, one per Toodledo user) │ │
│ Toodledo sign-in │ ◄────────────────│ AES-GCM encrypted {access, refresh, expiry, call count} │ │
└────────────────────┘ │ single in-flight refresh · persists rotated refresh token first │ │
└────────────────────────────────────────────────────────────────────┼─┘
▼
https://api.toodledo.com/3/*src/
core/ platform-agnostic (no Cloudflare imports)
dates.ts ISO <-> Toodledo timestamps (GMT-noon dates, floating times)
token-manager.ts refresh/rotation/serialisation/encryption logic
toodledo-oauth.ts authorize URL + token endpoint
toodledo-client.ts API calls, batching (50), pagination (1000), retry/backoff
lookups.ts folder/context/goal/location cache + name resolution
schemas.ts zod input schemas
format.ts raw task <-> tool I/O
tools.ts MCP tool definitions
worker/ Cloudflare glue
auth-handler.ts /authorize, /callback, consent page
token-store.ts ToodledoTokenStore Durable Object
mcp-agent.ts ToodledoMCP (McpAgent)
index.ts Worker entry (OAuthProvider)
test/ vitest unit tests (Toodledo is mocked)
scripts/smoke-test.mjs end-to-end test against a deployed instanceThe core only uses fetch and WebCrypto, so it can be reused on another runtime by swapping src/worker/.
Related MCP server: ticktick-mcp
Self-hosting (≈30 minutes)
Prerequisites
Node.js 20+ and npm
A free Cloudflare account
A Toodledo account
A Claude plan that supports custom connectors
1. Get the code
git clone https://github.com/<you>/toodledo-mcp.git
cd toodledo-mcp
npm install
npm run check # typecheck + lint + tests2. Log in to Cloudflare and create the KV namespace
npx wrangler login
npx wrangler kv namespace create OAUTH_KVCopy the printed id into wrangler.toml (replace REPLACE_WITH_YOUR_KV_NAMESPACE_ID). The KV id is not a secret.
Durable Objects need no manual setup: the [[migrations]] block in wrangler.toml creates them on first deploy (SQLite-backed, available on the free plan).
3. First deploy (to learn your URL)
npx wrangler deployNote the URL, e.g. https://toodledo-mcp.<your-subdomain>.workers.dev. Visiting it shows a small "toodledo-mcp is running" page. It can't authorize anyone yet because the secrets aren't set.
4. Register a Toodledo app
Sign in to Toodledo, then open https://api.toodledo.com/3/account/doc_register.php.
Create a new application:
Redirect URI:
https://toodledo-mcp.<your-subdomain>.workers.dev/callback(it must match exactly)Name/description/website: anything you like.
Keep the Client ID and Client Secret handy for the next step. Don't paste them anywhere else.
5. Set the secrets
Every secret goes in through Wrangler's interactive prompt or a pipe, so it never lands in a file or your shell history:
npx wrangler secret put TOODLEDO_CLIENT_ID # paste when prompted
npx wrangler secret put TOODLEDO_CLIENT_SECRET # paste when prompted
openssl rand -base64 32 | npx wrangler secret put TOKEN_ENCRYPTION_KEY
openssl rand -base64 32 | npx wrangler secret put COOKIE_ENCRYPTION_KEYOptional: restrict the instance to your own Toodledo account (recommended). Leave this unset for the first connection. Afterwards, toodledo_get_account shows your userid:
npx wrangler secret put ALLOWED_TOODLEDO_USERIDS # e.g. "td1234567890abc"⚠️ Don't rotate
TOKEN_ENCRYPTION_KEYcasually. Stored Toodledo tokens become unreadable and you'll have to reconnect.
6. Smoke test (optional, recommended)
npm run smoke -- https://toodledo-mcp.<your-subdomain>.workers.devThis opens your browser for consent and Toodledo sign-in, then runs list_folders, list_tasks, add_tasks, edit_tasks, get_task, complete_tasks and delete_tasks on a throwaway task titled [toodledo-mcp smoke test] …. Add --keep to leave the task in Toodledo. See Verification for MCP Inspector instructions.
7. Add the connector in Claude
In claude.ai (web or desktop): Settings → Connectors → Add custom connector.
Name:
Toodledo. URL:https://toodledo-mcp.<your-subdomain>.workers.dev/mcp.Click Add, then Connect. Approve the consent page, then sign in to Toodledo and allow access. You only do this once.
In a chat, turn the connector on from the tools menu if it isn't already. The connector syncs to Claude on iPhone/Android and works in scheduled tasks.
Try: "List my open Toodledo tasks due this week, grouped by folder."
Local development
cp .dev.vars.example .dev.vars # fill in values (never commit .dev.vars)
npm run dev # http://localhost:8787For a local Toodledo login you'd need a second Toodledo app whose redirect URI is http://localhost:8787/callback.
Tool reference
All dates are YYYY-MM-DD and all times are HH:MM (24h). Folder, context, goal and location inputs accept a name (case-insensitive) or an id. 0 or "none" clears them. Outputs include { id, name } objects.
Tool | Kind | What it does |
| read | Alias, plan (subtasks need a paid plan), date format, last-edit timestamps |
| read | Filters: |
| read | One task by id, all fields |
| write | Batch (≤200): |
| write | Batch partial update by |
| write | Batch complete. Repeating tasks roll to the next occurrence |
| destructive | Batch permanent delete. Requires |
| read |
|
| read | |
| read | Level ( |
| read | |
| write | Create by name |
| write |
|
Enum values: priority negative, low, medium, high, top. status none, next_action, active, planning, delegated, waiting, hold, postponed, someday, canceled, reference. duedatemod due_by, due_on, due_after, optionally.
Read tools have readOnlyHint: true. Delete has destructiveHint: true.
Toodledo date conventions (how conversion works)
Dates (
duedate,startdate,completed,added) are stored by Toodledo as a unix timestamp at 12:00 GMT of that day. Noon keeps the calendar day the same in nearly every timezone. This server converts2026-11-08⇄1794139200and ignores the time part on the way back.Times (
duetime,starttime) are floating: the GMT clock time is the time you chose (18:30stays18:30anywhere). When you change only the time on an existing task, the server reads the task's current date first so the time stays on the right day.modifiedis a real instant, returned as ISO 8601 UTC.toodledo_complete_tasksdefaults to today in UTC. Claude is told to pass your local date when it knows it.
Security notes
No authless mode.
/mcprequires an OAuth access token issued by this server. Tokens are issued only after a person approves the consent page and signs in to Toodledo.Consent page and CSRF. Dynamic client registration is open, as MCP clients expect. The consent page shows the client name and redirect host, so an unknown app can't silently get a token. The flow uses a signed CSRF cookie, and the Toodledo
stateis bound to the browser with a signed cookie.Restrict accounts. Set
ALLOWED_TOODLEDO_USERIDSso only your Toodledo account can use your instance and your Workers quota.Encryption at rest. Toodledo access and refresh tokens are encrypted with AES-256-GCM using
TOKEN_ENCRYPTION_KEY. The ciphertext is bound to the user id, so blobs can't be swapped between users. Claude-side OAuth grants are handled byworkers-oauth-provider, which stores only hashes of its tokens.Secrets only live in Cloudflare (
wrangler secret put)..dev.varsis git-ignored. CI uses no secrets.Scopes. The server requests the Toodledo scopes
basic tasks write, and nothing for notes, outlines, lists or sharing.Revoking access. Disconnect the connector in Claude, revoke the app in Toodledo's account settings, or delete the worker.
See SECURITY.md for reporting vulnerabilities.
Token lifecycle (why it survives > 2 hours)
Toodledo rule | How it's handled |
Access token lasts 2h | Refreshed automatically 5 minutes before expiry |
~100 API calls per access token | Calls are counted per token. A refresh happens at 90, or on a rate-limit error after heavy use |
Refresh token is single-use | Every refresh goes through one Durable Object per user with a single in-flight promise. The new refresh token is persisted before the access token is handed out |
Refresh token dies after 30 days unused | Tools return: "Toodledo authorization has expired… Reconnect the Toodledo connector in Claude…" |
~10 token requests per hour | If the token endpoint is rate limited, the current access token keeps being used while it's still valid |
Errors 1/2 (invalid token) | One forced refresh and retry, then a re-authorize error |
Error 3 / HTTP 429, 5xx, network | Exponential backoff (0.5s, 1s, 2s) |
Batch writes go to Toodledo in chunks of 50 (the API maximum). Task listing reads pages of 1000.
Limitations
Filtering is client-side for everything except completion and
modified_after, because Toodledo'stasks/gethas no folder or due-date filters.max_scan(default 2000, max 5000) caps how many tasks are read per call, and each 1000 tasks costs one API call.If you don't use the connector for 30 days, the Toodledo refresh token expires and you'll need to reconnect once.
Subtasks (
parent) need a paid Toodledo plan.Not in v1: notes, outlines, lists, habits, collaboration/sharing, webhooks, editing or deleting folders, contexts and goals.
"Today" defaults to UTC when completing tasks without a
date.
Verification
Option A: script. npm run smoke -- <your worker URL> (see step 6).
Option B: MCP Inspector.
npx @modelcontextprotocol/inspectorTransport Streamable HTTP, URL
https://toodledo-mcp.<your-subdomain>.workers.dev/mcp.Open Auth settings → Quick OAuth flow (or Connect) and complete the consent page and Toodledo sign-in.
Tools → List tools, then run:
toodledo_list_folderswith{}toodledo_list_taskswith{"limit": 5, "sort": "due"}toodledo_add_taskswith{"tasks":[{"title":"Inspector test","duedate":"2026-11-15","priority":"high"}]}(note the returnedid)toodledo_edit_taskswith{"tasks":[{"id": <id>, "title":"Inspector test (edited)","duetime":"18:30"}]}toodledo_complete_taskswith{"ids":[<id>]}
Token refresh > 2h. Make one call, wait more than 2 hours, then make another. It should succeed with no re-login. To watch rotations, run npx wrangler tail (tokens are never logged).
Contributing
See CONTRIBUTING.md. npm run check must pass.
License
MIT. Not affiliated with Toodledo or Anthropic.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
Related MCP Connectors
Manage Redbooth tasks, task lists, comments, tags and files from Claude and other AI assistants.
Notes, tasks, habits, journal and 6 more tools Claude can read and change, with undo. Free.
Lets Claude, ChatGPT, and Muse read and update your beckett tasks, notes, calendar, and lists.
Task management for people and AI agents, with scoped OAuth access to issues, projects, and docs.
Related MCP Servers
- AlicenseAqualityDmaintenanceConnects Claude to Todoist for transforming meeting notes into actionable tasks with inferred due dates and priorities. It enables full task lifecycle management, including creating subtasks, listing projects, and completing tasks through natural language.7MIT
- AlicenseAqualityDmaintenanceMCP server for TickTick using the official OAuth 2.0 API. Create, list, update, complete, and delete tasks just by talking to Claude.73MIT
- AlicenseNot gradedqualityDmaintenanceConnects Claude to your TickTick account with 28 tools for full CRUD task management, smart queries, batch operations, and GTD support, letting you manage tasks through natural conversation.1MIT
- FlicenseBqualityCmaintenanceConnects Claude to Google Tasks, enabling users to list, create, update, complete, reopen, and delete tasks through natural language.9-