Skip to content

Commit 6bbe507

Browse files
committed
docs(readme): make Streamable HTTP the default transport
The README presented the /mcp endpoint as a niche alternative even though it is on by default on a loopback bind and costs less to run: no per-agent subprocess, no loopback hop, async client instead of a synchronous one. Both transports expose the same tool surface, so the token cost is identical and the choice is purely operational. Say so explicitly, add a comparison table, and lead the quickstart with the URL form while keeping the stdio bridge documented for hosts that need it.
1 parent 1fadcdc commit 6bbe507

1 file changed

Lines changed: 68 additions & 16 deletions

File tree

README.md

Lines changed: 68 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,23 @@ uvx --from caucus-mcp caucus-hub --host 127.0.0.1 --port 8765
8686
```
8787

8888
**2. Point each agent at the hub.** Drop this into the repo's `.mcp.json` (or
89-
your MCP client's config). It is copy-pasteable as-is on any machine with `uv`:
90-
no prior install, and the bridge names the agent after its working directory.
89+
your MCP client's config). The hub already serves an MCP endpoint at `/mcp`, so
90+
there is nothing to install and no subprocess to spawn:
91+
92+
```json
93+
{
94+
"mcpServers": {
95+
"caucus": {
96+
"type": "http",
97+
"url": "http://127.0.0.1:8765/mcp"
98+
}
99+
}
100+
}
101+
```
102+
103+
If your MCP client only speaks stdio, use the bridge instead. It is
104+
copy-pasteable as-is on any machine with `uv` (no prior install) and names the
105+
agent after its working directory:
91106

92107
```json
93108
{
@@ -101,6 +116,9 @@ no prior install, and the bridge names the agent after its working directory.
101116
}
102117
```
103118

119+
Both expose the exact same tools. See [Which transport?](#which-transport) for
120+
the trade-off.
121+
104122
**3. Open the console** at **<http://127.0.0.1:8765/>**, tell each agent to
105123
connect to the caucus, and watch them talk.
106124

@@ -216,8 +234,9 @@ pip install caucus-mcp # or plain pip
216234

217235
Update with `uv tool upgrade caucus-mcp` (or `pipx upgrade caucus-mcp`).
218236

219-
Once installed, the hub command and the `.mcp.json` snippet drop the `uvx`
220-
wrapper:
237+
Only the machine running the hub needs this. Agents that connect over
238+
Streamable HTTP install nothing at all; the snippet below is for the stdio
239+
bridge, which drops the `uvx` wrapper once installed:
221240

222241
```bash
223242
caucus-hub --host 127.0.0.1 --port 8765
@@ -255,7 +274,7 @@ uv pip install -e ".[dev]"
255274

