Skip to content

Efecto MCP: tool calls never deliver to browser on one machine (same account works on another) #3

Description

@mlentdesign

Summary

On one of my Macs ("Air"), every Efecto MCP tool call times out after 35s and session_status flips browserConnected to false. The same account on my other Mac ("Mini") works normally. Pairing succeeds on Air — only post-pairing tool calls fail. I've narrowed it to a server-side broadcast delivery problem on the design:doc-sync:<docId> realtime channel.

Environment

  • Efecto MCP package: 0.7.1 (latest at time of report)
  • Browser: Firefox (current stable), same Firefox version on both machines
  • OS: macOS (Darwin 25.4.0)
  • Same Efecto account signed in on Air and Mini
  • Reproducible with brand-new empty docs (not specific to one document)

Reproduction

  1. create_session → success, returns design URL
  2. Open URL in Firefox on Air → pair completes, wait_for_connection returns browserConnected: true, paired: true
  3. Run any tool (e.g. list_artboards, zoom_to_fit) → times out after 35s
  4. session_status immediately after → browserConnected: false, paired: true
  5. Retry pairing → succeeds again, same failure on next tool call

Browser-side diagnostics

Console log on every new session

[Collab] Creating channel: design:doc:<docId> peerId: <peerId>
[Collab] Pairing channel joined
[Collab] Sync channel status: CHANNEL_ERROR "Unauthorized: You do not have permissions to read from this Channel topic: design:doc-sync:<docId>"
[Collab] Sync channel down, retrying: CHANNEL_ERROR "Unauthorized: ..." attempt: 0
[Collab] Channel status: SUBSCRIBED
[Collab] Connected to design:doc:<docId>
[Collab] Sync channel status: SUBSCRIBED

The doc-sync channel initially returns Unauthorized, then eventually flips to SUBSCRIBED on retry. The main design:doc: channel subscribes cleanly first try.

SSE stream

GET https://efecto.app/api/v1/design/sessions/<sessionId>/stream

  • Status 200, Content-Type: text/event-stream
  • Delivers {"type":"connected","sessionId":"..."} then {"type":"heartbeat","timestamp":...} every 15s indefinitely
  • Healthy. Not the problem.

Supabase realtime WS

wss://qdgjvtsntmehftjdfhop.supabase.co/realtime/v1/websocket?...

  • Status 101 Switching Protocols
  • Receives phoenix heartbeat and phx_reply {status:"ok"} every 15s
  • During the 35s tool-call timeout window, only heartbeats arrive. No design:doc-sync: broadcast carrying the tool command is ever delivered.

So the browser is correctly subscribed to design:doc-sync:<docId>, but the backend never broadcasts (or fails to deliver) the tool-call message to it on this machine.

Ruled out

  • VPN / Firefox Enhanced Tracking Protection
  • MCP package version (latest 0.7.1)
  • Stale doc — happens on brand-new empty docs
  • Reachability — efecto.app 200, Supabase auth health 401 (expected)
  • Stale MCP processes — only one running, restarted Claude Code
  • Sign-out / sign-in fresh JWT on Air
  • Multi-session conflict — closed all other tabs on Mini, still fails
  • Account mismatch — confirmed same email/account works on Mini

Unrelated noise (mention only so you can ignore)

  • [BrandKit Sync] Pull failed: Could not find the table 'public.brand_kits' in the schema cache
  • [UserProfile Sync] Pull failed: Could not find the table 'public.user_profile' in the schema cache
  • Cookie '__cf_bm' has been rejected for invalid domain. websocket
  • Multiple GoTrueClient instances detected in the same browser context

Sample session IDs (Air, 2026-05-11)

  • 9372ae56-9091-403b-9f1a-380fe44b6703 (doc f77772b3-84ab-4530-b643-b4e6b364ed30)
  • d09a5c07-018b-4b66-9ee9-cdcb5725922b (doc c13b9f49-9284-495e-8fea-d3e0a28a2b7b)
  • 042272ff-ec5f-44dc-8d0b-7e174c039ce9 (doc 28b6df91-1fe7-4699-95f8-bbb903aac636)

Hypothesis

Tool-call commands are published from MCP server → Efecto backend → broadcast on design:doc-sync:<docId> to the subscribed browser. The initial Unauthorized on doc-sync (even though it retries to SUBSCRIBED) suggests the channel-auth check briefly fails for this session/JWT on this machine. After it flips to SUBSCRIBED the browser believes it's subscribed, but my best guess is the publisher side (or the channel-auth state in your backend) still treats the subscription as unauthorized and either skips the broadcast or routes it nowhere.

Something is environmental to Air (since Mini, same account, works), but not anything visible to me on the browser side. Happy to capture additional logs if helpful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions