Skip to main content

cloudlens

Cloud cost findings priced at your negotiated rates, reconciled to your actual invoice, and delivered as changes you can merge.

Runs on your machine. Reads your bill and your code. Sends nothing anywhere.

cloudlens check --profile your-aws-profile
About $210.44 a month.
$141.26 a month looks avoidable (67% of the bill).

$137.39/month — Client VPN endpoint billed continuously with nobody connecting
  Why: 4,656 endpoint-hours billed, with 0.0 connection-hours
  Do:  Delete the endpoint, or disassociate its subnets.
  Risk if wrong: A VPN kept for break-glass access is unused by design.

$3.23/month — Amazon DynamoDB is just over its free allowance
  Why: 24,056 unit-hours billed against a free allowance of 18,600
  Do:  Reduce to 18,600 or below and the charge disappears entirely.

That is the whole product. Everything below is optional depth.

Or ask an agent instead of running a command — see Use it from Claude.


Why another one

Three things this does that the others do not.

It knows what you actually pay. The AWS Price List API is documented as "for informational purposes only". Every tool that prices findings from it — including the pre-deploy estimators — is wrong for any customer with an enterprise discount, commonly by 20–40%, always in the direction of overstating. cloudlens derives your real rate card from your own bill:

Rate card  4 rates derived from your own billing data (4 measured)
Observed discount off public pricing: 16.0% — pricing findings at list price
would overstate savings by roughly this much.

It refuses to publish numbers that don't tie out. Every run reconciles computed spend against your real invoice. If it doesn't match, you get the discrepancy instead of a savings figure.

┏━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┓
┃ Period  ┃ Computed ┃ Invoice ┃  Delta ┃          ┃
┡━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━┩
│ 2026-07 │  $253.46 │ $253.46 │ +0.00% │ ties out │
└─────────┴──────────┴─────────┴────────┴──────────┘

It proves savings against history rather than projecting them.

"Had this been applied at the start of 2026-06, your actual invoices for 2026-06 and 2026-07 would have been $27.22 and $27.22 lower — computed against your own line items."


Install

Nothing to install:

uvx --from cloudlens-mcp cloudlens check --profile prod

(--from names the package, cloudlens names the command inside it. Bare uvx cloudlens-mcp starts the MCP server instead, which is the other half.)

Or clone it, to run the tests or work on it:

git clone <repo> && cd cloudlens
uv sync --extra dev        # or: pip install -e ".[dev]"
uv run cloudlens demo
uv run pytest

Python 3.11+. Five dependencies: duckdb, boto3, rich, typer, openpyxl. The lockfile is committed, so installs are reproducible.


Use

Without a repo — works on day one

Source access is a hard ask on a first engagement, so everything here comes from the bill alone. No CloudWatch, no agent, no describe permission.

cloudlens scan     --cur s3://bucket/prefix/ --invoices invoices.json
cloudlens trends   --cur s3://bucket/prefix/
cloudlens profile  --cur s3://bucket/prefix/

An hourly CUR is a time series, not a ledger — so the weekly rhythm of every resource is already in it:

i-0uatworker   billed 1,464h · active 405h · 72% idle · $55.34

        00              06              12              18
  Sun  ························
  Mon  ·········█████████······
  Fri  ·········█████████······
  Sat  ························

With a repo — ownership, AI defects, mergeable fixes

cloudlens findings --cur s3://... --repo . --invoices invoices.json --detail
cloudlens report   --cur s3://... --repo . --out report.xlsx
cloudlens fix      --cur s3://... --repo . --id gp2-to-gp3-001 --write

Attribution resolves ownership through a ten-rung ladder — code first, because git history outlives CloudTrail's 90-day window:

Attribution  92.4% of $1,091.56 traced to an owner
│    1 │ infrastructure as code          │ $433.84 │ 53.2% │
│    3 │ AWS-generated tag               │ $302.40 │ 37.1% │
│    — │ no owner found                  │  $38.64 │  4.7% │

In CI

cloudlens ci --cur s3://... --plan tfplan.json --repo . \
             --max-monthly-increase 500

Posts a PR comment nothing else can produce — the cost of the change at your rates, plus existing waste attached to the code being touched.


Commands

check Start here. What is wasting money, in plain English
scan Rate card and reconciliation
trends · profile What changed, what spiked, weekly usage rhythm
attribute · ask · answer Who owns what; ask a human; record the answer
findings Waste, priced and citing AWS best practices
aiscan LLM cost defects in source — unbounded loops, uncapped prompts
fix · tagplan Findings as mergeable diffs
ci Price a Terraform plan, comment on the PR
report Six-sheet spreadsheet for finance

