Cloud cost management and FinOps with coding agents
PLAgent-driven cloud cost management connects Claude Code, Codex or Cursor to a read-only billing MCP server (AWS Billing and Cost Management, or Vantage for multi-cloud). The agent explains what moved the bill, ranks right-sizing candidates by risk and drafts the infrastructure-as-code change. Cost Explorer totals and terraform plan verify it; a human approves each change.
This page is for the developer or tech lead who owns a service’s cloud bill. Finance asks why spend jumped this month, nobody remembers launching anything, and the growth sits in an untagged EC2-Other line. The console answers one question per twenty clicks. You want a ranked story with evidence, and a change you can merge safely.
This page covers cloud infrastructure spend. For what the coding agents themselves cost, see AI usage cost governance.
What you get from an agent-driven FinOps loop
Section titled “What you get from an agent-driven FinOps loop”- A read-only billing MCP setup for Claude Code, Codex and Cursor, with an IAM role that cannot change a resource.
- Six copy-paste prompts: cost drivers, untagged spend, anomaly triage, right-sizing to Terraform, a quarterly forecast, and over-requested Kubernetes deployments.
- A verification routine that checks the agent’s numbers against Cost Explorer without re-reading its analysis line by line.
- A failure-modes list for the ways this goes wrong: wrong account, quiet lookback windows, missing tags, and an agent with write access.
Which billing MCP server should you connect?
Section titled “Which billing MCP server should you connect?”Pick the narrowest server that answers your cost questions. A general cloud server with write tools is the wrong default for FinOps work.
| Your spend | Server | Transport and auth | Why this one |
|---|---|---|---|
| AWS only | awslabs.billing-cost-management-mcp-server (PyPI 0.0.39, checked 2026-09-26) | stdio via uvx, your AWS_PROFILE | Cost Explorer, forecasts, Cost Anomaly Detection, Budgets, Compute Optimizer, Cost Optimization Hub, Savings Plans and cost allocation tags in one server |
| AWS, Azure, GCP, Kubernetes and SaaS | Vantage MCP | Hosted https://mcp.vantage.sh/mcp with OAuth, or npx -y vantage-mcp-server with a VANTAGE_TOKEN | One normalised view across providers, if your organisation already uses Vantage |
| Broader AWS work (Lambda runtimes, drift) | AWS MCP Server through the Agent Toolkit for AWS | SigV4 proxy via uvx | AWS’s recommended general server. Setup is on cloud and platform MCP servers |
If you would rather not keep a server connected, the Agent Toolkit for AWS aws-core plugin also ships an aws-billing-and-cost-management skill. It covers cost analysis, Savings Plans and Reserved Instances, Compute Optimizer right-sizing, anomalies and CUR queries with Athena, and suits a guided cost review; install steps are on cloud and platform MCP servers. Either way, the read-only IAM role below is the control.
As of 0.0.39 (checked 2026-09-26), the AWS billing server’s tools read and analyse; none of them resize or delete resources (Storage Lens queries do write Athena results to S3). Enforce that with IAM rather than trusting the tool list. The Vantage server can also create Vantage objects such as reports, so scope its token accordingly.
Set up read-only cost access
Section titled “Set up read-only cost access”New to MCP? Start with essential MCP servers.
-
Create a read-only billing role. Attach a policy with read actions only:
ce:Get*,ce:Describe*,ce:List*,compute-optimizer:Get*,cost-optimization-hub:Get*,cost-optimization-hub:List*,savingsplans:Describe*,pricing:Get*,pricing:Describe*,budgets:ViewBudgetandbudgets:DescribeBudgetActionsFor*. The Savings Plans and commitment-analysis generation tools also needce:StartSavingsPlansPurchaseRecommendationGenerationandce:StartCommitmentPurchaseAnalysis. Those start a recommendation job and change no resource, but they are notGetactions, so leave them out if you do not use those tools. The server’s README lists the exact actions per tool. Give it a profile name such asfinops-readonlyin~/.aws/config. -
Confirm the identity before the agent sees it. In a terminal, run:
Terminal window aws sts get-caller-identity --profile finops-readonlyThe account ID must be the payer (management) account if you want organisation-wide spend. A member account sees only its own costs.
-
Install
uvfrom Astral’s installation guide. The server runs throughuvx. -
Register the server. The definition is the same for every tool; only the file or command differs.
Terminal window claude mcp add aws-billing \-e AWS_PROFILE=finops-readonly -e AWS_REGION=us-east-1 -e FASTMCP_LOG_LEVEL=ERROR \-- uvx awslabs.billing-cost-management-mcp-server@latestThe default scope is
local, which keeps the profile name out of the repository. Check the connection withclaude mcp list, or/mcpinside a session.Terminal window codex mcp add aws-billing \--env AWS_PROFILE=finops-readonly --env AWS_REGION=us-east-1 --env FASTMCP_LOG_LEVEL=ERROR \-- uvx awslabs.billing-cost-management-mcp-server@latestThis writes an
[mcp_servers.aws-billing]table to~/.codex/config.toml. Check it withcodex mcp list.Add the server to
.cursor/mcp.jsonin the project, or to~/.cursor/mcp.jsonfor every project:{"mcpServers": {"aws-billing": {"command": "uvx","args": ["awslabs.billing-cost-management-mcp-server@latest"],"env": {"AWS_PROFILE": "finops-readonly","AWS_REGION": "us-east-1","FASTMCP_LOG_LEVEL": "ERROR"}}}}Enable it in Cursor’s MCP settings and confirm the billing tools appear in the tool list before you prompt.
-
Add Vantage if you run more than one cloud. The hosted server signs you in through the browser, so no token sits in a config file:
Terminal window # Claude Code: then run /mcp in a session to finish OAuthclaude mcp add --transport http vantage https://mcp.vantage.sh/mcp# Codex: run `codex mcp login vantage` if it asks you to authenticatecodex mcp add vantage --url https://mcp.vantage.sh/mcpIn Cursor, add
"vantage": { "url": "https://mcp.vantage.sh/mcp" }undermcpServers.
Explain the bill: which services moved, and why?
Section titled “Explain the bill: which services moved, and why?”Run analysis sessions in a mode that cannot edit files, so the agent reads and reports only.
Start with claude --permission-mode plan, or press Shift+Tab until the mode reads plan. Claude can call the billing tools and write its findings, but it proposes rather than edits. Claude may ask before each MCP tool call; approve the read-only billing tools or add them to permissions.allow.
Start with codex -c default_permissions=":read-only" (permission profiles are beta in Codex CLI 0.157.1). The sandbox governs shell commands, not MCP calls (checked against Codex CLI 0.157.1), so the IAM role remains the real limit.
Switch the agent to Plan Mode for the analysis. Move to Agent mode only when you reach the Terraform change later on this page.
Then ask a question with a named metric, window, grouping and output shape:
The last numbered line is the one that makes the output checkable. You compare one total, not ten rows (see how to prove the numbers are right).
The usual next question is the untagged spend, because a large untagged bucket is the most common reason nobody can explain a bill:
Tag activation applies from the moment you switch it on, not to past bills, unless you request a backfill. Expect this month’s report to stay partly untagged even after you fix the tags.
Triage an anomaly without paging the whole team
Section titled “Triage an anomaly without paging the whole team”If AWS Cost Anomaly Detection is enabled, the server can read its findings. Let the detector decide what is anomalous and let the agent explain it; an agent inventing its own thresholds produces a different answer every run. For versioned, replay-tested alert rules, use deterministic anomaly detection.
Turn a right-sizing recommendation into a reviewed change
Section titled “Turn a right-sizing recommendation into a reviewed change”Compute Optimizer and Cost Optimization Hub produce the candidates; the agent’s job is to rank them, attach the risk, and edit your infrastructure-as-code rather than the live resource. For the IaC review workflow itself, see infrastructure as code with AI.
How you drive the edit differs by tool:
Leave plan mode (Shift+Tab to acceptEdits) for this prompt only. Claude asks before it runs terraform plan unless you have allowed that command in .claude/settings.json. Keep terraform apply out of the allow list.
Run codex -c default_permissions=":workspace" -a on-request (permission profiles are beta in 0.157.1). The workspace profile lets Codex edit the Terraform files, while terraform plan still needs network access and provider credentials, so it arrives as an approval request: read it before you accept.
Switch to Agent mode and reference the Terraform file with @. Review the diff Cursor shows before you accept it, and keep the change on a branch so you can discard it if the plan looks wrong.
The change then goes through your normal pipeline: pull request, terraform plan in CI, and approval by the service owner. Savings Plans and Reserved Instance purchases never go through the agent. Those are one- or three-year financial commitments, so the agent drafts the recommendation and finance signs it off.
For approval modes and sandboxes side by side, see permissions, sandboxes and approval modes.
Forecast next quarter’s spend and check it against budgets
Section titled “Forecast next quarter’s spend and check it against budgets”A flat “same as last month” projection fails for any service with seasonality. Use Cost Explorer’s own forecast, which includes a prediction interval, and have the agent join it to your budgets:
Forecasts inherit the quality of your tags. If a quarter of the bill is untagged, every per-team number is an estimate; fix tag coverage first.
Script it for a weekly report
Section titled “Script it for a weekly report”For a scheduled report, compute the numbers in code and let the model only explain them. The deltas are then deterministic and testable, and the model cannot miscount.
// weekly-cost-report.mts: run with `npx tsx weekly-cost-report.mts`// (.mts makes tsx emit ESM, which the top-level await below needs)import { CostExplorer } from '@aws-sdk/client-cost-explorer';import Anthropic from '@anthropic-ai/sdk';
const ce = new CostExplorer({ region: 'us-east-1' }); // uses AWS_PROFILEconst anthropic = new Anthropic(); // reads ANTHROPIC_API_KEY from the environment
const day = (offset: number) => new Date(Date.now() - offset * 864e5).toISOString().slice(0, 10);async function byService(start: string, end: string): Promise<Map<string, number>> { const { ResultsByTime = [] } = await ce.getCostAndUsage({ TimePeriod: { Start: start, End: end }, Granularity: 'MONTHLY', Metrics: ['UnblendedCost'], GroupBy: [{ Type: 'DIMENSION', Key: 'SERVICE' }], }); const totals = new Map<string, number>(); for (const period of ResultsByTime) { for (const g of period.Groups ?? []) { const name = g.Keys?.[0] ?? 'unknown'; totals.set(name, (totals.get(name) ?? 0) + Number(g.Metrics?.UnblendedCost?.Amount ?? 0)); } } return totals;}
// Skip the last two days: Cost Explorer data for today and yesterday is still incomplete.const [current, previous] = await Promise.all([byService(day(9), day(2)), byService(day(16), day(9))]);const movers = [...current] .map(([service, cost]) => ({ service, cost, delta: cost - (previous.get(service) ?? 0) })) .sort((a, b) => b.delta - a.delta) .slice(0, 5);
const msg = await anthropic.messages.create({ model: 'claude-opus-5-5', max_tokens: 4000, // Opus 5.5 always thinks, and thinking tokens count against this limit messages: [{ role: 'user', content: `These are the five AWS services whose cost grew most this week versus last week, as JSON.Write a five-line summary for the engineering channel. Use the numbers exactly as given; do not compute new ones.${JSON.stringify(movers)}`, }],});for (const block of msg.content) if (block.type === 'text') console.log(block.text);claude-opus-5-5 is Anthropic’s recommended starting model (and Claude Code’s default from v2.1.280, on both release channels); a cheaper model works for a summary this short, and the models hub lists prices. Store ANTHROPIC_API_KEY in your scheduler’s secret store, never in the script. The Budgets API lives in a separate package, @aws-sdk/client-budgets.
Kubernetes cost: requests versus usage
Section titled “Kubernetes cost: requests versus usage”When the spend sits in a cluster, the waste usually hides in container requests far above real usage. Connect a Kubernetes MCP server in read-only mode; setup and the read_only = true TOML setting are on infrastructure MCP servers. The server sees current usage from the metrics API, not history, so a request cut based on one afternoon is a guess. Pair it with your Prometheus data for the p95 over at least a week.
How do you prove the agent’s cost numbers are right?
Section titled “How do you prove the agent’s cost numbers are right?”You do not re-read the analysis. You check a few numbers that the rest depends on, and you let existing gates check the change.
| What to verify | How | Who signs off |
|---|---|---|
| The bill totals | Run the same query yourself and compare the one grand total the prompt asked for: aws ce get-cost-and-usage --time-period Start=2026-08-01,End=2026-09-01 --granularity MONTHLY --metrics UnblendedCost --group-by Type=DIMENSION,Key=SERVICE --profile finops-readonly (replace the dates with the period the agent stated). A mismatch means the agent queried a different period, account or metric. | You |
| Each recommendation is real | Every row must name a resource ARN or ID and a Compute Optimizer or Cost Optimization Hub finding. Spot-check one with aws compute-optimizer get-ec2-instance-recommendations --instance-arns INSTANCE_ARN. INSTANCE_ARN is the ARN from the agent’s row. Drop any row without a source. | You |
| The change does only what it says | terraform plan in CI shows one attribute change per resource and no replacements you did not expect. A forces replacement line on a database is a stop. | Service owner, in the pull request |
| Production survives it | Watch latency, error rate and throttling for seven days after the change, against the service’s SLO, with the previous instance type recorded for rollback. See monitoring and observability. | On-call |
| The saving happened | Next month, rerun the cost-driver prompt and compare the service’s cost with the estimate you merged. | Tech lead |
What breaks when an agent analyses cloud costs?
Section titled “What breaks when an agent analyses cloud costs?”-
Every query comes back empty or with an access error. The profile resolves to the wrong account, the role lacks
ce:Get*, or Cost Explorer was never enabled in the billing console. Runaws sts get-caller-identity --profile finops-readonly, fix the policy, enable Cost Explorer, and restart the agent so it relaunches the server. -
The server never starts.
uvxis not on the PATH the agent process sees, which is common when the agent is launched from a desktop app. Runuvx awslabs.billing-cost-management-mcp-server@latestin a terminal: it should start and wait on stdin. Then restart the tool, or set the absolute path touvxas thecommand. -
The numbers disagree with the console. Cost Explorer data is not real time, so today’s and yesterday’s spend may still be incomplete. The agent may also have used
BlendedCostorAmortizedCost, or a member account instead of the payer. Ask it to restate the metric, period and account, then rerun. -
The bill for the analysis grows. Cost Explorer API requests are billed per request, and an agent that loops over daily granularity per service can issue hundreds. Ask for monthly granularity first, narrow to daily only on the services that moved, and do not attach the billing server to an unattended loop.
-
A right-size causes throttling. The recommendation came from a quiet lookback window, or from average rather than peak utilisation. Revert to the recorded instance type through the same pipeline, then rerun the right-sizing prompt with a lookback that includes your monthly peak.
-
Allocation numbers are wrong by team. Tags are missing or were activated mid-month. Treat per-team figures as estimates until tag coverage is high, and rerun the untagged-spend prompt after each tagging change.
-
The agent reports a server or tool that does not exist. A prompt that names a server you never configured does nothing, and the agent may fill the gap with plausible figures. Use the exact server name from
claude mcp listorcodex mcp list, and reject any figure that the verification table cannot reproduce.
Where to go next with cloud cost work
Section titled “Where to go next with cloud cost work”- Cloud and platform MCP servers: read-only identities for AWS, Azure and Google Cloud beyond billing.
- Infrastructure as code with AI: review and ship the Terraform change this page produces.
- Deterministic anomaly detection: turn cost alerts into versioned rules with a scoped agent diagnosis.
- AI usage cost governance: the other bill, for Claude Code, Codex and Cursor themselves.
- DevOps with AI: the rest of the operate stage.