Skip to content

Tool Reference

The CloudQuell MCP server exposes 54 tools40 read tools and 14 write tools. This page lists every one, grouped by domain, with what it does, its key parameters, whether it reads or writes, the OAuth scope it requires, and its MCP annotations.

Everything here is derived directly from the deployed tool definitions (src/tools/, src/schemas/, src/tools/register.ts). If a tool isn’t on this page, it isn’t in the server.

Scope, and the write gate. Read tools require the read scope, which every connection has. Write tools need FOUR things, all checked server-side before any downstream call: the admin:write scope, the organization’s MCP writes switch turned on (off by default for every organization — an admin enables it at Settings → Organization → AI agent access), an admin/super_admin org role, and confirm: true on the call. A token with admin:write also has read, and a cak_ service key never has admin:write. See Authentication & authorization.

Annotations. Every tool carries MCP tool annotations that clients use to drive UI and confirmation prompts. They are hints, not enforcement — the real gate is the four-check write gate above.

Annotation shown Meaning
read-only readOnlyHint: true — never modifies state.
write · additive readOnlyHint: false, destructiveHint: false — creates/updates, reversible.
write · destructive destructiveHint: true — removes a record (e.g. delete/cancel).
· idempotent idempotentHint: true — repeating the same call has no extra effect.
· side-effecting dispatches something real to the outside world (e.g. a test message).

All tools set openWorldHint: true (they call live CloudQuell backends).

Common parameters. Almost every tool accepts:

  • response_formatconcise (default; key fields only, fewer tokens) or detailed (the full parsed payload).
  • limit — caps the rows returned in list sections (defaults noted per tool).
  • integration_id — scope to one (or more) provider connections; omit for the whole organization.

All tool output is capped at ~25,000 tokens (~100 KB); on overflow the tool returns a short message telling the agent how to narrow the request rather than truncating silently.

Structured output. query_costs, get_forecast, compare_periods, get_weekly_cost_slices and get_ai_spend declare an outputSchema and return structuredContent alongside the text, so a client can read typed JSON without re-parsing a string. The text content is unchanged — the structured half is exactly the same JSON, truncation notice included.

Data freshness. CloudQuell cost data is ingested daily, not in real time, and the cloud providers’ own billing exports lag 2-3 days. Call get_data_freshness before reporting numbers to a person, and quote the lastUpdated value alongside them.


Start here. One call that answers “what should I look at today?” — the entry point for scheduled/headless agents and for a Monday-morning review. It composes up to eight of the read tools on this page and hands back one briefing; each section then drills down with its own named tool.

Tool What it does Key parameters R/W · scope Annotation
get_finops_briefing Runs up to eight read tools in parallel and joins them, in this order: freshness, spend, movers, anomalies, budgets, commitments, savings, and AI spend (only with include_ai_spend). Freshness is reported first, so every figure below it carries its trust level — when the verdict is not fresh the briefing opens with a warning. Each section degrades independently: one that fails or times out returns { status: "unavailable", reason } and is listed in sectionsUnavailable, and one a provider cannot have (commitments for an LLM provider, savings outside AWS/Azure) returns not_applicable. Text output is compact markdown; structuredContent has one key per section plus generatedAt, window, costBasis, sectionsUnavailable. period (weekly default / daily), provider, integration_id, cost_basis, include_ai_spend (default false), items_per_section (default 5, max 10), anomaly_min_pct (default 25), anomaly_min_cost (default 100), response_format Read · read read-only

⚠️ Never read a missing section as zero. A section named in sectionsUnavailable was not produced — it is not “no spend”, “no anomalies” or “no budgets at risk”. Say which sections were missing when you report.

Drill-down map — each section’s own tool:

Section Drill into
freshness get_data_freshness
spend get_forecast
movers compare_periods
anomalies list_anomalies, then investigate_anomaly
budgets get_budget_status
commitments get_expiring_commitments
savings get_savings
ai_spend get_ai_spend

include_ai_spend adds direct provider-billed Anthropic + OpenAI spend as its own section. Those dollars are not in the cloud totals elsewhere in the briefing and must never be added to them; AWS-billed Bedrock is excluded there because it already is inside the cloud numbers.

