Skip to main content
Glama
jcrispiniano

huckleberry-mcp-worker

by jcrispiniano

huckleberry-mcp-worker

一个为 Huckleberry 婴儿追踪应用实现的 模型上下文协议 服务器,运行在 Cloudflare Worker 上。

这是 bckenstler/py-huckleberry-mcp 的 TypeScript 移植版本。原作是一个通过 google-cloud-firestore 与 Firestore 通信的 Python stdio 服务器,由于使用 gRPC 协议,无法在 Workers 上运行。此移植版本通过 fetch 调用 Firebase REST API 访问同一后端,并通过 Streamable HTTP 提供 MCP 服务。

实际区别是:它始终在线。客户端记录小睡时无需笔记本电脑保持唤醒。

工具

Python 服务器中的所有 23 个工具均已实现,此外还增加了 delete_record。

领域

工具

儿童

list_children, get_child_name

睡眠

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

喂养

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

尿布

log_diaper, get_diaper_history

成长

log_growth, get_latest_growth, get_growth_history

记录

delete_record

每个历史工具都会报告每条记录的 interval_id,这正是 delete_record 所接受的参数。

Related MCP server: remote-mcp-authless

针对 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 推导得出。

list_children 中的 birth_date 始终为 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_Paulo

HUCKLEBERRY_TIMEZONE 默认为 America/New_York。它决定了如何解释像 "2026-08-17T15:47:00" 这样的朴素日期时间,因此正确设置它很重要。

部署:

npm run deploy

身份验证

Worker 的 URL 是公开的,而服务器持有儿童健康记录的凭据,因此每个请求都必须携带 bearer token:

Authorization: Bearer <MCP_AUTH_TOKEN>

未经有效令牌的请求会在调用 Huckleberry 之前得到 401 响应。使用类似 openssl rand -base64 32 的命令生成一个令牌。

无法发送标头的客户端

某些 MCP 客户端只接受一个 URL——例如 claude.ai 的自定义连接器,它接受一个 URL 和可选的 OAuth 凭据,但没有用于 Authorization 的字段。对于这些客户端,服务器也支持将令牌作为 URL 的最后一段路径:

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

设计说明

无状态。 每个请求通过 Cloudflare 的 agents SDK 中的 createMcpHandler 创建一个全新的 McpServer。不涉及 Durable Objects 或会话存储,因为每个工具都是一个自包含的读取或写入操作。

令牌缓存。 Firebase ID 令牌有效期为一个小时,缓存在模块作用域内,因此落在热隔离区的请求可以跳过重新身份验证。冷隔离区多耗费一次往返。在空中被拒绝的令牌会触发一次重新身份验证和重试。

数值类型。 Firestore 区分整数和双精度浮点数,应用将某些字段写为一种类型,将其他字段写为另一种类型。必须存储为双精度浮点数的值会包装在 dbl() 中,以便此服务器写入的记录与应用写入的记录匹配。

多条目文档。 历史数据有两种形态:带有顶层 start 的普通文档,以及在 data 下包含许多条目的批量文档。嵌套的起始时间无法在服务器端过滤,因此批量文档会被整体获取并在 Worker 中过滤。记录通过 is_multi_entry 报告它们来自哪种形态。

删除记录

Python 服务器没有删除功能,普遍认为后端不允许删除。事实并非如此:对文档路径的 DELETE 操作会返回 200。真正缺少的是记录的 ID,历史工具从未报告过它。

因此历史工具现在会返回 interval_id,而 delete_record 会删除其指定的记录。批量条目——多个记录打包在一个文档的 data 下——通过 <documentId>#<entryKey> 进行寻址,并作为其父文档的一个字段被移除。

删除操作还会将 prefs.last* 重新指向最新的幸存记录。应用直接读取这些指针,因此删除操作如果不重新指向,会导致应用显示一条已不存在的记录。

已知限制

  • 删除是永久性的。 无法撤销。在调用 delete_record 之前,请先通过历史查询进行确认。

  • 固体食物只读。 get_feeding_history 会报告固体食物条目及其食物名称和反应,但没有创建固体食物条目的工具。

  • start_sleep 不会阻止已运行的计时器。 Python 服务器记录说明它会在这种情况下失败,但实际上从未检查过;此处保留了此行为,而未进行静默更改。

  • 备注不会往返进入睡眠记录。 details 字段是一个固定的复选框结构,不是自由文本。

许可证

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    A
    maintenance
    Huckleberry MCP server for Claude, Cursor, and other AI assistants. Query and log baby sleep, feeds, diapers, growth, pumping, and solids.
    29
    21 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    MCP server for UploadThing that lets AI assistants upload, list, and delete files on UploadThing's CDN via natural language. Runs as a Cloudflare Worker for always-on serverless access.
    16 npm
    MIT