diff --git a/mcp/packages/plugin/src/main.ts b/mcp/packages/plugin/src/main.ts index 17744bf5e0..13342069a6 100644 --- a/mcp/packages/plugin/src/main.ts +++ b/mcp/packages/plugin/src/main.ts @@ -1,7 +1,5 @@ import "./style.css"; -const KEEP_ALIVE_TIME = 30000; // 30 seconds - // get the current theme from the URL const searchParams = new URLSearchParams(window.location.search); document.body.dataset.theme = searchParams.get("theme") ?? "light"; @@ -75,10 +73,6 @@ function connectToMcpServer(baseUrl?: string, token?: string): void { ws.onmessage = (event) => { try { - if (event.data === "keep-alive") { - // Keep alive response, ignore it - return; - } console.log("Received from MCP server:", event.data); const request = JSON.parse(event.data); // Forward the task request to the plugin for execution @@ -88,11 +82,8 @@ function connectToMcpServer(baseUrl?: string, token?: string): void { } }; - const interval = setInterval(() => ws?.send("keep-alive"), KEEP_ALIVE_TIME); - ws.onclose = (event: CloseEvent) => { console.log("Disconnected from MCP server"); - clearInterval(interval); const message = event.reason || undefined; updateConnectionStatus("disconnected", "Disconnected", false, message); ws = null; diff --git a/mcp/packages/server/src/PluginBridge.ts b/mcp/packages/server/src/PluginBridge.ts index ebdc38f819..10dfb5eeb9 100644 --- a/mcp/packages/server/src/PluginBridge.ts +++ b/mcp/packages/server/src/PluginBridge.ts @@ -5,6 +5,8 @@ import { PluginTaskResponse, PluginTaskResult } from "@penpot/mcp-common"; import { createLogger } from "./logger"; import type { PenpotMcpServer } from "./PenpotMcpServer"; +const KEEP_ALIVE_TIME = 30000; // 30 seconds + interface ClientConnection { socket: WebSocket; userToken: string | null; @@ -38,6 +40,8 @@ export class PluginBridge { * channel between the MCP mcpServer and Penpot plugin instances. */ private setupWebSocketHandlers(): void { + let interval: NodeJS.Timeout | undefined; + this.wsServer.on("connection", (ws: WebSocket, request: http.IncomingMessage) => { // extract userToken from query parameters const url = new URL(request.url!, `ws://${request.headers.host}`); @@ -72,10 +76,6 @@ export class PluginBridge { ws.on("message", (data: Buffer) => { this.logger.debug("Received WebSocket message: %s", data.toString()); try { - if (data.toString() === "keep-alive") { - ws.send("keep-alive"); - return; - } const response: PluginTaskResponse = JSON.parse(data.toString()); this.handlePluginTaskResponse(response); } catch (error) { @@ -90,6 +90,9 @@ export class PluginBridge { if (connection?.userToken) { this.clientsByToken.delete(connection.userToken); } + if (interval) { + clearInterval(interval); + } }); ws.on("error", (error) => { @@ -99,7 +102,14 @@ export class PluginBridge { if (connection?.userToken) { this.clientsByToken.delete(connection.userToken); } + if (interval) { + clearInterval(interval); + } }); + + interval = setInterval(() => { + ws?.ping(); + }, KEEP_ALIVE_TIME); }); this.logger.info("WebSocket mcpServer started on port %d", this.port);