Skip to main content
Glama
SarjuThakkar

Skylight MCP server

by SarjuThakkar

Servidor MCP de Skylight

Permite que un anillo Pebble Index añada eventos por voz a un calendario familiar de Skylight. El agente en la nube de Pebble es el cliente MCP; este servidor se encarga del trabajo HTTP contra la API no oficial de Skylight. Pebble nunca se comunica directamente con Skylight, y Skylight nunca ve tu cuenta de Pebble.

La única herramienta expuesta es create_event (solo escritura: Pebble no necesita volver a leer el calendario, y eliminar list_events mantuvo la superficie de herramientas sin ambigüedades). Puede etiquetar automáticamente un perfil de miembro de la familia predeterminado y entiende "me"/"myself" como esa persona, o cualquier otro miembro por nombre.

Transporte: Streamable HTTP. Autenticación: un token Bearer estático en la cabecera Authorization (Pebble no admite flujos de inicio de sesión OAuth para servidores MCP personalizados, solo una cabecera fija).

¿Es reutilizable para el Pebble + Skylight de otra persona?

Sí: nada en el código está ligado a una persona concreta. Cada valor específico de la cuenta (inicio de sesión de Skylight, id del frame, zona horaria, qué miembro de la familia es el predeterminado, el token Bearer) proviene de una variable de entorno, y los nombres de los miembros de la familia se resuelven en vivo contra las categorías de tu Skylight, no están codificados. Cualquiera con su propia cuenta de Skylight, un Pebble Index y un lugar donde alojar un pequeño servicio HTTP en Python puede ejecutar su propia copia. Ver Despliegue más abajo: es un puñado de comandos de CLI, no una edición manual de código.

Related MCP server: Google Calendar AutoAuth MCP Server

Variables de entorno

Variable

Obligatoria

Descripción

SKYLIGHT_EMAIL

Tu correo de inicio de sesión de app.ourskylight.com.

SKYLIGHT_PASSWORD

Tu contraseña de inicio de sesión de app.ourskylight.com.

SKYLIGHT_FRAME_ID

El número de app.ourskylight.com/calendar/<id> con la sesión iniciada.

MCP_BEARER_TOKEN

Token estático que Pebble envía como Authorization: Bearer <token>. Genéralo con openssl rand -hex 32.

SKYLIGHT_TIMEZONE

no

Zona horaria IANA en la que se interpretan las horas de eventos naive. El valor por defecto es America/Chicago. Esto es también lo que el docstring de la herramienta le dice al agente de Pebble, por lo que se mantiene sincronizado automáticamente.

SKYLIGHT_DEFAULT_MEMBER

no

El nombre de perfil de un miembro de la familia de Skylight (debe coincidir con una etiqueta de categoría de tu calendario). Se usa cuando se omite who, y es a lo que se resuelven "me"/"myself"/"i". Déjalo sin definir para no etiquetar por defecto.

PORT

no

Lo establece automáticamente Railway/la mayoría de los hosts. El valor por defecto es 8000 localmente.

Configuración local

python3 -m venv .venv && source .venv/bin/activate   # needs Python 3.10+
pip install -r requirements.txt

cp .env.example .env   # then fill in real values
export $(grep -v '^#' .env | xargs)   # or use your own env loader
export MCP_BEARER_TOKEN=$(openssl rand -hex 32)

python skylight_mcp_server.py

El servidor escucha en http://0.0.0.0:8000 (o en $PORT si está definido), el endpoint de MCP en /mcp y la comprobación de salud en /healthz (no requiere autenticación).

Pruebas con MCP Inspector

npx @modelcontextprotocol/inspector

En la interfaz del Inspector:

  1. Transporte: Streamable HTTP

  2. URL: http://localhost:8000/mcp

  3. En Autenticación, añade la cabecera Authorization: Bearer <your MCP_BEARER_TOKEN>

  4. Conéctate, luego llama a create_event con un título de prueba y comprueba que llegó al perfil correcto en la aplicación Skylight.

Despliegue en Railway

Opción A: el asistente deploy.sh

export SKYLIGHT_EMAIL=you@example.com
export SKYLIGHT_PASSWORD=...
export SKYLIGHT_FRAME_ID=1234567
export MCP_BEARER_TOKEN=$(openssl rand -hex 32)
# optional:
export SKYLIGHT_TIMEZONE=America/Chicago
export SKYLIGHT_DEFAULT_MEMBER=YourName

./deploy.sh

