Skip to main content
Glama

GlassCloud

用于 Rokid Bridge 和 GlassBridge 的云服务器——处理设备链接、MCP 工具中继、带图库的图像存储以及服务器端 LLM 场景描述。

功能概述

GlassCloud 是 Rokid 智能眼镜应用的后端。它提供:

  1. 设备链接 — Web 控制台与 Android 应用之间的二维码或基于令牌的配对

  2. MCP 工具中继 — 通过 WebSocket 将来自眼镜的 Gmail 和日历工具调用代理到 Google API

  3. 图像库 — 接收从眼镜上传的场景图像,存储并附带元数据,并在 Web 图库中显示

  4. 服务器端 LLM — 当接收到没有描述的图像时,自动调用 Gemini 或 ChatGPT 生成描述,然后返回给应用以在眼镜上显示

  5. 公共图库链接 — 每个用户拥有公共共享令牌,无需登录即可查看图库

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

快速开始

# 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

打开 http://localhost:3000/console 访问 Web 控制台。


配置

所有环境变量在启动时都会通过 Zod 进行验证。如果缺少必需变量,服务器将打印缺失字段并退出。

生成密钥

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

运行此命令两次——一次用于 JWT_SECRET,一次用于 ENCRYPTION_KEY。

必需变量

变量

描述

JWT_SECRET

签署设备 JWT。至少 32 个字符。必须是随机且保密的。

ENCRYPTION_KEY

在静态存储时加密 OAuth 令牌和 LLM API 密钥 (AES-256-GCM)。至少 32 个字符。

GOOGLE_CLIENT_ID

Google OAuth 2.0 客户端 ID

GOOGLE_CLIENT_SECRET

Google OAuth 2.0 客户端密钥

GOOGLE_CALLBACK_URL

