A Cloudflare Worker + Next.js 16 reference implementation that plans a focused day with Workers AI, streams the intermediate events to the browser, and syncs the resulting tasks into Todoist through the official Model Context Protocol (MCP) Streamable HTTP endpoint. The project is distributed under the Apache 2.0 License (see LICENSE).
- Frontend: React 19 App Router page (
src/app/page.tsx) that captures a single natural-language prompt, streams NDJSON events from/plan, and optionally records a short voice note that flows through/api/transcribe. - Planning pipeline:
/plan(documented inopenapi/plan.yaml) validates the request, runs intent classification + scenario-specific planning with@cf/openai/gpt-oss-120b/@cf/openai/gpt-oss-20b, discovers Todoist projects/labels dynamically, and streams every stage as newline-delimited JSON. Details live indocs/PLAN_PIPELINE.md. - Todoist MCP integration: Uses
StreamableHTTPClientTransportto connect tohttps://ai.todoist.net/mcp, lists whatever metadata/tools are available (legacy or official), and callsadd-task(s)with bothprojectIdandproject_idfields plus normalized priorities (p1…p4). - Voice transcription:
/api/transcribeproxies base64 WebM/Opus audio to@cf/openai/whisper-large-v3-turbo, enforcing an 8 MB limit so the front-end can overwrite the prompt and immediately submit/plan.
- Intent-aware planning:
single_reminder,multi_step_plan,recipe_plan, andgeneral_plantemplates enforce task counts, dependencies, and tone. - Metadata-driven prompts: Todoist projects/labels fetched via MCP are injected into the AI prompt and exposed through
debug.metadataevents to minimize “Inbox” fallbacks. - Priority normalization: Natural-language cues such as
P0,P1, or “high priority” map to Todoist REST priority numbers (4 = P1,1 = P4). Bulk tools automatically convert top1…p4strings. - Streaming UX:
/planreplies withapplication/x-ndjsonevents (status,ai.plan,todoist.task,final,error) so the UI can display progress and failures instantly. - Voice-first flow: Browser MediaRecorder →
/api/transcribe→ prompt submission in one click, with graceful fallbacks when permissions or size limits fail.
- Node.js 20+
pnpm9+- Wrangler CLI 4.45+
- Cloudflare account with Workers AI enabled
- Todoist account + API token approved for the MCP beta (
https://ai.todoist.net/mcp)
| Name | Description |
|---|---|
FRONTEND_ORIGIN |
Single allowed origin for CORS and Basic Auth prompts. |
TODOIST_MCP_URL |
MCP Streamable HTTP endpoint (default https://ai.todoist.net/mcp). |
TODOIST_TOKEN |
Bearer token recognized by Todoist MCP. |
BASIC_AUTH_USER / BASIC_AUTH_PASS |
Credentials for HTTP Basic auth across /plan and /transcribe. |
AI binding |
Configured in wrangler.jsonc to access Workers AI (e.g., binding: "AI"). |
Populate .dev.vars for local runs, then set the same names in Cloudflare via wrangler secret put.
pnpm install
pnpm dev # Next.js dev server (no Worker bindings)
pnpm lint # ESLint flat config for Next.js 16 + TS strict
pnpm preview # Build via OpenNext + Wrangler preview
wrangler dev # Run the Worker locally at http://127.0.0.1:8787Example streaming request:
curl -u "$BASIC_AUTH_USER:$BASIC_AUTH_PASS" \
-N -H "Content-Type: application/json" \
-H "Origin: $FRONTEND_ORIGIN" \
-d '{"prompt":"Plan a mindful evening"}' \
http://127.0.0.1:8787/planpnpm run deploy # Builds with opennextjs-cloudflare and runs `wrangler deploy`The script produces .open-next/worker.js, uploads static assets, and publishes to wrangler.jsonc's Worker name.
- Tail logs with sanitization disabled to capture Todoist payloads:
LOG_FILE=$(mktemp -t wrangler-tail).log WRANGLER_LOG_SANITIZE=false npx wrangler tail cf-todoist-daily-agent --format json > "$LOG_FILE" 2>&1 &
- Trigger
/planwhile the tail is running. Look for:[todoist.tools]– discovered MCP tools.[todoist.debug.metadata]– first few projects/labels (confirms metadata scope).[todoist.debug.call-args]– exactadd-task(s)payload (checkproject_id,priority,due*).
- Cross-reference the Todoist Activity Log to confirm tasks landed in the expected project and priority.
OPTIONS /plan– CORS preflight (204).POST /plan– Main planner endpoint returningapplication/x-ndjson(seeopenapi/plan.yaml).POST /transcribe– Voice helper, returns{ text, language }or an error payload.
OpenAPI schemas define request/response bodies for automation and client generation.
pnpm lintpnpm previewwrangler dev --localfollowed by a sample curl (as above) to validate NDJSON streaming and Todoist MCP connectivity.
Licensed under the Apache License, Version 2.0.