Skip to main content
Glama

GlassCloud

Servidor en la nube para Rokid Bridge y GlassBridge: gestiona la vinculación de dispositivos, el retransmisor de herramientas MCP, el almacenamiento de imágenes con galería y la descripción de escenas mediante LLM en el lado del servidor.

Qué hace

GlassCloud es el backend para las aplicaciones de gafas inteligentes Rokid. Proporciona:

  1. Vinculación de dispositivos — Emparejamiento mediante código QR o token entre la consola web y la aplicación de Android.

  2. Retransmisor de herramientas MCP — Proxy para llamadas a herramientas de Gmail y Calendar desde las gafas a las APIs de Google a través de WebSocket.

  3. Galería de imágenes — Recibe imágenes de escenas subidas desde las gafas, las almacena con metadatos y las muestra en una galería web.

  4. LLM en el lado del servidor — Cuando llega una imagen sin descripción, llama automáticamente a Gemini o ChatGPT para generar una y luego la devuelve a la aplicación para mostrarla en las gafas.

  5. Enlaces de galería pública — Tokens de uso compartido público por usuario para que las galerías puedan verse sin iniciar sesión.

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  Rokid Glasses  │────▶│   GlassCloud    │────▶│  Google APIs    │
│  + Android App  │ WS  │  (This Server)  │     │  Gmail/Calendar │
└─────────────────┘     └─────────────────┘     └─────────────────┘
                               │  │
                    REST API   │  │  Server-side LLM
                               ▼  ▼
                        ┌─────────────────┐
                        │  Web Console    │
                        │  Gallery · LLM  │
                        │  Settings · QR  │
                        └─────────────────┘

Inicio rápido

# Install dependencies
npm install

# Copy and fill in environment variables
cp .env.example .env
# Edit .env — see Configuration section below

# Development (auto-reload)
npm run dev

# Production build + run
npm run build
npm start

Abra http://localhost:3000/console para acceder a la consola web.


Configuración

Todas las variables de entorno se validan al inicio con Zod. El servidor imprimirá los campos faltantes y se cerrará si faltan variables requeridas.

Generación de secretos

node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"

Ejecute esto dos veces: una para JWT_SECRET y otra para ENCRYPTION_KEY.

Variables requeridas

Variable

Descripción

JWT_SECRET

Firma los JWT del dispositivo. Mín. 32 caracteres. Debe ser aleatorio y secreto.

ENCRYPTION_KEY

Cifra los tokens OAuth y las claves API de LLM en reposo (AES-256-GCM). Mín. 32 caracteres.

GOOGLE_CLIENT_ID

ID de cliente de Google OAuth 2.0

GOOGLE_CLIENT_SECRET

Secreto de cliente de Google OAuth 2.0

GOOGLE_CALLBACK_URL

