Inspiration
Our family had a specific problem in mind: when you are a caregiver at 9pm and realize the kids' medicine is basically empty, you don't want to open five apps. You want one assistant that already knows what's low, whether it's safe to deliver today, which slots are open, and can book the whole thing — but only after you say yes.
Most voice assistants stop at "here's a link." We wanted something that actually takes the next step but doesn't overstep. That gap between "helpful" and "doing things behind your back" is where the design of this project lives.
What it does
Family Caretaker is a proactive agent built on an MCP server using Streamable HTTP (spec 2025-11-25). It exposes five tools:
check_inventory— reads from Turso and returns anything at or below its low-stock thresholdcheck_weather— pulls a live forecast from Open-Meteo for a city and datefind_upcoming_slots— returns all open delivery slots across the next seven days in one querybook_delivery— writes to Turso, but only after explicit confirmationlist_appointments— returns everything that's already booked
A typical turn looks like this: the user says "check the inventory." The agent calls the tool, sees Children's Tylenol is at 1 (threshold 3), and proposes a delivery. It checks the weather for the day, reads open slots across the next week, and asks which time works. Nothing gets booked until the user picks one.
The UI supports voice input and text-to-speech in both English and Hindi. When the user has been idle for a couple of minutes, the agent sends a proactive alert about low-stock items over Server-Sent Events — but it stays quiet while a conversation is active.
How we built it
The core is a Node.js + Express server that hosts the MCP endpoint on POST /mcp using StreamableHTTPServerTransport in stateless mode. The LLM is Groq's gpt-oss-20b, called through the OpenAI-compatible SDK. The web client is a single-page HTML/JS chat UI that talks to /chat on the server and receives structured cards for inventory, weather, slots, and bookings.
Turso (cloud SQLite) holds four tables: inventory, appointments, availability, and sessions. The sessions table stores every message, so restarting the server does not wipe the conversation. The availability table drives the slot lookup — when a slot is booked, is_booked flips to 1 and the slot disappears from future proposals.
The booking flow has two safety layers. The system prompt tells the model not to claim success without a real tool result. More importantly, the book_delivery tool itself validates every request in code: item must exist in inventory, date cannot be in the past, slot must be genuinely available, and confirmed must be true. If any check fails, the tool returns a message starting with "Rejected:" and writes nothing. Those rules are covered by four unit tests using Vitest.
Deployment is on Render's free tier. Everything runs at zero cost: Groq for reasoning, Turso for storage, Open-Meteo for weather, Render for hosting.
Challenges we ran into
The first blocker was transport. The project originally used the old HTTP+SSE transport, and every request returned a 500. It took a while to realize SSE is deprecated in the current MCP spec and Alexa+ specifically requires Streamable HTTP. Switching to StreamableHTTPServerTransport in stateless mode fixed it.
The second issue was model churn. Groq retired llama-3.3-70b-versatile mid-project, and the error just said "model not found" without naming a replacement. We moved to gpt-oss-20b after checking the migration docs.
The third and most interesting challenge was LLM hallucination. During early testing, the agent once said "your delivery is all set" while all three booking calls had actually failed. That was the moment we moved the confirmation and validation checks from the prompt into the tool itself, and added explicit rules to the system prompt about not lying. Since then, the agent honestly reports failures.
Smaller ones: PowerShell mangles JSON when passing to curl, so we wrote the body to a file and used --data-binary @file. MCP Inspector's --url flag fails on Windows, but starting it without flags and entering the URL in the UI works. And Hindi TTS requires the language pack to be installed on Windows — we added voice detection and a graceful fallback.
Accomplishments that we're proud of
The booking flow genuinely respects user intent. In testing, when we said "hi" the agent replied with a greeting. When we said "check the inventory" it only checked inventory. When we said "check all the upcoming slots" it made exactly one tool call to fetch seven days at once. It does what you ask, not more.
The deterministic safety layer is the piece we're most confident about. Even if the LLM tries to book something invalid, the tool refuses and the user sees an honest "Rejected: ..." message. The four unit tests are simple, but they prove the rules work as designed.
Also proud that the whole thing runs on free tiers. No credit card, no AWS credits, no subscription. Anyone who clones the repo can run it end to end without spending money.
What we learned
Prompts are a weak contract. If you want a model not to lie, you have to enforce the truth in the tool, not the prompt. The system prompt still helps (the model produces better responses when it knows the rules), but the guarantee comes from code.
Deprecation is quiet. Both the SSE transport and the retired Groq model failed with generic errors. The migration paths were in the docs, but the error messages didn't point at them.
Cross-session state is a design decision, not a database choice. Moving from an in-memory array to Turso was almost trivial to code, but it changed the demo completely — after a full server restart, the conversation and bookings are still there.
Idle detection matters for proactive features. A proactive notification is only helpful if it arrives when the user is not already mid-conversation. Adding a simple "last user message timestamp" check was a small change with a big effect on how the product feels.
What's next for Family Caretaker MCP Agent
The obvious next step is a real calendar integration. find_upcoming_slots reads from a seeded availability table today; swapping it for Google Calendar would make the slot proposals genuinely real. Similarly, book_delivery writes a row to a table but doesn't dispatch an order — integrating a grocery or pharmacy API would close that loop.
Beyond that, we want to add multi-item booking (book several low-stock items in one turn), medication expiry tracking (alert when something in the cupboard is about to expire), and a proper deployment of the MCP server behind an actual Alexa+ skill so the assistant lives where it was meant to live.
The code is MIT licensed and the whole stack is reproducible on free tiers, so anyone who wants to extend it can start from git clone and be running in a couple of minutes.
Built With
- css
- express.js
- gpt-oss-20b
- groq
- html
- javascript
- libsql
- mcp-sdk
- model-context-protocol
- node.js
- open-meteo
- openai
- render
- server-sent-events
- sqlite
- streamable-http
- turso
- typescript
- vitest
- web-speech-api
- zod
Log in or sign up for Devpost to join the conversation.