OAuth 重定向 URI — 必须与 Google Cloud 控制台中注册的内容匹配(例如 https://yourserver.com/auth/google/callback)

可选变量

变量

默认值

描述

PORT

3000

HTTP 服务器端口

NODE_ENV

development

development

production

test

LOG_LEVEL

info

trace

debug

info

warn

error

fatal

DATABASE_PATH

./data/glasscloud.db

SQLite 数据库文件路径

CORS_ORIGINS

http://localhost:3000

允许的 CORS 源列表(逗号分隔)

RATE_LIMIT_WINDOW_MS

60000

速率限制窗口(毫秒)

RATE_LIMIT_MAX_REQUESTS

60

每个 IP 每个窗口的最大请求数(适用于 /api/*)

WS_PING_INTERVAL_MS

30000

WebSocket 保活 ping 间隔

WS_PONG_TIMEOUT_MS

10000

关闭连接前等待 pong 的时间

.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

Google OAuth 设置

  1. 前往 Google Cloud Console → APIs & Credentials

  2. 创建一个 OAuth 2.0 客户端 ID (Web 应用)

  3. 将您的回调 URL 添加到 已获授权的重定向 URI:https://yourserver.com/auth/google/callback

  4. 在项目中启用 Gmail API 和 Google Calendar API

  5. 在 OAuth 同意屏幕 → 测试用户 下添加测试用户(应用处于测试模式时必需)

关于 Google 作用域的说明: 此应用请求 gmail.readonly 和 calendar.events。对于超过 100 个用户的公共部署,Google 要求进行 CASA 安全评估。对于私人或测试用途,请保持应用处于测试模式。


LLM 设置(服务器端场景描述)

GlassCloud 可以自动为未附带描述的上传图像生成场景描述(例如当 Rokid 应用处于“绕过 LLM”模式时)。生成的描述将:

  • 保存到数据库并显示在图库中

  • 在上传 API 响应中返回,以便应用可以立即将其显示在眼镜上

配置

  1. 在 /console 登录并点击标题中的 LLM Settings →

  2. 选择一个提供商(Gemini 或 ChatGPT)并粘贴您的 API 密钥

  3. 可选地添加自定义提示词并选择一个作为激活状态

默认提示词为:"Describe the scene in this image concisely."

API 密钥

API 密钥使用 ENCRYPTION_KEY (AES-256-GCM) 进行静态加密。如果未配置 API 密钥,服务器端 LLM 将被静默跳过,且带有空描述的图像将按原样存储。


Web 控制台页面

URL

描述

/console

仪表板:统计信息、设备链接、MCP 服务管理

/console/link

生成用于配对设备的二维码/链接令牌

/console/gallery

图像库(带缩略图、详情、删除功能的表格视图)

/console/gallery/photo/:id

带有元数据的全尺寸图像

/console/settings/llm

LLM 提供商、API 密钥和提示词管理

/public/gallery/:token

公共图库(无需登录)

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

公共照片详情


REST API 端点

设备与认证

端点

方法

认证

描述

/health

GET

无

带有连接统计信息的健康检查

/auth/google

GET

无

发起 Google OAuth 流程

/auth/google/callback

GET

无

OAuth 回调

/api/link/exchange

POST

无

将链接令牌交换为设备 JWT

/api/devices

GET

设备 JWT

列出已链接的设备

/api/devices/:id

DELETE

会话

取消链接设备

图像

端点

方法

认证

描述

/api/images/upload

POST

设备 JWT

上传图像 + 元数据 (multipart/form-data)

/api/images/:id

GET

设备 JWT

按 ID 获取图像元数据

上传字段

字段

类型

必需

描述

image

文件

是

JPEG, PNG, 或 WebP — 最大 20 MB

scene_description

字符串

是

场景描述(可以是空字符串)

device_model

字符串

是

设备型号名称

device_instance_id

字符串

是

唯一设备标识符

captured_at

字符串

否

图像捕获时的 ISO 8601 时间戳

image_width

数字

否

图像宽度(像素)

image_height

数字

否

图像高度(像素)

llm_provider

字符串

否

设备端使用的 LLM(例如 Gemini, ChatGPT, None)

如果 scene_description 为空且配置了服务器端 LLM,服务器将调用 LLM 并在响应中包含 llmDescription:

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

MCP

端点

方法

认证

描述

/api/mcp/services

GET

设备 JWT

列出可用的 MCP 服务和工具


WebSocket 协议

连接地址:ws://localhost:3000/ws?deviceId=YOUR_DEVICE_ID

客户端 → 服务器

// 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": "..." }

服务器 → 客户端

// 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" }

可用 MCP 工具

Gmail

工具

描述

gmail.get_unread

获取未读邮件数量和摘要

gmail.search

按查询搜索邮件

gmail.get_message

按 ID 获取完整邮件内容

日历

工具

描述

calendar.get_today

获取今天的日程

calendar.get_events

获取 N 天内的日程

calendar.create_event

创建新日程


数据库架构

数据库为处于 WAL 模式的 SQLite。架构在启动时创建;新列通过幂等迁移添加。

-- 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, ...)

目录结构

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

数据文件写入 ./data/:

  • ./data/glasscloud.db — SQLite 数据库

  • ./data/images/ — 原始上传图像

  • ./data/thumbnails/ — 400×400 JPEG 缩略图(由 Sharp 生成)


安全性

  • OAuth 令牌 使用 ENCRYPTION_KEY 进行 AES-256-GCM 静态加密

  • LLM API 密钥 使用相同的密钥进行静态加密

  • 设备 JWT 使用 JWT_SECRET (HS256) 签名;在每个 API 请求上进行验证

  • 链接令牌 仅以 SHA-256 哈希形式存储;单次使用;5 分钟过期

  • 所有 /api/* 路由上的 速率限制(可通过环境变量配置)

  • 所有响应上的 Helmet 安全标头

  • 公共图库令牌 为随机 UUID;重新生成一个会立即撤销之前的链接


许可证

MIT

Related MCP Connectors