Inspiration

At 2 a.m., when checkout starts failing, the on-call engineer's first ten minutes go to opening dashboards: metrics in one tab, deployments in another, vulnerability reports in a third, the ticketing tool in a fourth. The answer is usually one sentence ("errors jumped right after deployment 482"), but getting there takes clicks, context switching and memory of how the system fits together.

I wanted to see if a voice assistant could give that sentence directly. If Alexa+ can talk to tools through MCP, it can talk to the cloud. The goal: ask your cloud, don't dig for it.

What it does

Alexa CloudOps Copilot is an MCP server that gives a voice assistant seven cloud-operations tools:

  • diagnose_service: "Why is checkout degraded?" Reads live Amazon CloudWatch metrics, compares the last 10 minutes with the previous hour and with an error SLO, and names the deployment that likely caused it.
  • service_overview: "Which services are degraded?" Checks everything at once and names each degraded service.
  • list_failed_deployments and check_critical_cves: what failed recently, and which CVSS ≥ 9 vulnerabilities affect production.
  • create_incident_ticket: a write action that never runs without a spoken "yes".
  • recall and remember: an operational memory built on a knowledge graph.

Every answer is written for the ear: one short speech text to read aloud, plus structured details for the screen.

How we built it

The MCP server uses the MCP Python SDK over Streamable HTTP. Tool annotations (readOnlyHint / destructiveHint) tell the client which tools change something.

Real data. A small simulated shop pushes Requests, Errors and LatencyMs to CloudWatch every 10 seconds; a --chaos flag makes checkout-api fail. Let $e_{10}$ be the error rate over the last 10 minutes and $b_{60}$ the rate over the previous hour. A service is degraded when

$$ e_{10} > \max\left(2\%,\ 3\,b_{60}\right) \quad \lor \quad e_{10} \geq 5\% $$

The first condition catches sudden jumps. The second is an SLO floor, because I found that after an hour of failure the baseline "learns" the outage, and 12% errors started looking normal.

Safe writes. Creating a ticket takes two calls. The first returns a preview and a one-time confirmation code. The code is bound to a SHA-256 fingerprint of the exact payload, expires after 5 minutes and is single-use. An invented, reused or edited ticket is rejected, so the model can't skip the human.

Knowledge graph. The model's weights never change, so what the copilot learns lives in a graph of services, owner teams, dependencies, deployments, CVEs, tickets and notes. It powers three things:

  1. Cause vs. impact: if a degraded service's dependencies are healthy, the cause is local, and everything that depends on it is the blast radius.
  2. Learning from work: every confirmed ticket is linked to its service and to the deployment that caused it, so the next diagnosis says "a similar incident was filed before".
  3. Fewer tokens: a graph lookup returns a few pre-digested facts instead of long conversation history, logs or dashboards.

The agent. It is built with Strands Agents, with interchangeable model providers: Amazon Bedrock (the intended path), Groq (used for the demo) and Ollama.

voice-mcp-sim (open source). I couldn't test on a real Alexa+ device, so I built a browser voice assistant that tests any MCP server. You talk, it shows every tool call live, and it answers with Amazon Polly voices. Browser speech recognition is used when available, with a Whisper fallback when it fails.

Everything is covered by pytest, with AWS mocked by moto.

Challenges we ran into

  • Bedrock quota at zero. My new AWS account had a daily token quota of 0, marked not adjustable, for every model, even after upgrading to a paid plan. Because Strands abstracts the model provider, I switched to Groq without touching the agent code, and opened a support case.
  • Silent hangs. Throttled calls made the agent retry quietly for minutes. I wrote a script that tests each layer separately (tool listing, direct tool call, model alone, full agent) with timeouts.
  • A model that answered from memory. Streaming responses from one provider sometimes duplicated text, and follow-up questions were answered from conversation history instead of live data. That is dangerous for an ops tool. Non-streaming calls plus a strict "always call a tool for live state" rule fixed it.
  • Designing for the ear. "2 deployments failed" is useless if you can't see which ones. Long lists became "First…, Second…" sentences.
  • No Alexa+ device path for custom MCP servers during the hackathon, which became the reason voice-mcp-sim exists.

Every friction point is documented in the repo's FRICTION_LOG.md.

Accomplishments that we're proud of

  • A diagnosis from real CloudWatch metrics in one spoken sentence, including what caused it and what it affects.
  • A confirmation flow that holds even if the model misbehaves.
  • A copilot that remembers past incidents and team knowledge instead of starting from zero every time.
  • An open-source tool, voice-mcp-sim, that other MCP builders can use today.

What we learned

  • How MCP works end to end: tools, annotations and Streamable HTTP.
  • Building agents with Strands, and why provider abstraction matters when quotas fail.
  • CloudWatch metric math, and why baselines need an SLO floor.
  • That voice UX is its own discipline: short answers, spoken lists, and confirmations for anything that writes.
  • That safety has to live in the server, not only in the prompt.

What's next for Alexa CloudOps Copilot

  • Connect to a real Alexa+ device as soon as custom MCP servers are supported.
  • Run on Amazon Bedrock once the quota is approved: one environment variable, no code change.
  • Real integrations: CloudWatch alarms, AWS CodeDeploy history, Amazon Inspector findings and Jira.
  • Move the knowledge graph to Amazon Neptune for multi-team use.

Built With

Share this project:

Updates

Submission history