Inspiration
Every "agent in chat" design we have seen gives the agent an account: its own key, its own memberships, its own audit trail. That is right for an agent that works in the room as a peer. It is wrong for the agent at your elbow — the one reading over your shoulder that says "want me to answer that?" That agent should have no key at all. WebMCP is the first thing that makes that agent practical: the tools live in your tab, under your session, and they can see what you are looking at. No server, no OAuth, no bot account.
What it does
Waggle is a small NIP-29 group-chat client that publishes twelve WebMCP tools. Seven are reads — the current view
(including the message you have selected), channels, a channel's messages, a thread, search, a member. Five are
propose_* tools — message, reply, reaction, channel topic, join. A proposal is not a post: it is a card in the
Waggles dock. You edit it, then Sign & send with a key the agent never touches, or reject it. The signed event
carries ["proposed-by","webmcp","<n>"], so anyone reading the relay can tell agent-drafted from hand-typed.
How we built it
src/tools/is framework-free and talks only to aWaggleContextinterface, so the same tools can be lifted into another client. Registration usesdocument.modelContext.registerToolwithreadOnlyHintannotations on reads.src/relay/speaks NIP-29 + NIP-42 + NIP-50 over nostr-tools, with a mock relay for zero-network demos.- Identity is NIP-07 if present, otherwise a key generated in the page. The demo relay is a real Buzz relay we deployed for this, open to throwaway keys so judges can post.
scripts/e2e.mjsproves the loop through the browser's own API:getTools()→executeTool()→ human click → event found on the relay by an unrelated key, provenance intact.
Challenges
Chrome passes execute() its arguments as a JSON string, and navigator.modelContext is deprecated in favour of
document.modelContext — both learned by running the real browser, not the docs. The relay rejects events more than
15 minutes off server time, which shaped how we seed a believable conversation. And the hardest design question was
the smallest one: the button says Sign & send, not Send, because the word sign is the whole point.
What's next
Carry the tools module into Buzz as a right-dock feature, and emit Buzz's reserved approval kinds (46010/46030) so a proposal, its ruling, and the resulting message are three linked events in one log — the correction log an agent can learn from.
Testing instructions
No login, no credentials: Waggle generates a throwaway Nostr key in your browser on first load, and the demo relay accepts it.
- Open https://app.waggle.thecrowbarcrew.cc in a WebMCP-capable browser: ChatGPT desktop app → Work → its built-in browser (Site tools on in Settings → Browser → Permissions), or Chrome 150+ with
chrome://flags/#enable-webmcp-testingenabled plus the Model Context Tool Inspector extension or DevTools → Application → WebMCP.- The header chip should read WebMCP · 12 tools (green). In ChatGPT, "Site tools" in the address bar lists them.
- Try: "What did I miss in #general?" — then click any message and say "Reply to this saying thanks, I'll take a look." A proposal card appears in the right-hand dock; nothing is sent until you click Sign & send.
- The cross-site errand: "Check the shop for a leather bag under $200 and answer Marco" — the store's URL is findable in Marco's thread in #general.
- Zero-network mode for a quick look: append
?relay=mock. Manual tool bench:?dev=1.#try-waggleis the sandbox channel — post anything.
Log in or sign up for Devpost to join the conversation.