Valkama

Valkama

A local MCP server with a web board that lets coding agents manage kanban cards, checklists, and work tracking through 30 MCP tools, with live updates and session tracking.

Category
访问服务器

README

Valkama

A kanban board your coding agents write to, on your own machine.

Valkama is a local MCP server with a web board attached. Register it once in Claude Code or Codex, and your agents claim cards, tick checklists and attach commits as they work. You watch it happen in a browser window or a desktop app, on the same board where you plan.

It is built for one person: whoever runs a local development loop and is tired of the work living in three places at once. There is no account, no cloud and no service to keep alive. Everything is one SQLite file in your home directory, and the server only exists while a client is talking to it.

What it does

  • 30 MCP tools for the board — create, move, claim, comment, link, check off, summarise. claim_card is atomic, so two agents cannot start the same card.
  • A live board UI at http://127.0.0.1:8642/, in English or Russian. It never polls: updates arrive over Server-Sent Events.
  • A record of who did what. Every move, claim, takeover and link change is an event on the card, next to commit hashes and session ids the agents attach.
  • Session tracking. Launch an agent from a card with an explicit delivery contract, and the outcome comes back as a typed result instead of an exit code.
  • A dashboard over the same data — flow, throughput, cycle time — that reports "unknown" instead of inventing a zero when history is missing.
  • A desktop window and a tray icon on Windows, so the board is an app rather than a browser tab, and you can see at a glance whether an agent is working.

Requirements

Needed for Version
Python the server, the MCP tools, the CLI 3.11 or newer
Node.js rebuilding the web UI or the desktop app 20.19+ or 22.12+ — Vite 7's floor (only if you build)
Git cloning any

The server imports nothing outside the Python standard library — no pip install step, no virtualenv. That is deliberate: your agent client launches it with whatever Python it finds, and a missing dependency would be a failure you only see as a disappeared board.

The built UI is committed to the repository, so a fresh clone serves the board without Node installed at all.

Platforms. Developed and used on Windows 11. The server's platform-specific branches are guarded and it should run on macOS and Linux, but that is not exercised. The tray icon, the installer and session-root lookup are Windows-only by design — see Limitations.

Install

1. Clone it

git clone https://github.com/Muratovnik/valkama.git
cd valkama
python valkama.py serve

Open http://127.0.0.1:8642/. You should see an empty board directory. Stop the server with Ctrl+C — agents spawn their own copy and do not need this one running.

2. Register it with your agent

Claude Code — one command, user scope so every project gets it:

claude mcp add valkama --scope user --env VALKAMA_AUTHOR=claude -- python /absolute/path/to/valkama/valkama.py mcp

Codex — add this to ~/.codex/config.toml:

[mcp_servers.valkama]
command = "python"
args = ["/absolute/path/to/valkama/valkama.py", "mcp"]
env = { VALKAMA_AUTHOR = "codex", PYTHONUTF8 = "1", PYTHONIOENCODING = "utf-8" }

Use an absolute path in both. The client launches the server from its own working directory, which is rarely yours.

VALKAMA_AUTHOR is what claims and comments are signed with. Give each client a different one, or every card will say agent.

3. Check that it worked

Restart the client, then ask it to list boards. In Claude Code:

> use the valkama mcp server to list boards

You should get an empty list rather than an error. If the tools are missing, /mcp shows the server's status; a server that failed to start needs a new conversation, not a reconnect.

4. Optional: the desktop app (Windows)

cd desktop
npm ci
npm run dist                            # builds release/Valkama Setup <version>.exe
cd ..
.\windows\install-desktop.ps1 -WhatIf   # show what would change
.\windows\install-desktop.ps1 -Build    # rebuild, remove older copies, install

The installer is not a double-click because each past rename changed the NSIS appId, so a new installer lands beside the old copy instead of over it. install-desktop.ps1 reads what is actually registered under HKCU, stops anything running from those directories, runs each old copy's own uninstaller, and installs the current one. It only ever touches something registered under one of this product's names and installed under %LOCALAPPDATA%\Programs; anything else is reported and left alone.

Commands

python valkama.py <command> [options]
Command What it does
mcp speak MCP over stdio — what the agent registrations run
serve [--port 8642] serve the JSON API and the board UI
summary [--board NAME] a short text report, meant for session hooks
runtime print this checkout's backend and static identity
dump [--out FILE] export the whole database as JSONL
graph [--board NAME] [--format mermaid|json] the dependency graph of one board
merge-boards --target NAME --source OLD [--source ...] consolidate boards, keeping every id
attach NAME PATH [--label TEXT] attach another database file as a scope
detach NAME drop a scope from every view; the file is untouched
scopes [--json] list attached scopes and their boards
purge-stream [--session ID] [--include-active] [--retention] delete purgeable stream events; analytics rows stay
import-routa FILE import a Routa export