URI de redirección de OAuth: debe coincidir con lo registrado en Google Cloud Console (ej. https://yourserver.com/auth/google/callback)

Variables opcionales

Variable

Predeterminado

Descripción

PORT

3000

Puerto del servidor HTTP

NODE_ENV

development

development

production

test

LOG_LEVEL

info

trace

debug

info

warn

error

fatal

DATABASE_PATH

./data/glasscloud.db

Ruta del archivo de base de datos SQLite

CORS_ORIGINS

http://localhost:3000

Lista separada por comas de orígenes CORS permitidos

RATE_LIMIT_WINDOW_MS

60000

Ventana de límite de tasa en milisegundos

RATE_LIMIT_MAX_REQUESTS

60

Máximo de solicitudes por ventana por IP (se aplica a /api/*)

WS_PING_INTERVAL_MS

30000

Intervalo de ping de mantenimiento de WebSocket

WS_PONG_TIMEOUT_MS

10000

Tiempo de espera para pong antes de cerrar la conexión

Ejemplo de .env

PORT=3000
NODE_ENV=production
LOG_LEVEL=info
DATABASE_PATH=./data/glasscloud.db

JWT_SECRET=<generate with command above>
ENCRYPTION_KEY=<generate with command above>

CORS_ORIGINS=https://yourserver.com

GOOGLE_CLIENT_ID=123456789.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-xxxxx
GOOGLE_CALLBACK_URL=https://yourserver.com/auth/google/callback

Configuración de Google OAuth

  1. Vaya a Google Cloud Console → APIs & Credentials

  2. Cree un ID de cliente de OAuth 2.0 (Aplicación web)

  3. Añada su URL de callback a URIs de redirección autorizados: https://yourserver.com/auth/google/callback

  4. Habilite la API de Gmail y la API de Google Calendar en el proyecto

  5. Añada usuarios de prueba en Pantalla de consentimiento de OAuth → Usuarios de prueba (requerido mientras la aplicación está en modo de prueba)

Nota sobre los alcances de Google: Esta aplicación solicita gmail.readonly y calendar.events. Para una implementación pública con más de 100 usuarios, Google requiere una evaluación de seguridad CASA. Para uso privado o de prueba, mantenga la aplicación en modo de prueba.


Configuración de LLM (Descripción de escenas en el servidor)

GlassCloud puede generar automáticamente descripciones de escenas para imágenes subidas sin una (ej. cuando la aplicación Rokid está en modo "Bypass LLM"). La descripción generada es:

  • Guardada en la base de datos y mostrada en la galería

  • Devuelta en la respuesta de la API de subida para que la aplicación pueda mostrarla en las gafas inmediatamente

Configuración

  1. Inicie sesión en /console y haga clic en LLM Settings → en el encabezado

  2. Seleccione un proveedor (Gemini o ChatGPT) y pegue su clave API

  3. Opcionalmente, añada prompts personalizados y seleccione uno como activo

El prompt predeterminado es: "Describe la escena en esta imagen de forma concisa."

Claves API

Proveedor

Dónde obtenerla

Gemini

Google AI Studio → API keys

ChatGPT

OpenAI Platform → API keys

Las claves API se cifran en reposo usando ENCRYPTION_KEY (AES-256-GCM). Si no hay ninguna clave API configurada, el LLM del lado del servidor se omite silenciosamente y las imágenes con descripciones vacías se almacenan tal cual.


Páginas de la consola web

URL

Descripción

/console

Panel: estadísticas, vinculación de dispositivos, gestión de servicios MCP

/console/link

Generar código QR / token de enlace para emparejar un dispositivo

/console/gallery

Galería de imágenes (vista de tabla con miniaturas, detalles, eliminar)

/console/gallery/photo/:id

Imagen a tamaño completo con metadatos

/console/settings/llm

Gestión de proveedor de LLM, clave API y prompt

/public/gallery/:token

Galería pública (no requiere inicio de sesión)

/public/gallery/:token/photo/:id

Detalles de foto pública


Endpoints de la API REST

Dispositivo y autenticación

Endpoint

Método

Autenticación

Descripción

/health

GET

Ninguna

Comprobación de estado con estadísticas de conexión

/auth/google

GET

Ninguna

Iniciar flujo de Google OAuth

/auth/google/callback

GET

Ninguna

Callback de OAuth

/api/link/exchange

POST

Ninguna

Intercambiar token de enlace por JWT de dispositivo

/api/devices

GET

JWT Dispositivo

Listar dispositivos vinculados

/api/devices/:id

DELETE

Sesión

Desvincular un dispositivo

Imágenes

Endpoint

Método

Autenticación

Descripción

/api/images/upload

POST

JWT Dispositivo

Subir imagen + metadatos (multipart/form-data)

/api/images/:id

GET

JWT Dispositivo

Obtener metadatos de imagen por ID

Campos de subida

Campo

Tipo

Requerido

Descripción

image

archivo

JPEG, PNG o WebP — máx. 20 MB

scene_description

string

Descripción de la escena (puede ser cadena vacía)

device_model

string

Nombre del modelo del dispositivo

device_instance_id

string

Identificador único del dispositivo

captured_at

string

No

Marca de tiempo ISO 8601 cuando se capturó la imagen

image_width

número

No

Ancho de la imagen en píxeles

image_height

número

No

Alto de la imagen en píxeles

llm_provider

string

No

LLM usado en el dispositivo (ej. Gemini, ChatGPT, None)

Si scene_description está vacío y hay un LLM de servidor configurado, el servidor llamará al LLM e incluirá llmDescription en la respuesta:

{
  "imageId": "uuid",
  "originalFilename": "uuid.jpg",
  "thumbnailFilename": "uuid_thumb.jpg",
  "receivedAt": 1714000000000,
  "capturedAt": 1714000000000,
  "llmDescription": "A person walking through a crowded market..."
}

MCP

Endpoint

Método

Autenticación

Descripción

/api/mcp/services

GET

JWT Dispositivo

Listar servicios y herramientas MCP disponibles


Protocolo WebSocket

Conectar en: ws://localhost:3000/ws?deviceId=YOUR_DEVICE_ID

Cliente → Servidor

// Execute a tool
{ "type": "tool_execute", "requestId": "uuid", "serverId": "gmail",
  "toolName": "gmail.get_unread", "arguments": { "maxResults": 10 } }

// Link device to user account
{ "type": "link_device", "requestId": "uuid",
  "linkToken": "from-qr-code", "deviceId": "..." }

// Get user account info
{ "type": "get_user_account", "requestId": "uuid", "deviceId": "..." }

Servidor → Cliente

// Immediate progress (for voice feedback while tool runs)
{ "type": "tool_progress", "requestId": "uuid",
  "status": "executing", "message": "Checking your emails..." }

// Tool result
{ "type": "tool_result", "requestId": "uuid",
  "result": { "success": true, "content": "You have 3 unread emails..." } }

// Error
{ "type": "error", "requestId": "uuid", "error": "Token expired" }

Herramientas MCP disponibles

Gmail

Herramienta

Descripción

gmail.get_unread

Obtener recuento y resúmenes de correos no leídos

gmail.search

Buscar correos por consulta

gmail.get_message

Obtener contenido completo del correo por ID

Calendar

Herramienta

Descripción

calendar.get_today

Obtener eventos de hoy

calendar.get_events

Obtener eventos para N días

calendar.create_event

Crear un nuevo evento


Esquema de base de datos

La base de datos es SQLite con modo WAL. El esquema se crea al inicio; las nuevas columnas se añaden mediante migraciones idempotentes.

-- Users (from Google OAuth)
users (
  id, google_id, email, display_name, profile_picture_url,
  public_gallery_token,          -- UUID for public gallery share link
  llm_provider,                  -- 'Gemini' or 'ChatGPT' (default: 'Gemini')
  openai_api_key_encrypted,      -- AES-256-GCM encrypted
  gemini_api_key_encrypted,      -- AES-256-GCM encrypted
  active_prompt_id,              -- FK to llm_prompts.id
  created_at, updated_at
)

-- Linked devices
devices (id, user_id, device_name, device_model, last_seen_at, last_heartbeat_at, linked_at, created_at)

-- QR code link tokens (single-use, 5 min expiry)
link_tokens (id, user_id, expires_at, used_at, used_by_device_id, created_at)

-- Encrypted Google OAuth tokens
oauth_tokens (id, user_id, provider, access_token_encrypted, refresh_token_encrypted, ...)

-- Scene images from glasses
glass_images (
  id, device_model, device_instance_id,
  scene_description,             -- May be empty; server-side LLM fills it if blank
  original_filename, thumbnail_filename,
  captured_at, received_at, created_at,
  image_width, image_height,     -- Pixels (nullable)
  user_id,                       -- FK to users.id (nullable for legacy rows)
  llm_provider                   -- Which LLM generated the description
)

-- User-defined LLM prompts
llm_prompts (id, user_id, name, text, created_at)

-- Third-party MCP servers registered via console
third_party_mcp_services (id, name, description, owner_user_id, endpoint_url, auth_type, auth_config_encrypted, tools_json, ...)

Estructura de directorios

src/
├── index.ts                    # Entry point — starts HTTP + WebSocket servers
├── config/
│   ├── env.ts                  # Zod environment validation (exits on invalid config)
│   └── mcp-services.ts         # Built-in MCP service definitions
├── server/
│   ├── express.ts              # Express app — middleware, route mounting, error handling
│   ├── sessions.ts             # In-memory session store for console auth
│   └── websocket.ts            # WebSocket server with zombie connection cleanup
├── routes/
│   ├── auth.ts                 # Google OAuth flow
│   ├── console.ts              # Web console dashboard
│   ├── devices.ts              # Device management API
│   ├── gallery.ts              # Image gallery (authenticated + public)
│   ├── health.ts               # Health check
│   ├── images.ts               # Image upload + retrieval API
│   ├── link.ts                 # QR code token generation
│   ├── mcp.ts                  # MCP services API
│   └── settings.ts             # LLM settings page
├── services/
│   ├── auth.service.ts         # OAuth + token refresh mutex
│   ├── device.service.ts       # Device CRUD
│   ├── image.service.ts        # Image save/list/delete + thumbnail generation
│   ├── link.service.ts         # QR code token handling
│   ├── llm.service.ts          # LLM settings CRUD + callLlm() (Gemini / ChatGPT)
│   ├── mcp-proxy.service.ts    # MCP tool execution with input coercion
│   └── mcp-registry.service.ts # Third-party MCP server registry
├── websocket/
│   ├── handler.ts              # Message routing with progress feedback
│   ├── protocol.ts             # Message type definitions
│   └── connection.ts           # Connection tracking
├── db/
│   ├── index.ts                # SQLite connection + WAL mode
│   └── schema.ts               # CREATE TABLE + ALTER TABLE migrations
├── utils/
│   ├── crypto.ts               # AES-256-GCM encrypt/decrypt + token generation
│   ├── logger.ts               # Pino structured logging
│   └── cache.ts                # LRU cache for MCP tool results
└── types/
    ├── api.ts                  # REST API types
    ├── mcp.ts                  # MCP types
    └── websocket.ts            # WebSocket message types

Los archivos de datos se escriben en ./data/:

  • ./data/glasscloud.db — Base de datos SQLite

  • ./data/images/ — Imágenes originales subidas

  • ./data/thumbnails/ — Miniaturas JPEG de 400×400 (generadas por Sharp)


Seguridad

  • Tokens OAuth cifrados en reposo con AES-256-GCM usando ENCRYPTION_KEY

  • Claves API de LLM cifradas en reposo con la misma clave

  • JWT de dispositivos firmados con JWT_SECRET (HS256); verificados en cada solicitud API

  • Tokens de enlace almacenados solo como hash SHA-256; de un solo uso; caducidad de 5 minutos

  • Límite de tasa en todas las rutas /api/* (configurable vía env)

  • Cabeceras de seguridad Helmet en todas las respuestas

  • Tokens de galería pública son UUIDs aleatorios; regenerar uno revoca instantáneamente el enlace anterior


Licencia

MIT

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

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/jerryliu816/glasscloud'

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