Skip to main content
Glama

Hearth

Hearth is a self-hosted MCP server that lets a family look after an aging parent by voice: medication check-ins, appointments, a daily summary, missed-dose escalation, and sharing that the parent controls. It ships with voice-sim, an MIT-licensed voice harness that drives any MCP server through an LLM and scores it against a golden eval.

Architecture

┌──────────────────────── voice-sim (MIT, generic) ─────────────────────────┐
│  Browser: index.html + app.js        Agent server (Node, 127.0.0.1 only)  │
│  ─ mic / TTS (Web Speech) ◄──SSE──►  ─ LLM provider: Gemini | Groq | Mock │
│  ─ push-to-talk, text fallback       ─ MCP client (Streamable HTTP)       │
│  ─ profile switch (id/label/emoji)   ─ confirmation gate (FR-HARN-2)      │
│  ─ trace list                        ─ headless `eval` CLI                │
└───────────────────────────────────────────────┬───────────────────────────┘
                                                │ POST/GET/DELETE /mcp (SSE)
                                                │ Authorization: Bearer
┌──────────────────────── hearth-mcp ────────────▼──────────────────────────┐
│ node:http ─► guard (Host/Origin/public-mode) ─► auth → Principal ─►       │
│ session router (404/403) ─► per-session McpServer (role tools only) ─►    │
│ handlers (strict zod in-handler) ─► domain services ─► db.tx ─► SQLite    │
│ Scheduler evaluate(now): boot / 60 s / clock routes · Clock (injected)    │
│ pino (redacted) · /healthz · /dev/* (gated)                               │
└───────────────────────────────────────────────────────────────────────────┘

MCP spec 2025-11-25 on @modelcontextprotocol/sdk@1.32.1, TypeScript on Node ≥ 22.16, SQLite through node:sqlite. The full specification is docs/SPEC.md.

Related MCP server: CareCompanion

Quick start

  1. Run it. Docker Compose v2.24 or newer is the only requirement:

    docker compose up

    The first run builds the image. The server seeds a synthetic "Shah family" on first boot. Both ports are published on 127.0.0.1 only:

    • Hearth MCP server: http://127.0.0.1:8787/mcp (health check: http://127.0.0.1:8787/healthz)

    • voice-sim: open http://localhost:5173 in Chrome

  2. Add an LLM key (optional). voice-sim needs one to answer; the MCP server does not.

    cp .env.example .env    # then set GEMINI_API_KEY= (and optionally GROQ_API_KEY= as a fallback)
    docker compose up

    .env is git-ignored and is read only at runtime. Keys never reach the browser. For the snappiest voice, set LLM_PROVIDERS=groq,gemini and LLM_RPM=30 in .env: on Groq a turn answers in about 2.5 s (FL-16).

  3. Connect MCP Inspector. Run npx @modelcontextprotocol/inspector@2.11.0, choose Streamable HTTP, use http://127.0.0.1:8787/mcp, and add the header Authorization: Bearer demo_caregiver (or demo_parent). The full checklist is in docs/inspector.md.

Metrics

ID

Metric

Target

Measured

Source

M1

Tool routing on the 24-item golden set (gemini-3.5-flash-lite)

≥ 22/24

24/24

eval/results/latest.json

M2a

Confirmation compliance on the golden set

24/24

24/24

eval/results/latest.json

M2b

Tier ≥ 2 commits without an elicitation in the audit log

0

0

npm run eval:mock (CI)

M3

Final spoken replies of 25 words or fewer

≥ 23/24

24/24

eval/results/latest.json

M4

Tool latency p95, excluding time spent waiting on the human

≤ 300 ms

51 ms

eval/results/latency.txt

M5

Median end of speech → start of spoken reply, 10 voice turns

≤ 3.5 s

2.56 s (Groq gpt-oss-120b first, Chrome's recogniser)

scripts/voice-timing.mjs, 2026-10-21

M6

Inspector lists the 11 caregiver tools and completes a confirmed write

pass

pass (7/7 checks)

docs/inspector.md

M7

Fresh clone → docker compose up → Inspector connected / first voice answer

≤ 5 min each

4 min 24 s / 48 s

timed run, 2026-10-20 (cold build 187 s)

CI runs typecheck, lint, the test suites, the keyless mock eval, the M1–M3 threshold check and a secret scan on every push (.github/workflows/ci.yml).

Screenshots

MCP Inspector connected as the caregiver, with an elicitation-confirmed write:

MCP Inspector

voice-sim, push-to-talk with the tool trace:

voice-sim

Roles & tools

Each MCP session gets only its role's tools, so an out-of-role call is simply "tool not found". Writes are tiered: T0 reads, T1 low-risk writes without confirmation, T2/T3 writes confirmed by the user through elicitation.

Tool

Parent (Mom)

Caregiver (Arnav)

Tier

get_daily_summary, list_medications, get_appointments, get_status_help

✓

✓

T0

get_pending_messages

✓

✓

T1

log_dose

✓

T1

get_sharing

✓

T0

set_sharing

✓

T2

get_alerts

✓

T0

ack_alert

✓

T1 (T2 when clearing several)

upsert_medication, upsert_appointment, send_check_in

✓

T2

cancel_appointment

✓

T3

The parent gets 8 tools and the caregiver gets 11. Demo bearer tokens are demo_parent and demo_caregiver.

Trust boundary

Confirmation is enforced by the server, not by the LLM or the client. Every T2/T3 write asks the human through MCP elicitation, reads back exactly what will change, and re-validates the plan before committing. It follows that a client without elicitation support cannot run T2/T3 tools; they fail closed. A confirm-token fallback for such clients is future work (decision D8 in the spec).

Privacy

  • All seed data is synthetic: the "Shah family", its medications and its appointments are invented.

  • Free-tier LLM providers may retain prompts for training or review. Don't put real health data through voice-sim with a free-tier key.

  • With a Groq key, push-to-talk audio goes to Groq for transcription (Whisper). Set VOICE_SIM_STT=browser to keep speech recognition in Chrome instead.

  • API keys and bearer tokens stay in .env and the server process. They never reach the browser, the event stream, logs or eval reports, and CI fails on a secret-pattern scan.

  • Error logs carry the error class, code and stack, never the message, which can echo user input.

Tunnels

The server binds 127.0.0.1 by default. To reach it through a tunnel:

  • Add the exact tunnel hostname to HEARTH_ALLOWED_HOSTS. Never rewrite the Host header to get past the check.

  • A non-loopback allowed host or any forwarding header (cf-ray, x-forwarded-for, forwarded, …) switches on public mode: /dev/* returns 404 and the demo_ tokens are refused with 401.

  • Mint real tokens with npm run seed -w packages/hearth-mcp -- --public; they are printed once. In public mode the server never seeds an empty database itself, since nobody would see its tokens; it logs this command instead.

  • voice-sim is never tunnelled. It holds your LLM keys and listens on loopback only.

voice-sim as a standalone MCP harness

packages/voice-sim is generic and MIT-licensed: it contains nothing Hearth-specific and works with any Streamable HTTP MCP server.

  • Profiles. profiles.json lists who can talk, as [{ "id", "label", "emoji", "headers" }]. Headers (for example an Authorization bearer) stay on the agent server; the browser sees only id, label and emoji. Point VOICE_SIM_PROFILES at the file and VOICE_SIM_MCP_URL at your server, then run npm run serve -w packages/voice-sim. VOICE_SIM_LANG sets the speech recognition language (Compose uses en-IN; empty means the browser's language).

  • Speech to text. With GROQ_API_KEY set, push-to-talk audio is recorded in the browser and transcribed on the agent server by Whisper (GROQ_STT_MODEL, default whisper-large-v3-turbo), which is far more accurate than Chrome's recogniser for accented English. A clip without voice in it is never sent, because Whisper invents words from silence (FL-18). Without a Groq key, or with VOICE_SIM_STT=browser, Chrome's recogniser is used.

  • Providers. Gemini, Groq and a scripted Mock, tried in LLM_PROVIDERS order with retry, backoff and a per-minute throttle. A turn is capped at 4 tool calls and 15 s, excluding waits on the human and on the throttle.

  • Eval CLI. voice-sim eval --server URL --file golden.jsonl --profiles P --dev-token T [--provider gemini|groq|chain|mock] runs a JSONL golden set and scores routing, confirmation compliance, brevity and final status into JSON and Markdown reports. Hearth's set is eval/golden.jsonl.

License

MIT. See LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables agentic voice assistants to run daily check-ins for someone living alone, capturing wellbeing, medication, and appointments, while keeping family informed via summaries and escalating when needed.
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables eldercare coordination through medication reminders with safety guardrails, daily voice check-ins with symptom escalation, and a family caregiver dashboard.
    8
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables older adults to log medication doses by voice, receive double-dose and safety alerts, record mood check-ins, request help, and exchange family messages, while giving caregivers multilingual AI digests, adherence reports, refill forecasts, and proactive notifications.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables families to coordinate caregiving through a self-hosted MCP server, tracking medication doses, daily check-ins, appointments, handoff notes, and family alerts via Alexa+ or any MCP host.
    15 npm
    MIT