Skip to main content

Overview

The WebSocket relay is a lightweight Bun-powered server that acts as a message router between MCP servers and Figma plugins. It runs on port 3055 by default and provides channel-based message isolation.

Why a Relay Server?

The relay solves several architectural challenges:
MCP servers communicate via stdio with AI agents, but need WebSocket connectivity to reach Figma plugins. The relay bridges this gap.
Multiple users can run MCP servers simultaneously on the same machine. The relay uses channel isolation to prevent message conflicts.
The relay handles WebSocket lifecycle events (connect, disconnect, reconnect) and maintains client state across channels.
The relay efficiently broadcasts messages to all clients in a channel except the sender, preventing echo loops.

Server Architecture

Core Components

socket.ts

Data Structures

The relay uses a Map of Sets to organize clients by channel:
This structure provides O(1) channel lookups and O(n) broadcast operations within a channel.

Connection Lifecycle

1. Client Connection

When a client connects, they receive a welcome message:
socket.ts
Clients cannot send or receive messages until they join a channel.

2. Joining a Channel

Clients send a join message to enter a channel:
The relay processes the join request:
socket.ts

3. Sending Messages

Once in a channel, clients can exchange messages:
The relay broadcasts to channel members:
socket.ts
The relay excludes the sender from broadcasts to prevent echo loops and ensure clean request-response flow.

4. Client Disconnection

When a client disconnects, they’re removed from all channels:
socket.ts

Message Format

Join Message

Regular Message

Broadcast Message (relayed)

System Message

Error Message

Configuration

Port Configuration

The relay port is configurable via environment variable:
Read from environment in code:
socket.ts

Host Configuration

For WSL or remote access, uncomment the hostname option:
socket.ts
Binding to 0.0.0.0 exposes the relay to your network. Only use this in trusted environments.

CORS Headers

The relay includes CORS headers for browser-based clients:
socket.ts

Logging and Debugging

The relay provides detailed console logging:
socket.ts

Example Log Output

Performance Characteristics

Benchmarks

  • Channel lookup: O(1) using Map
  • Client broadcast: O(n) where n = clients in channel
  • Join/leave: O(1) for Set operations
  • Memory: ~100 bytes per client per channel

Scalability

The relay is designed for local development, not high-scale production:
  • Supported: 1-10 clients per channel, 1-10 active channels
  • Memory: Grows linearly with client count
  • CPU: Minimal (less than 1% on modern hardware)
  • Network: No compression or batching optimizations
For production deployments, consider using a battle-tested WebSocket server like Socket.IO or Centrifugo.

Starting the Relay

Development Mode

Production Mode

For production, use a process manager like PM2:

Docker Deployment

Example Dockerfile for containerized deployment:
Build and run:

Error Handling

The relay handles common error scenarios:

Invalid JSON

Missing Channel Name

Not in Channel

Troubleshooting

”Connection refused” on port 3055

Cause: Relay server is not running. Solution:

“No other clients in channel”

Cause: Only one client in the channel. Solution: Connect both MCP server and Figma plugin to the same channel:

Messages not routing

Cause: Clients in different channels. Solution: Verify channel names match exactly (case-sensitive):

Next Steps

System Architecture

Understand the full three-component pipeline

Channel Communication

Learn about channel-based isolation