Skip to main content
Glama
README.md
# AgentChat

An **MCP hub** that lets two agents send messages to each other, with their
conversation rendered live in a terminal UI.

```
 Agent A ─┐                         ┌──────────────────────────────┐
          ├─ HTTP /mcp ──▶ uvicorn ─┤  FastMCP tools ──▶  Hub  ──▶  │  Textual TUI
 Agent B ─┘                         └──────────────────────────────┘  (live feed)
```

One long-running process hosts the MCP server (Streamable HTTP transport) **and** the
TUI on a single asyncio event loop, sharing an in-memory conversation store. Two
*separately running* agents (e.g. two Claude Code or Claude Desktop sessions) connect
to it as MCP clients and talk through it.

> Why HTTP and not stdio? stdio spawns a *separate* server process per client, so two
> agents couldn't share a conversation. A single HTTP hub is required for shared state.

## Install

```bash
uv pip install -e .        # or: pip install -e .
```

Requires Python 3.11+.

## Run the hub

```bash
python -m agentchat                       # binds 127.0.0.1:8000, endpoint /mcp
python -m agentchat --port 9000 --title "My Agents"
```

A Textual TUI opens showing the live transcript (color-coded per sender, with
timestamps) plus a status line of participants and message count. Press `q` to quit.

## MCP tools

| Tool | Purpose |
| --- | --- |
| `send_message(sender, content, recipient=None)` | Send a message. With two agents, omit `recipient` to reach the other one. |
| `wait_for_message(agent, timeout_seconds=60)` | **Blocks** until a message arrives for `agent`; returns a notice (not an error) on timeout. |
| `get_history(limit=50)` | Recent transcript. |
| `list_participants()` | Names that have joined. |

Identity is **parameter-based**: each agent picks a name and passes it consistently as
`sender` / `agent`.

## Wire up two agents

Add the hub to each agent's MCP config (see `examples/mcp-config.json`):

```json
{ "mcpServers": { "agentchat": { "type": "http", "url": "http://127.0.0.1:8000/mcp" } } }
```

Then tell each agent its name. A typical exchange:

- Agent **bob**: call `wait_for_message(agent="bob")`
- Agent **alice**: call `send_message(sender="alice", content="hi bob")`
- bob's wait returns the message; bob replies with `send_message(sender="bob", ...)`,
  while alice now calls `wait_for_message(agent="alice")`.

## Try it without real agents

With the hub running, in another terminal:

```bash
python examples/demo_agents.py
```

Two simulated agents (`alice`, `bob`) ping-pong a few messages — watch them appear in
the hub's TUI.

## Notes / future ideas

- Conversation state is in-memory only; restarting the hub clears history.
- Identity could be bound to the HTTP session id instead of a parameter for stronger
  guarantees, at the cost of a small handshake.