MCP server for Deep Work Timer (deepworktimer.com): pomodoro and deep work time tracking with a permanent per-skill ledger, for Claude Code, Claude Desktop, Cursor and any MCP client.
Strong naming conventions (verb_noun pattern: dwt_status, dwt_create_task, dwt_list_projects). All 14 tools have descriptions (avg ~120 chars, within 10-1024 range). Input schemas present for all tools with proper Zod validation (z.string, z.number, z.boolean). However, parameter descriptions are minimal or missing context about dependencies and constraints. Output schemas are not documented, LLMs cannot predict response structure. Error handling exists (ApiError class) but recovery guidance is sparse. Risk annotations (READ_ONLY, WRITE, DESTRUCTIVE) are present in tool metadata but not exposed in schema.
Discard the active session without recording it. The session must be owned by this device (call dwt_status to check).
Mark a task as completed.
Create a project to group tasks (e.g. a repo, a course, a certification).
Create a task. Put skills in the description as #tags (e.g. 'Fix auth bug #python #django @1h'); an @Nh/@Nm marker sets the estimate. #tags only attach to skills that already exist on the account. Returns the created task with its attached skills.
Today's ledger statement: each completed focus session with its tasks and minutes.
The 10,000-hour ledger: lifetime focus hours for every #skill the user has tagged, sorted by hours, with the next milestone. Use to answer 'how many hours have I put into X'.
Output schemas not documented. LLMs cannot predict response structure (e.g., what fields dwt_status returns, what dwt_list_tasks yields). Forces agents to guess or fail on chaining.
Risk annotations (READ_ONLY, WRITE, DESTRUCTIVE) present in code but not exposed via tool schema. LLMs cannot see which tools are safe to retry or have side effects.
Parameter descriptions lack constraint details. E.g., dwt_create_task accepts #skill tags in description but does not document that tags must already exist on account. dwt_start_session accepts 1-240 min but description does not explain default (pomodoro setting).
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 65 | 2026-07-28+ | v2 |
List the user's projects (id, name). Tasks live in projects or unassigned.
List open tasks. Without project_id returns unassigned tasks; with it, that project's tasks. Set snoozed=true to see snoozed tasks instead.
Manually log a fixed pomodoro (without a server session). Use when you forgot to start the timer but want to record the time anyway.
Record the active session (mark it completed). The session must be owned by this device (call dwt_status to check). Returns the completed session with all segments.
Start a server-side focus session (default length: the account's pomodoro setting, usually 25 min; 1 to 240 minutes). There is ONE active session per account: starting takes over any session running on another device, so call dwt_status first and prefer dwt_switch_task when a session is already running.
Total focus time for today, last 7 days, last 30 days, last 365 days and all time, plus best day and 30-day daily average.
Show the active Deep Work Timer session (if any: task, time remaining, which device owns it) and today's total focus time. Call this first before starting or logging anything.
Move the active session's open segment to a different task. Time is split honestly between tasks; total is conserved. Use this instead of dwt_start_session when a session is already running.
Error handling returns ApiError with HTTP status but no recovery guidance. E.g., 'HTTP 404' tells LLM nothing about what to do next (retry? call discovery tool? ask user?).
No pagination support on list tools. dwt_list_tasks, dwt_list_projects, dwt_lifetime_skills return unbounded arrays. Large result sets risk context window exhaustion.