Skip to main content
Glama
jcrispiniano

huckleberry-mcp-worker

by jcrispiniano

huckleberry-mcp-worker

Ein Model Context Protocol-Server für die Huckleberry-Babytracking-App, ausgeführt als Cloudflare Worker.

Dies ist ein TypeScript-Port von bckenstler/py-huckleberry-mcp. Das Original ist ein Python- stdio-Server, der über google-cloud-firestore mit Firestore kommuniziert, was gRPC spricht und daher nicht auf Workern ausgeführt werden kann. Dieser Port erreicht dasselbe Backend über die Firebase-REST-API mit fetch und bedient MCP über Streamable HTTP.

Der praktische Unterschied: Er ist immer erreichbar. Es muss kein Laptop laufen, damit ein Client ein Nickerchen protokollieren kann.

Tools

Alle 23 Tools des Python-Servers sind implementiert, plus delete_record.

Bereich

Tools

Kinder

list_children, get_child_name

Schlaf

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

Füttern

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

Windel

log_diaper, get_diaper_history

Wachstum

log_growth, get_latest_growth, get_growth_history

Einträge

delete_record

Jedes Verlaufstool meldet die interval_id jedes Eintrags, die von delete_record benötigt wird.

Korrekturen gegenüber dem Python-Server

Beim Portieren wurden vier Fehler gefunden, die hier behoben sind.

Stilldauern wurden in der falschen Einheit geschrieben. Das Backend speichert leftDuration / rightDuration in Sekunden – das schreibt auch der eingebaute Timer der App – aber log_breastfeeding übergab die Minuten des Aufrufers einfach so. Die Protokollierung einer 5-minütigen Fütterung zeichnete 5 Sekunden auf. Aufrufer mussten zuvor 300 übergeben, um 5 Minuten zu bedeuten; hier bedeutet left_duration_minutes: 5 fünf Minuten.

Eintägige Verlaufsabfragen lieferten nichts zurück. Beide Enden eines Datumsbereichs wurden auf Mitternacht aufgelöst, sodass start_date == end_date ein leeres Fenster ergab und der Server für einen Tag, der viele Einträge hatte, keine meldete. Bereiche sind jetzt halboffen: [start_of_start_date, start_of_end_date + 1 day), sodass beide Enden inklusive sind.

end_time im Schlafverlauf war immer null. Der Code las ein end-Feld aus, das das Backend nie schreibt. Es wird jetzt aus start + duration abgeleitet.

birth_date in list_children war immer null. Das Backend-Feld ist birthdate; der Server las birthDate.

get_feeding_history gibt jetzt auch für jeden Eintrag den mode sowie die dazugehörigen Details zurück: Menge und Typ für Fläschchen, Lebensmittelnamen und Reaktionen für feste Nahrung. Ohne sie ist ein Eintrag für feste Nahrung eine leere Zeile, die von einer Still-Sitzung der Länge Null nicht zu unterscheiden ist – genau so wird ein einwandfreier Eintrag fälschlicherweise für einen fehlenden gehalten.

Einrichtung

Erfordert Node 18+ und ein Cloudflare-Konto.

npm install
npx wrangler login

Legen Sie die Geheimnisse fest – sie werden von Cloudflare verschlüsselt gespeichert und befinden sich nie im Repository:

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 hat den Standardwert America/New_York. Es entscheidet, wie naive Datums-/Uhrzeitangaben wie "2026-08-17T15:47:00" interpretiert werden, daher ist die korrekte Einstellung wichtig.

Bereitstellung:

npm run deploy

Authentifizierung

Die Worker-URL ist öffentlich, und der Server enthält Anmeldedaten für die Gesundheitsdaten eines Kindes, daher muss jede Anfrage das Bearer-Token enthalten:

Authorization: Bearer <MCP_AUTH_TOKEN>

Anfragen ohne gültiges Token erhalten eine 401, bevor ein Huckleberry-Aufruf erfolgt. Generieren Sie ein Token mit etwas wie openssl rand -base64 32.

Clients, die keine Header senden können

Einige MCP-Clients akzeptieren nur eine URL – benutzerdefinierte Connectors von claude.ai beispielsweise akzeptieren eine URL und optionale OAuth-Anmeldedaten ohne Feld für Authorization. Für diese akzeptiert der Server das Token auch als letztes Pfadsegment:

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