Instala la CLI de Railway si no está presente, te pide que inicies sesión (OAuth en el navegador: esta parte no se puede automatizar), crea el proyecto en la primera ejecución, establece todas las variables de entorno, despliega e imprime la URL pública. Vuélvelo a ejecutar en cualquier momento después de editar skylight_mcp_server.py para enviar una nueva compilación: el enlace del proyecto se guarda en ~/.railway/config.json vinculado a este directorio, no en el repositorio, por lo que nada específico de Railway termina en git.

Opción B: a mano

railway login                                  # browser OAuth
railway init --name skylight-mcp               # first time only
railway variable set SKYLIGHT_EMAIL=you@example.com --service skylight-mcp --skip-deploys
railway variable set SKYLIGHT_PASSWORD=... --service skylight-mcp --skip-deploys
railway variable set SKYLIGHT_FRAME_ID=1234567 --service skylight-mcp --skip-deploys
railway variable set MCP_BEARER_TOKEN=$(openssl rand -hex 32) --service skylight-mcp
railway up -c -y --service skylight-mcp        # builds the Dockerfile, deploys
railway domain --service skylight-mcp          # public HTTPS URL, real cert

Volver a desplegar más tarde (ya seas tú, después de un cambio de código, o cualquier otra persona que ya haya ejecutado la configuración una vez) es simplemente:

railway up -c -y --service skylight-mcp

Esa es toda la historia del redespliegue: no hay archivo de configuración más allá del Dockerfile que ya está en este repositorio, ni pipeline de CI. railway logs --service skylight-mcp sigue los logs en vivo, lo cual es útil, ya que los argumentos de create_event se registran en cada llamada (ver Solución de problemas).

Apunta la configuración del cliente MCP de Pebble a https://<your-railway-domain>/mcp con el token Bearer de la configuración.

Configuración de la aplicación Pebble

En los ajustes del servidor MCP de la aplicación Pebble:

  • Nombre: lo que quieras, pero sin espacios ni caracteres especiales — ver Solución de problemas. Tanto SkylightCalendar como skylight-calendar funcionan.

  • URL: https://<your-railway-domain>/mcp

  • Transporte: Streamable (el menú desplegable dice literalmente "SSE/Streamable": elige Streamable, no SSE)

  • Autorización: Bearer <your MCP_BEARER_TOKEN> — la cadena completa, incluido el prefijo Bearer .

Las herramientas MCP personalizadas solo se ejecutan en el modo de grabación de doble clic de Pebble (el clic simple usa las acciones integradas de Pebble). Asegúrate de que este servidor esté asignado al grupo de sandbox que use tu doble clic.

Cómo funciona el etiquetado de miembros de la familia

Los miembros de la familia no están configurados en este servidor en absoluto: create_event llama a GET /frames/{id}/categories en tu cuenta real de Skylight (almacenado en caché en memoria por proceso) y compara el argumento who con esas etiquetas, sin distinguir mayúsculas de minúsculas. "me"/"myself"/"i" se resuelven a SKYLIGHT_DEFAULT_MEMBER. Si una coincidencia exacta falla, recurre a una coincidencia difusa (difflib) con las mismas etiquetas, ya que el reconocimiento de voz de Pebble puede distorsionar nombres menos comunes (p. ej., tanto "Metree" como "May Tree" siguen resolviéndose a "Maitree" — verificado en vivo). Los nombres que siguen sin coincidir con nada no bloquean el evento: se crea sin etiqueta de perfil, y la confirmación lo indica, de modo que un error de audición es visible en lugar de ser silenciosamente incorrecto.

Frases de ejemplo para probar

Cada una ejercita una parte diferente de la herramienta: después de decir una (doble clic en el anillo), revisa en Skylight la fecha/hora, si es de día completo o con hora, y qué perfil(es) se etiquetaron:

  • "Añade una cita con el dentista mañana a las 2 p. m." Evento con hora, usa el perfil de SKYLIGHT_DEFAULT_MEMBER por defecto, sin ubicación.

  • "Bloquea el próximo lunes como día de vacaciones." No se dice ninguna hora → se guarda como un evento de día completo (se detecta automáticamente a partir de la fecha sola: no necesitas decir "todo el día" para que funcione).

  • "Añade un viaje a Chicago del 2 al 3 de septiembre." Evento de día completo de varios días: abarca ambos días de forma inclusiva.

  • "Añade el corte de pelo de Maitree el próximo martes a las 10 a. m." who explícito: etiqueta el perfil de esa persona en lugar del predeterminado.

  • "Añade la noche de cine en familia el viernes a las 7 p. m. para Maitree y para mí." Etiquetado de varias personas: se guarda etiquetado para ambos.

  • "Añade una cita con el dentista en el consultorio del Dr. Smith el próximo miércoles a las 3 p. m." Prueba la captura del campo location.

