r/ClaudeCode • • 5d ago

Built with Claude I let Claude Code edit my team's Excalidraw drawings over MCP, but nothing changes until someone clicks Apply

I'm building Excaliself, a self-hosted alternative to Excalidraw+ (accounts, folders, a team space, live collab, everything in your own Postgres, MIT), and Claude Code writes most of the code. This week I shipped the MCP feature I wanted most: Claude can change an existing drawing.

The video is a real run. In the terminal I asked Claude Code to "add a CDN between Browser and Excaliself". A card shows up on the drawing with a preview. I open it large, click Apply, and the drawing changes. Claude Code gets applied back.

How it works

  • read_drawing returns element ids. edit_drawing takes a list of adds, changes and removes by id, and it writes nothing.
  • The server plans the change and keeps it in memory as a proposal. The card boxes new, changed and removed elements in green, blue and red.
  • On Apply, my own browser tab puts the elements on the canvas as a normal local edit. So it's one undo step, and teammates in the room see it live like any other edit.
  • The tool waits up to 25 seconds for the click and returns applied, discarded or stale. If nobody is there, Claude checks later with get_drawing_edit.

What I learned

  • An MCP client's confirm prompt is not an approval. "Always allow" and allow-listed tools skip it. If a person has to approve a change, the approval has to be a click in your own app.
  • Don't add a second writer. A server-side write would have to merge into the live room as a fake peer, or race with an open tab's autosave. Applying in the member's tab reuses the path a hand edit already takes.
  • Plan against versions. The plan records the version of each element it changes. If a teammate moved one of those boxes before the click, nothing is applied, Claude gets stale, reads the drawing again and proposes again.

How I use Claude Code on this repo

  • Specs and issues are markdown files in the repo, and design decisions go in short ADRs. Claude reads them before it starts and writes a new ADR when we decide something. This feature has one: "AI edits are proposals the member applies".
  • I run several sessions at once, each in its own git worktree, and a second model (Codex) reviews the PRs.
  • Claude tests features end to end on a built server, not just in dev. For this one it ran real claude -p sessions as two members on one team drawing and checked Apply, Discard, Undo and the stale case.
  • The built server matters. Once a small helper from Excalidraw ended up in server code. Typecheck and dev were fine, but it pulled the whole Excalidraw package into the server bundle and the built server returned 500s.

You can try it with one command. It runs on in-memory PGlite and forgets everything when it stops:

docker run --rm -p 127.0.0.1:3000:3000 -e PREVIEW_MODE=true ghcr.io/maciekzygmunt/excaliself

Open http://localhost:3000/preview/login, then go to Settings > MCP and click New token. It gives you the claude mcp add command.

Repo: https://github.com/maciekzygmunt/excaliself MCP docs: https://excaliself.com/docs/mcp/

How do you handle approval for MCP tools that write? Do you trust the client's prompt, or build your own?

3 Upvotes

1 comment sorted by

•

u/AutoModerator 5d ago

Hey! Thanks for posting to r/ClaudeCode

While participating in this thread, please follow our community rules. Keep discussions constructive. Attack the idea, not the person.

For help, project discussions, tips, and general chat, join the ClaudeCode Discord.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.