update_alert
Update an existing cost alert. Use when the user asks to change an existing alert's settings, condition, or destinations. 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". messageWidgets replaces the message-widget list wholesale (exactly one ALERT widget required; no DIGEST on alerts); omit to leave the stored widgets unchanged. To edit, read the current list via get: each entry carries config, a lossless writable copy in the exact shape this field accepts — echo every config you are NOT changing back verbatim and edit only the entries you mean to change, so untouched widgets keep their full stored settings (the prose parameters summary is truncated and NOT writable). If any entry's config is null, its stored settings cannot be expressed here — do not replace messageWidgets then.
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" }
Tool call template
Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"arguments": {
"alertId": "<alertId>",
"context": "<context>"
},
"name": "update_alert"
}
}Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Explicit window end (inclusive, YYYY-MM-DD). Use with from instead of datePreset. | |
| from | No | Explicit window start (YYYY-MM-DD). Use with to instead of datePreset. | |
| name | No | Display name for the alert. | |
| slug | No | Organization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs). | |
| dedup | No | Deduplication 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. | |
| scout | No | Scout persona NAME (from list_scouts) or its id. Null clears the assignment; omitted leaves it unchanged. | |
| emails | No | Email addresses (required if EMAIL) | |
| tagIds | No | Replaces 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). | |
| alertId | Yes | Alert ID from search, list_alerts, get, or create_alert. | |
| context | Yes | A few words on why you are calling this tool, for the server developer's analytics. Describe people and things by role, such as "a customer". Do not quote the user or include names, emails, or other personal details. | |
| queries | No | Replaces 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` (use 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. | |
| scopeId | No | 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. | |
| condition | No | Alerts 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`. | |
| llm_model | No | The model identifier you are running as, for example "claude-opus-4-8" or "gpt-5.2". Pass "unknown" if you are not certain. Recorded for the server developer's analytics. | |
| datePreset | No | Official date preset (same as Explore, e.g. MTD, LAST_MONTH). Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Mutually exclusive with from/to. | |
| description | No | Alert description. | |
| messageWidgets | No | Replaces the alert's message-widget list wholesale (alert body plus optional TEXT / GRAPH_SNAPSHOT / TOP_FLOP / DASHBOARD_PDF extras). Omit to leave the stored list unchanged. Exactly one ALERT widget is required; DIGEST is not supported on alerts. Read the current list via `get` and echo each entry's `config` back verbatim for widgets you are not changing (the prose `parameters` summary is truncated and not writable). | |
| slackChannelId | No | Slack 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. | |
| teamsChannelId | No | Teams channel ID (required if TEAMS) | |
| conversation_id | No | The conversation_id this server returned earlier in this conversation, unchanged, including after later user messages. Omit it if you have none. Recorded for the server developer's analytics. | |
| notificationChannel | No | Notification channel |