One small script, one Cloudflare Worker. Any framework.
The client goes in your page, any framework. The Worker holds each session; deploy your own.
npm install github:acoyfellow/echo git clone https://github.com/acoyfellow/echo && cd echo npx wrangler secret put ECHO_SIGNING_SECRET bun run deploy
Name the functions agents may call and mark each read or mutation. Nothing else in the page is reachable.
import { createEcho } from '@acoyfellow/echo'; const echo = createEcho({ appId: 'todo', workerBase }); echo.register({ listTodos: { effect: 'read', run: () => todos, }, addTodo: { effect: 'mutation', run: ({ text }) => add(text), }, }); connectButton.onclick = () => echo.connect(); stopButton.onclick = () => echo.stop();
The person presses Connect and gets one temporary MCP URL for any number of agents. Each agent sends a script that runs in a sandbox with no network; calls land in the tab one at a time. Stop ends every agent.
// echo_run { runId: 'r1', code: ... } const todos = await app.listTodos({}); for (const todo of todos) { if (!todo.completed) { await app.setCompleted({ id: todo.id, completed: true, }); } } await app.addTodo({ text: 'Plan the next release' }); return app.listTodos({});
Ways to let an agent act inside a web app today. A dash means it depends on how you build or configure it.
A real todo app with Echo added. Press Connect agent, copy the URL into any MCP client, and watch the list change.
Want two agents at once? The whiteboard lets several draw on one board.