A production-oriented Kotlin message bus for coordinating local or remote coding agents. It provides a Ktor broker over HTTP plus Server-Sent Events, and an MCP stdio adapter so agents can discover peers, subscribe to topics, publish broadcasts, and send direct messages.
MCP stdio HTTP + SSE
agent process <----------> adapter <--------------------+
|
agent process <----------> adapter <--------------------+--> Ktor broker
| registry
agent process <----------> adapter <--------------------+ topics
queues
disk state
- Agent registration with presence and descriptions.
- Direct messages by id or name, with online agents preferred when names collide.
- Topic publish/subscribe with sender echo suppression.
- Server-Sent Events for live delivery plus bounded offline queues.
- JSON disk persistence for agents, subscriptions, and queued messages.
- Stale offline agent pruning.
- Environment or properties-file configuration.
- Official Kotlin MCP SDK stdio adapter exposing
bus_publish,bus_send,bus_subscribe,bus_list,bus_whoami, andbus_set_description. - JDK 21, Gradle Kotlin DSL, JUnit 5 tests, and GitHub Actions CI.
Install JDK 21 and Gradle with SDKMAN, then build:
./gradlew buildStart the broker:
BUS_CONFIG=examples/broker.properties ./gradlew run --args=brokerRun an MCP adapter from another terminal:
BUS_AGENT_ID=planner \
BUS_AGENT_NAME=planner \
BUS_AGENT_DESC="plans work" \
BUS_SUBSCRIBE=build \
./gradlew run --args=mcpFor an MCP client configuration, use the installed distribution command after ./gradlew installDist:
{
"mcpServers": {
"agent-bus": {
"command": "build/install/agent-bus-kt/bin/agent-bus-kt",
"args": ["mcp"],
"env": {
"BUS_BROKER_URL": "<broker-url>",
"BUS_AGENT_NAME": "planner",
"BUS_SUBSCRIBE": "build"
}
}
}
}The broker accepts JSON:
GET /healthPOST /registerwithagentId, optionalname, optionaldescriptionPOST /subscribewithagentId,channelPOST /unsubscribewithagentId,channelPOST /publishwith optionalfrom,channel,contentPOST /sendwith optionalfrom,to,contentGET /agentsGET /channelsGET /stream?agentId=<id>&name=<name>&desc=<description>
domain: validated value objects and bus entities.application:BusService, use-case DTOs, repository and clock ports, message id generation, concurrency control.infrastructure: JSON file persistence and runtime configuration.interfaces.http: Ktor HTTP/SSE adapter and wire DTOs.interfaces.mcp: official Kotlin MCP SDK stdio adapter plus broker HTTP client.
- Start a broker with
BUS_CONFIG=examples/broker.properties ./gradlew run --args=broker. - Start agent
plannerwithBUS_SUBSCRIBE=build. - Start agent
builderwithBUS_SUBSCRIBE=build. plannercallsbus_publishon channelbuildwith a task summary.builderreceives the channel event through the adapter and replies withbus_sendtoplanner.plannerusesbus_listto inspect online agents, descriptions, subscriptions, and queued messages.
This keeps orchestration generic: agents coordinate through topics for shared work and direct messages for handoffs.
Set values in the environment or in a Java properties file pointed to by BUS_CONFIG. Environment values override file values.
| Key | Purpose | Default |
|---|---|---|
BUS_HOST |
Broker bind host | localhost |
BUS_PORT |
Broker port | 8799 |
BUS_STATE |
Broker JSON state path | broker-state.json |
BUS_STALE_MS |
Offline agent prune age | 1800000 in the example config |
BUS_QUEUE_CAPACITY |
Per-agent offline queue cap | 1000 |
BUS_BROKER_URL |
Adapter broker base URL | http://localhost:8799 |
BUS_AGENT_ID |
Adapter stable id | generated from name |
BUS_AGENT_NAME |
Adapter display name | current directory name |
BUS_AGENT_DESC |
Adapter role description | empty |
BUS_SUBSCRIBE |
Comma-separated startup topics | empty |
./gradlew test
./gradlew buildThe repository is intentionally small but layered. Keep domain and application code free of Ktor or MCP dependencies; add transport behavior in interfaces.*.