todokit-mcp
An MCP server for Todokit, a task management and productivity tool with JSON storage.
One-Click Install
Features
- Task management: add, update, complete/reopen, and delete todos.
- Batch operations: add multiple todos and bulk delete with filters.
- Rich filtering: status, priority, tags, due dates, and free-text search.
- Tagging: tags are normalized (trimmed, lowercase, unique) and can be added or removed.
- Safe deletion: dry-run previews before deleting; bulk delete defaults to a safety limit.
- JSON persistence with queued writes and atomic file writes.
- Optional diagnostics events (tool calls/results, storage, lifecycle) via Node diagnostics channels.
- List summaries with counts (pending, completed, overdue) and pagination metadata.
Quick Start
npx -y @j0hanz/todokit-mcp@latest
The server runs over stdio (no HTTP endpoint) and registers MCP tools on startup.
Installation
NPX (recommended)
npx -y @j0hanz/todokit-mcp@latest
Global install
npm install -g @j0hanz/todokit-mcp
Then run:
todokit-mcp
From source
git clone https://github.com/j0hanz/todokit-mcp-server.git
cd todokit-mcp-server
npm install
npm run build
npm start
Configuration
Storage path
By default, todos are stored in todos.json next to the server package (the project root when running from source). To control where data is written, set the TODOKIT_TODO_FILE environment variable to an absolute or relative path ending with .json. Relative paths resolve from the current working directory. The directory is created as needed; if the file does not exist, the server starts with an empty list.
Examples:
# macOS/Linux
TODOKIT_TODO_FILE=/path/to/todos.json npx -y @j0hanz/todokit-mcp@latest
# Windows PowerShell
$env:TODOKIT_TODO_FILE = 'C:\path\to\todos.json'
npx -y @j0hanz/todokit-mcp@latest
JSON formatting
By default, todos are written as pretty-printed JSON (2-space indentation). To write compact JSON instead, set TODOKIT_JSON_PRETTY to 0 or false.
TODOKIT_JSON_PRETTY=0 npx -y @j0hanz/todokit-mcp@latest
CLI options
The server accepts a few CLI flags (use -- to forward args when running via npx).
npx -y @j0hanz/todokit-mcp@latest -- --todo-file ./todos.json --diagnostics --log-level debug
| Flag | Alias | Description |
|---|---|---|
--todo-file | -f | Override the todo storage path (same as TODOKIT_TODO_FILE). |
--diagnostics | -d | Enable diagnostics output (JSON lines) to stderr. |
--log-level | -l | Diagnostics log level: error, warn, info, debug (default: info). |
The log level is only used when diagnostics output is enabled.
Diagnostics
Diagnostics events are always published on Node's diagnostics_channel and can be subscribed to programmatically. When --diagnostics is set, the server attaches default subscribers and prints JSON events to stderr (stdout stays reserved for MCP traffic).
Channels:
todokit:tool— tool call + tool result eventstodokit:storage— read/write/close eventstodokit:lifecycle— shutdown events
Tools
All tools return a JSON payload in both content (stringified) and structuredContent.
Inputs are validated with strict Zod schemas, so unknown fields are rejected.
Success payload:
{
"ok": true,
"result": {}
}
Error payload:
{
"ok": false,
"error": { "code": "E_CODE", "message": "Details" }
}
The result shape is tool-specific. If a query matches multiple todos, most tools return E_AMBIGUOUS with preview matches and a hint to use an exact id. delete_todo with dryRun: true instead returns an ok response with matches and totalMatches for preview.
add_todo
Add a new todo item.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| title | string | Yes | - | The title of the todo (1-200 chars) |
| description | string | No | - | Optional description (max 2000 chars) |
| priority | string | No | normal | Priority level: low, normal, high |
| dueDate | string | No | - | Due date in ISO format (YYYY-MM-DD) |
| tags | array | No | - | Array of tags (max 50, 1-50 chars) |
Result fields:
item(todo)summarynextActions
add_todos
Add multiple todo items in one call.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| items | array | Yes | - | Array of todo objects (same fields as add_todo, 1-50 items) |
Result fields:
items(todos)summarynextActions
list_todos
List todos with filtering, search, sorting, and pagination.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| status | string | No | all | Filter by status: pending, completed, all |
| completed | boolean | No | - | Deprecated; status takes precedence when provided |
| priority | string | No | - | Filter by priority: low, normal, high |
| tag | string | No | - | Filter by tag (must contain) |
| query | string | No | - | Search text in title, description, or tags |
| dueBefore | string | No | - | Filter todos due before this date (YYYY-MM-DD) |
| dueAfter | string | No | - | Filter todos due after this date (YYYY-MM-DD) |
| sortBy | string | No | createdAt | Sort by: dueDate, priority, createdAt, title |
| order | string | No | asc | Sort order: asc, desc |
| limit | number | No | 50 | Max number of results (1-200) |
| offset | number | No | 0 | Number of results to skip (0-10000) |
Result fields:
items(todos)summarycounts(total,pending,completed,overdue)limitoffsethasMore(true if more results are available after this page)
Notes:
- Overdue calculations compare
dueDateagainst the server's local calendar date (YYYY-MM-DD).
update_todo
Update fields on a todo item. Provide either id or query to identify the todo.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| id | string | No | - | The ID of the todo to update |
| query | string | No | - | Search text to find a single todo to update |
| title | string | No | - | New title |
| description | string | No | - | New description |
| completed | boolean | No | - | Completion status |
| priority | string | No | - | New priority level |
| dueDate | string | No | - | New due date (YYYY-MM-DD) |
| tags | array | No | - | Replace all tags (max 50) |
| tagOps | object | No | - | Tag modifications to apply (add/remove arrays) |
| clearFields | array | No | - | Fields to clear: description, dueDate, tags |
Notes:
- If both
tagsandtagOpsare provided,tagswins and replaces the list. - If no updatable fields are provided, the tool returns an error.
Result fields:
item(todo)summarynextActions
complete_todo
Set completion status for a todo item. Provide either id or query.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| id | string | No | - | The ID of the todo to complete |
| query | string | No | - | Search text to find a single todo |
| completed | boolean | No | true | Set completion status |
Result fields:
item(todo)summary(includes already-complete or reopen messages)nextActions
delete_todo
Delete a todo item. Provide either id or query.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| id | string | No | - | The ID of the todo to delete |
| query | string | No | - | Search text to find a single todo |
| dryRun | boolean | No | false | Simulate deletion without changing data |
Result fields:
deletedIds(array)summarynextActions(only when not dryRun)dryRun(when dryRun is true)matches,totalMatches(dry-run + multiple matches)
delete_todos
Delete multiple todos matching filters. At least one filter is required; defaults to limit=10 for safety.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| status | string | No | - | Filter by status: pending, completed, all |
| priority | string | No | - | Filter by priority: low, normal, high |
| tag | string | No | - | Filter by tag |
| dueBefore | string | No | - | Delete todos due before this date (YYYY-MM-DD) |
| dueAfter | string | No | - | Delete todos due after this date (YYYY-MM-DD) |
| query | string | No | - | Search text filter (1-200 chars) |
| dryRun | boolean | No | false | Preview deletion without removing data |
| limit | number | No | 10 | Max items to delete (1-100, safety limit) |
Notes:
- At least one filter (status, priority, tag, dueBefore, dueAfter, query) is required.
- The default limit of 10 prevents accidental mass deletions.
Result fields:
deletedIds(array)summarytotalMatchedmatches(dry-run only, array of previews)dryRun(when dryRun is true)nextActions(only when not dryRun)
Data Model
A todo item has the following shape:
{
"id": "string",
"title": "string",
"description": "string?",
"completed": false,
"priority": "low|normal|high",
"dueDate": "YYYY-MM-DD?",
"tags": ["string"],
"createdAt": "ISO timestamp with offset",
"updatedAt": "ISO timestamp with offset?",
"completedAt": "ISO timestamp with offset?"
}
Notes:
dueDateusesYYYY-MM-DD(date only).createdAt,updatedAt, andcompletedAtare ISO 8601 timestamps with offset (e.g.,2025-02-28T10:30:00Z).
Client Configuration
VS Code
Add this to your mcpServers configuration in settings.json:
{
"todokit": {
"command": "npx",
"args": ["-y", "@j0hanz/todokit-mcp@latest"]
}
}
Claude Desktop
Add this to your claude_desktop_config.json:
{
"mcpServers": {
"todokit": {
"command": "npx",
"args": ["-y", "@j0hanz/todokit-mcp@latest"]
}
}
}
Cursor
- Go to Cursor Settings > Features > MCP
- Click + Add New MCP Server
- Name:
todokit - Type:
command - Command:
npx -y @j0hanz/todokit-mcp@latest
Development
Prerequisites
- Node.js >= 20.0.0
Scripts
| Command | Description |
|---|---|
| npm run build | Compile TypeScript to JavaScript |
| npm run dev | Run server in watch mode for development |
| npm start | Run the built server |
| npm run test | Run unit tests (node --test + tsx) |
| npm run test:coverage | Run unit tests with coverage |
| npm run lint | Run ESLint |
| npm run format | Format with Prettier |
| npm run format:check | Check formatting with Prettier |
| npm run type-check | Run TypeScript type checking |
| npm run dup-check | Run duplicate code checks (jscpd) |
| npm run clean | Remove the dist/ build output |
| npm run inspector | Launch the MCP inspector (pass server cmd after --) |
Manual verification
npm run build
npm run inspector -- node dist/index.js
Project structure
src/
index.ts # MCP server entrypoint (stdio)
tools/ # Tool registrations
schemas/ # Zod input/output schemas
lib/ # Storage, matching, shared helpers
tests/ # Unit tests
docs/ # Assets (logo)
Contributing
Contributions are welcome. Please run npm run format, npm run lint, npm run type-check, npm run build, npm test, npm run test:coverage, and npm run dup-check before opening a PR.
License
This project is licensed under the MIT License - see the LICENSE file for details.