Tool What it does Key parameters R/W · scope Annotation
query_costs The one flexible cost-query tool. Returns a cost slice for the org. view="overview" (default) = MTD vs. previous month, per-account & per-service rollups, service comparison. view="detailed" = the pivot vocabulary for the scope (available services, tag keys, linked accounts) — not pivot tables; see the note below. account_id accepts a sub-account name or a 12-digit account id (the id is resolved for you). cost_basis pins the accounting basis (layered over the org’s saved settings) and is echoed back as costBasis. view (default overview), provider (aws/azure/gcp/snowflake/anthropic/openai), start_date/end_date (YYYY-MM-DD), account_id (name or id), service, cost_basis (use_amortized/include_credits/include_discounts/include_refunds/include_taxes), limit, response_format Read · read read-only
get_forecast Projected month-end spend, org-wide plus per-service and per-account rankings. A projection computed from ingested daily data, not a backend forecast — it uses the same algorithm and anchors as the dashboard’s “Forecasted Month-End” KPI, so the numbers agree. Returns method (prev-month-shape/linear/flat-mtd/waiting) and a plain-English confidence note to report alongside the figure. Per-entity rows pace independently and do not sum to the total. provider, integration_id, account_id (name or id), service, limit (default 10), response_format Read · read read-only
compare_periods The “what changed?” tool. Compares two windows and ranks movers by the size of the change, flagging each new / gone / changed. Deltas are period_a minus period_b. period_a/period_b ({start_date, end_date}), preset (mom default / wow / yoy), group_by (service default / account), provider, integration_id, cost_basis, limit (default 25), response_format Read · read read-only
get_ai_spend AI/LLM spend. Direct provider spend (Anthropic, OpenAI) by default; AWS Bedrock is AWS-billed and already inside cloud spend, so it arrives only on an explicit include_bedrock: true (direct + Bedrock) or provider: "bedrock" (Bedrock alone). Break down by model, token type, workspace/project, api_key, service_tier, cost_type, provider, or day; each row carries cost (dollars), tokens and tokenMeteredCost (divide by that, not cost, for $/1M). When Bedrock is included the answer separates directTotal (not in cloud totals) from crossBilledTotal (already in cloud totals) and allAiTotal; never add any of those — or totalCost — to a cloud figure. provider (anthropic/openai/bedrock, default anthropic), include_bedrock (default false), group_by, model, token_type, workspace, api_key, start_date/end_date (req), response_format Read · read read-only

Cost basis. Without cost_basis, figures use the organization’s saved cost settings. Setting any field of cost_basis replaces those settings for that call — every field you omit takes the API default (credits / discounts / refunds false, taxes true, amortized false), not your saved value. Ask for the finance view with {"use_amortized": true}; leave it off for the engineering (unblended) view. The applied basis comes back as costBasis.

query_costs views: overview and detailed are enabled today. The other values (savings, anomalies, budget_status, tag_coverage, allocation, commitments, resource_breakdown) are recognized but served by dedicated tools instead — use get_savings, list_anomalies, get_budget_status, get_tag_coverage, get_allocation_breakdown, and list_commitments. Passing one of those view values to query_costs returns a message pointing you to the right tool.

view="detailed" returns the pivot VOCABULARY, not pivot tables. The group_bydimensions pivot this view was built on was never consumed by the cost-dashboard backend — the parameter was parsed and dropped, so a caller got a 200 and an unpivoted payload. group_by is gone from query_costs and the endpoint now 400s on dimensions. What view="detailed" returns is availableServices / availableTagKeys / availableLinkedAccounts — the values you can filter on. For the pivots themselves use compare_periods (service / account over a date window), get_tag_coverage (tag pivots) or get_resource_breakdown (resource-level detail); arbitrary group-by pivots are served by the cost-pivot-v2 job API, which this server does not yet expose. view="overview" is unaffected.

The only route to arbitrary group-by breakdowns. query_costs view="detailed" returns the pivot vocabulary (pivotsAvailable: false), and compare_periods can only group by service or account — everything else lives here.

