kanban-agent-mcp
Self-hosted kanban board built for AI agents
Node 26 stdlib backend • zero npm dependencies (SQLite) • vanilla JS, no build step MCP server onboard — your agents work the board natively
A single-container kanban board: Node 26 stdlib backend (zero npm
dependencies by default — node:http + built-in node:sqlite), vanilla JS
frontend with no build step. Visual style inspired by Twenty CRM
(accent #4662d5, background #fcfcfc).
Why "for agents"? The board is a shared workspace where AI coding agents (Claude Code, Cursor, Codex, OpenCode, …) act as first-class users: at the planning stage an agent breaks a feature into tasks and puts them on the board; while implementing, it drags cards along the pipeline, leaves progress in the notes, and closes the task when done. The human sees live progress, the agent gets structure instead of a to-do in a chat. Two integration channels are built for this:
- MCP server (
POST /mcp) — 11kanban_*tools: list projects, stages and tasks, create/update/move/delete tasks, manage assignees. Point any MCP client at the instance URL. - REST + bearer tokens — the same operations over plain HTTP:
Authorization: Bearer kb_…withreadorwritescopes; stored tokens are hashed (sha256), every mutation is audited.
More: multi-user access with roles, a setup wizard on first run, dynamic pipeline (columns configured in the UI), optional PostgreSQL.
- Multi-user: administrator account is created in a first-run setup wizard (in the browser, no passwords in env vars or config files); the admin can invite more users (each with their own login/password).
- Dynamic pipeline: kanban columns (stages) are configured in the UI.
- API + MCP: bearer-token automation for agents, MCP server at
POST /mcp, audit log. - Optional PostgreSQL: switch the storage engine via environment variables; SQLite stays the zero-config default.
Quick start (Docker)
docker build -t kanban .
docker volume create kanban_data
docker run -d --name kanban --restart unless-stopped \
-p 3100:3100 -v kanban_data:/data \
kanban
Open http://localhost:3100/ — the setup wizard greets you on first run:
- Pick the interface language (English / Русский / 中文).
- Create the administrator account (username + password).
- Start using the board; add users later under Users (admins only).
Optional hardening for exposed instances:
-e KANBAN_SETUP_TOKEN=…makes the wizard ask for that token before accepting the administrator account, so a stranger cannot claim your fresh instance first.
docker compose
docker-compose.yml is included. Option A (simplest — volume auto-created):
remove external: true from volumes: in the compose file. Option B
(explicit, protects against compose-project renames):
docker volume create kanban_data
docker compose up -d
Storage engines
Environment variables:
# either a full connection string
DATABASE_URL=postgres://user:pass@host:5432/kanban
# or individual parts
POSTGRES_HOST=host
POSTGRES_PORT=5432
POSTGRES_USER=user
POSTGRES_PASSWORD=pass
POSTGRES_DB=kanban
POSTGRES_SSL=1 # optional: enable TLS
The schema is created automatically on both engines; migrations are
idempotent. To move an existing SQLite installation to PostgreSQL, export
with GET /api/export and re-import the JSON into the new instance.
Run without Docker
npm install # only needed for PostgreSQL mode
KANBAN_PORT=3100 KANBAN_DATA=./data node server.js
Requires Node ≥ 26 (built-in node:sqlite).
MCP for AI agents
The MCP endpoint is POST {URL}/mcp (JSON-RPC 2.0, Streamable HTTP,
stateless). Bearer-token auth only — create a token in Agents & tokens.
curl -X POST http://localhost:3100/mcp \
-H "Authorization: Bearer kb_…" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Tools: kanban_list_projects, kanban_create_project, kanban_list_tasks,
kanban_get_task, kanban_create_task, kanban_update_task,
kanban_move_task, kanban_delete_task, kanban_list_members,
kanban_list_custom_fields, kanban_list_stages.
Read-scope tokens may call the read tools; mutations (create/update/move/ /delete) require the write scope. Never hardcode stage ids — take them
from kanban_list_stages.
Users and roles
Passwords are stored only as scrypt hashes; sessions are HTTP-only cookies stored in the database (they survive restarts and can be revoked).
Agents (automation) authenticate with bearer tokens (Authorization: Bearer kb_…), created in Agents & tokens. Only the sha256 hash of a
token is stored; the full value is shown once at creation.
Environment variables
API overview
Human-facing auth: POST /api/login {username, password} → cookie sid.
Agent auth: Authorization: Bearer kb_… on /api/* and /mcp.
GET/POST /api/projects PATCH/DELETE /api/projects/:id (+?archived=0|1|all)
GET/PUT /api/projects/:id/access {user_ids:[…]} (admin only; PUT = full replace)
GET/POST /api/tasks GET /api/tasks?project=<id>|none
PATCH/DELETE /api/tasks/:id POST /api/tasks/:id/move {stage, before_id?|after_id?}
GET /api/tasks/:id
GET/POST /api/stages PATCH/DELETE /api/stages/:id?reassign=<stage_id>
GET/POST /api/members PATCH/DELETE /api/members/:id
GET/POST /api/custom-fields PATCH/DELETE /api/custom-fields/:id
GET/PATCH /api/view-fields (per-view column settings)
GET/POST /api/users PATCH/DELETE /api/users/:id (admin only)
GET /api/audit (admin only)
GET /api/sessions DELETE /api/sessions/:sid (admin only)
GET /api/export (admin only)
GET/POST /api/tokens PATCH/DELETE /api/tokens/:id
GET /api/me POST /api/setup (while no users exist)
Stages are dynamic: ids come from GET /api/stages. Exactly one stage has
is_done: 1 (the finish); completion checks use the flag, not a hardcoded
id. project_id: null is a valid location (“No project”).
Tasks accept an optional urgency field ('h' | 'm' | 'l', empty/clears to
null) on create/patch — shown as a colored square next to the task number.
Project visibility: admin sessions and bearer tokens see every project;
member sessions see only projects granted to them via
/api/projects/:id/access (and cannot see “No project” tasks).
Files
Development
The app is three files of vanilla JS with no build step. Style colors live
in :root CSS variables (public/style.css); icons are inline SVG in the
ICONS object (public/app.js); UI strings live in the I18N dictionary
(English is canonical, additions go to all three locales).
Author
I build self-hosted tools and write about development. Questions and feedback about the project are welcome:
- 📺 YouTube — https://youtube.com/@rikamalov
- 💬 Telegram — https://t.me/my_python_notes
License
MIT — do whatever you want, attribution appreciated.