Skip to main content
Glama
README.md
# 🍲 KitchenSync

**An Alexa+ MCP server that turns voice into dinner.** KitchenSync gives an AI agent a complete, live model of one household kitchen β€” pantry inventory with expiry tracking, a recipe book with ingredient-level matching, a shopping list, and the meal plan β€” exposed through 14 MCP tools over **Streamable HTTP (spec `2025-11-25`)**.

> Your fridge is a database you've never been able to query. KitchenSync fixes that: *"Alexa, what can I cook tonight?"* now has a real answer, backed by tool calls.

![KitchenSync chat experience](docs/screenshots/01-chat-cook-ideas.png)

**▢️ Watch the 2:14 narrated demo:** [`docs/demo-video/kitchensync-demo.mp4`](docs/demo-video/kitchensync-demo.mp4) (subtitles burned in β€” an `.srt` sits next to it)

**Hackathon tracks:** Primary **Alexa+** (self-hosted MCP server, Streamable HTTP, spec 2025-11-25) Β· Mini challenge **Open Source** (MIT). The Fire TV–style [Cook Mode](#-fire-tv-cook-mode) view connects the living room to the same MCP server.

---

## Why

Every household runs a tiny supply chain β€” buy food, store it, cook it, throw out what spoils β€” and it's all tracked in nobody's head. Generic assistants guess. An agent with **tools** doesn't have to:

| You say | The agent does (real MCP tool calls) |
|---|---|
| "What can I cook tonight?" | `pantry_list_items` β†’ `recipes_match_by_ingredients` β†’ *"Cacio e Pepe, 100%, 15 min…"* |
| "What's expiring soon?" | `pantry_expiring_soon` β†’ `recipes_match_by_ingredients` β†’ *"spinach in 2 days β€” a frittata would use it up"* |
| "Let's have the chicken tinga tacos tonight" | `mealplan_set` β†’ *"you're missing tortillas and limes β€” want them on the list?"* |
| "Add tortillas and limes to the shopping list" | `shopping_add_items` βœ“ |
| "I'm back from the store!" | `shopping_mark_purchased` β†’ the pantry **auto-restocks**, and the tacos now match at 100% |
| "Start cook mode" | `recipes_get` β†’ the recipe lands on the TV screen, D-pad step-by-step |

The shopping loop closes: **plan β†’ buy β†’ restock β†’ cook β†’ use** β€” every step a tool call an agent can chain.

## Architecture

```
        you (voice)                       any MCP client
            β”‚                        (Inspector, agents, …)
            β–Ό                                   β”‚ JSON-RPC
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                    β–Ό POST /mcp
 β”‚  simulated Alexa+ web   β”‚   plain fetch   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚  experience (public/)   β”‚ ───────────────▢│  KitchenSync MCP server  β”‚
 β”‚  rule-based planner or  β”‚  Streamable     β”‚  (src/, TypeScript)      β”‚
 β”‚  any OpenAI-compatible  β”‚  HTTP           β”‚  14 tools Β· 3 resources  β”‚
 β”‚  LLM w/ tool-calling    β”‚                 β”‚  2 prompts Β· stateless   β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                         β”‚ JSON state
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                       β–Ό
        β”‚  Fire TV Cook Mode     β”‚   same MCP endpoint   src/data/state.json
        β”‚  (public/tv.html)      β”‚ ◀──────────────────── (auto-seeded)
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

One process serves everything: the MCP endpoint, the simulated Alexa+ experience, and the TV view β€” so `localhost` demos "just work" with zero configuration.

## Quickstart

```bash
npm install
npm start
```

| URL | What |
|---|---|
| `http://localhost:3000/` | Simulated Alexa+ experience (chat) |
| `http://localhost:3000/tv` | Fire TV-style Cook Mode |
| `http://localhost:3000/health` | Health + counts |
| `POST http://localhost:3000/mcp` | The MCP endpoint (Streamable HTTP) |

Requires Node 20+ (24 recommended). The pantry auto-seeds with a realistic 42-item kitchen (incl. items about to expire, so the demo always has something to say). `npm run reset` gives you a fresh one.

**Try it from any MCP client** β€” the endpoint is stateless, so a single POST is a complete conversation turn:

```bash
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"pantry_expiring_soon","arguments":{"days":3}}}'
```

Works with **MCP Inspector** too: `npx @modelcontextprotocol/inspector`, transport = Streamable HTTP, URL = `http://localhost:3000/mcp`.

## The MCP API

### Tools (14)

| Tool | What it does |
|---|---|
| `pantry_list_items` | Full inventory: quantities, storage location, days-to-expiry |
| `pantry_add_item` | Add/restock an item (merges by name) |
| `pantry_use_item` | Mark as used while cooking; auto-removes at zero |
| `pantry_remove_item` | Remove an item |
| `pantry_expiring_soon` | Waste-reduction lens: items inside an N-day window |
| `recipes_search` | By keyword / max minutes / cuisine / diet |
| `recipes_match_by_ingredients` | ⭐ Ranks recipes by % of required ingredients you have; reports exact missing items (staples like salt/oil ignored) |
| `recipes_get` | Full recipe: ingredients with quantities + numbered steps |
| `shopping_list_items` | Read the list |
| `shopping_add_items` | Add items (typically the `missing` ones from matching) |
| `shopping_remove_items` | Remove items |
| `shopping_mark_purchased` | βœ… Check off after a store run β€” purchased items **restock the pantry automatically** |
| `mealplan_set` | Plan a meal (fuzzy names OK: "the pad thai") |
| `mealplan_get` | What's for dinner (default: today) |

Every tool returns structured JSON in `content[0].text`, designed for agent chaining. The server also ships `instructions` in its `initialize` response describing the intended flows.

### Resources (3)

`pantry://inventory` Β· `shopping://list` Β· `mealplan://today`

### Prompts (2)

`plan_dinner` (plan tonight from the pantry, waste-aware) Β· `reduce_waste` (find dishes that use up what's expiring)

## The simulated Alexa+ experience

The bundled web app (`/`) looks and feels like an Echo Show: an animated Alexa orb, typewriter replies, live tool-call cards with expandable JSON-RPC frames, and side panels (pantry / shopping list / tonight's plan) that update **as the tools mutate state**. The **MCP wire log** drawer (bottom-right) shows every real JSON-RPC request/response.

Two interchangeable planners drive it:

1. **Rule-based (default)** β€” deterministic intent β†’ tool-call chains, zero config, always works offline. The full demo runs on this.
2. **Real LLM (optional)** β€” click βš™ and point it at any OpenAI-compatible endpoint (Ollama, LM Studio, vLLM, Bedrock via proxy…). It performs genuine tool-calling against the same MCP server, same wire log.

This is the "simulated Alexa+ experience" path from the track brief β€” and because the server underneath is a **real, spec-compliant MCP server**, the same tools are ready for a hosted integration.

## πŸ“Ί Fire TV Cook Mode

`/tv` is a 10-foot living-room UI β€” big type, ambient scene, readable from the couch:

- Shows tonight's plan (set by voice through MCP) with an ingredient checklist: green βœ“ = in the pantry, amber ! = missing
- **Cook Mode**: `Enter` starts, `←`/`β†’` step through the recipe exactly like a Fire TV remote's D-pad, `i` flips the ingredient overlay
- Live-syncs every 15s β€” set dinner from the chat, watch the TV update

## Testing

```bash
npm run smoke       # spawns an isolated server on :3999 and drives the full
                    # demo journey over real MCP Streamable HTTP (29 assertions:
                    # handshake, protocol version, all tool flows, edge cases)
```

`npm test` aliases are kept minimal on purpose β€” the smoke suite *is* the app's contract. It covers: initialize negotiation (`2025-11-25`), tools/resources/prompts listings, the cook-matching chain, meal planning, shopping β†’ pantry restock loop (with a 100%-match assertion after restock), expiry ordering, fuzzy-name resolution, and error suggestions.

## Repo layout

```
src/
  index.ts        Express: POST /mcp (stateless Streamable HTTP) + static hosting
  server.ts       McpServer factory: 14 tools, 3 resources, 2 prompts
  store.ts        Pantry/shopping/mealplan state (JSON-persisted, seeded)
  recipes.ts      Recipe matching engine (loose ingredient equality, staples)
  util.ts         Name normalization + aliases + date math
  data/recipes.json   26 original recipes, 6 cuisines, diet-tagged
public/
  index.html + app.js + kitchen.js    Simulated Alexa+ experience
  tv.html + tv.js                     Fire TV-style Cook Mode
scripts/
  smoke.mjs       E2E journey test       req-*.json   curl-ready payloads
  screenshot.mjs  UI screenshots (optional, needs `npm i -D puppeteer`)
docs/
  demo-script.md  3-minute demo video storyboard
  screenshots/    Captured by scripts/screenshot.mjs
PRODUCT_FEEDBACK.md   Per-tool feedback + friction log (built during the Amazon
                       Developer Hackathon, Oct 2026 β€” submission window missed,
                       shared publicly as a portfolio piece)
```

## Feedback & friction

Development feedback on every tool/SDK used β€” plus a friction log with severity, workarounds, and suggestions β€” lives in [PRODUCT_FEEDBACK.md](PRODUCT_FEEDBACK.md).

## Roadmap

- Multi-household + auth (API keys per family)
- Receipt scanning β†’ `shopping_mark_purchased` (photo of the grocery receipt restocks the pantry)
- Dietary profiles ("grandma is visiting β€” gluten-free this week") constraining `recipes_match_by_ingredients`
- Real Alexa+ preview integration once available to outside developers
- Bedrock-native LLM planner option

## License

MIT β€” see [LICENSE](LICENSE).