feat(search-events): support time series via events-stats - #1305
Merged
Merged
Conversation
"X over time / per hour / per day / trend" now returns a bucketed series instead of failing. The embedded agent decides the granularity: it sets timeSeries.interval when the user names one ("per hour" -> 1h), otherwise leaves it null so Sentry picks a sensible bucket for the range. Never a required input.
- api-client: getEventsTimeSeries (events-stats) + response schema
- agent: timeSeries {yAxis, interval} output + prompt guidance (previously returned a 'not supported' error)
- handler: time series branch -> events-stats + formatter
- formatter: bucketed table with total/peak
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…non-additive aggregates Cleanup to follow existing search_events patterns, plus a correctness fix from PR review: - Match the sibling result formatters: title the timeseries output `# Search Results for "<query>"` (the previously-unused `inputQuery`) and move the yAxis into a `## <yAxis> over time` section heading. - Reuse the existing `formatExecutedTimeRange` helper instead of a bespoke time-range branch. - Move the `EventsStatsResponseSchema` import back into alphabetical order. - Document why the timeseries branch deliberately skips `validateEventsSearch` (it validates the /events/ discover shape, not /events-stats/). - Fix: `Total` summed buckets for every yAxis, which is wrong for non-additive aggregates (count_unique, avg, percentiles, rates). Only render Total for additive aggregates (count(), sum(...)); Peak stays. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
betegon
marked this pull request as ready for review
September 12, 2026 06:19
Warden (mcp-audit) flagged that the client-visible search_events description still said "TWO query types" after the events-stats timeseries path landed, so tools/list never told clients that "errors per hour" / "over time" works. - Add the TIME SERIES mode (and an example) to the tool description. - Trim offsetting verbosity to stay under the 2048-char budget: tighten the intro line, merge the two org/project hints, drop the redundant level:error example. - Regenerate toolDefinitions.json and skillDefinitions.json. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
search_eventscouldn't answer "over time" questions. Depending on phrasing the embedded agent either:AI_NoOutputGeneratedError/ "could not construct a valid query" (the MCP-SERVER-F1Z failure mode), orWhat this does
Adds first-class time series via the
events-statsendpoint. "X per hour / per day / trend / over time" now returns a bucketed series.The agent decides the granularity — it's never a required input:
interval: "1h".interval: null, so Sentry picks a sensible bucket for the range (mirrorsget_interval_from_range; it rejects intervals that would make too many buckets).Before / after (verified live with the real model, gpt-5.6-luna)
AI_NoOutputGeneratedError— fails1h1dcount()count()(unchanged)Related Sentry issues
AI_NoOutputGeneratedError(~60k users). "Over time" queries were one source of these no-output failures (see the before/after above). Already resolved by the environment-grounding fix (fix(search-events): ground the agent in the org's real environments #1300); this removes the time-series subset of the underlying cause so those requests return data instead of dead-ending.Changes
getEventsTimeSeries(→/events-stats/, omitsintervalwhen null) +EventsStatsResponseSchema.timeSeries { yAxis, interval }on the output schema; prompt now instructs the model to use it (replacing the old "not supported → return an error" guidance).timeSeriestogetEventsTimeSeries+ a new formatter; skips the sort-in-fields check for it.formatTimeSeriesResults— bucketed table with total and peak.docs/specs/search-events.md.Test plan
pnpm --filter @sentry/mcp-core tsc— clean;biome lint— clean; full mcp-core suite — 1419 passed.timeSeries→ handler callsevents-stats→ formatted buckets/total/peak.gpt-5.6-luna) against mocked Sentry — the four queries above behaved exactly as the table shows.🤖 Generated with Claude Code