/m/:id/alerts holds the rules for one server.
A rule is a metric, a comparator, a threshold and a scope. It is evaluated once a night against the previous day, and where it trips it delivers to everyone on the account whose accepted channels overlap the rule’s.
Scope is the whole design
A rule narrows by exactly the two dimensionstool_hours is keyed by: a tool and a client. Either may be left as every.
That is deliberate, and it is where the value is. Consider two rules on the same server, the same metric and the same day:
One rule finds the problem; the other cannot see it. Both ship on the sample MCP every new account is seeded with, for exactly that contrast.
A rule can only ask a question a panel can answer, which is the other half of the reasoning: a rule you cannot check on screen is a rule nobody trusts.
The metrics
A closed vocabulary, not free SQL. Every value is a ratio or a count derivable from one day oftool_hours rows, which keeps evaluation a single grouped read.
GET /v1/mcps/:id/alerts returns this catalogue alongside the rules, and each metric carries the unit its threshold is expressed in and the direction that makes sense for it.
That is not decoration. A rate is stored as 0.6 and typed as 60, so a client that does not know the unit writes a rule which can never fire and looks entirely reasonable in the table. And nobody wants to be told their first-call rate went up.
Every rule has a noise floor
min_calls, defaulting to 20.
Two empties out of three calls is 67% and means nothing. Publishing it teaches people to distrust every alert after it, which costs more than the alert was worth.
Rules are named
Asked for at creation, and required. A list identified only byfirst_call_rate < 0.6 tells you the condition and never the intent.
What fires is frozen
When a rule trips, the finding copies the metric, comparator, scope and rule name as they were at that moment. A rule can be renamed or deleted afterwards, and a notification that cannot say why it was sent is worse than none. The wording is not stored — it is rendered from those fields, so the inbox, an email and the MCP server read the same sentence. Prose stored in a database is a second copy of it.Evaluation
02:15 UTC, fifteen minutes after the nightly pass. Not beside it:first_call_rate is written by that pass, so a rule evaluated in the same minute would read a half-computed rate — firing on a figure that was never true, or missing one that was.
Idempotent in both directions. Re-running a day cannot produce a second copy of the same finding, which is what makes recovering a missed night a loop rather than a cleanup.
Toggling a rule off is a one-field call.
PATCH /v1/alerts/:id leaves omitted fields alone, so two people silencing rules at once cannot clobber each other’s thresholds.History
/m/:id/alerts also shows what fired: the day, the observed value, the threshold it crossed, and how many calls it was measured over.
Alerts are a paid feature
Creating a rule, switching an existing one back on, and subscribing to the weekly digest all require Pro or Scale. Disabling and unsubscribing stay open on any plan — somebody whose subscription ended must be able to tidy up what they can no longer run — and the nightly evaluation skips free accounts, so a rule that outlives its plan does not keep filling an inbox.Related
- Channels — where a firing is delivered
- The weekly digest
- Insights — the same findings, computed on read rather than fired at you