Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Vantage MCP for AI Agents

What Is Vantage MCP

Vantage is the cloud cost-management tool HungryHub uses for rightsizing recommendations and savings analysis (see EKS Cost Optimization 2026 and Kubernetes CPU Request Rightsizing).

Vantage ships two official MCP (Model Context Protocol) servers, both remote HTTP — no local install, no npx:

ServerURLAuthPurpose
Vantage (data)https://mcp.vantage.sh/mcpOAuth (or API token)Query your real cost data, reports, recommendations
Vantage Docshttps://docs.vantage.sh/mcpNone (public)Search Vantage product docs, setup guides

Source docs:

MCP is an open protocol, so both servers work with any compatible client (Claude Code, Copilot, Cursor, OpenCode, custom agents).

What the Agent Can Do

Vantage (data) MCP — the agent queries your live Vantage account: cost reports, provider resource reports, rightsizing recommendations, and savings opportunities. This replaces the manual “download the Provider Resource Report CSV from Vantage → Cost Reports” step described in Kubernetes CPU Request Rightsizing — the agent pulls the same data directly during a conversation.

Vantage Docs MCP — single search tool that finds relevant Vantage guides, setup steps, and implementation details with links back to the docs.

HungryHub Account State (verified via MCP, June 2026)

Single workspace: Default (workspace token redacted — get it from https://console.vantage.sh/settings/tokens or GET /v2/me with your API token), currency USD, no currency conversion. Web UI: https://console.vantage.sh/settings/integrations.

Integrations (cost providers connected)

Vantage exposes 6 provider types; HungryHub uses all of them. Five are native integrations, one (custom_provider) is the CSV/API bucket holding vendors Vantage has no native connector for:

Provider keyTypeWhat it tracks
awsNativeAWS org o-e33ctelaj8 — all 9 accounts via management acct 891572013503 (see StackSet below)
kubernetes (kubernetes_agent)NativeEKS workload costs — feeds rightsizing
githubNativeGitHub Actions / org spend (account 53513081)
mongoNativeMongoDB Atlas
databricksNativeDatabricks
custom_providerCSV/APIDigitalOcean, Aiven, Netlify, Redpanda, Hetzner, Cloudflare, OpenRouter, Fal.ai

So 13 distinct vendors are monitored: AWS, Kubernetes, GitHub, MongoDB, Databricks, DigitalOcean, Aiven, Netlify, Redpanda, Hetzner, Cloudflare, OpenRouter, Fal.ai.

The custom_provider vendors are fed by the vantage-cost-sync app (see AGENTS.md repo #24). It fetches each vendor’s billing, normalizes to the FinOps FOCUS CSV format, and uploads to Vantage as a Custom Provider. ensure_provider() is idempotent (looks up the existing integration by account_identifier before creating), so each vendor stays a single stable integration — see the note below.

Cloudflare — invoice PDF, not API. Cloudflare has no usable cost API (its billable-usage API returns usage quantities but not dollar amounts yet), so cost comes from the monthly invoice PDF emailed to the billing address (payment@hungryhub.com). The cloudflare_invoice provider parses every PDF in a committed cloudflare-invoices/ folder; a new invoice PDF is dropped there each month. Usage charges land in the previous month and plan/subscription fees in the upcoming month, matching how the invoice itemises them. Likewise, Hetzner Cloud has no billing API — that provider computes cost from live resources × the /pricing endpoint, emitting one per-day record (one day = hourly_rate × 24 or monthly_rate / 30) per project; the daily cron sums them into the correct monthly total (see the daily-MTD inflation note below).

History — custom_provider duplicate sprawl (fixed, hungryhub-terraform#415). Until June 2026 the sync recreated a new accss_crdntl_* integration on every CI run (the state file was ephemeral in CI), leaving ~95 orphaned entries. Fixed by making ensure_provider idempotent and pruning the orphans down to one per vendor. If you ever see custom_provider entries multiplying again, check that fix first. To query a custom provider in VQL, scope to its token: (costs.provider = 'custom_provider:accss_crdntl_...') — a bare (costs.provider = 'custom_provider') returns 0.

History — daily-MTD inflation bug (fixed, vantage-cost-sync#11). From the start of the daily cron (0 7 * * *) through mid-2026, the DigitalOcean and Hetzner providers uploaded the full month-to-date cumulative cost on every run. Vantage’s custom-provider CSV appends every row, so N daily uploads of MTD produced roughly N(N+1)/2 inflation. Live evidence (queried 2026-06-18):

ProviderVantage AprVantage MayVantage Jun 1-18Actual
DigitalOcean$0$2,223$8,912.90$1,300 MTD
Hetzner$0$0$2,779.46~$400 MTD

Fixed by emitting one record per day in the requested range, with billed_cost = monthly_amount / days_in_month (DigitalOcean) or billed_cost = hourly_rate × 24 / monthly_rate / 30 (Hetzner) and charge_period_start == charge_period_end set to that single day. The daily cron now syncs a single day (--start-date today --end-date today); 30 daily uploads sum to the correct monthly total.

Aiven / Netlify / Redpanda were unaffected because they use the vendors’ own billing APIs and return finalized per-period totals. Native providers (AWS, K8s, GitHub, Mongo, Databricks) were also unaffected.

Backfill (done 2026-06-19). Deleted the stale DO and Hetzner integrations (the two original accss_crdntl_* tokens for DigitalOcean and Hetzner; lookup via GET /v2/integrations?provider=custom_provider to confirm) and re-synced with per-day records. Post-backfill Vantage shows:

ProviderAprilMayJun 1-17
DigitalOcean$2,416$2,223$1,291
Hetzner(combined Apr 1 – Jun 17 = $897)

OpenRouter + Fal.ai (added, vantage-cost-sync#12). Vantage has no native support for OpenRouter or Fal.ai (verified via docs.vantage.sh/mcp — the connecting_*.mdx list includes Anthropic, OpenAI, Anyscale but neither OpenRouter nor Fal.ai). Both go through the custom_provider CSV path via vantage-cost-sync. Daily cron (07:00 UTC) syncs today’s activity for both; 30 daily uploads sum to the correct monthly total (same per-day pattern as DO / Hetzner). The OpenRouter activity API only retains 30 days, so missed daily runs lose history; the monthly cron on the 3rd is the safety net.

Workspace-assign quirk (fixed, vantage-cost-sync#12). Vantage’s POST /integrations/custom_provider silently drops workspace_tokens from the request body (the create endpoint only accepts name + description — verified via /api/integrations/create-custom-provider-integration.mdx). Without a follow-up PUT, the new integration has workspace_tokens=[] and uploaded cost data never appears in cost reports. ensure_provider now calls _assign_workspace after a successful POST. Best-effort: a 5xx on the PUT is logged but does not abort the sync. If you ever see a fresh custom_provider:accss_crdntl_* with workspace_tokens=[], PUT it manually:

curl -X PUT -H "Authorization: Bearer $VANTAGE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"workspace_tokens":["<workspace_token>"]}' \
  "https://api.vantage.sh/v2/integrations/accss_crdntl_XXX"

AWS — org-wide connection (CloudFormation StackSet)

The AWS integration spans the entire AWS Organization (o-e33ctelaj8), not just one account. Two layers, intentionally separate — not duplicates:

  1. Cost / CUR data — the management account 891572013503 connection. Because Vantage is connected to the root/management account, it profiles every member account and reports org-wide accrued costs through the single consolidated CUR. This is the cost source.
  2. Active Resources (per-account IAM role) — a service-managed CloudFormation StackSet (ConnectToVantage17573-...) deploys a read-only vantage-integration IAM role into each member account, unlocking resource-level inventory (EC2/RDS/etc.) per account. This does not re-import costs, so there is no double-counting.

All 9 accounts now appear once each under the aws provider, sharing the org provider_uuid (arn:aws:organizations::891572013503:account/o-e33ctelaj8/<id>):

Account IDName
891572013503HungryHub-Root (management)
202255947274production
079994049689sandbox
965444437277HungryHub GenAI Sandbox
512438352490Hungry Hub-AI
380983552701Hungry Hub-Security
454538763126Hungry Hub-Audit Log
993490993790Hungry Hub-Log Archive
858647427345Surasit Sachdev

How it was set up (run from the management account, profile root = 891572013503):

# Step 1 — create the StackSet (SERVICE_MANAGED, auto-deploy on for new accounts)
aws cloudformation create-stack-set \
  --profile root --region us-east-1 \
  --auto-deployment Enabled=true,RetainStacksOnAccountRemoval=true \
  --permission-mode SERVICE_MANAGED \
  --stack-set-name ConnectToVantage17573-<id> \
  --template-url https://vantage-public.s3.amazonaws.com/vantage-integration-nocur-latest.json \
  --parameters ParameterKey=VantageID,ParameterValue='<vantage-id>' \
    ParameterKey=VantageDomain,ParameterValue='https://console.vantage.sh' \
    ParameterKey=VantageHandshakeID,ParameterValue='<handshake-id>' \
    ParameterKey=VantagePingbackArn,ParameterValue='arn:aws:sns:us-east-1:630399649041:cross-account-cloudformation-connector' \
    ParameterKey=VantageIamRole,ParameterValue='<vantage-iam-role>' \
  --capabilities CAPABILITY_IAM

# Step 2 — fan out to every member account (Root OU = r-onzh)
aws cloudformation create-stack-instances \
  --profile root --region us-east-1 \
  --stack-set-name ConnectToVantage17573-<id> \
  --regions us-east-1 \
  --deployment-targets OrganizationalUnitIds=r-onzh

Get the exact VantageID/VantageHandshakeID/VantageIamRole parameters from the Vantage console (Integrations → AWS → Connect via CloudFormation StackSet) — they are connection-specific. The Vantage SNS pingback ARN (630399649041) and template URL are constant.

Notes:

  • The management account 891572013503 is excluded by SERVICE_MANAGED (it’s already connected via the CUR integration) — expected, not an error.
  • --auto-deployment Enabled=true → any new org account is connected automatically.
  • Roles are read-only; the only outward grant is cross-account trust to Vantage’s account 630399649041.
  • Active Resources data backfills over a few hours after the StackSet completes.
  • Vantage docs reference: search the docs MCP for “Connecting Multiple AWS Accounts” / “Connecting via Stackset”, or https://docs.vantage.sh → Provider Integrations → AWS.

(The custom_provider duplicate-import issue that this section used to warn about was fixed in June 2026 — see the custom_provider note under Integrations above.)

Kubernetes — a new cluster only appears after its AWS account’s CUR is ingested

The Vantage Kubernetes Agent (one per cluster, installed via Helm — managed in hungryhub-terraform/helm-releases/vantage-agent.tf) reports pod/node metrics, but a new cluster does not show up as a kubernetes integration until the underlying cloud account’s cost data is ingested. Per the Vantage K8s agent docs: the agent needs a connected primary provider (AWS here) so Vantage can join its metrics to the EC2 node costs and compute pod costs.

Concretely, when we added the sandbox cluster eks-dev-262 (account 079994049689):

  • The agent installed fine and uploaded reports immediately (verified in its logs).
  • But the cluster did not appear in list-cost-integrations for ~a day, because the sandbox AWS account had only just been connected via the StackSet — its first CUR can take up to 24h to arrive (status=connected, last_updated=null until then).
  • Prod eks-prod-21 shows immediately only because its AWS CUR was ingested long ago.

So if a freshly-installed agent’s cluster is missing from the integrations list: it’s almost certainly not an agent problem — check whether the cluster’s AWS account has ingested a CUR yet (GET /integrations?provider=awslast_updated non-null). Wait out the ≤24h CUR window before debugging the agent.

Spend snapshot (native providers, May 2026)

ProviderMonthly cost (USD)
AWS$13,316.58
Kubernetes$1,787.24
GitHub$796.91
MongoDB$136.77
Databricks$27.85
Total (native)$16,065.34

(Custom-provider spend — DigitalOcean/Aiven/Netlify/Redpanda — is tracked separately and not included above.)

Open recommendations

TypePotential savings/moScope
kubernetes:workload:rightsizing$615.7534 workloads, 80 resources — feeds Kubernetes CPU Request Rightsizing
aws:elasticache:reserved-instances$0 (0 resources)RI buy suggestion, prod 202255947274
aws:rds:reserved-instances$0 (0 resources)RI buy suggestion, prod 202255947274

The Kubernetes rightsizing recommendation is the live source behind the manual CSV workflow — the agent can now pull it directly (see examples below).

Setup

HungryHub config (this workspace)

Both servers are configured in the workspace-root .mcp.json (which is gitignored). Vantage uses OAuth, so no token is stored in the file:

{
  "mcpServers": {
    "vantage": {
      "type": "http",
      "url": "https://mcp.vantage.sh/mcp"
    },
    "vantage-docs": {
      "type": "http",
      "url": "https://docs.vantage.sh/mcp"
    }
  }
}

On first connect, Claude Code opens a browser to complete the Vantage OAuth flow. Manage / re-trigger auth from inside a session with the /mcp command. vantage-docs needs no auth.

Alternative: API token instead of OAuth

For headless/CI contexts where the interactive OAuth browser flow won’t work, pass a Vantage API token (vntg_tkn_..., generated in Vantage → Settings → API Tokens) as a bearer header. Never commit the raw token — reference it via env var:

{
  "mcpServers": {
    "vantage": {
      "type": "http",
      "url": "https://mcp.vantage.sh/mcp",
      "headers": {
        "Authorization": "Bearer ${VANTAGE}"
      }
    }
  }
}
# In ~/.zshrc / ~/.bashrc, or a gitignored .env loaded into the shell
export VANTAGE="vntg_tkn_..."

OAuth is preferred for interactive local use (no long-lived secret on disk). Use the API token only where OAuth is not possible.

Other AI clients

Both are plain remote HTTP MCP servers; point any MCP-capable client at the same URLs.

Cursor / Windsurfmcp.json:

{
  "mcpServers": {
    "vantage":      { "url": "https://mcp.vantage.sh/mcp" },
    "vantage-docs": { "url": "https://docs.vantage.sh/mcp" }
  }
}

Codex CLI:

codex mcp add Vantage     -- npx -y mcp-remote https://mcp.vantage.sh/mcp
codex mcp add VantageDocs -- npx -y mcp-remote https://docs.vantage.sh/mcp

After saving, restart the client. Vantage tools appear in the tool list.

Practical Examples

These prompts work in any MCP-compatible client once the data server is authenticated.

Pull current rightsizing recommendations

List Vantage's current rightsizing recommendations for our Kubernetes workloads,
with estimated monthly savings per namespace.

Replaces the manual CSV download for Kubernetes CPU Request Rightsizing.

Check savings opportunities

What cost savings has Vantage identified this month? Sort by estimated savings.

Mirrors the “Vantage Savings Identified” report referenced in EKS Cost Optimization 2026.

Search the docs

How do I set up a Vantage cost report filtered to a single EKS cluster?

Routes to the vantage-docs search tool and returns guide links.

Key Tools & VQL Notes

The data server exposes ~80 tools (cost reports, budgets, recommendations, anomalies, virtual tags, dashboards, billing rules). The ones you reach for most:

ToolUse
get-myselfReturns workspace token(s) — needed for almost every other call
list-cost-integrationsAll connected providers + accounts (the integration inventory above)
list-cost-providersProvider keys valid in VQL (per workspace)
list-recommendationsOpen savings recommendations (filter open/resolved/dismissed, min_savings, provider)
query-costsAd-hoc cost query via VQL (no saved report needed)
list-recommendation-resources / get-recommendation-detailsDrill into a specific recommendation
list-anomaliesCost spikes against a cost report token

VQL gotchas (learned the hard way):

  • Every query needs a provider: (costs.provider = '<key>'). Keys come from list-cost-providers — note Kubernetes is kubernetes in VQL but kubernetes_agent in the provider list; custom_provider for the CSV vendors.
  • Multiple providers → OR: ((costs.provider = 'aws') OR (costs.provider = 'mongo')).
  • AWS services use short names: AmazonEC2, AmazonRDS (not the long display names). Use list-cost-services to get exact names.
  • Custom providers must be scoped by token: (costs.provider = 'custom_provider:accss_crdntl_...') — a bare custom_provider returns 0.
  • Default date range is 30 days; pass start_date/end_date (YYYY-MM-DD) for anything else.

Example — native-provider spend for May 2026 (the snapshot above):

query-costs(
  workspace_token = "<workspace_token>",   # from `GET /v2/me`
  filter = "((costs.provider='aws') OR (costs.provider='kubernetes') OR
            (costs.provider='mongo') OR (costs.provider='databricks') OR
            (costs.provider='github'))",
  groupings = ["provider"], date_bin = "month",
  start_date = "2026-05-01", end_date = "2026-05-31"
)

Limitations

  • Data server requires auth — OAuth (browser) or API token; without it, only vantage-docs works.
  • Docs server is read-only search — no access to your cost data, just product docs.
  • OAuth needs an interactive browser — for CI/headless, use the API-token variant.
  • .mcp.json is gitignored — config is local per machine; the token/OAuth session does not sync.