Configuration

Everything is an environment variable; there is no configuration file.

Variable Default What it changes
VALKAMA_DB ~/.valkama/valkama.sqlite3 where the database lives
VALKAMA_AUTHOR agent the name written into claims and comments
VALKAMA_NO_TRAY unset set to anything to suppress the tray icon
VALKAMA_SOURCE_ROOT the checkout's grandparent the workspace root the desktop app may open files from
VALKAMA_PORT 8642 the port the desktop app expects the server on
VALKAMA_SCRIPT derived from the install record absolute path to valkama.py, for the desktop app and tray
VALKAMA_PYTHON python from PATH which interpreter the desktop app and tray launch
VALKAMA_TRAY_MUTEX Local\ValkamaTrayIcon the mutex tray sessions coordinate through
CODEX_WORKFLOW_REGISTRY %LOCALAPPDATA%\CodexWorkflow\projects.json the registry that maps a session to its project root

--port on serve overrides the port for that process. VALKAMA_PORT tells the desktop app where to look; set both if you move the port.

The board

Six fixed columns: Backlog, Todo, Dev, Review, Done, Blocked.

A card becomes an epic when other cards point parent_id at it. The board keeps a persistent index of epics and renders one selected six-column view; inside each lane, children are grouped under their epic instead of repeating the epic id on every card.

Three things make a card honest about its own progress:

  • A checklist with stable ids. Agents claim an item (claim_checklist_item) and complete it by id (tick_item). No invented percentages, and two agents splitting a card each hold their own item.
  • Typed refs — commit hashes, session ids, memory entry ids — attached with attach_ref, so the next agent reads pointers instead of doing archaeology.
  • An activity trace. Creations, moves, claims, takeovers, releases, completions and link changes are all recorded with an author. get_card returns it, so nobody has to guess who did what. Reordering within a lane is deliberately not history.

Cards relate to each other the way beads proved useful for agents. blocked_by / blocks feed list_cards(ready=true) — the take-next queue of cards that are queued, unclaimed and unblocked. discovered_from records where work found en route came from. Blockers that aren't cards stay comments.

Guards refuse a move the board could not honestly report: dev needs an executor, done needs every checklist item closed and a summary, blocked needs a linked blocker or a stated reason. A refusal names its guard, and force=true carries the move through as a recorded override.

Concurrent moves are resolved, not raced. A drag sends the column the card was in when you grabbed it. If it has since moved, the server answers 409 with who moved it where, and the drop is refused rather than silently undoing an agent's work.

Rolling back a merge

merge-boards writes a clean SQLite backup before it touches anything. To undo one: stop every client, delete any -wal / -shm file beside ~/.valkama/valkama.sqlite3, then copy the kanban-premerge-*.sqlite3 snapshot named in that merge's own result over the database. test_a_merge_can_be_rolled_back_from_the_snapshot_it_takes runs exactly that sequence, so the path is tested rather than assumed.

Schema upgrades snapshot the database into ~/.valkama/backups/ before any ALTER runs, keeping the last five.

Launching agents from a card

The launch dialog records a delivery contract, not just a command: an expected_effect (change_required, no_change_acceptable or read_only_finding), an optional review mode, and an interface version.

Both clients get an enforced JSON result schema. The persisted outcome is one of launch_failed, refused, expected_no_change, unexpected_no_change, partial or completeexit code zero is not delivery. Only complete, or an expected_no_change the contract allows, moves Dev to Review. A spawn failure restores the exact pre-launch lane and claim and stays visible on the card.

Resume works only with the client's own stored session identity: a generated UUID for fresh Claude launches, the thread id from Codex's JSON event stream. The runner never guesses which task to continue from a title, a directory, a timestamp or --last.

Worktree launches run a preflight before mutating anything: the path must be a repository top level and not a submodule, and the sibling target must not escape, traverse a symlink or junction, or already exist without a real worktree registration.

The dashboard

?board=<name>&view=dashboard is a read-only projection over the same cards and events: status visits, flow, throughput, cycle/reopen/blocked KPIs, and an as_of timestamp.

Its rule is that missing history stays missing. Coverage is reported as confirmed, inferred, partial or unknown; a gap is null or a lower bound, never a made-up zero. A contradictory move invalidates the preceding segment at the gap and resumes at the observed destination, so no duration is fabricated across a hole.

The optional usage panel reads local Codex rollout or Claude JSONL journals, if you configure the roots. It is deliberately conservative: exact card-linked session refs only, no newest-file heuristics, data marked source=local_journal. Cost appears only when a journal states it. Sessions linked to several cards are labelled non-exclusive and counted once.

The desktop app and the tray

desktop/ is a thin Electron shell. It checks that the Python server is listening, then shows the board in a real window with its own process, taskbar entry and icon. It runs the server from this repository, not a bundled copy, so the window and your agents can never be on different versions.

cd desktop
npm ci
npm start        # run the window from source
npm run dist     # build the installer into release/

release/ is git-ignored — a 90 MB installer does not belong in a repository. Rebuild and reinstall after changing desktop/main.js; UI-only changes just need npm run build in web/.

The window can open a Markdown source at an exact #kb: anchor through VS Code's URL handler, but only inside the approved workspace root. Plain browser mode has no local-file authority and copies the pointer instead.

The tray icon appears while an agent holds an MCP session and disappears when the last one ends, so it answers "is anybody working here right now?". Clicking it always does something visible: it opens the app, opens a browser, starts the server, offers a restart, or explains the refusal in a dialog. When the running server is this checkout's but older than your working tree, the dialog says which half drifted and offers to restart it. A listener that does not identify itself as this checkout is refused — holding the port is not proof of whose process it is.

Set VALKAMA_NO_TRAY=1 to turn it off.

Running electron from a VS Code terminal fails with app is undefined, because VS Code exports ELECTRON_RUN_AS_NODE=1. Clear that variable first. The installed app is unaffected.

Building the UI

cd web
npm ci
npm run dev      # Vite on :5173, proxying /api to the Python server on :8642
npm run build    # refresh web/dist

Vue 3 + Vite + TypeScript. web/dist is committed on purpose, so a clone serves the built board with no build step — rebuild and commit it whenever web/src changes.

The Python side serves web/dist plus the JSON API: /api/boards, /api/board, /api/card, /api/activity, /api/move, /api/events. GET /api/integrations is a read-only inventory of observed session adapters and local knowledge services — identity, capabilities, health and who owns their configuration. It loads no third-party code and invents no enable switches.

How the repository is laid out

Path Owns
valkama.py the entry point, and nothing else — it prepares sys.path and hands off to server/cli.py
server/ the Python server: domain modules, and the cli, http_surface and mcp_surface above them
web/ the Vue application, its build and its tests
desktop/ the Electron window — its own npm package, tests and release output
windows/ what exists only because the host is Windows: the tray script, the icon, its generator, the installer
tests/ the Python suite, mirroring server/
docs/ the product's written contracts

windows/ is separate from desktop/ because they answer different questions. desktop/ is an application — JavaScript, npm, an asar. windows/ is PowerShell, an .ico and an NSIS installer, and the Electron app is one of its consumers rather than its owner.

Five documents state what code cannot:

Limitations

Worth knowing before you adopt it:

  • Single user, single machine. No authentication, no multi-tenancy, no remote access. The server binds 127.0.0.1 and assumes everyone who can reach it is you.
  • Windows is the exercised platform. The tray, the installer and the session-root registry lookup are Windows-only. The server should run on macOS and Linux; nobody has proven it.
  • No MCP prompts or resources. The board is a task queue. Project context belongs somewhere else.
  • No hosted anything. No sync between machines, no shared board, no backup other than the snapshots it takes locally.
  • The MCP server is spawned by your client, so it lives as long as the session and does not update itself. See docs/connection-contract.md for how version skew is made visible instead of silent.

Development

Every change runs all of these, from the repository root. The Python toolchain is pinned in requirements-dev.txt and configured in pyproject.toml; none of it is a runtime dependency.

python -m ruff check .
python -m ruff format --check .
typos
vulture server tests valkama.py vulture_whitelist.py --min-confidence 60
mypy
lint-imports --cache-dir .cache/import-linter
semgrep scan --config p/python --config p/security-audit --metrics off --error server valkama.py
python -m coverage run -m unittest discover -s . -p "test_*.py"
python -m coverage report
cd web
npm test
npm run typecheck
npm run build
cd ../desktop
npm test

npm run build is not optional and not last. The server serves the snapshot of web/dist it read at startup, so a browser check against a listener that predates the build inspects the bundle that build replaced. Rebuild, restart the listener, then verify anything live.

Issues and pull requests are welcome — CONTRIBUTING.md has the setup, the commit convention, and the handful of architectural rules that would otherwise send a pull request back. Released changes are recorded in CHANGELOG.md.

License

MIT.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选