Qué está verificado frente a lo asumido

La API de Skylight no es oficial y ha sido sometida a ingeniería inversa. El flujo de autenticación y las formas de los payloads de este servidor se probaron en vivo contra una cuenta real el 2026-08-26/27 (consulta el docstring del módulo en skylight_mcp_server.py para conocer los pasos exactos de inicio de sesión). Hallazgos notables que contradecían las suposiciones iniciales extraídas de una captura de OpenAPI de diciembre de 2025:

  • El antiguo inicio de sesión POST /api/sessions (correo/contraseña → autenticación Basic) está retirado: ahora devuelve 401 "This version of Skylight is no longer supported." El flujo real es un intercambio de código de autorización OAuth2 de 4 pasos (no se requiere PKCE para que este flujo tenga éxito, aunque también existe una variante con PKCE en el mundo real).

  • skylight-api-version: 2026-05-01 es obligatorio en cada llamada a la API.

  • date_max en GET .../calendar_events es un límite superior exclusivo.

  • El ends_at de los eventos de día completo también es exclusivo: un evento de día completo de un solo día necesita ends_at a la medianoche del siguiente día (o, de forma equivalente, igual a starts_at, que también funciona), y un período de N días necesita ends_at ampliado un día más allá del último día inclusivo. create_event maneja esta ampliación internamente para que su propio argumento end siga siendo inclusivo para quien lo llama.

  • Los miembros de la familia se etiquetan mediante category_ids (un array) en el payload de creación; los ids de categoría provienen de GET .../categories y se almacenan en caché por proceso.

Si Skylight vuelve a cambiar su API, estos son los lugares con más probabilidades de romperse: _login() (los pasos de OAuth) y la forma del payload de calendar_events en create_event.

Solución de problemas

Pebble dice "invalid tool call, action failed" y no llega nada al calendario. Revisa primero railway logs --service skylight-mcp — cada llamada a create_event registra sus argumentos sin procesar, y los fallos de la API de Skylight también se capturan y registran. Dos cosas con las que este proyecto ya se ha encontrado:

  • El nombre del servidor MCP tiene un espacio o un carácter especial en la configuración de la aplicación Pebble. Confirmado en el foro de Pebble: un espacio en el campo Name del servidor hace que el agente construya un nombre de herramienta compuesto incorrecto y la llamada nunca llega al servidor, sin que se genere ningún error visible (verás ListToolsRequest en los logs pero ningún CallToolRequest). Renómbralo para que contenga únicamente caracteres alfanuméricos y guiones.

  • Argumentos opcionales de herramienta tipados como anulables (str | None). Algunos validadores estrictos de llamadas a funciones rechazan un esquema JSON con anyOf: [string, null] antes siquiera de enviar la solicitud. Este servidor usa en su lugar str = "" simple (cadena vacía = "no proporcionado"), específicamente para evitar eso.

No se pudo parsear una fecha/hora. create_event captura esto y devuelve una cadena de error descriptiva (visible dondequiera que Pebble muestre los resultados de la herramienta) en lugar de fallar, indicando exactamente qué no pudo parsear.

Un evento se guardó a una hora incorrecta (p. ej., 2 a. m.). Casi con seguridad es una confusión entre hora naive y UTC. El manejo de horas naive de create_event siempre asume SKYLIGHT_TIMEZONE, nunca UTC: si ves esto, comprueba si Pebble envió por error una hora UTC sin zona horaria (revisa el argumento start sin procesar en los logs).

Verificación de la comprobación del token Bearer

# No token -> 401
curl -i https://<your-railway-domain>/healthz    # should be 200, no auth needed
curl -i https://<your-railway-domain>/mcp         # should be 401

# With token -> reaches the MCP layer
curl -i https://<your-railway-domain>/mcp \
  -H "Authorization: Bearer <your MCP_BEARER_TOKEN>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2026-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'

Maintenance

ActivityMaintained
ResponsivenessNo issues

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

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Transforms macOS calendar management into a conversational experience using natural language, allowing users to create, manage, and update calendar events seamlessly through an MCP-compatible client.
    327
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to manage Google Calendar through natural language interactions with features like creating, updating, and deleting events, searching calendars, and supporting natural language date/time inputs.
    27
    2
    MIT
  • F
    license
    Not graded
    quality
    F
    maintenance
    Enables programmatic management of Google Calendar events through natural language interactions, supporting creation, reading, updating, and deletion of events with features for recurring events, attendees, and reminders.
    2

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/SarjuThakkar/skylight-mcp-pebble'

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