replay a stream.place chat from a jetstream archive streamplace-mcp.fastmcp.app/stats
streaming mcp atproto
README.md

streamplace-mcp #

an MCP server that replays the chat of a Streamplace broadcast, live or historical, out of the stream.waow.tech archive and the Jetstream tail. chat on Streamplace is place.stream.chat.message records in each chatter's own repo, so "what was said" is a window query over the whole network, and the archive is the index for it.

live: https://streamplace-mcp.fastmcp.app/mcp (no auth) · stats · listed at mcp.waow.tech

claude mcp add streamplace --transport http https://streamplace-mcp.fastmcp.app/mcp

use #

the latest broadcast — a handle picks the streamer's most recent session, live or ended:

catch_up(stream="atproto.com")

a historical broadcast — list the streamer's sessions, then replay one by its AT-URI:

list_streams(streamer="atproto.com")
  → [{uri: "at://did:plc:…/place.stream.livestream/3mtwc62aunr2k", title: "Off Protocol LIVE", created_at: "2026-08-25T16:59:50Z", …}, …]

catch_up(stream="at://did:plc:…/place.stream.livestream/3mtwc62aunr2k")
  → {complete: true, stats: {messages: 220, chatters: 40, …}, messages: [{at, handle, text}, …]}

a session older than the archive's sealed edge is one call. a session that is live or ended in the last few hours needs the socket for its recent stretch, so catch_up works to a time budget and returns complete, a reason, and a cursor; call it again with the cursor for the rest. summary_only returns the stats without the messages; limit and since slice the list. docs/replay.md walks through both cases.

design #

  • archive first, socket second — sealed segments are read by block index as contiguous byte ranges and decoded locally, so an hour of chat is one round of parallel fetches. the Jetstream tail only covers what is not sealed yet, and only within a budget the caller sets.
  • the server holds the archive key — the archive is bearer-gated. callers get replay without a credential; the metered key lives with the deployment.
  • provenance on every result — where the archive ended, which host the tail used, and why a result is incomplete. a summarizer can say what it did not see.
  • moderation is visible — a deleted record within the replayed window is marked, and a chatter with no resolvable handle is marked suspended or deactivated, so what moderation acted on can be skipped.
  • bounded for strangers — tool calls are limited per caller, replays are capped globally with a short wait and then a plain "busy", and a sealed window is fetched once and cached. a popular stream costs the network once, not once per viewer.
  • no new protocol surface — the archive and the socket are used as upstream Jetstream v2 defines them. anything this exposes as slow is a case for the server, not a divergence from it.

develop #

uv sync                                                  # deps
uv run pytest                                            # offline tests
JETSTREAM_ARCHIVE_API_KEY=… uv run streamplace-mcp       # serve on :8782
JETSTREAM_ARCHIVE_API_KEY=… uv run streamplace-replay atproto.com   # transcript to stdout

docs #

docs/ — replaying and paging, how the reads work, what bounds a public endpoint, and how it is deployed.

license #

MIT