Skip to main content
Glama
ui.html6.66 kB
<!doctype html> <html> <head> <style> body { font-family: Inter, sans-serif; font-size: 11px; padding: 8px; margin: 0; background: #2c2c2c; color: #fff; } .status { padding: 4px 8px; border-radius: 4px; } .connected { background: #1e4620; } .disconnected { background: #4a1e1e; } .connecting { background: #4a3a1e; } .status-row { display: flex; align-items: center; gap: 8px; } #reconnect-btn { display: none; padding: 4px 8px; border-radius: 4px; border: none; background: #0d99ff; color: #fff; font-size: 11px; cursor: pointer; } #reconnect-btn:hover { background: #0b85e0; } #reconnect-btn.visible { display: block; } .port-row { display: flex; align-items: center; gap: 6px; margin-top: 8px; } .port-label { color: #999; } #port-input { width: 60px; padding: 4px 6px; border-radius: 4px; border: 1px solid #444; background: #1e1e1e; color: #fff; font-size: 11px; } #port-input:focus { outline: none; border-color: #0d99ff; } </style> </head> <body> <div class="status-row"> <div id="status" class="status disconnected">Disconnected</div> <button id="reconnect-btn" onclick="manualReconnect()">Reconnect</button> </div> <div class="port-row"> <span class="port-label">Port:</span> <input type="number" id="port-input" value="3055" min="1024" max="65535" onchange="changePort()" /> </div> <script> const CONFIG = { defaultPort: 3055, reconnectMaxAttempts: 10, reconnectBaseDelay: 1000, reconnectMaxDelay: 30000, }; let socket = null; let reconnectAttempts = 0; let reconnectTimer = null; const statusEl = document.getElementById("status"); const reconnectBtn = document.getElementById("reconnect-btn"); const portInput = document.getElementById("port-input"); function getServerUrl() { const port = parseInt(portInput.value, 10) || CONFIG.defaultPort; return "ws://localhost:" + port; } function changePort() { // Disconnect from current server and connect to new port if (socket) { socket.close(1000, "Port changed"); socket = null; } if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; } reconnectAttempts = 0; connect(); } function setStatus(state, text) { statusEl.textContent = text; statusEl.className = "status " + state; // Show reconnect button only when disconnected or failed if (state === "disconnected") { reconnectBtn.classList.add("visible"); } else { reconnectBtn.classList.remove("visible"); } } function manualReconnect() { if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; } reconnectAttempts = 0; connect(); } function connect() { if (socket && socket.readyState === WebSocket.OPEN) return; setStatus("connecting", "Connecting..."); try { socket = new WebSocket(getServerUrl()); socket.onopen = () => { console.log("[UI] Connected to port " + portInput.value); setStatus("connected", "Connected: " + portInput.value); reconnectAttempts = 0; // Ask main thread for handshake info parent.postMessage( { pluginMessage: { type: "get_handshake_info" } }, "*", ); }; socket.onmessage = (event) => { let message; try { message = JSON.parse(event.data); } catch (e) { console.error("[UI] Parse error:", e); return; } if (message.type === "handshake_ack") { console.log("[UI] Handshake acknowledged"); return; } if (message.type === "ping") { socket.send( JSON.stringify({ type: "pong", timestamp: message.timestamp }), ); return; } // Forward commands to main thread if (message.requestId && message.command) { parent.postMessage( { pluginMessage: { type: "command", requestId: message.requestId, command: message.command, payload: message.payload || {}, }, }, "*", ); } }; socket.onclose = (event) => { console.log("[UI] Closed:", event.code); setStatus("disconnected", "Disconnected"); socket = null; if (event.code !== 1000) scheduleReconnect(); }; socket.onerror = (e) => console.error("[UI] Error:", e); } catch (error) { console.error("[UI] Failed:", error); scheduleReconnect(); } } function scheduleReconnect() { if (reconnectAttempts >= CONFIG.reconnectMaxAttempts) { setStatus("disconnected", "Failed"); return; } const delay = Math.min( CONFIG.reconnectBaseDelay * Math.pow(2, reconnectAttempts), CONFIG.reconnectMaxDelay, ); reconnectAttempts++; setStatus("connecting", "Retry in " + delay / 1000 + "s"); reconnectTimer = setTimeout(connect, delay); } function sendToServer(data) { if (socket && socket.readyState === WebSocket.OPEN) { socket.send(JSON.stringify(data)); } } // Messages from main thread window.onmessage = (event) => { const msg = event.data.pluginMessage; if (!msg) return; if (msg.type === "handshake_info") { sendToServer({ type: "handshake", payload: msg.payload }); } else if (msg.type === "command_response") { sendToServer({ responseTo: msg.requestId, payload: msg.payload }); } }; connect(); </script> </body> </html>

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/magic-spells/figma-mcp-bridge'

If you have feedback or need assistance with the MCP directory API, please join our Discord server