I typed the wrong alarm name on purpose. It found the right one, ruled out DynamoDB, and located the fault in the service's own code. Four tool calls, under two minutes.
In my previous post I ran a CloudWatch investigation entirely from the console: click Investigate on a failing metric, accept a hypothesis, fill the facts, get an RCA. That flow is good, and it is the right one when you want a document at the end.
This is the other way in. Kiro CLI plus the AWS MCP servers, running in a terminal, talking to the same CloudWatch data. No console tabs, no report, just questions and answers.
What you get is different in a useful way. The console runs a structured investigation with a defined output. The CLI is conversational. You ask about an alarm, it pulls the alarm history, notices something adjacent, pulls that too, and tells you what it found. When you are triaging at 2 AM and do not yet know what you are looking for, that is the better shape.
Kiro CLI is the successor to Amazon Q Developer CLI. It reads the same .kiro/ configuration as Kiro IDE, so the MCP setup in this post works in both.
CloudShell is the fastest path because credentials are already there. No profile, no keys.
Open CloudShell from the console header, pick your region, and work in /tmp:
cd /tmp
curl --proto '=https' --tlsv1.2 -sSf \
'https://desktop-release.q.us-east-1.amazonaws.com/latest/kirocli-x86_64-linux.zip' \
-o 'kirocli.zip'
unzip kirocli.zip
Then put it on your PATH:
export PATH="$HOME/.local/bin:$PATH"
That export does not persist. CloudShell sessions time out, and every new tab or reconnect starts without it. If kiro-cli suddenly says command not found, that is why. Add it to ~/.bashrc if you are going to be in there a while, since CloudShell keeps your home directory between sessions.
Log in with the device flow:
kiro-cli login --use-device-flow
Choose Use for Free with Builder ID. Copy the URL it prints into a browser, sign in with your AWS Builder ID, or create one, and come back. Then check it works:
kiro-cli
You should get the Kiro banner and a prompt. /quit to come back out.
For anything beyond a workshop, install it locally. One command on macOS and Linux:
curl -fsSL https://cli.kiro.dev/install | bash
The installer detects an existing Amazon Q CLI install and upgrades it in place. It offers to modify your shell config so PATH is set for you, which is worth saying yes to. On Debian and Ubuntu there is also a .deb, and a universal AppImage for other distributions, both on the Kiro downloads page. Windows 11 installs from PowerShell.
If anything looks wrong afterwards:
kiro-cli doctor
That catches most PATH and shell-integration problems on its own.
One difference from CloudShell: locally, the MCP servers use your AWS credentials, so you need a working profile. Set AWS_PROFILE in the MCP config, which I will come to next.
The AWS MCP servers run through uvx, so install uv and a Python it can use:
curl -LsSf https://astral.sh/uv/install.sh | sh
uv self update
uv python install 3.10
You do not need sudo for any of this. It installs under your home directory, which matters for the next step.
Kiro reads MCP configuration from two places:
~/.kiro/settings/mcp.json, applies everywhere<project-root>/.kiro/settings/mcp.json, applies to that projectFor ops work you want user level. And this is shared configuration: if you use Kiro IDE, drop the same file at the same path and the IDE picks up the same servers.
mkdir -p ~/.kiro/settings
nano ~/.kiro/settings/mcp.json
sudo nano ~/.kiro/settings/mcp.json writes a root-owned file into your home directory. Kiro CLI runs as you, and you then get permission errors that look like config problems. Edit it as your normal user.
Here is the config I would actually recommend for CloudWatch work. Two servers: CloudWatch for metrics, alarms and logs, and CloudTrail for the change events that explain most incidents.
{
"mcpServers": {
"awslabs.cloudwatch-mcp-server": {
"autoApprove": [],
"disabled": false,
"command": "uvx",
"args": ["awslabs.cloudwatch-mcp-server@latest"],
"env": {
"FASTMCP_LOG_LEVEL": "ERROR",
"AWS_REGION": "us-west-2"
},
"transportType": "stdio"
},
"awslabs.cloudtrail-mcp-server": {
"autoApprove": [],
"disabled": false,
"command": "uvx",
"args": ["awslabs.cloudtrail-mcp-server@latest"],
"env": {
"FASTMCP_LOG_LEVEL": "ERROR",
"AWS_REGION": "us-west-2"
},
"transportType": "stdio"
}
}
}
Field by field, because these trip people up:
| Field | What it does |
|---|---|
command / args | uvx fetches and runs the server package. The @latest suffix re-checks PyPI on every start, which costs a few seconds of load time. Drop it and manage the uv cache yourself if you want faster startup. |
AWS_REGION | The region the server queries. Set it to where your workload runs, not where you happen to be sitting. |
AWS_PROFILE | Not shown above because CloudShell does not need it. On a local machine, add it and point it at your named profile. |
FASTMCP_LOG_LEVEL | ERROR keeps the server quiet. Set it to DEBUG when a server will not start. |
disabled | Turn a server off without deleting the block. Useful when you are narrowing down which server is misbehaving. |
autoApprove | Tool names that run without asking you first. Leave it empty until you know exactly which tools you are happy to auto-run. |
The workshop I did also had the Application Signals server configured, and it is worth adding if you have Application Signals deployed with SLOs defined. If you do not, it adds 38 tools that will never have anything to say. Add it only when the telemetry exists:
"awslabs.cloudwatch-appsignals-mcp-server": {
"autoApprove": [],
"disabled": false,
"command": "uvx",
"args": ["awslabs.cloudwatch-applicationsignals-mcp-server@latest"],
"env": {
"FASTMCP_LOG_LEVEL": "ERROR",
"AWS_REGION": "us-west-2"
}
}
Note the mismatch, which catches everyone: the server key is usually written cloudwatch-appsignals-mcp-server, but the package is awslabs.cloudwatch-applicationsignals-mcp-server. Copy the package name exactly.
Start the CLI. The first launch is slow because uvx is downloading packages.
kiro-cli
/mcp
You want running against each server and a tool count. If a server is stuck or failed, set FASTMCP_LOG_LEVEL to DEBUG and start again. Usually it is a typo in the package name or a region the credentials cannot reach.
Now the part that matters. I asked it about an alarm, and I deliberately got the name wrong.
Investigate the alarm petfood-api-slo in us-west-2 region
There is no alarm called petfood-api-slo. It called get_alarm_history, found nothing useful, then called get_active_alarms and found what I actually meant:
It reported the mismatch plainly, named the real alarm SLI-HealthAlarm-pet-api-rs-SLO, and kept going instead of stopping to ask me. It noticed the SLO had been created at 05:29 and gone into ALARM at 05:31, straight from INSUFFICIENT_DATA, then ran a root-cause audit.
The finding is where it earned its keep. A Rust service, petfood-api-rs, throwing server faults on POST /api, broken down by route:
Then it ruled out the obvious suspect. The only downstream call was DynamoDB GetItem on ddbPetFoods, returning Status: OK at around 3ms every time. The fault was inside the service's own add_cart_item code path, not in DynamoDB.
It also caught the shape of the failure: 6 to 30 faults per minute over three hours, averaging about four. Intermittent but steady, not a spike. That changes the entire investigation, because you stop looking for a deployment or a traffic event and start looking for a conditional path in the code.
Total elapsed: under two minutes, across four tool calls. Doing that by hand means the alarms page, the SLO page, the trace map and Log Insights, in four tabs.
The CloudWatch MCP server gives the agent tools for alarms, metrics and log queries. What you get out depends heavily on how you ask. A few patterns that hold up:
add_cart_item and to check recent deployments. Take it up on that rather than starting a fresh prompt.With the CloudTrail server added, the follow-up that pays off most is "what changed in this account in the hour before the alarm fired". That is the question that solves the majority of real incidents, and it is tedious to answer by hand.
In CloudShell the MCP servers inherit your console session's credentials. Whatever you can see, the agent can see. That is convenient in a workshop and worth thinking about in a customer account.
Locally, point AWS_PROFILE at a profile scoped to what the agent actually needs: CloudWatch read, Logs read, CloudTrail lookup. Read-only. There is no reason for an investigation profile to hold write permissions.
Two more things. Keep autoApprove empty until you have watched which tools get called and decided each one is safe to run unattended. And remember the output can contain account IDs, ARNs, table names and log content, so treat your terminal scrollback the same way you would treat a console screenshot before pasting it into a ticket or a Slack channel.
| Kiro CLI with MCP | CloudWatch Investigations | |
|---|---|---|
| Shape | Conversational. You ask, it answers, you follow up | Structured investigation with hypotheses to accept or rule out |
| Output | Answers in your terminal | An incident report you complete with facts |
| Setup | CLI, uv, an mcp.json | An investigation group with an IAM role, once per region |
| Retained | Nothing beyond your scrollback | 7 to 90 days, shared with your team |
| Best for | Fast triage when you do not yet know the question | Anything that needs a document at the end |
I use both, for different halves of the same incident. The CLI to work out what broke. The console to write down what happened. For the whole DevOps Agent comparison, I broke an EC2 instance to test that one back in March.
The setup is fifteen minutes and the same mcp.json works in Kiro IDE. If you already have a Builder ID, there is nothing stopping you doing this today.