huckleberry-mcp-worker
huckleberry-mcp-worker
Huckleberry 아기 추적 앱용 Model Context Protocol 서버로, Cloudflare Worker로 실행됩니다.
이 프로젝트는 bckenstler/py-huckleberry-mcp를 TypeScript로 포팅한 것입니다. 원본은 google-cloud-firestore를 통해 Firestore와 통신하는 Python stdio 서버로, gRPC를 사용하기 때문에 Worker에서 실행할 수 없습니다. 이 포팅은 Firebase REST API를 통해 fetch로 동일한 백엔드에 접근하며, Streamable HTTP를 통해 MCP를 제공합니다.
실질적인 차이점: 항상 켜져 있습니다. 클라이언트가 낮잠을 기록하기 위해 노트북이 켜져 있을 필요가 없습니다.
도구
Python 서버의 모든 23개 도구가 구현되었으며, delete_record가 추가되었습니다.
영역 | 도구 |
아기 |
|
수면 |
|
수유 |
|
기저귀 |
|
성장 |
|
기록 |
|
모든 기록 조회 도구는 각 레코드의 interval_id를 반환하며, delete_record가 이를 인자로 받습니다.
Python 서버 대비 수정 사항
포팅 과정에서 발견된 네 가지 결함을 수정했습니다.
모유 수유 시간이 잘못된 단위로 기록되었습니다. 백엔드는 leftDuration/rightDuration을 초 단위로 저장합니다(앱 자체 타이머가 그렇게 기록합니다). 하지만 log_breastfeeding은 호출자가 전달한 분을 그대로 전달했습니다. 5분 수유를 기록하면 5초로 기록되었습니다. 호출자는 이전에 5분을 의미하려면 300을 전달해야 했지만, 여기서는 left_duration_minutes: 5가 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와 함께 관련 세부 정보(병의 양과 종류, 이유식의 음식 이름과 반응)도 반환합니다. 이것이 없으면 이유식 기록은 빈 행이 되어 수유 시간이 0인 간호 세션과 구분할 수 없습니다. 바로 이 때문에 완벽하게 유효한 기록이 누락된 것으로 오인될 수 있습니다.
설정
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"와 같은 naive datetime이 어떻게 해석될지 결정하므로 올바르게 설정하는 것이 중요합니다.
배포:
npm run deploy인증
Worker URL은 공개되어 있으며, 서버는 아기의 건강 기록에 대한 자격 증명을 보유하고 있으므로 모든 요청은 bearer 토큰을 포함해야 합니다.
Authorization: Bearer <MCP_AUTH_TOKEN>유효하지 않은 토큰이 있는 요청은 Huckleberry 호출이 이루어지기 전에 401을 반환합니다. 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":{}}'설계 노트
무상태. 각 요청은 Cloudflare의 agents SDK에서 createMcpHandler를 통해 새로운 McpServer를 생성합니다. Durable Objects나 세션 저장소가 사용되지 않습니다. 모든 도구는 자체 포함된 읽기 또는 쓰기이기 때문입니다.
토큰 캐싱. Firebase ID 토큰은 1시간 동안 유효하며 모듈 범위에서 캐시됩니다. 따라서 웜 아이솔레이트에 도달하는 요청은 재인증을 건너뜁니다. 콜드 아이솔레이트는 한 번의 추가 왕복이 필요합니다. 중간에 거부된 토큰은 한 번의 재인증 및 재시도를 트리거합니다.
숫자 타입. 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
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