Both tools drive an asynchronous Athena job: run_cost_pivot submits and waits briefly, returning rows if the job is quick and a jobId handle if it is not; get_cost_pivot collects a handle. Jobs are org-scoped and expire 24 hours after creation. There is no cancel tool.

Tool What it does Key params Scope Annotations
run_cost_pivot Groups spend by any 1-3 dimensions at monthly / weekly / daily granularity. Dimensions: service, account, region, provider, service_category, subcategory (usage type), usage_family, charge_type, charge_subtype, tagged, cost_center, resource (rules below), or tag:<key>. Returns rows largest-_total-first with one key per dimension (named verbatim — a tag row has a literal "tag:user_app" key), one per time column, plus _total; columns, grandTotals, and both the requested and served window. dimensions (req, 1-3), exactly one of provider / integration_id / integration_ids (req), granularity (default monthly), start_date/end_date or months_back (default 3), services, account_names, cost_centers, cost_basis, wait_seconds (default 20, max 22), limit (default 100, max 500), response_format Read · read read-only
get_cost_pivot Collects a job started by run_cost_pivot. Still running → { status, pollAfterMs }; succeeded → the same shape as above. job_id (req), cursor (inert — see below), limit, response_format Read · read read-only

⚠️ Three behaviours that will otherwise surprise you.

  1. Tag keys are case- and hyphen-sensitive. Call get_available_tag_keys first and copy the key exactly. A wrong key does not error — it collapses every row into one lowercase untagged bucket, which reads as total non-compliance.
  2. The window is clamped silently — daily to ~30 days, weekly to ~55, monthly to ~6 months, plus the org’s retention floor. The response always carries requestedWindow and returnedWindow, and adds a windowNote when they differ. Report figures against the window that was served.
  3. RESPONSE_TOO_LARGE (413) is the main failure mode for a wide pivot. This backend returns every matching row in one response and does not page (nextCursor is always null, cursor is inert). The fix is fewer dimensions or a shorter windowlimit is applied client-side after sorting by _total desc and cannot shrink the server-side payload.

Adding resource breaks any pivot down to individual resources — “which instances is this service’s spend actually on?”. It carries four rules the other dimensions do not, and all four are checked before the job is submitted, so a mistake comes back as a sentence rather than an error code and a wasted query:

  1. resource must be the LAST dimension. It is the innermost grouping.
  2. Scope with integration_id only — never provider or integration_ids. Resource ids are only meaningful inside a single connection.
  3. At most 2 other dimensions before it. Each one multiplies the resource cross-product, which is what drives RESPONSE_TOO_LARGE.
  4. A monthly window covers at most 3 months, not the usual 6. The backend clamps this silently, so the tool refuses instead — otherwise you would report figures against a window you did not ask for.

Reading the rows — verified against prod, and not what you would assume:

  • _resource_id and _region are OPTIONAL and INDEPENDENT. A row may carry both, either, or neither, within the same response. Check before using them, and never read a missing _resource_id as “this resource has no id” — it means the backend attributed none.
  • The displayed resource value is sometimes the full ARN and sometimes just a short name, so prefer _resource_id for console links and fall back to naming the resource without one.
  • resource can be the empty string "" — spend with no resource attribution at all (support, commitment fees, tax). Not a bug, and not null.
  • Rows valued "Others" are the backend’s collapse bucket. Detect them by that literal string: such a row can still carry _resource_id and _region when only one small resource was folded into it.
{ "dimensions": ["service", "resource"],
"integration_id": "<id from list_integrations>",
"granularity": "monthly", "months_back": 1 }

For the single-service, single-day question, get_resource_breakdown is still the better tool — it takes a service and a date directly and runs no job. Use a resource pivot when you want resources across a grouping, or over several time columns.

