# kanban-mcp
Model Context Protocol (MCP) server for kanban project management. Provides 47 tools covering boards, columns, cards, card relations (parent/child), sprints, bulk operations, import/export, and undo/redo.
## Architecture
`kanban-mcp` runs in-process: it holds a `KanbanContext` from `kanban-service` directly in memory. All tool handlers call into `KanbanContext` and persist state after every mutating operation.
```mermaid
graph TD
CLIENT[MCP Client
Claude / Cursor / etc.] -->|JSON-RPC| MCP[kanban-mcp
KanbanMcpServer]
MCP --> CTX[McpContext]
CTX --> SVC[KanbanContext
kanban-service]
SVC --> STORE[PersistenceStore]
STORE --> STORAGE[*.json / *.sqlite]
```
### Concurrency Model
Every mutating operation follows a **reload-before-mutate** pattern:
1. `reload()` — re-read state from disk, picking up any external changes
2. Execute the operation against in-memory state
3. `save()` — atomically write updated state to disk
Read operations use cached in-memory state. Both the TUI and MCP server treat the on-disk file as the source of truth for writes while tolerating brief staleness on reads.
## Installation
### From Nix (recommended)
```bash
nix build .#kanban-mcp
```
### From Cargo
```bash
cargo install --path crates/kanban-mcp
```
## Usage
```bash
kanban-mcp /path/to/boards.json
kanban-mcp /path/to/boards.sqlite
```
## MCP Client Configuration
**Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"kanban": {
"command": "kanban-mcp",
"args": ["/path/to/boards.json"]
}
}
}
```
**Claude Code** (`.mcp.json` in project root):
```json
{
"mcpServers": {
"kanban": {
"command": "kanban-mcp",
"args": ["boards.json"]
}
}
}
```
---
## Tools Reference
### Identifiers
Most tool inputs accept either an opaque UUID or a friendlier reference, resolved server-side:
- `board`, `column`: UUID or the entity's name.
- `sprint`: UUID, name, or sprint number.
- `card`: UUID or a short identifier like `KAN-5`. If the identifier matches multiple cards, the tool returns the full list for disambiguation.
- `cards` (bulk operations): array of UUIDs or card identifiers (for example `["KAN-1", "KAN-2", "42"]`); all referenced cards must share a board.
### Boards (9 tools)
| Tool | Description | Required params | Optional params |
|------|-------------|-----------------|-----------------|
| `tool_create_board` | Create a new kanban board | `name: String` | `card_prefix: String` |
| `tool_list_boards` | List boards (honors sort/order; falls back to the configured default) | — | `archived`, `sort` (position/name/created_at/archived_at), `order` (asc/desc), `page: u32`, `page_size: u32` |
| `tool_get_board` | Get a specific board by UUID or name | `board: String` | — |
| `tool_update_board` | Update board properties | `board: String` | `name`, `description`, `sprint_prefix`, `card_prefix`, `task_sort_field`, `task_sort_order` |
| `tool_set_board_sort` | Persist the default board-list sort in app config | — | `sort` (position/name/created_at/archived_at), `order` (asc/desc) |
| `tool_delete_board` | Delete board and all its columns, cards, sprints | `board: String` | — |
| `tool_archive_board` | Archive a board (hides it from the live list) | `board: String` | — |
| `tool_restore_board` | Restore an archived board to the live list | `board: String` | — |
| `tool_delete_archived_board` | Permanently delete an archived board and its subtree | `board: String` | — |
### Columns (6 tools)
| Tool | Description | Required params | Optional params |
|------|-------------|-----------------|-----------------|
| `tool_create_column` | Create a new column in a board | `board: String`, `name: String` | `position: i32` |
| `tool_list_columns` | List all columns in a board | `board: String` | — |
| `tool_get_column` | Get a specific column by UUID or name | `column: String` | — |
| `tool_update_column` | Update column properties | `column: String` | `name`, `position`, `wip_limit: u32`, `clear_wip_limit: bool` |
| `tool_delete_column` | Delete column and all its cards | `column: String` | — |
| `tool_reorder_column` | Move column to a new position | `column: String`, `position: i32` | — |
### Cards (8 tools)
| Tool | Description | Required params | Optional params |
|------|-------------|-----------------|-----------------|
| `tool_create_card` | Create a new card in a column | `board: String`, `column: String`, `title: String` | `description`, `priority` (low/medium/high/critical), `points: u8`, `due_date` (YYYY-MM-DD or RFC 3339) |
| `tool_list_cards` | List cards with filters. Returns `CardSummary` (title, status, priority, points — use tool_get_card for full detail). | — | `board`, `column`, `sprint`, `status`, `archived`, `sort` (points/priority/created_at/updated_at/due_date/status/position/default), `order` (asc/desc), `page: u32`, `page_size: u32` |
| `tool_get_card` | Get card by UUID or identifier (e.g. `KAN-5`). Returns list if ambiguous. | `card: String` | — |
| `tool_update_card` | Update card properties | `card: String` | `title`, `description`, `priority`, `status` (todo/in_progress/blocked/done), `points: u8`, `due_date`, `clear_due_date: bool` |
| `tool_move_card` | Move card to a different column | `card: String`, `column: String` | `position: i32` |
| `tool_archive_card` | Archive a card (restorable) | `card: String` | — |
| `tool_restore_card` | Restore an archived card | `card: String` | `column: String` |
| `tool_delete_card` | Delete a card permanently | `card: String` | — |
### Card–Sprint (2 tools)
| Tool | Description | Required params |
|------|-------------|-----------------|
| `tool_assign_card_to_sprint` | Assign a card to a sprint | `card: String`, `sprint: String` |
| `tool_unassign_card_from_sprint` | Remove card from its sprint | `card: String` |
### Card Utilities (2 tools)
| Tool | Description | Required params |
|------|-------------|-----------------|
| `tool_get_card_branch_name` | Get git branch name for a card | `card: String` |
| `tool_get_card_git_checkout` | Get `git checkout -b ` command | `card: String` |
### Card Relations (4 tools)
| Tool | Description | Required params |
|------|-------------|-----------------|
| `tool_set_card_parent` | Add a parent → child edge between two cards. Rejects cycles and self-reference. | `child: String`, `parent: String` |
| `tool_remove_card_parent` | Remove a parent → child edge. | `child: String`, `parent: String` |
| `tool_list_card_parents` | List direct parents of a card (returns `Vec`). | `card: String` |
| `tool_list_card_children` | List direct children of a card (returns `Vec`). | `card: String` |
All identifiers accept UUIDs or card identifiers like `KAN-5` per the rules in the Identifiers section. Cross-board parent/child is permitted today.
### Bulk Card Operations (3 tools)
| Tool | Description | Required params |
|------|-------------|-----------------|
| `tool_archive_cards` | Archive multiple cards | `cards: Vec` (UUIDs or identifiers, e.g. `["KAN-1", "KAN-2"]`) |
| `tool_move_cards` | Move multiple cards to a column | `cards: Vec`, `column: String` |
| `tool_assign_cards_to_sprint` | Assign multiple cards to a sprint | `cards: Vec`, `sprint: String` |
### Sprints (8 tools)
| Tool | Description | Required params | Optional params |
|------|-------------|-----------------|-----------------|
| `tool_create_sprint` | Create a new sprint | `board: String` | `name: String`, `prefix: String` |
| `tool_list_sprints` | List sprints for a board | `board: String` | — |
| `tool_get_sprint` | Get a specific sprint by UUID, name, or number | `sprint: String` | — |
| `tool_update_sprint` | Update sprint properties | `sprint: String` | `name`, `prefix`, `card_prefix`, `start_date`, `end_date`, `clear_start_date: bool`, `clear_end_date: bool` |
| `tool_activate_sprint` | Activate a sprint | `sprint: String`, `duration_days: u32` | — |
| `tool_complete_sprint` | Mark sprint as completed | `sprint: String` | — |
| `tool_cancel_sprint` | Cancel a sprint | `sprint: String` | — |
| `tool_delete_sprint` | Delete a sprint | `sprint: String` | — |
### Sprint Carry-over (1 tool)
| Tool | Description | Required params |
|------|-------------|-----------------|
| `tool_carry_over_sprint_cards` | Move uncompleted cards from a completed/cancelled sprint to a planning sprint | `from_sprint: String`, `to_sprint: String` |
### Import / Export (2 tools)
| Tool | Description | Required params | Optional params |
|------|-------------|-----------------|-----------------|
| `tool_export_board` | Export board data as JSON string | — | `board: String` (omit for all boards) |
| `tool_import_board` | Import board from JSON string | `data: String` | — |
### Undo / Redo (2 tools)
| Tool | Description |
|------|-------------|
| `tool_undo` | Undo the last operation |
| `tool_redo` | Redo the last undone operation |
Undo/redo state is maintained in memory across tool calls within a single server session. History is cleared on server restart.
---
## Error Handling
| Error type | MCP error code |
|------------|---------------|
| Domain errors (not found, validation, cycle, bad input) | `INVALID_PARAMS` |
| I/O, serialization, internal errors | `INTERNAL_ERROR` |
Domain errors (not found, validation) map to `INVALID_PARAMS`; all other errors map to `INTERNAL_ERROR`.
---
## Position in the workspace
```mermaid
graph TD
PER[kanban-persistence]
BE[kanban-backend] --> PER
JSON[kanban-persistence-json] --> BE
SQL[kanban-persistence-sqlite] --> BE
SVC[kanban-service] --> PER
SVC --> BE
MCP[kanban-mcp] --> PER
MCP --> BE
MCP --> SVC
MCP -.->|feature: json, default-on| JSON
MCP -.->|feature: sqlite, default-on| SQL
```
Solid arrows are normal (`[dependencies]`) edges; dotted arrows are
feature-gated (both on by default). `kanban-mcp` also enables
`kanban-service`'s `schemars` feature, so the wire DTOs it re-exports as
`kanban_service::api` derive `schemars::JsonSchema` for use as `Parameters`
in `rmcp` tool handlers. As with `kanban-cli`, `kanban-mcp` — not
`kanban-service` — registers the concrete storage backends it ships with
(KAN-1027). See the [root README](../../README.md) for the full workspace
dependency graph.
## Dependencies
| Crate | Purpose |
|-------|---------|
| [`kanban-service`](../kanban-service/README.md) (feature `schemars`) | `KanbanContext`, all domain operations, schema-derived wire DTOs |
| [`kanban-core`](../kanban-core/README.md) | Shared types, config |
| [`kanban-domain`](../kanban-domain/README.md) | Domain models |
| [`kanban-persistence`](../kanban-persistence/README.md) | `PersistenceStore`, `StoreRegistry` |
| [`kanban-backend`](../kanban-backend/README.md) | `KanbanBackend`, `KanbanBackendRegistry` |
| [`kanban-persistence-json`](../kanban-persistence-json/README.md) (optional, feature `json`, default-on) | JSON backend, registered at startup |
| [`kanban-persistence-sqlite`](../kanban-persistence-sqlite/README.md) (optional, feature `sqlite`, default-on) | SQLite backend, registered at startup |
| `rmcp` | MCP server/transport SDK |
| `schemars` | JSON Schema for tool parameters |
| `tokio` | Async runtime |
| `serde` + `serde_json` | Serialization |
| `clap` | CLI argument parsing (data file path) |
| `tracing` + `tracing-subscriber` | Structured logging |
| `anyhow` + `thiserror` | Error handling |
## Related crates
Used by: none — `kanban-mcp` is a binary entry point, not a library dependency of any other workspace crate.