Guardian MCP
Provides MCP tools for Amazon Alexa+ to interact with Guardian, enabling voice-driven household safety event reporting, policy management, incident handling, and status queries.
Integrates with Ring as an observation source, ingesting Ring events via EventBridge/Lambda so Guardian can reason about doorbell and person detections and make policy-based decisions.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Guardian MCPThere's someone at my front door, should I escalate?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Guardian MCP
The Alexa+ MCP server for Guardian — an AI household safety agent that reasons about events, context, and policy before acting, rather than just forwarding alerts.
Architecture
Alexa+ ──(MCP tools/call)──► src/server.ts ──► src/tools.ts ──► decide() ──► store
Ring ──(EventBridge)────► src/lambda/ringEventHandler.ts ──► decide() ──► store
Dashboard (browser) ──(REST poll)──► src/server.ts /api/* ──► storeTwo independent entry points — the synchronous MCP path (Alexa+ voice
turns) and the asynchronous event path (Ring → EventBridge → Lambda) —
both call the exact same decide() function and read/write the exact
same store. That's deliberate: the reasoning and the state are the
product; MCP and EventBridge are just two doors into it.
Related MCP server: a207-router-mcp
What's in this repo
src/types/domain.ts— household/event/policy/incident data modelsrc/store/— storage layer, swappable:types.ts—IGuardianStoreinterface everything else codes againstmemoryStore.ts— in-memory, seeded, zero AWS dependency (default)dynamoStore.ts— real DynamoDB implementationindex.ts— picks the backend viaSTORE_BACKENDenv varseedData.ts— the demo household, shared by both backends
src/decisionEngine.ts— rule-based decision engine (deterministic, no AWS), including pattern-of-events escalation (Scenario D: no single event is alarming, but a cluster of unusual events in a short window is)src/bedrockDecisionEngine.ts— Bedrock-backed decision engine, with automatic fallback to the rule engine if the Bedrock call fails or times outsrc/decide.ts— picks the engine viaDECISION_ENGINEenv varsrc/policyCompiler.ts— Guardian Rules: turns a plain-language rule ("if Mom doesn't respond after two attempts, notify me") into a structuredPolicyvia Bedrock — no rule-based fallback here, since guessing a wrong structured policy is worse than reporting it couldn't parse the rulesrc/tools.ts— the 13 MCP tools Alexa+ callssrc/app.ts— the Express app (MCP endpoint, dashboard REST API, dashboard static files) — nolisten()call, shared by local dev and Lambdasrc/server.ts— local-dev entry point (app.listen())src/lambda/mcpHandler.ts— wraps the same app for Lambda + API Gateway viaserverless-http— this is what Alexa+ actually talks to once deployedsrc/lambda/ringEventHandler.ts— EventBridge-triggered Lambda for the Ring ingestion pathsrc/scripts/seedDynamo.ts— populates DynamoDB tables with the demo householdpublic/index.html— the dashboard (house status, active incidents, Contact/Escalate buttons) — this is your Fire TV screen; cast the browser tab if you don't build a native apptemplate.yaml— AWS SAM: both Lambdas, all 6 DynamoDB tables, the EventBridge rule, least-privilege IAM, and a CloudWatch dashboardaddon-package/addon.json— the Alexa+ add-on manifest, built to Amazon's real MCP Toolkit schema, with placeholders for what only you can providesrc/__tests__/decisionEngine.test.ts— automated tests for all four demo scenarios (A/B/C/D) plus the fallback path and two regression guards for real bugs the tests themselves caught (see below)src/__tests__/store.test.ts— regression test for a bug inaddEvent's timestamp handling, found via live testing rather than the existing suite (see below).github/workflows/ci.yml— typecheck + build + test on every push/PRinfra/*.sh— raw AWS CLI fallback if you need to provision outside of SAM
Run it locally (zero AWS dependency)
npm install
npm run build
npm start
# Guardian MCP server listening on http://localhost:3000/mcpDashboard: open
http://localhost:3000/Health check:
GET /health
This runs entirely on MemoryStore + the rule-based decision engine —
no AWS credentials needed to develop against it.
Try the reasoning pipeline directly
curl -s -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": "report_event",
"arguments": { "source": "ring", "type": "person_detected", "location": "front_door" }
}
}'This is the "unknown visitor at the door" scenario from the demo
script. With the seeded household (Mary home and marked vulnerable),
it returns a tier: "ask" decision asking whether Mary needs
anything — Scenario C from the design doc — and the reasoning always
includes "I won't unlock the door without your confirmation" no matter
which tier resolves the event. No Alexa+ or real Ring device required
to see it work.
Call initialize then tools/list first if you want the full tool
catalog and schemas (any MCP client, or curl with an
Accept: application/json, text/event-stream header, works).
Turning on Bedrock
export DECISION_ENGINE=bedrock
export AWS_REGION=us-east-1
export BEDROCK_MODEL_ID=anthropic.claude-3-5-sonnet-20241022-v2:0
npm startIf the Bedrock call fails for any reason (permissions, model not enabled in-region, network blip mid-demo), it automatically falls back to the rule engine and logs why — the demo doesn't crash, it just gets slightly less nuanced for that one decision.
Teaching Guardian a new rule (Guardian Rules)
curl -s -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": "add_policy",
"arguments": { "rule": "If someone knocks after 10pm, always wake me even if it seems minor" }
}
}'Requires DECISION_ENGINE=bedrock (or just Bedrock credentials present
— the compiler always uses Bedrock, there's no rule-based fallback for
this one). Without credentials it fails loudly and explains why,
rather than crashing or silently guessing.
Bugs and gaps found along the way
Worth documenting honestly rather than glossing over:
The hard constraint was too broad.
p-never-auto-unlockmatched anyperson_detectedevent, so a scheduled visitor (e.g. the cleaner, arriving in their normal Monday window) would incorrectly trigger the same "I won't unlock the door" refusal as a genuinely unknown visitor — Scenario A from the design doc was never actually achievable. Fixed by adding an expected-visitor context check that runs first. (Found by writing tests.)A catch-all policy was silently matching everything.
p-quiet-hourshad an emptyappliesTo, which the originalmatches()function treated as "matches any event" — meaning it won before the intended hardcoded default ever ran, making that default dead code. Fixed by requiring policies to specify at least one criterion to auto-match. (Found by writing tests.)Scenarios B and C didn't exist, and the "refusal" demo was tier-mislabeled. The original build only ever implemented Scenario A (expected visitor) and D (pattern escalation) — B (owner away → simple notify) and C (vulnerable member home → ask if assistance is needed) were never coded. Worse: the "AI refuses an unsafe action" demo moment was hardcoded to
tier: "escalate"at 95% confidence, which doesn't match the design doc's own transcript for that exact situation ("I'll notify you and continue monitoring" — restrained, not urgent) and contradicts the Bedrock engine's own system prompt, which explicitly says to use escalate sparingly. Fixed by implementingcheckVulnerableMemberHome(C) andcheckOwnerAway(B) as real context checks, and folding the never-auto-unlock constraint into normal policy resolution so its tier follows context (inform/ask) while the refusal language itself stays constant across every tier. (Found by a direct question — "did we only have A and D, is there B and C" — not by the test suite. The lesson: passing tests only prove the code does what the tests assume it should; they don't catch a scenario that was never implemented or a demo that was confidently mislabeled.)
All three are now regression-tested in decisionEngine.test.ts.
Adding the
timestampoverride itself introduced a new bug.tools.ts's{ source, type, location, timestamp }object literal always creates an owntimestampproperty —undefinedwhen the caller omits it, but present nonetheless.addEvent's object spread was ordered{ timestamp: computedDefault, ...input }, so that explicitundefinedsilently overwrote the computed default — every event created without an explicit timestamp ended up with no timestamp at all, which broke Scenario D's pattern detection (it filters by timestamp). Caught by live-testing all four scenarios end to end after the B/C fix, not by the existing test suite — every existing test happened to always pass an explicit timestamp. Fixed by reordering the spread soid/timestampare always assigned after the spread, and added a targeted regression test (store.test.ts) that reproduces the exact input shapetools.tsproduces — verified to fail against the old code before confirming the fix.
Deploying (Lambda + API Gateway + DynamoDB + EventBridge)
Everything is wired in template.yaml (AWS SAM). One-time setup: install
the SAM CLI.
npm run build
sam build
sam deploy --guidedsam deploy --guided will prompt for a stack name and region, then
create:
McpFunction— the MCP server (Lambda + HTTP API), the public HTTPS endpoint Alexa+ talks toRingEventFunction— the Ring ingestion Lambda, subscribed to an EventBridge rule matchingsource: "guardian.ring"6 DynamoDB tables (members, visitors, policies, events, incidents, config)
A CloudWatch dashboard (
guardian-agent) with invocation/error/latency widgets — including p50/p99 latency against Alexa+'s 500ms requirementIAM roles scoped to exactly what each function needs (DynamoDB CRUD on its own tables,
bedrock:InvokeModelscoped to Anthropic models — notbedrock:*)
Start with DecisionEngine=rules (the default parameter) to confirm the
whole pipeline works with zero Bedrock dependency, then redeploy with
DecisionEngine=bedrock once you've confirmed model access:
sam deploy --parameter-overrides DecisionEngine=bedrockAfter deploy, seed the tables (same demo household as local dev):
npm run seed:dynamoThe stack output McpEndpoint is the URL you need for the next step.
Alexa+ track compliance
The Devpost rules for the Alexa+ track require: "a working Agent Skill
or a self-hosted MCP server, implementing MCP spec version (minimum
acceptable version is 2025-11-25)." Guardian satisfies this on the
MCP server branch — it negotiates 2025-11-25 correctly and is
deployed at a public HTTPS endpoint. No additional registration step
is required to meet the track requirement.
To verify spec compliance against the running server:
npx @modelcontextprotocol/inspector
# point it at https://h14vepqrzj.execute-api.us-east-1.amazonaws.com/mcp
# or http://localhost:3000/mcp for local devOptional — Alexa+ MCP Toolkit (Private Preview): if you have
Private Preview access, addon-package/addon.json is already built to
Amazon's real add-on schema with all URLs filled in. Register and
deploy with:
npm install -g @alexa-ai/cli
alexa-ai configure # LWA OAuth, one-time
cd addon-package && alexa-ai deployThis is an enhancement on top of an already-compliant submission, not a requirement.
Wiring in real Ring events
The EventBridge rule and Lambda subscription are already created by
sam deploy (see above) — nothing further to provision. Point your
Ring webhook/poller at a small adapter that calls EventBridge
PutEvents with Source: "guardian.ring", DetailType: "RingEvent",
and a Detail of { eventType, location }. Keep Ring as the
observation source only — all reasoning stays in the decision engine,
per the product's core design principle (Ring produces observations,
Guardian produces decisions).
For quick manual testing without a real Ring device:
aws events put-events --entries '[{
"Source": "guardian.ring",
"DetailType": "RingEvent",
"Detail": "{\"eventType\":\"person_detected\",\"location\":\"front_door\"}"
}]'infra/dynamodb-tables.sh and infra/eventbridge-rule.sh are kept as
a raw-CLI fallback if you ever need to provision outside of SAM (e.g.
debugging a single resource) — normal path is sam deploy.
Docs
SUBMISSION.md— judge-facing writeup: problem, differentiation, architecture, AWS usageDEMO_SCRIPT.md— both demos, timed, mapped to actual tool callsCONTRIBUTING.md— the extension points that make this reusable beyond Guardian specificallyFRICTION_LOG.md— template + one real entry, for the Open Source and general judging bonusLICENSE— MIT
Store listing assets
addon-package/media/ has a generated icon set (all 6 required sizes)
and a carousel image, styled to match the dashboard — real files, not
placeholders, ready to upload to wherever you host static assets
(S3+CloudFront, GitHub Pages, etc.). Regenerate them with
python3 brand-assets/generate_icons.py and
python3 brand-assets/generate_carousel.py if you want to tweak the
look (both are plain PIL, no network dependency).
addon-package/legal/privacy-policy.md and terms-of-use.md are
drafts scoped to exactly what this codebase actually collects and
does — not generic boilerplate. Replace the bracketed placeholders,
get them reviewed, host them, then point addon.json's
privacyPolicyUrl / termsOfUseUrl at the hosted versions.
Build order status
✅ MCP server + rule-based decision engine (zero AWS deps, tested)
✅ Bedrock decision engine with automatic fallback
✅ DynamoDB store, swappable via
STORE_BACKENDenv var✅ Ring → EventBridge → Lambda ingestion path
✅ Dashboard (Fire TV screen)
✅ Pattern-of-events escalation (Scenario D)
✅ NL policy compiler (Guardian Rules)
✅ SAM deployment (Lambda + API Gateway + DynamoDB + EventBridge + CloudWatch)
✅
addon.jsonbuilt to Amazon's real MCP Toolkit schema✅ Open-source packaging: LICENSE, CONTRIBUTING.md (real extension points, not boilerplate), FRICTION_LOG.md
✅ Demo script, timed and mapped to tested tool calls, with a backup-video plan
✅ Store listing assets (generated icon set + carousel image) and privacy policy / terms drafts scoped to what the code actually does
✅ Judge-facing submission writeup (
SUBMISSION.md)You: record your demo video (MCP Inspector or curl against the deployed endpoint fully satisfies the track requirement — a real voice interaction via the bridge tool or Alexa+ Private Preview is a bonus, not a requirement), fill in the friction log and the AWS-feedback section of
SUBMISSION.mdas you go
This server cannot be deployed
Maintenance
Related MCP Connectors
The system of record for AI agent authority: playbooks, routed policy questions, reusable rules.
Manage incident alerts, events, and workflows with custom automations
Zero-secret MCP gateway for AI agents: risk-scored, audited calls with human-in-the-loop approval.
- AgenTruxOAuthcom.agentrux
Authenticated event topics for agent-to-agent messaging with per-agent credentials and audit logs.
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceEnables AI agents to control Alexa-connected smart home devices, including voice announcements, music control, smart lighting, sensor monitoring, and volume management through the Alexa API.-
- FlicenseBqualityBmaintenanceProvides deterministic intent routing and safety gating for multi-agent systems, enforcing P0 critical word detection, mutually exclusive hard rules (MX-1/2/3), and a permission matrix as pure functions via four MCP tools.4-
- AlicenseNot gradedqualityCmaintenanceEnables Alexa+ agents to maintain auditable operational continuity across shifts by turning speech into verifiable state, persisting unresolved work, refusing unverified actions, and requiring human approval before executing and confirming high-risk tasks.MIT
- AlicenseNot gradedqualityCmaintenanceEnables context-aware household safety workflows to coordinate smart-home events, household context, policies, risk, and safe actions through auditable MCP tools for status, event evaluation, wellness checks, rule creation, and action requests.MIT