{"slug": "how-agents-and-people-edit-the-same-page-at-once-a-remote-mcp-server-on-durable", "title": "How agents and people edit the same page at once: a remote MCP server on Durable Objects and Yjs", "summary": "A developer built Blink Artifacts, a remote MCP service that lets any MCP client publish a shareable web page which humans edit in the browser while an agent keeps editing it over MCP. Each artifact is a Cloudflare Durable Object holding a Yjs CRDT document, with the agent seeing plain files and writes guarded by exact find/replace matching, baseRev conflict detection and a changes_since diff tool. Published pages are served from per-artifact subdomains on a separate domain inside a sandboxed iframe with no cookies or credentials, and the server acts as its own OAuth 2.1 authorization server for claude.ai and Claude Desktop connectors.", "body_md": "Coding agents are good at making things you want to share: a one-page project summary, a dashboard, a slide deck. Sharing is where it gets awkward. Claude's artifacts live inside a claude.ai account, other agents have nothing comparable, and once a teammate wants to fix a sentence, you are back to copying HTML around.\n\nI built [blink artifacts](https://artifact.blinkbrosai.com/?utm_source=devto) to fix that: any MCP client publishes a page over remote MCP, you get one link, and people edit it in the browser while the agent keeps editing it over MCP. This post is about the parts that were harder than they looked.\n\nEvery artifact is a Cloudflare Durable Object holding a Yjs document. The browser editors (CodeMirror for HTML, ProseMirror for docs, a canvas for slides) sync to it over a WebSocket. The Durable Object uses WebSocket hibernation, so an idle artifact costs nothing while sockets stay open.\n\nThe agent never sees Yjs. Over MCP it sees plain files: `index.html`, `doc.md`, one HTML file per slide. Reads project the Yjs state into text; writes apply a text diff back into the shared document, inside the same Durable Object, so a human typing and an agent writing are just two clients of one CRDT.\n\nD1 keeps the index (accounts, artifacts, members, tokens), R2 keeps uploaded files, and version history lives in the artifact's own Durable Object storage.\n\nAn agent's view of a file is always a little stale: a person may have changed it since the agent last read it. So the write tools are built to refuse rather than guess:\n\n`edit_file` takes exact find/replace pairs. If the text matches nowhere it returns `no_match`; if it matches more than once, `multi_match`. Either way nothing is written, and the agent re-reads.` write_files` takes an optional `baseRev`. If any file it touches changed after that revision, it returns `conflict` with the paths, and the agent merges instead of overwriting.`changes_since(rev)` returns only what changed, so an agent coming back to a page after your team edited it reads a diff, not the whole thing.\nThis turned out to matter more than the CRDT itself. Yjs makes concurrent edits converge; it does not make an agent's overwrite of a paragraph you just rewrote a good idea.\n\nPublished pages are arbitrary HTML and JavaScript, so they never run on the app's origin. Each artifact is served from its own subdomain on a separate domain, keyed by a secret that is rotated when access changes, inside a sandboxed iframe. The page gets no cookies and no credentials. When it wants shared state (a small database, comments, the viewer's identity) it asks the parent window over `postMessage`, and the shell makes the API call with the viewer's own role.\n\nPeople can ask questions on a page: select an element, type `@` and pick an agent. There is no model on the server. The question waits in the artifact's Durable Object until the owner's own agent picks it up (with a background listener, or by long-polling `asks_wait`), answers it in a comment or writes the answer into the doc block, and resolves it. The agent that answers is the one you already pay for and already trust with your code.\n\nCLI agents connect with a bearer token. claude.ai and Claude Desktop custom connectors expect OAuth, so the server is also its own OAuth 2.1 authorization server: protected-resource and authorization-server metadata, dynamic client registration, PKCE (S256), short-lived access tokens and rotating refresh tokens, all on D1. In claude.ai you add `https://artifact.blinkbrosai.com/mcp` under Settings → Connectors, sign in with an email code, approve, and that is it.\n\nIt is free for 3 active artifacts, no card. Setup for Claude Code, Codex, Copilot CLI, Antigravity and claude.ai is in the [docs](https://artifact.blinkbrosai.com/docs?utm_source=devto).\n\nI built most of it with Claude Code: I wrote the acceptance tests first, Claude wrote most of the implementation, I read every diff. Happy to answer questions about any of the pieces above, and I would especially like to hear what breaks.", "url": "https://wpnews.pro/news/how-agents-and-people-edit-the-same-page-at-once-a-remote-mcp-server-on-durable", "canonical_source": "https://dev.to/remzi_binar/how-agents-and-people-edit-the-same-page-at-once-a-remote-mcp-server-on-durable-objects-and-yjs-43ie", "published_at": "2026-10-29 00:32:35+00:00", "updated_at": "2026-10-29 00:41:27.015910+00:00", "lang": "en", "topics": ["ai-agents", "agent-protocols", "ai-tools", "developer-tools"], "entities": ["Blink Artifacts", "Cloudflare", "Yjs", "Claude Code", "claude.ai", "Claude Desktop", "Codex", "GitHub Copilot CLI"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/how-agents-and-people-edit-the-same-page-at-once-a-remote-mcp-server-on-durable", "markdown": "https://wpnews.pro/news/how-agents-and-people-edit-the-same-page-at-once-a-remote-mcp-server-on-durable.md", "text": "https://wpnews.pro/news/how-agents-and-people-edit-the-same-page-at-once-a-remote-mcp-server-on-durable.txt", "jsonld": "https://wpnews.pro/news/how-agents-and-people-edit-the-same-page-at-once-a-remote-mcp-server-on-durable.jsonld"}}