Use it from Claude

Two ways, both read-only.

MCP server. Copy .mcp.json.example to .mcp.json:

{
  "mcpServers": {
    "cloudlens": {
      "command": "uvx",
      "args": ["cloudlens-mcp@latest"],
      "env": { "AWS_PROFILE": "your-readonly-profile" }
    }
  }
}

Nothing to clone and nothing to install. uvx fetches the package, builds a throwaway environment and runs it. The CLI is the same package, asked for by command name:

uvx --from cloudlens-mcp cloudlens check --profile prod

Replace @latest with ==0.1.0 when you want a pinned version.

Six tools: what_is_wasting_money, what_was_not_examined, what_changed, free_tier_status, show_fix, capabilities.

Skill. One command, which also has nothing to clone:

uvx --from cloudlens-mcp cloudlens install

It writes the skill to ~/.claude/skills/cloudlens/ and prints the MCP entry to paste. --skills-dir puts it elsewhere, --mcp-config .mcp.json writes the entry rather than printing it.

The skill teaches an agent how to read the output — which confidence tiers can be added together, why a short findings list needs the coverage number beside it, and always to relay the failure case before recommending a deletion. The MCP server carries the essentials in its own instructions, which arrive over the wire, so the two agree by construction: the skill ships inside the package next to the server that describes it.

On guardrails

AWS's Agent Toolkit needs aws:CalledViaAWSMCP deny policies so an agent cannot do more through MCP than the human should, because that toolkit can call anything.

This needs none. There is no mutating AWS call anywhere in the codebase — the tool names contain no verbs, show_fix returns a diff for you to review rather than applying it, and the only file ever written goes into your own working copy. There is no privilege to escalate, so there is nothing to fence off. Ask the capabilities tool and it will say so itself.

The credential is the AWS profile already on the machine. Nothing new is issued, nothing is stored, and nothing leaves the host.


Access

Minimum is read on one S3 prefix. See docs/SETUP.md; for client engagements see docs/MULTI_CLIENT.md and the self-expiring onboarding stack.

No write action, anywhere. fix --write edits your local working copy so you can review it with git diff; it never calls a mutating AWS API.


What it will not do

Deliberate, and the reason to trust the numbers it does give:

  • Won't price from a public price list when it has never seen that usage type in your account. It says unpriced and explains why.
  • Won't claim a saving it can't replay against your real line items. Those say "estimate rather than a replay of history."
  • Won't report a resource as idle because it emits no activity data. Absence of evidence is not evidence of idleness.
  • Won't tell you to schedule something with no stopped state.
  • Won't reformat your Terraform to change one attribute.
  • Won't apply anything. You merge.

Confidence is stated on every figure — measured, derived or bounded — and never summed into one optimistic headline.


Status

253 tests. Full pipeline works end to end.

Validated against synthetic data only. The fixture plants findings with known values and computes ground truth independently of the code under test, so the logic and arithmetic are sound. What that cannot prove is that a real AWS bill matches the assumptions — the reconciliation tolerance (0.5%), the Terraform-type-to-usage-type mapping, and the flow-log field casing are all calibrated against data I wrote.

Running it against one real CUR is the highest-value next step, and the fastest way to find out which assumptions are wrong.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cloudlens_mcp-0.1.1.tar.gz (277.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cloudlens_mcp-0.1.1-py3-none-any.whl (143.6 kB view details)

Uploaded Python 3

File details

Details for the file cloudlens_mcp-0.1.1.tar.gz.

File metadata

  • Download URL: cloudlens_mcp-0.1.1.tar.gz
  • Upload date:
  • Size: 277.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.11 {"installer":{"name":"uv","version":"0.9.11"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for cloudlens_mcp-0.1.1.tar.gz
Algorithm Hash digest
SHA256 56427bf1158bab9156aa6031a24b94344f7393ea294d49ddbcba7515890622f4
MD5 b06c7095780791b15fc6d8453377c598
BLAKE2b-256 61c633f5488c9eb98299391a098f9fef7a8654a3b680997bf6575a25a39c72ec

See more details on using hashes here.

File details

Details for the file cloudlens_mcp-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: cloudlens_mcp-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 143.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.11 {"installer":{"name":"uv","version":"0.9.11"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for cloudlens_mcp-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 00aca573a787a699116eeaad09bcad0f0a334a94a1d3df481155f16e7af400bd
MD5 72d66a78516bad26327cf49fba4f51b8
BLAKE2b-256 25016483de0bd43a795dff88fe2aec045b2f1342e685e9eac7543a3775a450a3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page