mcp-agent-collaboration
# MCP Agent Collaboration
In-memory MCP server for cooperative collaboration between separate agents.
The intended workflow is:
1. A coordinator/main agent starts this MCP server as a dedicated Streamable HTTP process.
2. The coordinator creates a topic and joins it.
3. Secondary agents join the same topic with friendly names such as `builder` or `reviewer`.
4. Agents exchange direct and broadcast messages through MCP tools.
5. Idle agents long-poll with `read_messages`.
6. Working agents use `check_in` to report progress and read messages in one call.
Messages are held only in memory. Restarting the server clears all topics, members, and messages.
After a restart, old `join_token` values are invalid and agents must re-join.
## Install
```bash
python3 -m venv .venv
. .venv/bin/activate
pip install -e .
```
## Run
```bash
mcp-agent-collaboration --host 127.0.0.1 --port 8000
```
The MCP endpoint is:
```text
http://127.0.0.1:8000/mcp
```
For Codex, add a Streamable HTTP MCP server in `config.toml`:
```toml
[mcp_servers.agent_collaboration]
url = "http://127.0.0.1:8000/mcp"
tool_timeout_sec = 600
```
Set `tool_timeout_sec` high enough for your preferred long-poll duration. The server itself does not impose a maximum wait; the MCP client/tool runtime may still have its own timeout.
### Codex Autostart
For Codex, the preferred setup is the stdio autostart proxy. Codex launches the
proxy as a normal stdio MCP server; the proxy starts the shared Streamable HTTP
server on localhost if it is not already running, then forwards tool calls to it.
From this source checkout:
```bash
codex mcp add agent_collaboration \
--env PYTHONPATH=/home/vkolotoff/projects/mcp-agent-collaboration/src \
-- python3 -m mcp_agent_collaboration.autostart_stdio
```
After installing the package, this shorter form is enough:
```bash
codex mcp add agent_collaboration -- mcp-agent-collaboration-stdio
```
Defaults:
- `MCP_AGENT_COLLAB_HOST=127.0.0.1`
- `MCP_AGENT_COLLAB_PORT=8000`
- `MCP_AGENT_COLLAB_PATH=/mcp`
- `MCP_AGENT_COLLAB_LOG=/tmp/mcp-agent-collaboration.log`
Override them with `--env` only when needed.
To install the package into your user-level Python environment:
```bash
python3 -m pip install --user /home/vkolotoff/projects/mcp-agent-collaboration
codex mcp add agent_collaboration -- mcp-agent-collaboration-stdio
```
`codex mcp add` writes to the global Codex MCP config by default, so the server
is available to future Codex sessions after restart.
## Tools
### `create_topic`
Create a topic by string name.
```json
{
"topic": "build-123"
}
```
### `join_topic`
Join a topic with a friendly agent name. The returned `join_token` is required for message operations.
```json
{
"topic": "build-123",
"agent_name": "reviewer",
"role": "secondary",
"create_if_missing": true
}
```
Agent names are unique within a topic. The literal name `all` is reserved for broadcast messages.
### `send_message`
Send a direct message to one agent or a broadcast to all agents currently joined.
```json
{
"join_token": "opaque-token",
"recipient": "reviewer",
"body": {
"type": "review_request",
"task_id": "task-001",
"summary": "Implementation is ready for review."
}
}
```
Use `"recipient": "all"` for broadcast. Broadcast recipients are snapshotted at send time, so agents who join later do not receive older broadcasts. The sender receives its own broadcast by default because it is also a joined agent; set `include_self` to false to opt out.
Compact output is the default:
```json
{
"id": "msg_123",
"stored": true
}
```
Pass `"verbosity": "full"` only when you need topic, sender, and recipient metadata.
### `read_messages`
Read and consume pending messages for the joined agent.
```json
{
"join_token": "opaque-token",
"timeout_ms": 600000,
"max_messages": 20
}
```
Compact output is the default:
```json
{
"timed_out": false,
"messages": [
{
"id": "msg_123",
"from": "reviewer",
"body": {
"type": "review_result",
"status": "approved"
}
}
]
}
```
Pass `"verbosity": "full"` only when you need topic, recipient, timestamp, or broadcast snapshot metadata.
Long-poll behavior:
- If messages are already pending, return immediately.
- If no messages are pending and `timeout_ms > 0`, hold the request open until a relevant message arrives or the requested timeout elapses.
- If `timeout_ms` is `0`, return immediately with pending messages or an empty timeout response.
- The server does not impose its own maximum timeout.
- Returned messages are consumed.
Deletion behavior:
- Direct messages are deleted after the recipient reads them.
- Broadcast messages are deleted after every send-time recipient has read them.
- If an agent leaves a topic, it is removed from unread recipient sets so old broadcasts can be cleaned up.
### `check_in`
Optionally send a message and read pending messages in one tool call. This is
the preferred work-loop tool for secondary agents because it avoids a separate
`send_message` call followed by `read_messages`.
```json
{
"join_token": "opaque-token",
"timeout_ms": 0,
"recipient": "coordinator",
"body": {
"type": "progress",
"task_id": "task-001",
"done": "Added compact read tests.",
"next": "Update docs.",
"blockers": []
}
}
```
Compact output:
```json
{
"sent": {
"id": "msg_123",
"stored": true
},
"timed_out": true,
"messages": []
}
```
Omit `body` to use `check_in` as a compact read. Use a long `timeout_ms` when
idle, and `timeout_ms: 0` or a short timeout between work chunks.
`body: null` is treated the same as omitting `body`, so it cannot be used as a
sent message payload. If `body` is provided with a large `timeout_ms`, the send
confirmation is returned only when the read side wakes or times out; use
`timeout_ms: 0` for fire-and-return progress updates.
### `leave_topic`
Leave a topic and stop receiving future messages.
```json
{
"join_token": "opaque-token"
}
```
### `list_topics`
List topics with member and pending-message counts.
### `list_topic_members`
List members in a topic.
## Collaboration Contract
This MCP does not forcibly interrupt running agents. Messages wake agents that are currently blocked in `read_messages`; agents that are actively working see messages at their next check-in.
Secondary agents must:
- Join with a clear role name.
- Send a readiness message to the coordinator.
- Work in bounded chunks.
- Use `check_in` to send progress to the coordinator and read messages at reasonable intervals.
- Always poll after completing a work chunk, after sending a review result, and after reporting task completion.
- Treat urgent or cancellation messages as priority instructions when seen.
- Send `task_complete` when done.
- Ask the coordinator for more work, then enter idle long-poll mode.
The coordinator must:
- Start the server.
- Create the topic.
- Join as `coordinator` or another clear main-agent name.
- Assign tasks to secondary agents.
- Watch progress, blockers, completion messages, and requests for more work.
- Poll after sending assignments, clarifications, cancellations, or follow-up work so queued replies are not missed.
Recommended message body types:
- `presence`
- `task_assignment`
- `progress`
- `task_complete`
- `request_more_work`
- `review_request`
- `review_result`
- `cancel_task`
- `interrupt`
`interrupt` is cooperative. It is not forced preemption.
## Test
```bash
python3 -m unittest discover -s tests
```
TDQS
Scored across 8 tools
Each tool has a clearly distinct purpose: topic lifecycle (create, join, leave), messaging (send, read, check_in), and listing (topics, members). check_in is a convenience combination but its description clarifies its dual role.
All tool names follow a consistent verb_noun pattern (create_topic, join_topic, send_message, read_messages, list_topics, list_topic_members). Minor phrasal verb 'check_in' still fits the style.
Eight tools cover the domain of topic-based collaboration without redundancy or bloat. Each tool serves a distinct function and the count is well within the ideal range.
The surface covers topic creation, joining/leaving, messaging, and listing topics/members. A delete_topic operation is missing but might be intentionally omitted for ephemeral in-memory topics, so minor gap only.