feat(canvas): route agent calls from the host MCP server to the mounted canvas
Merged
GN
2d ago+3276+3276+0123456789012345678901234567890123456789-63-63-01234567890123456789
Summary
- Agents need a path into the canvas that always lands in their own project.
- Part 3 of 10 in a stacked series. Review and merge bottom-up; each PR targets the one below it. Canvas mode v3 (figcraft engine). Spec:
spec-openpencil-canvas-mode; architecture spine 2026-10-16 (AD-17 to AD-31).
Related Issue
No issue. Split from #1369 so each part stays under 50 files.
Type of Change
- feat: new feature
What Changed
- Links the fork's
figcraft-mcpand implements itsBackendasBridge. - The parent router resolves session to project on every call, times out with
CANVAS_TIMEOUTand answersCANVAS_CLOSEDwhen nothing is mounted. Calls travel over the existing/wschannel on both surfaces.
Scope
- E3-1. Tools are registered in a later PR.
How It Was Tested
-
bun run typecheckon this branch - Each part is a checkpoint that was built and tested when it was made (
cargo testfor canvas and host_mcp, vitest, real runs in headless Edge). The bottom and top of the stack were rebuilt and re-tested on currentdev.
Checklist
- PR title follows the conventional commit format
- Explained why no issue exists
- Added or updated tests
- Read AGENTS.md
- A human reviewed the complete diff before submission
๐ค Generated with Claude Code
Summary by cubic
Part 3 of the canvas stack (merge bottom-up): routes agent calls from the host MCP server to the renderer's mounted canvas, so agent canvas tools always land in the session's own project. Calls previously had no path into the canvas; now Bridge::call sends a Canvas frame to the parent over the existing loopback channel.
- Links the fork's
figcraft-mcpand implements itsBackendasBridge; nothing constructs itsHeadless/Attachedbackends or aSession. - The parent resolves session โ project on every call, owns the
CANVAS_TIMEOUT, and answersCANVAS_CLOSEDwhen nothing is mounted. - The renderer leg reuses
/ws:canvas_mount/canvas_unmount/canvas_replyrequests and a top-levelcanvas_callframe work on desktop Channel and web socket alike; mounts re-report on reconnect. check-figcraft-pin.mjsnow fails closed on atag =mismatch withcanvas/figcraft.pinand warns for the interimrev =pin.