Source code (MIT): github.com/guptachetan1995/alexa-plus. Live MCP server: http://16.176.3.215:3000/mcp on AWS EC2. It speaks MCP over Streamable HTTP, so a browser tab shows HTTP 400; connect an MCP client instead, for example npx -y @modelcontextprotocol/inspector --cli http://16.176.3.215:3000/mcp --method tools/list (details).

Inspiration

Smart home owners run dozens of connected devices through fragmented vendor apps — a separate download, login, and interface per brand. There is no unified way to discover what a home can do, no consistent interface across brands, and no single place to see the state of the house. Sequencing an action across two brands means jumping between two apps.

Handing that to an agent fixes the fragmentation and creates a worse problem: an agent that can unlock your front door is an agent that can unlock your front door by mistake. Most demos answer this with a confirmation dialog the agent itself can decide to skip.

What it does

Smart Home Agent is a self-hosted MCP server that exposes a whole smart home through one interface, plus a simulated Alexa+ web client that drives it. The agent can discover devices, read their state, check the home's automation policy, and compose multi-device scenes. What it cannot do — structurally, not by convention — is change anything.

Every mutation goes through a propose → confirm → execute lifecycle: the agent calls propose_action (or compose_scene), which creates a proposal with its expected outcome, rationale, and policy check but changes no state. The conversation stops on a "Confirmation needed" panel with Confirm and Decline. Only if the person clicks Confirm does the server mint a one-time confirmation token — minted by exactly one function, reachable through exactly one owner-only REST route, never through any tool the agent can call. execute_action accepts that token once, for that exact device, action and parameters, re-checks the automation policy, and only then writes an audit entry recording the person as the actor.

Try to skip any of that and the call is refused with a narrated reason, not a silent no-op: no token, an unknown token, an unapproved proposal, a replayed token, a token approved for a different action, or a policy denial at execute time — each covered by its own test.

How we built it

  • MCP server (server/) — Express 5 + the official @modelcontextprotocol/sdk, speaking Streamable HTTP at spec revision 2025-11-25 on /mcp (POST, GET, DELETE, with full session-id issuance, reuse and termination). Eight tools: four read-only (list_devices, get_device_state, check_automation_policy, read_audit_log) and two propose/execute pairs (propose_action/execute_action, compose_scene/execute_scene).
  • Simulated Alexa+ client (client/) — a React conversation UI with no bundler and no build step (React loads from a CDN import map). It is a genuinely separate project — its own package.json, and it imports nothing from server/; it reaches the server only over HTTP, which the entry's verify.sh enforces with a cross-import check.
  • The approval boundary — ProposalStore.approve() is the only code in the system that ever sets a confirmation token, and its only caller is the owner-only POST /proposals/:id/approve REST route. No MCP tool wraps it. That is what makes "only a person can authorize a change" a property of the architecture rather than a promise in a prompt.
  • Deterministic by default — the planner walks a scripted conversation, so the demo and the tests run identically with no LLM and no API key.

Challenges we ran into

Two dependency gaps cost real debugging time: createMcpExpressApp() ships no CORS handling, so a cross-origin browser client fails with a bare "Failed to fetch" whose real cause (a preflight 404 and a missing Access-Control-Expose-Headers: Mcp-Session-Id) is invisible in a Node integration test, since Node's fetch isn't subject to CORS. And Jest 30 renamed --testPathPattern to --testPathPatterns as a hard error with no deprecated alias, so every still-current Jest tutorial fails on first run.

AWS services used

  • Amazon Bedrock (Converse API, tool-use loop, model amazon.nova-micro-v1:0) is an optional planner (PLANNER=bedrock) that replaces the scripted turn sequence with real model reasoning. Every tool call still goes through the same MCP client, and every change still needs the person's Confirm: the model has no path to mint a confirmation token. Proven with a live Converse call from AWS CloudShell that returned a real tool-use decision (HTTP 200).
  • AWS EC2 hosts the MCP server itself at http://16.176.3.215:3000/mcp (t3.micro, Amazon Linux 2023, ap-southeast-2).

This entry is also in the Open Source mini-challenge: a new, MIT-licensed project created inside the submission window.

What's next

  • An HTTPS endpoint and the OAuth 2.1 + PKCE onboarding flow a real Alexa+ add-on needs.
  • A real Alexa+ surface in the loop (the Alexa+ MCP Toolkit or an Agent Skill) in place of the simulated client.
  • Persistence for devices, proposals and the audit log, which live in memory today.

Built With

Share this project:

Updates

Submission history