Inspiration
When several family members take turns caring for one person at home, each person only knows what happened on their own shift. That creates two risks with medication: a dose can be given twice because two people each think it is still due, or it can be missed because each thinks someone else gave it. Notes such as "the clinic called" or "she felt dizzy" can also get lost between shifts. We wanted one shared record that anyone in the household can ask or update by voice, with busy hands, and that refuses to record the same dose twice without asking.
What it does
Care Relay keeps one shared log for a household that looks after someone at home.
- Ask: "Did Mom get her evening pills?" The answer comes from the log, with who logged it and when.
- Log: "I gave Mom her evening pills." Planned items are matched to their time slot.
- Guard: if someone else already logged that slot, Care Relay does not save a second entry. It reads back who logged it and when and asks first. The chain stops until a person answers.
- Note: "Heads up, Mom said she felt dizzy after dinner" is saved as a note flagged for the next shift.
- Hand off: "I'm heading out, hand off to Jun" returns what needs attention, the notes, what was done since the last hand-off, and what is next. The next hand-off starts from that point.
- Card: status and hand-off render as an MCP Apps card. Its "Mark done" button calls an app-only tool through the host. Care Relay only records what the family logs. It gives no medical or dosing advice.
How we built it
- Self-hosted MCP server in Node.js with the official MCP TypeScript SDK (1.32.1), negotiating protocol 2025-11-25 over Streamable HTTP at /mcp (stateless per request; state is a JSON file, so it survives restarts and new sessions).
- Tools: set_care_plan, log_care, check_status, shift_handoff, and app-only mark_done_from_card. All declare outputSchema and return structuredContent. Resources: ui://care-relay/card.html (text/html;profile=mcp-app) and care://plan. Prompt: start_shift.
- MCP Apps view (ui/card.html) written against the 2026-01-26 MCP Apps spec: ui/initialize handshake, tool-input and tool-result notifications, size-changed, and tools/call back to the server.
- Simulated Alexa+ console (the hackathon's simulated-experience option): a real MCP client over Streamable HTTP that advertises the io.modelcontextprotocol/ui extension, a rule-based planner that chains tool calls from one sentence, a host bridge that renders the card in a sandboxed iframe and hides app-only tools from the model, and browser speech input/output.
- 11 automated tests (node:test), including end-to-end tests with the SDK client over real HTTP: protocol version, MCP Apps metadata, duplicate refusal, agent chaining, and state after a server restart.
- Built with an AI coding agent (Claude), which wrote most of the code, tests and demo under the entrant's direction.
Challenges we ran into
- The MCP client validates structuredContent strictly against outputSchema; extra fields were rejected, so the schemas list every field the card uses.
- Slot matching: one medicine can be planned twice a day, so a log is matched to the nearest planned time within a window instead of by name only. A test covers 08:00 and 20:00 doses not colliding.
- No Alexa+ device test path for MCP servers was available to us, so we built a small host to show the full voice-to-card flow.
Accomplishments that we're proud of
- The duplicate guard never decides on its own: when a second dose is reported for the same slot, the agent stops the chain, reads back who logged it and when, and waits for a person.
- A full shift hand-off from one sentence, shown as an interactive MCP Apps card whose button calls an app-only tool.
- The server is plain MCP 2025-11-25 over Streamable HTTP, so the same server works with any MCP client, and its state survives restarts (covered by a test).
What we learned
- Tests over real HTTP found problems the unit tests did not: the MCP client rejected structuredContent that carried a field the output schema did not list (three end-to-end tests failed until the schemas were completed), and a failing test left the HTTP server open, which hung the test run until open connections were closed on shutdown.
- A hand-off test showed that planned items never logged earlier in the day stay in "needs attention" at the next hand-off. We kept that on purpose, since a forgotten morning dose is exactly what the next person should see.
- Running the demo end to end showed a stale card staying on screen after the duplicate warning; the console now hides the card when a reply has no UI.
- A review before publishing found that the default data path broke when the project sits in a folder whose name has non-ASCII characters (URL path encoding); it now uses fileURLToPath.
What's next for Care Relay
HTTPS and authentication, one data store per household, reminders when an item becomes overdue, and testing with a real Alexa+ integration.
Built With
- css
- html
- javascript
- mcp-apps
- model-context-protocol
- node.js
- streamable-http
- zod
Log in or sign up for Devpost to join the conversation.