MCP (Model Context Protocol) server for md2do task manager - intelligent markdown task management
The md2do MCP server has 11 tools with solid naming conventions (verb_noun pattern: scan_tasks, list_tasks, get_task, etc.). Tool descriptions are present and adequate (averaging ~110 characters), explaining what each tool does. However, the server has significant gaps: (1) Input schemas are visible in the prompt but NOT verified in actual source code, the code snippet provided does not show the tool registration or schema definitions in packages/mcp/src/index.ts, only file references. (2) Parameter descriptions are sparse, the 'filters' parameter in scan_tasks is described as 'Optional filters to apply to tasks' but its internal structure is not explained; the 'sort' parameter in list_tasks similarly lacks detail on valid sort keys. (3) Output schemas are undocumented, the prompt states what tools return conceptually, but actual response field names, types, and structures are not visible. (4) Error handling is absent, no tool documents retryability, error codes, recovery actions, or what-to-do-next guidance. (5) No tool annotations (readOnlyHint, destructiveHint, idempotentHint) are present, despite several tools being destructive (delete_task) or write-heavy (update_task, create_task, ingest_tasks). The server lacks the security and guidance patterns expected of production-grade tools.
Create a new task in a markdown file
Delete a task from a markdown file
Apply complex filters to tasks (by assignee, priority, status, dates, tags, path)
Get detailed information about a specific task by ID
Get statistics about tasks (total, completed, overdue, by priority, by assignee)
Ingest tasks from external sources (JSONL format) into markdown files
List all tasks from scanned markdown files with optional filtering and sorting
Migrate markdown files from legacy bracket syntax to new tag/brace syntax
Output schemas completely undocumented. No visible documentation of return types, field names, or structures for any of the 11 tools. Tools return task lists, statistics, or boolean results, but exact field names and data types are not specified anywhere in the provided code or documentation.
Input schemas not visible in source code. The prompt describes parameter names and types, but the actual tool registration in packages/mcp/src/index.ts is not provided. Cannot verify JSON Schema correctness, enum constraints, or parameter type definitions. Per HARD SCORING RULES, if schemas cannot be verified, schema scores are capped at 35-45.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 50 | 2026-07-28+ | v2 |
Scan markdown files for TODO tasks and return structured task data
Sort tasks by various criteria (due date, priority, file, assignee, completion status)
Update a task's properties (completion status, priority, assignee, due date, etc.)
No error handling guidance. None of the 11 tools document error codes, recovery actions, or what the LLM should do if a call fails. Tools like delete_task (destructive) and update_task (state-changing) lack confirmation or dry-run modes. No 'retryable' vs 'fatal' classification.
No tool annotations. Destructive tools (delete_task) and write tools (create_task, update_task, ingest_tasks, migrate_syntax) lack readOnlyHint, destructiveHint, or idempotentHint annotations. LLMs cannot distinguish safe reads from dangerous mutations without this metadata.
Parameter descriptions are generic and lack constraints. Examples: 'filters' in scan_tasks described as 'Optional filters to apply to tasks' without explaining filter keys or syntax. 'sort' in list_tasks lists examples ('priority', 'dueDate', 'file') in description instead of declaring an enum. Enums prevent LLM hallucination of invalid values.
migrate_syntax and ingest_tasks lack dry-run or confirmation workflow. migrate_syntax offers a dryRun flag which is good, but ingest_tasks (which writes external data into files) has no preview or review step. Per pattern:confirmation-request, irreversible operations should support user review.
Composition issue: filter_tasks and sort_tasks appear to be utility tools operating on previously-scanned data, but it's unclear whether they accept a task list input or require tasks to already be loaded into server memory. If stateful (server keeps task cache), this violates the protocol's stateless design. If stateless, they need an input parameter specifying which tasks to filter/sort.
No pagination support documented. list_tasks and scan_tasks could return hundreds of tasks, but no limit/offset or cursor parameters are visible. Returning thousands of tasks would blow the context window.
Natural identifier acceptance unclear. update_task requires 'taskId', but how does an LLM know what that ID is if it only has a task description or file location? Ideally, tools should accept human-friendly identifiers (task text, file+line) alongside IDs. Current design forces extra lookup calls.