256275
| Variable | Default | Meaning |
257276
| --- | --- | --- |
258-
| `CAUCUS_HUB_URL` | `http://127.0.0.1:8765` | Hub the bridge connects to. |
277+
| `CAUCUS_HUB_URL` | `http://127.0.0.1:8765` | Hub the bridge and the native connector reach out to. Unused when the client speaks Streamable HTTP to `/mcp`, where the URL is the config. |
259278
| `CAUCUS_PROJECT` | working-dir basename | Name this agent registers under. Set it only when you want a name different from the directory, or when two checkouts share a basename. |
260279
| `CAUCUS_MCP_HTTP` | on for loopback | The Streamable HTTP MCP endpoint at `/mcp` is served by default on a loopback bind. Set to `0` to disable it, or to `1` to force it on a non-loopback bind (same as `--no-mcp-http` / `--mcp-http`). See [Connect over Streamable HTTP](#connect-over-streamable-http-no-bridge-subprocess). |
261280

@@ -337,14 +356,16 @@ Node is a build-time dependency only. The running hub has no Node requirement.
337356
The hub is the common ground. How an agent reaches it depends on how that agent
338357
runs.
339358

340-
| | **Bridge connector** (`caucus-bridge`) | **Native connector** (`caucus-claude-agent`) |
359+
| | **MCP connector** (`/mcp` or `caucus-bridge`) | **Native connector** (`caucus-claude-agent`) |
341360
| --- | --- | --- |
342361
| For | Passive, turn-based MCP hosts: interactive **Claude Code / Codex / Gemini** sessions | An **autonomous agent** that owns its own event loop |
343362
| How it listens | An out-of-band `caucus-watch` process wakes the agent on inbound (a turn-based host cannot be pushed mid-turn) | Polls and injects inbound straight into the live conversation. No watcher, no wake-by-exit |
344-
| Setup | One line in `.mcp.json` | A CLI process you launch |
363+
| Setup | One block in `.mcp.json`: a URL (preferred) or a stdio command | A CLI process you launch |
345364
| Tools the agent calls | `join` / `say` / `watch_command` / `listen` ... (armed lazily, no setup) | none for plumbing. `say` / `list_peers` exist; joining and listening are automatic |
346365

347-
The bridge is a **constraint adapter** for hosts that cannot push. The native
366+
The MCP connector comes in two transports, Streamable HTTP and the stdio bridge,
367+
which expose an identical tool surface: see [Which transport?](#which-transport).
368+
Either way it is a **constraint adapter** for hosts that cannot push. The native
348369
connector is the clean shape for a bot that lives in the room. New runtimes ship
349370
their own native connector against the same hub, so the protocol stays shared.
350371

@@ -412,16 +433,48 @@ request handlers, so the operator brakes (Pause, Stop, rate limit, talking stick
412433
apply exactly as they do over the bridge. On a localhost bind it is on by default
413434
(opt out with `--no-mcp-http`); on a non-loopback bind it stays opt-in via
414435
`--mcp-http`. Either way it keeps the same localhost-first posture as the rest of
415-
the hub, with a DNS-rebinding guard on the handshake. Prefer it when your MCP
416-
client speaks Streamable HTTP and you would
417-
rather not run a per-session stdio subprocess. The `caucus-bridge` path stays the
418-
right choice for hosts that only do stdio.
436+
the hub, with a DNS-rebinding guard on the handshake.
437+
438+
The session is keyed on the `Mcp-Session-Id` header, so many agents share the one
439+
hub process; a background sweep drops sessions that armed but never joined.
440+
441+
### Which transport?
442+
443+
Both paths expose the **same tools, with the same schemas and the same
444+
docstrings**, so they cost the **same number of tokens**. What differs is what
445+
runs on your machine per agent session:
446+
447+
| | **Streamable HTTP** (`/mcp`) | **stdio bridge** (`caucus-bridge`) |
448+
| --- | --- | --- |
449+
| Processes per agent | none | one Python subprocess |
450+
| Hops per tool call | none: the MCP server is mounted *inside* the hub and reaches `HubState` over an in-process ASGI transport | tool → bridge → loopback HTTP → hub |
451+
| HTTP client | async `HubConnector` | synchronous `httpx.Client` |
452+
| Startup | already warm | interpreter spawn + imports per session |
453+
454+
**Default to Streamable HTTP.** With N agents, the stdio path means N Python
455+
interpreters whose only job is to proxy calls one extra hop. Reach for
456+
`caucus-bridge` when:
457+
458+
- your MCP host does not speak Streamable HTTP (still a few of them);
459+
- the hub is remote and you would rather not expose `/mcp` (the bridge already
460+
sits outside it);
461+
- you are debugging and a separate, inspectable process helps.
462+
463+
One operational nuance: over stdio the session lives and dies with the process,
464+
which is coarser but very predictable. Over HTTP it is tied to the session id and
465+
subject to the reaper.
466+
467+
Neither transport changes the token bill in a running caucus. That is driven by
468+
inbound messages and by `listen()` polling, which is exactly why
469+
`watch_command()` exists: it hands the waiting to a separate process with no LLM
470+
attached.
419471

420472
---
421473

422474
## 🧰 Tools exposed to each agent
423475

424-
These are the **bridge** connector's tools, for passive MCP-client sessions. The
476+
These are the **MCP** connector's tools, for passive MCP-client sessions. They
477+
are identical over Streamable HTTP and over the stdio bridge. The
425478
native `caucus-claude-agent` exposes `say` / `list_peers`, the channel tools,
426479
and the talking-stick tool, and does the joining and listening for you.
427480

@@ -516,12 +569,11 @@ flowchart TB
516569
N1["caucus-claude-agent<br/>(ClaudeSDKClient)"]
517570
end
518571
519-
A1 -- stdio --> B1["caucus-bridge"]
572+
A1 -- "Streamable HTTP (/mcp)" --> H[("Hub · FastAPI<br/>single source of truth")]
520573
A2 -- stdio --> B2["caucus-bridge"]
521-
B1 -- HTTP --> H[("Hub · FastAPI<br/>single source of truth")]
522574
B2 -- HTTP --> H
523575
W["caucus-watch<br/>(wakes the agent)"] -. HTTP .-> H
524-
B1 -. spawns .-> W
576+
passive -. "runs, either transport" .-> W
525577
526578
N1 -- "HTTP (HubConnector)" --> H
527579

0 commit comments

Comments
 (0)