huckleberry-mcp-worker
huckleberry-mcp-worker
Сервер Model Context Protocol для приложения отслеживания младенцев Huckleberry, работающий как Cloudflare Worker.
Это порт TypeScript для bckenstler/py-huckleberry-mcp. Оригинал — это Python-сервер stdio, который общается с Firestore через google-cloud-firestore, использующий gRPC и поэтому не работающий на Workers. Этот порт обращается к тому же бэкенду через Firebase REST API, используя fetch, и предоставляет MCP через Streamable HTTP.
Практическое отличие: он всегда включён. Ноутбуку не нужно быть включённым, чтобы клиент мог записать сон.
Инструменты
Все 23 инструмента из Python-сервера реализованы, плюс delete_record.
Область | Инструменты |
Дети |
|
Сон |
|
Кормление |
|
Подгузник |
|
Рост |
|
Записи |
|
Каждый инструмент истории сообщает interval_id каждой записи, который принимает delete_record.
Исправления по сравнению с Python-сервером
При портировании были обнаружены и исправлены четыре дефекта.
Длительность грудного вскармливания записывалась в неправильных единицах. Бэкенд хранит leftDuration / rightDuration в секундах — именно так пишет собственный таймер приложения, — но log_breastfeeding передавал минуты вызывающего напрямую. Запись 5-минутного кормления записывала 5 секунд. Ранее вызывающие должны были передавать 300, чтобы обозначить 5 минут; здесь left_duration_minutes: 5 означает пять минут.
Запросы истории за один день ничего не возвращали. Оба конца диапазона дат разрешались в полночь, поэтому start_date == end_date давал пустое окно, и сервер не сообщал о записях за день, в котором их было много. Диапазоны теперь полуоткрытые [start_of_start_date, start_of_end_date + 1 day), что делает оба конца включительными.
end_time в истории сна всегда было null. Код читал поле end, которое бэкенд никогда не записывает. Теперь оно выводится из start + duration.
birth_date в list_children всегда было null. Поле бэкенда — birthdate; сервер читал birthDate.
get_feeding_history теперь также возвращает mode каждой записи, а также связанные с ним детали: количество и тип для бутылочек, названия продуктов и реакции для твёрдой пищи. Без них запись о твёрдой пище — пустая строка, неотличимая от сеанса кормления нулевой длины — именно так хорошая запись ошибочно принимается за отсутствующую.
Настройка
Требуется Node 18+ и аккаунт Cloudflare.
npm install
npx wrangler loginУстановите секреты — они хранятся зашифрованными Cloudflare и никогда не находятся в репозитории:
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_PauloHUCKLEBERRY_TIMEZONE по умолчанию равен America/New_York. Он определяет, как интерпретируются наивные даты и время, такие как "2026-08-17T15:47:00", поэтому его правильная настройка важна.
Развёртывание:
npm run deployАутентификация
URL Worker является общедоступным, и сервер хранит учётные данные к медицинской карте ребёнка, поэтому каждый запрос должен содержать bearer-токен:
Authorization: Bearer <MCP_AUTH_TOKEN>Запросы без действительного токена получают 401 до любого вызова Huckleberry. Сгенерируйте токен с помощью чего-то вроде openssl rand -base64 32.
Клиенты, которые не могут отправлять заголовки
Некоторые MCP-клиенты принимают только URL — собственные коннекторы claude.ai, например, принимают URL и необязательные учётные данные OAuth без поля для Authorization. Для них сервер также принимает токен как последний сегмент пути:
POST https://<your-worker>.workers.dev/mcp/<MCP_URL_TOKEN>MCP_URL_TOKEN — это отдельный секрет от MCP_AUTH_TOKEN, и намеренно: пути запросов попадают в журналы доступа, историю браузера и рефереры так, как заголовки — нет. Их разделение означает, что утечка через URL не компрометирует учётные данные заголовка, и любой из них может быть заменён отдельно. Если MCP_URL_TOKEN не задан, маршрут возвращается к MCP_AUTH_TOKEN, что удобно, но отказывается от этого разделения.
npx wrangler secret put MCP_URL_TOKENПредпочитайте маршрут с заголовком везде, где клиент его поддерживает.
Конфигурация клиента
Для Claude Code:
claude mcp add --transport http huckleberry https://<your-worker>.workers.dev/mcp \
--header "Authorization: Bearer <MCP_AUTH_TOKEN>"Локальная разработка
cp .dev.vars.example .dev.vars # then fill it in; .dev.vars is gitignored
npm run devcurl -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":{}}'Заметки по дизайну
Без состояния. Каждый запрос создаёт новый McpServer через createMcpHandler из SDK agents Cloudflare. Никаких Durable Objects и хранилищ сессий не используется, потому что каждый инструмент — это самодостаточное чтение или запись.
Кэширование токенов. Токены Firebase ID действуют один час и кэшируются в области модуля, поэтому запросы, попадающие в тёплый изолят, пропускают повторную аутентификацию. Холодный изолят стоит одного дополнительного круга. Токен, отклонённый в процессе, вызывает одну повторную аутентификацию и повторную попытку.
Числовые типы. Firestore различает целые числа и числа с плавающей точкой, и приложение записывает одни поля как одно, а другие как другое. Значения, которые должны храниться как числа с плавающей точкой, оборачиваются в dbl(), чтобы записи, созданные здесь, соответствовали записям, созданным приложением.
Мульти-записные документы. История существует в двух формах: обычные документы с полем start верхнего уровня и пакетные документы, содержащие множество записей под полем data. Вложенные starts не могут быть отфильтрованы на стороне сервера, поэтому пакетные документы загружаются целиком и фильтруются в Worker. Записи сообщают, из какой формы они пришли, через поле is_multi_entry.
Удаление записей
У Python-сервера не было удаления, и общепринятое мнение заключалось в том, что бэкенд его не позволяет. Он позволяет: DELETE по пути документа возвращает 200. На самом деле отсутствовал идентификатор записи, который инструменты истории никогда не возвращали.
Теперь инструменты истории возвращают interval_id, и delete_record удаляет указанную запись. Пакетные записи (несколько записей, упакованных в один документ под data) адресуются как <documentId>#<entryKey> и удаляются как поле их родителя.
Удаление также перенаправляет prefs.last* на самую новую выжившую запись. Приложение читает эти указатели напрямую, поэтому удаление без перенаправления оставляет его показывающим запись, которой больше не существует.
Известные ограничения
Удаление необратимо. Нет функции отмены. Подтвердите запросом истории перед вызовом
delete_record.Твёрдая пища только для чтения.
get_feeding_historyсообщает записи о твёрдой пище с названиями продуктов и реакциями, но нет инструмента для её создания.start_sleepне защищает от уже запущенного таймера. Python-сервер документировал, что в этом случае произойдёт ошибка, но никогда не проверял; поведение сохранено здесь, а не молча изменено.Заметки не возвращаются в записи сна. Поле
details— это фиксированная структура флажков, а не свободный текст.
Лицензия
MIT
This server cannot be installed
Maintenance
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
Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer
Cloud-hosted MCP server for durable AI memory
Hosted remote MCP server for YNAB on Cloudflare Workers with OAuth
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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