Skip to main content
Glama
jcrispiniano

huckleberry-mcp-worker

by jcrispiniano

huckleberry-mcp-worker

Un servidor del Protocolo de Contexto de Modelo para la aplicación de seguimiento de bebés Huckleberry, ejecutándose como un Cloudflare Worker.

Se trata de una adaptación a TypeScript de bckenstler/py-huckleberry-mcp. El original es un servidor stdio de Python que se comunica con Firestore a través de google-cloud-firestore, el cual utiliza gRPC y, por lo tanto, no puede ejecutarse en Workers. Esta adaptación accede al mismo backend mediante la API REST de Firebase usando fetch, y ofrece MCP a través de HTTP Transmisible.

La diferencia práctica: siempre está activo. No es necesario que un portátil esté encendido para que un cliente registre una siesta.

Herramientas

Las 23 herramientas del servidor Python están implementadas, además de delete_record.

Área

Herramientas

Niños

list_children, get_child_name

Sueño

log_sleep, start_sleep, pause_sleep, resume_sleep, complete_sleep, cancel_sleep, get_sleep_history

Alimentación

log_breastfeeding, log_bottle_feeding, start_breastfeeding, pause_feeding, resume_feeding, switch_feeding_side, complete_feeding, cancel_feeding, get_feeding_history

Pañal

log_diaper, get_diaper_history

Crecimiento

log_growth, get_latest_growth, get_growth_history

Registros

delete_record

Cada herramienta de historial informa el interval_id de cada registro, que es lo que delete_record recibe como parámetro.

Correcciones respecto al servidor Python

Se encontraron cuatro defectos durante la adaptación y se corrigen aquí.

Las duraciones de la lactancia se escribían en la unidad incorrecta. El backend almacena leftDuration / rightDuration en segundos (que es lo que escribe el temporizador propio de la aplicación), pero log_breastfeeding pasaba directamente los minutos de la persona que llama. Registrar una toma de 5 minutos grababa 5 segundos. Quienes llamaban tenían que pasar 300 para indicar 5 minutos; aquí left_duration_minutes: 5 significa cinco minutos.

Las consultas de historial de un solo día no devolvían nada. Ambos extremos de un rango de fechas se resolvían a la medianoche, por lo que start_date == end_date producía una ventana vacía y el servidor no informaba registros para un día que sí los tenía. Los rangos ahora son semiabiertos [start_of_start_date, start_of_end_date + 1 día), haciendo que ambos extremos sean inclusivos.

end_time en el historial de sueño siempre era nulo. El código leía un campo end que el backend nunca escribe. Ahora se deriva de start + duration.

birth_date en list_children siempre era nulo. El campo del backend es birthdate; el servidor leía birthDate.

get_feeding_history ahora también devuelve el mode de cada registro, junto con los detalles que lo acompañan: cantidad y tipo para biberones, nombres de alimentos y reacciones para sólidos. Sin ellos, un registro de sólidos es una fila vacía, indistinguible de una sesión de lactancia de duración cero, que es exactamente cómo un registro perfectamente válido se confunde con uno inexistente.

Configuración

Requiere Node 18+ y una cuenta de Cloudflare.

npm install
npx wrangler login

Establece los secretos: se almacenan cifrados por Cloudflare y nunca residen en el repositorio:

npx wrangler secret put HUCKLEBERRY_EMAIL
npx wrangler secret put HUCKLEBERRY_PASSWORD
npx wrangler secret put MCP_AUTH_TOKEN     # a long random string you generate
npx wrangler secret put HUCKLEBERRY_TIMEZONE   # e.g. America/Sao_Paulo

HUCKLEBERRY_TIMEZONE tiene como valor predeterminado America/New_York. Decide cómo se interpretan las fechas y horas ingenuas como "2026-08-17T15:47:00", por lo que configurarlo correctamente es importante.

Despliegue:

npm run deploy

Autenticación

La URL del Worker es pública y el servidor tiene credenciales para el registro de salud de un niño, por lo que cada solicitud debe incluir el token de portador:

Authorization: Bearer <MCP_AUTH_TOKEN>

Las solicitudes sin un token válido reciben un 401 antes de realizar cualquier llamada a Huckleberry. Genere un token con algo como openssl rand -base64 32.

