Skip to main content
Glama

Costory: Your Finops MCP

update_alert

Destructive

Update an existing cost alert. Look up alertId via search / list_alerts / get / create_alert. All fields except alertId (and slug) are optional — omit a field to keep the stored value. Most edits (name, description, tagIds, condition, dedup) need nothing else. tagIds replaces the full list: existing IDs from list_tags and/or { name, color? } for new tags; color defaults to #6366F1; missing tags are created. Omit keeps stored tags; [] clears them. Explorer (queries + period) and notification dest are wholesale groups: if you send any field in the group, send the full group, written from scratch exactly as for create_alert — the stored queries from get are not a valid input. Inside the explorer group, omit scopeId to keep the alert's saved scope (send null to clear it); it cannot be sent on its own. scopeId is the same id as list_teams, stored on the alert (read it from get) and not merged into the stored queries. Do not send aggBy: the stored grain is always Day. Setting condition on a legacy threshold alert that has no dedup config succeeds but the response may include warning: pass dedup too (or in a follow-up call) to avoid notifying on every firing evaluation. Sharing is not this tool — use get_object_permissions then set_object_permissions with resourceKind "costAlert". EXAMPLE: rename → { alertId, name: "New name" } EXAMPLE: dest switch to Slack → { alertId, notificationChannel: "SLACK", slackChannelId: "C01ABC" } EXAMPLE: condition change → { alertId, condition: "a > 2000" } EXAMPLE: narrow the monitored series (scope kept) → { alertId, queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD", filterCel: "cos_provider in ["AWS"]" }], datePreset: "TRAILING_90_DAYS" }

Input Schema

NameRequiredDescriptionDefault
toNoExplicit window end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.
fromNoExplicit window start (YYYY-MM-DD). Use with to instead of datePreset.
nameNoDisplay name for the alert.
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
dedupNoDeduplication config controlling how often a still-firing group notifies. The window is per groupBy value; delivery stays one message listing newly eligible groups. Either CALENDAR (kind: CALENDAR, calendarUnit: WEEK | MONTH) = at most once per current ISO week / calendar month, or ROLLING (kind: ROLLING, windowDays: N) = at most once every N days.
emailsNoEmail addresses (required if EMAIL)
tagIdsNoReplaces the full tag list. Omit to keep stored tags; pass [] to clear. Pass existing tag IDs from `list_tags`, and/or new tag objects `{ name, color? }` (created in the org if missing; color defaults to #6366F1).
alertIdYesAlert ID from search, list_alerts, get, or create_alert.
queriesNoReplaces the monitored series wholesale, and `condition` references these `name`s. Same series objects as the `query` tool `queries` array (cost / metric / usage / externalMetric / formula / budget). Each requires `type` (never omit) and a `name` (prefer short ids like a/b/c); put human labels in `alias`. Write them from scratch: the stored `queries` returned by the `get` tool are a different, read-only shape.
scopeIdNoTeam scope id (list_teams), stored on the alert, not merged into query filters. A change still needs full queries plus period. Omit (with queries+period) to keep the saved scope; null clears it. Do not send scopeId alone.
conditionNoAlerts v3 firing rule: a single boolean expression over the query names (`name` field of each query). Supports arithmetic (+ - * /), comparisons (> >= < <= == !=), logical and/or/not, parentheses, and these window functions: rollingSum(a, N, UNIT) (trailing sum over the last N units, UNIT ∈ DAY|WEEK|MONTH, inclusive of today), weekToDateSum(a) (Monday-to-date), monthToDateSum(a) (1st-of-month-to-date), and timeShift(a, N, UNIT) (value shifted back N units; may wrap a window function). Examples: `a > 1000`, `rollingSum(a, 7, DAY) > 1000`, `(a - timeShift(a, 1, DAY)) / timeShift(a, 1, DAY) > 0.2`, `a > 10000 or rollingSum(a, 7, DAY) > 50000`.
datePresetNoOfficial date preset (same as Explore, e.g. MTD, LAST_MONTH). Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Mutually exclusive with from/to.
descriptionNoAlert description.
slackChannelIdNoSlack target id (required if SLACK): a channel id (C…) to post to a channel, or a Slack user id (U…) to deliver a direct message to that user. Use list_available_destinations to discover both channels and the signed-in user's DM.
teamsChannelIdNoTeams channel ID (required if TEAMS)
notificationChannelNoNotification channel

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedInput schema / properties / datePreset / description
      Previous value: -"Official date preset (same DatePreset as dashboards/reports, e.g. MTD, LAST_MONTH, TRAILING_30_DAYS). Prefer this over hand-computed from/to when a preset matches. Mutually exclusive with from/to."New value: +"Official date preset (same as Explore, e.g. MTD, LAST_MONTH). Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Mutually exclusive with from/to."
  2. Changed1 schema field changed
    • changedInput schema / properties / scopeId / description
      Previous value: -"Saved team scope id (from list_teams). Changing it still requires complete queries plus period. Omit (with queries+period) to keep the saved scope; send null to clear. Do not send scopeId alone."New value: +"Team scope id (list_teams), stored on the alert, not merged into query filters. A change still needs full queries plus period. Omit (with queries+period) to keep the saved scope; null clears it. Do not send scopeId alone."
  3. Added

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag destructiveHint=true and openWorldHint=true, but the description adds genuinely non-obvious behavior: `tagIds` replaces the whole list (`[]` clears), `scopeId` cannot be sent alone and null clears it, `aggBy` must never be sent because stored grain is always Day, and a legacy alert edit can succeed while emitting a `warning` about per-firing notifications.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is long, but appropriately so for a 16-parameter destructive mutation tool. It is front-loaded with purpose and the alertId lookup, then rules, then four concrete call examples — only mild redundancy with the schema's own field descriptions prevents a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex, destructive, annotation-covered mutation with no output schema, the description closes the gaps an agent needs: how to source alertId, which sibling handles sharing, group-atomicity rules, the Day grain constraint, and the `warning` that can appear in the response.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% so the baseline is 3, but the description adds cross-field rules the schema cannot express: the wholesale-group rule for queries+period, the omit-vs-null distinction for scopeId, the ban on `aggBy`, and that `condition` references query `name`s. Some prose (e.g. tagIds, condition examples) duplicates the schema text, so it is not fully additive, but the field-interaction guidance is valuable.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ("Update an existing cost alert") and immediately routes the agent on how to obtain the required alertId (search / list_alerts / get / create_alert). This clearly separates it from sibling create_alert, list_alerts, and get without the agent opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states the omit-to-keep default semantics, which edits need no other fields, that Explorer and notification-destination are wholesale groups requiring a full write from scratch, and that the stored `queries` from get are not valid input. It also names the correct alternative for sharing (get_object_permissions then set_object_permissions) and warns about the legacy-threshold `warning` requiring `dedup`.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources