@solesius-oss/click-clack-mcp
v1.0.8
Published
click-clack coordination hub as a stdio MCP server. Zero-config: `bun add -g @solesius-oss/click-clack-mcp` and point any MCP client at `click-clack-mcp`.
Maintainers
Readme
click-clack-mcp
The click-clack coordination hub
packaged as a stdio MCP server plus a typed Bun FFI client. Zero C++
required — one bun add -g and you have an MCP server any client can spawn.
Supported platforms: linux-x64, darwin-arm64. Prebuilt libclickclack
ships in the npm tarball, so there's no compiler dance on install.
Install
bun add -g @solesius-oss/click-clack-mcp # global → click-clack-mcp binary on $PATH
# or project-local:
bun add @solesius-oss/click-clack-mcpFrom this monorepo (dev):
bun install
bun run build:native # compiles libclickclack.<so|dylib> into ./native/<plat>/Native library resolution order:
$CLICK_CLACK_LIB(absolute path override)../native/<platform>-<arch>/libclickclack.<suffix>(shipped prebuild)../native/libclickclack.<suffix>(flat legacy layout).<repo>/build/libclickclack.<suffix>(in-tree dev builds).- Whatever the OS loader finds on
LD_LIBRARY_PATH/PATH.
Start an MCP server from anywhere
Once installed globally you get a click-clack-mcp binary. It speaks
line-delimited JSON-RPC 2.0 over stdin/stdout — point any MCP client
(VS Code, Claude Desktop, Cursor, …) at it:
Once installed globally you get a click-clack-mcp binary on your $PATH.
It speaks line-delimited JSON-RPC 2.0 over stdin/stdout — point any MCP
client (VS Code, Claude Desktop, Cursor, …) at it:
{
"mcpServers": {
"click-clack": {
"command": "click-clack-mcp",
"env": {
"CC_DATA_ROOT": "${HOME}/.click-clack"
}
}
}
}Environment variables (all optional):
| Var | Default |
| ---------------- | ------------------------------------- |
| CC_DATA_ROOT | <cwd>/.click-clack |
| CC_WAL_PATH | <CC_DATA_ROOT>/wal |
| CC_VIEWS_PATH | <CC_DATA_ROOT>/views |
| CLICK_CLACK_LIB| explicit path to libclickclack.* |
Library quickstart
import { ClickClackHub } from '@solesius-oss/click-clack-mcp'
const hub = ClickClackHub.open({
walPath: './data/wal',
viewsPath: './data/views',
})
try {
hub.postClack({
verb: 'ANNOUNCE',
taskId: 'release-notes',
subject: 'Draft v1.0 changelog',
as: 'alice',
})
hub.claimTask('release-notes', 'bob')
hub.reportProgress('release-notes', 50, 'halfway', 'bob')
hub.completeTask('release-notes', 'shipped', 'bob')
console.log(hub.queryTask('release-notes'))
} finally {
hub.close()
}API
ClickClackHub.open({ walPath, viewsPath })— boot the hub.hub.close()— release native resources (idempotent).hub.listTools()— every registered MCP tool name.hub.call<T>(tool, args, agentId?)— raw JSON dispatch; works with any tool.hub.jsonrpc(line)— feed a single JSON-RPC frame, get the response string (or""for notifications). The primitive behindclick-clack-mcp.- Sugar:
postClack,claimTask,reportProgress,completeTask,queryTask,queryTimeline,wait. ClickClackHub.nativeVersion()— version baked intolibclickclack.
Constraints
- Single hub per process. The underlying celer store is a global singleton; closing one hub releases it so you can open another, but two open at once is undefined behaviour.
- JSON-only payloads. Every tool takes a JSON object in, returns JSON out —
use
hub.call(tool, args)for anything not yet sugared.
Development
bun run build:native # cmake --build build-ffi -t click_clack_ffi
bun test # exercises the FFI surface end-to-end
bun run example # examples/hello.ts