Tool What it does Key parameters R/W · scope Annotation
get_savings The org’s full savings picture in one call: headline rollup (banked / open / potential), by-action-type breakdown, effective-savings-rate metrics, and the filtered list of recommendations (rightsizing, idle, commitment purchases) with dollar estimates, effort, and confidence. minMonthlySavings ($ floor), actionType, accountId (id or name), product, limit (default 50), response_format Read · read read-only
get_recommendation_history The status-change audit trail for one recommendation: status transitions, notes, realized savings, dismissed reason, timestamps. recommendation_id (req), limit, response_format Read · read read-only
update_recommendation_status Mark a savings recommendation applied, dismissed, in_progress, active, etc. Optionally record notes, realized_savings, and a dismissed_reason. recommendation_id (req), status (req), notes, realized_savings, dismissed_reason, confirm (req) Write · admin:write write · additive · idempotent
Tool What it does Key parameters R/W · scope Annotation
list_anomalies Lists cost anomalies, derived client-side from month-over-month and week-over-week movement (the backend has no precomputed anomaly list). Flags a service when its MoM increase clears min_pct_increase, or when spend appears for a service with no baseline (new-service anomaly). Covers every connected provider — for Anthropic/OpenAI the “service” granularity is the model; for Snowflake it’s the warehouse/usage type. provider (aws/azure/gcp/snowflake/anthropic/openai), min_pct_increase (default 25), min_cost (default 0), service, limit (default 50), response_format Read · read read-only
investigate_anomaly Deep-dives one service: chains three reads — anomalies view (weekly trend + MoM), per-resource breakdown for a date, and the ±7-day daily series — and returns a synthesized verdict on whether the trend looks anomalous. service (req), provider (aws/azure/gcp/snowflake/anthropic/openai), date (YYYY-MM-DD; defaults to current MoM period end), account_id, top_n_resources (default 15), response_format Read · read read-only
get_weekly_cost_slices Weekly per-service cost slices for the trailing ~12+ weeks plus the MoM-by-service comparison — for charting trends and spotting swings. provider (aws/azure/gcp/snowflake/anthropic/openai), service, account_id, limit (default 500), response_format Read · read read-only
get_resource_breakdown Breaks one service’s spend down to the individual resources behind it: resource id, type, account, region, operation, usage type, each resource’s share of that service’s spend over the window, and its prior-period cost. The step investigate_anomaly runs internally, exposed on its own. date defaults to the latest ingested day for that service; granularity sets the window — monthly (default) covers the whole calendar month containing date, daily covers just that day. service (req), date (YYYY-MM-DD), granularity (monthly default / weekly / daily), provider, account_id (name or id), integration_id, limit (default 25), response_format Read · read read-only
list_anomaly_dismissals Lists the currently-suppressed anomalies, each with its (service, period, window) key — the values undismiss_anomaly needs. limit, response_format Read · read read-only
dismiss_anomaly Suppresses an anomaly so it no longer surfaces in the feed (upsert). window is required — it is part of the dismissal key. service (req), period (req, e.g. “2026-06”), window (req, e.g. “mtd”), reason, confirm (req) Write · admin:write write · additive · idempotent
undismiss_anomaly Reverses a dismissal so the anomaly can surface again. Pass the same (service, period, window) key used to dismiss it. service (req), period (req), window (req), confirm (req) Write · admin:write write · destructive · idempotent
Tool What it does Key parameters R/W · scope Annotation
get_budgets Lists budget definitions: name, amount, currency, period, dates, threshold percentages, notification channels, and scope. integration_id, limit, response_format Read · read read-only
get_budget One budget definition by id. budget_id (req), response_format Read · read read-only
get_budget_status Current spend vs. budget: actual, forecast, actual/forecast %, variance, thresholds crossed, and a derived status (on_track / warning / over) per budget. integration_id, limit, response_format Read · read read-only
create_budget Creates a budget. Currency is not settable — the backend stamps the org’s display currency. name (req), amount (req), start_date (req), period (default monthly), integration_id, scope (platform/services/tagKey+tagValue/costCenterId), threshold_pcts, notification_channels, confirm (req) Write · admin:write write · additive
update_budget Updates an existing budget — only the fields you pass change; currency stays fixed. budget_id (req), name, amount, start_date, period, integration_id, scope, threshold_pcts, notification_channels, enabled, confirm (req) Write · admin:write write · additive · idempotent
delete_budget Removes a budget and its alerting by id. budget_id (req), confirm (req) Write · admin:write write · destructive · idempotent
Tool What it does Key parameters R/W · scope Annotation
list_commitments Lists Reserved Instances & Savings Plans with a utilization/expiry summary: type, status, days-until-expiry, utilization %, dollars saved, effective cost. integration_id, limit, response_format Read · read read-only
get_expiring_commitments Same data filtered by lifecycle status — defaults to expiring_soon (those needing renewal). status (default expiring_soon; expired/active/unknown), integration_id, limit, response_format Read · read read-only
Tool What it does Key parameters R/W · scope Annotation
get_tag_coverage Tagged-vs-untagged spend split, coverage per tag key, and the services with the most untagged spend — where tagging gaps hurt allocation accuracy. integration_id, limit, response_format Read · read read-only
Tool What it does Key parameters R/W · scope Annotation
get_allocation_breakdown How spend is allocated across cost centers for the current period: own spend, rolled-up spend (incl. descendants), % of total, parent linkage, plus a synthetic “Unallocated” bucket. integration_id, limit, response_format Read · read read-only
list_cost_centers The org’s cost-center definitions and their parent/child hierarchy (the allocation taxonomy). limit, response_format Read · read read-only
list_allocation_rules The rules that assign spend to cost centers (match dimension, service/tag, priority, enabled, integration scope). cost_center_id, limit, response_format Read · read read-only
Tool What it does Key parameters R/W · scope Annotation
list_saved_reports The org’s saved custom cost reports: name, description, chart type, and the pivot config (dimensions, metrics, granularity). integration_id, limit, response_format Read · read read-only
get_report One saved report by report_id (fetched from the list and filtered client-side — there is no per-report backend route). report_id (req), integration_id, response_format Read · read read-only
Tool What it does Key parameters R/W · scope Annotation
list_alert_rules The configured cost-alert rules: type (trend/threshold/anomaly/budget), cadence, thresholds, watched services/accounts, channels. An empty list is normal. integration_id, limit, response_format Read · read read-only
get_alert_rule One alert rule by id (filtered from the list client-side). alert_id (req), integration_id, response_format Read · read read-only
list_triggered_alerts The firing history — both cost-rule firings and budget-threshold crossings in one feed: subject, type, when, trigger vs. baseline value, delivery status. since (ISO date), severity (delivered/failed/suppressed), limit (1–500), response_format Read · read read-only
Tool What it does Key parameters R/W · scope Annotation
list_integrations Lists the org’s provider integrations / cloud connections (id, name, provider, status) — the integration_id values other tools accept. limit, response_format Read · read read-only
get_integration One integration by id. integration_id (req), response_format Read · read read-only
trigger_integration_ingest Kicks off (or re-runs) the on-demand data-ingest job for one integration. integration_id (req), confirm (req) Write · admin:write write · additive · idempotent
Tool What it does Key parameters R/W · scope Annotation
get_data_freshness Answers “can I trust these numbers?”. Checks every provider connection and returns a verdict — fresh / stale / degraded — with a one-line reason, plus per-connection rows (provider, sync status, last successful ingest, staleness in hours, any error message). degraded means a connection is failing, was never set up, or the account is frozen (recent data hidden on purpose). Run it first in any workflow that will show a number to a person. stale_after_hours (default 48), include_ingestion_detail (default true), limit (default 50), response_format Read · read read-only
Tool What it does Key parameters R/W · scope Annotation
list_notification_channels Lists the configured channels (channel_id, name, type, enabled) — the channel_id that delete/test need. limit, response_format Read · read read-only
create_notification_channel Creates a notification channel for cost alerts. channel_name (req), channel_type (req: slack/teams/email/webhook), destination (req: webhook URL or email), confirm (req) Write · admin:write write · additive
delete_notification_channel Removes a channel by id — it stops receiving alerts. channel_id (req), confirm (req) Write · admin:write write · destructive · idempotent
test_notification_channel Sends a real test message to a channel — recipients will see it. channel_id (req), confirm (req) Write · admin:write write · additive · side-effecting
Tool What it does Key parameters R/W · scope Annotation
list_organizations Every organization the signed-in user belongs to, with their role, tier, member count and which is the default. Note that all other tools act on the current organization only. limit, response_format Read · read read-only
get_current_organization The organization every other tool acts on: name, id, tier (and any override), status, member/connection counts, trial & cancellation state, and your role in it (your_role) — the thing that actually decides whether a write is accepted. response_format Read · read read-only
list_members The people in the current organization: user id, email, name, role, joined date, plus a count per role. Service accounts behind API keys are excluded. limit, response_format Read · read read-only
list_invites Invitations the organization has sent (pending and recently expired), each with the invite_id that cancel_invite needs. The single-use accept token is never returned. Requires an admin role. status (pending/expired), limit, response_format Read · read read-only
send_invite Invites a person to the org by email. email (req), role (viewer/contributor/admin/super_admin; default contributor), message, confirm (req) Write · admin:write write · additive
cancel_invite Revokes a pending invite — it can no longer be accepted. Get invite_id from list_invites. invite_id (req), confirm (req) Write · admin:write write · destructive · idempotent
update_organization_name Renames the organization. org_id (req), organization_name (req), confirm (req) Write · admin:write write · additive · idempotent
update_organization_preferences Updates org preferences (e.g. currency, language, dismissed_quick_setup). org_id (req), preferences (req), confirm (req) Write · admin:write write · additive · idempotent

