
Security News
Happy Birthday, Shai-Hulud
It has been one year since Shai-Hulud made its first appearance on npm.
cloud-finops-mcp
Advanced tools
MCP server exposing the OptimNow Cloud FinOps skill (reference library + named-pattern playbooks) as queryable tools.
MCP server exposing the OptimNow Cloud FinOps skill (reference library + named-pattern playbooks) as queryable tools for any MCP-aware client (Claude Code, Cursor, Codex CLI, Windsurf, Aider, Cline, etc.).
The skill itself ships in canonical Claude Agent-Skills format and is also installable
via the cross-tool installer (./install.sh) for direct context injection. This MCP
server is the enrichment path: instead of loading the full skill into the
prompt, the agent calls tools to discover, filter, and fetch only what it needs.
Six tools, all read-only, split across two surfaces.
References - long-form provider and discipline files. They vary by more than
tenfold, from ~160 lines (roughly 2K tokens) to ~1,800 lines (roughly 26K tokens), so
budget context per file rather than assuming a uniform size. Every listing entry
carries an approx_tokens hint for exactly that reason.
| Tool | Purpose |
|---|---|
list_references() | Browse the knowledge library: what guidance exists, with its FinOps Framework facets and an approx_tokens size hint. |
get_reference(name, section?) | Read one guide - mechanics, decision rules, worked examples. Whole by default, or one H2/H3 section when the question is narrower than the file. |
find_references(domain?, capability?, phase?, persona?, maturity?, persona_primary_only?) | Route a FinOps question (commitment sizing, chargeback design, ...) to the guides that serve it, by FinOps Framework facet. |
The reference faceted query supports any combination of:
domain - FinOps Framework domain (e.g. Optimize Usage & Cost, Quantify Business Value)capability - FinOps capability (matches both primary and secondary)phase - Inform, Optimize, Operatepersona - matches both primary and collaborating personaspersona_primary_only - optional flag: match persona against the primary
list only. Broad personas (Engineering) collaborate on nearly every file,
so the default match barely narrows; the flag is the reading-list cut.maturity - Crawl, Walk, RunThe listing prints the primary facets only. Secondary capabilities and
collaborating personas are still fully filterable through find_references;
they are kept out of the payload because they do not help a caller choose
while costing a sixth of a call that every session makes.
get_reference takes an optional section. It exists because the provider
pattern catalogues (finops-aws-patterns, finops-azure-patterns) are
enumerated lists past 25K tokens, and an agent asking about S3 lifecycle wants
one heading out of them, not the file.
get_reference("finops-aws-patterns") # ~26,600 tokens
get_reference("finops-aws-patterns", section="storage") # ~4,800 tokens
get_reference("finops-aws-patterns", section="networking") # ~2,600 tokens
"storage optimization patterns" finds "Storage Optimization Patterns (28)". H3 is not an extra:
the two catalogues carry a single H2 each, so an H2-only splitter would leave
the largest files in the library un-sectionable.content is prefixed with the reference's H1 so the chunk is
self-describing, and the payload carries partial: true, section,
section_level and full_lines.available_sections - every heading in the file - plus near-miss suggestions,
rather than silently handing back the whole body the caller was trying to
avoid. That error is ~140 tokens, so a wrong first guess costs almost nothing.section is unchanged in every respect: content is the file
verbatim, frontmatter included.Playbooks - small named-pattern runbooks (~90-150 lines, ~3-8 KB each):
| Tool | Purpose |
|---|---|
list_playbooks() | Browse the waste runbooks: which patterns of idle, orphaned, overprovisioned or leaking spend have a ready-made runbook. Carries the same approx_tokens hint. |
get_playbook(name) | Read one runbook: symptoms, detection queries, fix, anti-pattern. |
find_playbooks(scope?, service?, waste_category?, confidence?) | "We are wasting money on X - how do I find and fix it?" - filter runbooks by provider, service, waste category, confidence. Also the route for questions about your own estate ("which of my RIs are about to expire"): the server cannot see your account, so the runbook's detection query is the answer it hands over. |
The playbook faceted query supports:
scope - aws, azure, gcp, or cross-cloudservice - provider service (e.g. AWS NAT Gateway); exact-matchwaste_category - orphaned, idle, overprovisioned, commitment-mismatch,
schedule-blindness, modernization, ai-ml-inefficiency, egressconfidence - obvious, likely, possible (OptimNow three-tier model)All filters across both surfaces AND together. String matches are case-insensitive and exact (no substring matching).
When to use which surface:
Neither surface serves current prices. References carry billing mechanics - multipliers, commitment term structure, the shape of a break-even calculation - and any absolute figure inside them is illustrative and dated inline. For a current price, use a live pricing tool such as the OptimNow AI Pricing Hub rather than a figure remembered from a reference body.
pip install cloud-finops-mcp
Or run without installing via uv:
uvx cloud-finops-mcp
The server is deployed at:
https://cloud-finops-skills-590a051d.alpic.live/
Add it via Settings -> Connectors -> Add custom connector and paste exactly that
URL - trailing slash included, the widget sandbox domain is derived from it. A variant
form (/mcp, or no trailing slash) connects fine but silently disables widget
rendering, because the MCP Apps host validates the sandbox domain against the URL as
entered.
Do not wire a remote server through claude_desktop_config.json: Desktop silently
drops "type": "http" entries from that file, and the npx mcp-remote bridge adds
enough startup latency to blow Desktop's initialize timeout.
Claude Code can use the same hosted URL without any install:
claude mcp add --transport http cloud-finops https://cloud-finops-skills-590a051d.alpic.live/
For the local clients below, install the package first, then point the client at the
cloud-finops-mcp console script.
Project-level, in .mcp.json at the repo root:
{
"mcpServers": {
"cloud-finops": {
"command": "cloud-finops-mcp"
}
}
}
For user scope there is no ~/.claude/mcp.json - Claude Code does not read that
path. Register the server once for every project with:
claude mcp add --scope user cloud-finops -- cloud-finops-mcp
Restart Claude Code, then run /mcp to confirm the server is connected.
~/.cursor/mcp.json:
{
"mcpServers": {
"cloud-finops": {
"command": "cloud-finops-mcp"
}
}
}
~/.codex/config.toml:
[mcp_servers.cloud-finops]
command = "cloud-finops-mcp"
~/.windsurf/mcp.json:
{
"mcpServers": {
"cloud-finops": {
"command": "cloud-finops-mcp"
}
}
}
The server speaks MCP over stdio. Point any compatible client at cloud-finops-mcp
(or python -m cloud_finops_mcp).
stdio is the default and is what every local client above spawns. For a hosted deployment, the same six tools are served over streamable HTTP:
cloud-finops-mcp --transport http
/mcp (the SDK default, and what hosting platforms probe).0.0.0.0; port comes from $PORT, falling back to 8000. --host and
--port override both.uvicorn and starlette already ship as hard
dependencies of mcp, so there is no [http] extra to install.Nothing about the tools changes between transports. tests/test_e2e_http.py
mirrors the stdio suite over HTTP so the two cannot silently diverge.
Hosts that support MCP Apps can render three bundled widgets instead of raw
JSON: a playbook explorer on list_playbooks / find_playbooks (card
grid with facet filters plus a coverage-matrix view; clicking a card opens
the playbook inline), a playbook viewer on get_playbook (colour-coded
sections, Copy buttons on code blocks, a checkable Fix list, clickable
See-also links), and a reference browser on list_references /
find_references (facet dropdowns, live-filtered list, reading panel).
Each widget is a single self-contained HTML file; hosts without MCP Apps
support fall back to the plain tool result.
Rendering in Claude Desktop / claude.ai for a custom connector is gated by
the host's ui.domain validation of the connector URL (and historically by
Connectors Directory acceptance) - a conformant widget may still fall back
to text there. Other hosts (e.g. MCPJam's host emulation) render it as-is.
Agent prompt: "Use the cloud-finops MCP to find references for the Optimize phase aimed at Engineering."
Calls find_references(phase="Optimize", persona="Engineering") and gets back the
filtered subset (AWS, Azure, GCP, Bedrock, Databricks, etc.) without loading the full
skill into the prompt.
Agent prompt: "Pull the AWS reference."
Calls get_reference(name="finops-aws") and gets back the full markdown body
(~1,000 lines, roughly 13K tokens) instead of the entire knowledge base. That is one
of the larger references - see the size range noted above before fetching several.
Agent prompt: "What does the AWS pattern catalogue say about storage?"
Calls get_reference(name="finops-aws-patterns", section="storage") and gets back
the storage chapter (~4,800 tokens) rather than the whole catalogue (~26,600).
Agent prompt: "Show me the obvious-confidence AWS waste playbooks."
Calls find_playbooks(scope="aws", confidence="obvious") and gets back the list
of high-signal AWS patterns (zombie NAT gateway, orphaned EBS volumes, etc.).
Agent prompt: "Walk me through the zombie NAT gateway pattern."
Calls get_playbook(name="aws-zombie-nat-gateway") and gets back the ~90-line
runbook (problem, symptoms, detection query, fix, anti-pattern, see-also).
| If you... | Use |
|---|---|
| Want the skill loaded as static context for every chat | The cross-tool installer (./install.sh) |
| Have a big-codebase session with limited context budget | The MCP server (fetch on demand) |
| Want to filter references by FinOps domain/capability/phase/persona/maturity | The MCP server (find_references) |
| Use a client that doesn't support MCP | The cross-tool installer |
The two paths are complementary. You can install both.
git clone https://github.com/OptimNow/cloud-finops-skills.git
cd cloud-finops-skills/mcp_server
python scripts/sync_references.py # populate src/cloud_finops_mcp/data/
pip install -e ".[dev]"
pytest
The PyPI package version tracks the skill release. The trigger is a
.claude-plugin/plugin.json version bump reaching main, not a hand-cut tag:
the auto-tag-on-plugin-bump workflow reads the new version, creates the
matching vX.Y.Z tag, and publishes both the skill release zip and a new
cloud-finops-mcp wheel, so the bundled references match what the rest of the
repo ships. Versions must be full three-part semver (v1.27.0); the workflow
rejects anything else.
Because a plugin.json bump publishes, content PRs never touch it. Version
bumps live in dedicated release PRs that move four files together: plugin.json,
.claude-plugin/marketplace.json metadata.version, this package's
pyproject.toml, and server.json - which carries the version twice, in the
top-level version and in packages[0].version, both CI-gated since August 2026.
See the release-train rule in the repo's CLAUDE.md.
CC BY-SA 4.0 - same as the parent skill. Credit OptimNow.
FAQs
MCP server exposing the OptimNow Cloud FinOps skill (reference library + named-pattern playbooks) as queryable tools.
We found that cloud-finops-mcp demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
It has been one year since Shai-Hulud made its first appearance on npm.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.

Security News
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.