Clientes que no pueden enviar cabeceras

Algunos clientes MCP aceptan solo una URL: los conectores personalizados de claude.ai, por ejemplo, toman una URL y credenciales OAuth opcionales sin ningún campo para Authorization. Para esos, el servidor también acepta el token como el último segmento de la ruta:

POST https://<your-worker>.workers.dev/mcp/<MCP_URL_TOKEN>

MCP_URL_TOKEN es un secreto distinto de MCP_AUTH_TOKEN, y deliberadamente: las rutas de solicitud terminan en registros de acceso, historial del navegador y referentes de una manera que las cabeceras no. Mantenerlos separados significa que una fuga a través de una URL no compromete la credencial de la cabecera, y cualquiera de las dos puede rotarse de forma independiente. Si MCP_URL_TOKEN no está configurado, la ruta recurre a MCP_AUTH_TOKEN, lo cual es conveniente pero renuncia a esa separación.

npx wrangler secret put MCP_URL_TOKEN

Prefiera la ruta de la cabecera siempre que el cliente la admita.

Configuración del cliente

Para Claude Code:

claude mcp add --transport http huckleberry https://<your-worker>.workers.dev/mcp \
  --header "Authorization: Bearer <MCP_AUTH_TOKEN>"

Desarrollo local

cp .dev.vars.example .dev.vars   # then fill it in; .dev.vars is gitignored
npm run dev
curl -X POST http://localhost:8787/mcp \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

Notas de diseño

Sin estado. Cada solicitud construye un McpServer nuevo a través de createMcpHandler del SDK de agents de Cloudflare. No se utilizan Durable Objects ni almacenamiento de sesión, porque cada herramienta es una lectura o escritura autocontenida.

Caché de tokens. Los tokens de ID de Firebase duran una hora y se almacenan en caché en el ámbito del módulo, por lo que las solicitudes que llegan a un aislado cálido omiten la reautenticación. Un aislado frío cuesta un viaje de ida y vuelta adicional. Un token rechazado durante la ejecución desencadena una reautenticación y un reintento.

Tipos numéricos. Firestore distingue entre enteros y dobles, y la aplicación escribe algunos campos como uno y otros como el otro. Los valores que deben almacenarse como dobles se envuelven en dbl() para que los registros escritos aquí coincidan con los registros escritos por la aplicación.

Documentos con múltiples entradas. El historial se presenta en dos formas: documentos ordinarios con un start de nivel superior y documentos por lotes que contienen muchas entradas bajo data. Los inicios anidados no se pueden filtrar en el servidor, por lo que los documentos por lotes se obtienen completos y se filtran en el Worker. Los registros informan de qué forma provienen mediante is_multi_entry.

Eliminación de registros

El servidor Python no tenía función de eliminar, y la sabiduría popular era que el backend no lo permitía. Sí lo hace: un DELETE en la ruta del documento devuelve 200. Lo que realmente faltaba era el identificador del registro, que las herramientas de historial nunca informaban.

Por lo tanto, las herramientas de historial ahora devuelven interval_id, y delete_record elimina el registro que nombra. Las entradas por lotes (varios registros empaquetados en un documento bajo data) se abordan como <documentId>#<entryKey> y se eliminan como un campo de su padre.

Eliminar también reasigna prefs.last* al registro superviviente más reciente. La aplicación lee esos punteros directamente, por lo que una eliminación sin la reasignación deja mostrando un registro que ya no existe.

Limitaciones conocidas

  • Las eliminaciones son permanentes. No hay deshacer. Confirme con una consulta de historial antes de llamar a delete_record.

  • Los sólidos son de solo lectura. get_feeding_history informa entradas de sólidos con sus nombres de alimentos y reacciones, pero no hay ninguna herramienta para crear uno.

  • start_sleep no protege contra un temporizador ya en ejecución. El servidor Python documentó que fallaría en ese caso pero nunca lo comprobó; el comportamiento se conserva aquí en lugar de cambiarlo silenciosamente.

  • Las notas no se reflejan en los registros de sueño. El campo details es una estructura fija de casillas de verificación, no texto libre.

Licencia

MIT

-
license - not tested
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

View all 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/jcrispiniano/huckleberry-mcp-worker'

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