Use these to learn the valid filter values before querying.

Tool What it does Key parameters R/W · scope Annotation
get_metadata All three filter vocabularies in one call: available service codes, tag keys, and linked accounts ({ accountId, accountName }). integration_id, limit, response_format Read · read read-only
get_available_services The AWS service codes the org has cost data for (the valid service filter values). integration_id, limit, response_format Read · read read-only
get_available_tag_keys The cost-allocation tag keys available for grouping/filtering. integration_id, limit, response_format Read · read read-only
get_available_linked_accounts The linked AWS accounts as { accountId, accountName } pairs — to resolve ids ↔ names and find valid account_id filters. integration_id, limit, response_format Read · read read-only

Group Read tools Write tools
Briefing get_finops_briefing
Cost query_costs, get_forecast, compare_periods, get_ai_spend
Pivots run_cost_pivot, get_cost_pivot
Savings get_savings, get_recommendation_history update_recommendation_status
Anomalies list_anomalies, investigate_anomaly, get_resource_breakdown, get_weekly_cost_slices, list_anomaly_dismissals dismiss_anomaly, undismiss_anomaly
Budgets get_budgets, get_budget, get_budget_status create_budget, update_budget, delete_budget
Commitments list_commitments, get_expiring_commitments
Tag coverage get_tag_coverage
Allocation get_allocation_breakdown, list_cost_centers, list_allocation_rules
Reports list_saved_reports, get_report
Alerts list_alert_rules, get_alert_rule, list_triggered_alerts
Integrations list_integrations, get_integration trigger_integration_ingest
Operations get_data_freshness
Notifications list_notification_channels create_notification_channel, delete_notification_channel, test_notification_channel
Org & invites list_organizations, get_current_organization, list_members, list_invites send_invite, cancel_invite, update_organization_name, update_organization_preferences
Discovery get_metadata, get_available_services, get_available_tag_keys, get_available_linked_accounts
Total 40 14

The server also serves the six CloudQuell FinOps workflows as MCP prompts, so any client that lists prompts gets them without installing the skill pack: cloudquell-weekly-briefing, cloudquell-spend-review, cloudquell-anomaly-triage, cloudquell-budget-guardrails, cloudquell-savings-actions and cloudquell-allocation-hygiene. Each takes two optional arguments, period and provider, which are appended to the runbook as a focus note.

Not yet available (coming soon): async report generation — both generate_report (creating a job) and get_report_job_status (polling it) ship together as one unit. See the Changelog.

Not available at all: breaking a change down by product, usage type or tag over an arbitrary date range. compare_periods supports service and account only — the cost-dashboard data source has no windowed aggregation for the other three dimensions.