@j0hanz/todokit-mcp
v1.0.8
Published
A MCP server for Todokit, a task management and productivity tool with JSON storage.
Downloads
886
Maintainers
Readme
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.
- List summaries with counts (pending, completed, overdue) and pagination metadata.
Quick Start
npx -y @j0hanz/todokit-mcp@latestThe server runs over stdio (no HTTP endpoint) and registers MCP tools on startup.
Installation
NPX (recommended)
npx -y @j0hanz/todokit-mcp@latestGlobal install
npm install -g @j0hanz/todokit-mcpThen run:
todokit-mcpFrom source
git clone https://github.com/j0hanz/todokit-mcp-server.git
cd todokit-mcp-server
npm install
npm run build
npm startConfiguration
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@latestTools
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, tools return E_AMBIGUOUS with preview matches and a hint to use an exact id.
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
Add this to your mcpServers configuration in settings.json:
{
"todokit": {
"command": "npx",
"args": ["-y", "@j0hanz/todokit-mcp@latest"]
}
}Add this to your claude_desktop_config.json:
{
"mcpServers": {
"todokit": {
"command": "npx",
"args": ["-y", "@j0hanz/todokit-mcp@latest"]
}
}
}- 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.jsProject 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.
