MCP server providing create/read/update/list operations over tasks stored in a local SQLite database, with reminder management via standalone daemon
The Todo List MCP server has 5 tools with decent naming and mostly complete schemas, but suffers from significant issues in parameter descriptions, error handling documentation, and output schema clarity. Tool names follow verb_noun convention (create_tasks, read_tasks, update_tasks, list_tasks, delete_tasks) which is strong. However, parameter descriptions are inconsistent, some are detailed (e.g., list_tasks filters) while others are vague (e.g., 'Deprecated parameter'). The server exposes deprecated 'filenames' parameters alongside newer 'ids' parameters, creating confusion. Output schemas are not documented in the source code provided. Error handling is absent from all tool definitions. STDIO transport caps protocol readiness at 50, limiting overall quality score. The server follows the 4-tool average (create/read/update/list/delete is slightly higher at 5), which is reasonable.
Create one or more tasks in the SQLite database. Tasks are stored in the database with auto-generated IDs. Timestamps are automatically managed.
Delete one or more tasks from the SQLite database by ID. This operation is permanent and cannot be undone.
List all tasks or filter by status, priority, urgency, assignee, or tags. Returns paginated results with optional sorting. Use this to browse, search, or analyze your tasks.
Read one or more tasks from the SQLite database by ID. Returns complete task data including all fields and metadata. Use this to retrieve task details for review or before updating.
Update one or more existing tasks in the SQLite database. Only provided fields are updated; others remain unchanged. The updated_at timestamp is automatically updated.
Deprecated 'filenames' parameter appears in 4 of 5 tools (create_tasks, read_tasks, update_tasks, delete_tasks) alongside newer 'ids' parameter. This creates ambiguity for LLMs: which param should they use? Maintaining backward-compatibility parameters clutters the interface and invites confusion. The description 'Deprecated parameter (kept for backward compatibility)' does not explain WHY it still exists or when to use 'ids' vs 'filenames'.
Output schemas are NOT documented anywhere in the source code. The create_tasks tool returns a 'dict' with no documented structure. The description says 'Tasks are stored in the database with auto-generated IDs' but does not specify what fields are returned (e.g., does it return the created task objects with all fields, or just IDs, or a count?). This forces LLMs to guess what data they can extract for downstream operations.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | C | 67 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 0 | - | v1 |
No error handling documentation in any tool. The source shows DB operations (ensure_database_exists, create_tables) but tool definitions do not explain what happens on failure. E.g., create_tasks does not say 'If a task is invalid, returns an error with the invalid field and constraint.' This leaves LLMs unable to plan recovery steps.
read_tasks description is vague: 'Read one or more tasks from the SQLite database by ID. Returns complete task data including all fields and metadata.' Does 'complete task data' include timestamps? Tags? Assignee? What is 'metadata'? The description should enumerate the fields returned so LLMs know what data they can use.
delete_tasks does not warn about irreversible consequences in the description. The description 'Delete one or more tasks from the SQLite database by ID. This operation is permanent and cannot be undone.' states the fact but does not tell the LLM to seek confirmation first. Per pattern:confirmation-request, irreversible operations should support a dry-run or confirmation step to prevent accidental deletion.
Parameter 'ids' in read_tasks, update_tasks, and delete_tasks accepts a list but does not specify minimum/maximum count. Can you pass 1000 IDs in a single call? Will the server reject or timeout? Unbounded array parameters invite LLMs to pass absurd values.
create_tasks allows 'created_at' and 'updated_at' as optional input fields. This violates the principle that timestamps should be server-managed and auto-set. Allowing LLMs to manually set creation timestamps invites data integrity issues and confusion about what 'created_at' actually represents.
list_tasks 'limit' parameter defaults to 100 and caps at 1000, but no guidance on pagination result format. Does it return a 'next_offset' or 'total_count'? How does the LLM know when to stop paginating? The description should specify the pagination contract.