MCP_URL_TOKEN ist ein separates Geheimnis von MCP_AUTH_TOKEN, und zwar bewusst: Anforderungspfade landen in Zugriffsprotokollen, dem Browserverlauf und Referrern, anders als Header. Die Trennung bedeutet, dass ein Leck über eine URL die Header-Anmeldedaten nicht gefährdet, und beide können unabhängig voneinander rotiert werden. Wenn MCP_URL_TOKEN nicht gesetzt ist, fällt die Route auf MCP_AUTH_TOKEN zurück, was praktisch ist, aber diese Trennung aufgibt.

npx wrangler secret put MCP_URL_TOKEN

Bevorzugen Sie die Header-Route, wo immer der Client sie unterstützt.

Client-Konfiguration

Für Claude Code:

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

Lokale Entwicklung

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":{}}'

Designhinweise

Zustandslos. Jede Anfrage erstellt einen neuen McpServer über createMcpHandler aus dem Cloudflare agents-SDK. Es sind keine Durable Objects und keine Sitzungsspeicherung beteiligt, da jedes Tool ein in sich geschlossener Lese- oder Schreibvorgang ist.

Token-Caching. Firebase-ID-Token sind eine Stunde gültig und werden im Modul-Gültigkeitsbereich zwischengespeichert, sodass Anfragen, die auf einer warmen Isolate landen, die erneute Authentifizierung überspringen. Eine kalte Isolate kostet einen zusätzlichen Roundtrip. Ein während der Verarbeitung zurückgewiesenes Token löst eine erneute Authentifizierung und einen Wiederholungsversuch aus.

Numerische Typen. Firestore unterscheidet zwischen Ganzzahlen und Gleitkommazahlen, und die App schreibt einige Felder als das eine und andere als das andere. Werte, die als Gleitkommazahlen gespeichert werden müssen, werden in dbl() eingeschlossen, sodass hier geschriebene Einträge mit denen übereinstimmen, die von der App geschrieben wurden.

Dokumente mit mehreren Einträgen. Der Verlauf liegt in zwei Formen vor: gewöhnliche Dokumente mit einem start auf oberster Ebene und Batch-Dokumente, die viele Einträge unter data enthalten. Verschachtelte Starts können serverseitig nicht gefiltert werden, daher werden Batch-Dokumente vollständig abgerufen und im Worker gefiltert. Einträge geben über is_multi_entry an, aus welcher Form sie stammen.

Löschen von Einträgen

Der Python-Server hatte keine Löschfunktion, und die allgemeine Annahme war, dass das Backend dies nicht zuließ. Es tut es doch: Ein DELETE auf den Dokumentenpfad gibt 200 zurück. Was tatsächlich fehlte, war die ID des Eintrags, den die Verlaufstools nie gemeldet haben.

Daher geben Verlaufstools jetzt interval_id zurück, und delete_record entfernt den benannten Eintrag. Batch-Einträge – mehrere Einträge, die in einem Dokument unter data zusammengefasst sind – werden als <documentId>#<entryKey> angesprochen und als ein Feld ihres übergeordneten Dokuments entfernt.

Das Löschen aktualisiert auch prefs.last* auf den neuesten überlebenden Eintrag. Die App liest diese Zeiger direkt, sodass ein Löschen ohne diese Aktualisierung dazu führt, dass sie einen Eintrag anzeigt, der nicht mehr existiert.

Bekannte Einschränkungen

  • Löschungen sind endgültig. Es gibt keine Rückgängig-Funktion. Bestätigen Sie mit einer Verlaufsabfrage, bevor Sie delete_record aufrufen.

  • Feste Nahrung ist schreibgeschützt. get_feeding_history meldet Einträge für feste Nahrung mit ihren Lebensmittelnamen und Reaktionen, aber es gibt kein Tool, um einen zu erstellen.

  • start_sleep schützt nicht vor einem bereits laufenden Timer. Der Python-Server dokumentierte, dass er in diesem Fall fehlschlagen würde, hat es aber nie überprüft; das Verhalten wird hier beibehalten, anstatt es stillschweigend zu ändern.

  • Notizen werden nicht in Schlafaufzeichnungen zurückgespielt. Das Feld details ist eine feste Struktur von Kontrollkästchen, kein Freitext.

Lizenz

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