MCPcopy
hub / github.com/southleft/figma-console-mcp / start

Method start

src/core/websocket-server.ts:196–338  ·  view source on GitHub ↗

* Start the HTTP + WebSocket server. * HTTP serves the plugin UI content; WebSocket handles plugin communication.

()

Source from the content-addressed store, hash-verified

194 * HTTP serves the plugin UI content; WebSocket handles plugin communication.
195 */
196 async start(): Promise<void> {
197 if (this._isStarted) return;
198
199 return new Promise((resolve, reject) => {
200 let rejected = false;
201 const rejectOnce = (error: any) => {
202 if (!rejected) {
203 rejected = true;
204 reject(error);
205 }
206 };
207
208 try {
209 // Create HTTP server first — handles plugin UI requests
210 this.httpServer = createHttpServer((req, res) => this.handleHttpRequest(req, res));
211
212 // Attach WebSocket server to the HTTP server (shares the same port)
213 this.wss = new WSServer({
214 server: this.httpServer,
215 maxPayload: 100 * 1024 * 1024, // 100MB — screenshots and large component data can be big
216 verifyClient: (info, callback) => {
217 // Mitigate Cross-Site WebSocket Hijacking (CSWSH):
218 // Reject connections from unexpected browser origins.
219 const origin = info.origin;
220 // Exact match only — startsWith would let e.g.
221 // https://www.figma.com.attacker.example through.
222 const allowed =
223 !origin || // No origin — local process (e.g. Node.js client)
224 origin === 'null' || // Sandboxed iframe / Figma Desktop plugin UI
225 origin === 'https://www.figma.com' ||
226 origin === 'https://figma.com';
227 if (allowed) {
228 callback(true);
229 } else {
230 logger.warn({ origin }, 'Rejected WebSocket connection from unauthorized origin');
231 callback(false, 403, 'Unauthorized Origin');
232 }
233 },
234 });
235
236 // Error handler for startup failures (EADDRINUSE, etc.)
237 // Must be on BOTH httpServer and wss — the WSS re-emits HTTP server errors
238 // and throws if no listener is attached.
239 const onStartupError = (error: any) => {
240 if (!this._isStarted) {
241 try { if (this.wss) { this.wss.close(); this.wss = null; } } catch { /* ignore */ }
242 try { if (this.httpServer) { this.httpServer.close(); this.httpServer = null; } } catch { /* ignore */ }
243 rejectOnce(error);
244 } else {
245 logger.error({ error }, 'HTTP/WebSocket server error');
246 }
247 };
248
249 this.httpServer.on('error', onStartupError);
250 this.wss.on('error', onStartupError);
251
252 // Start listening on the HTTP server (which also handles WS upgrades)
253 this.httpServer.listen(this.options.port, this.options.host || 'localhost', () => {

Callers

nothing calls this directly

Calls 15

handleHttpRequestMethod · 0.95
startHeartbeatMethod · 0.95
handleMessageMethod · 0.95
findClientByWsMethod · 0.95
warnMethod · 0.80
addressMethod · 0.80
toStringMethod · 0.80
errorMethod · 0.80
nowMethod · 0.80
infoMethod · 0.65
hasMethod · 0.65

Tested by

no test coverage detected