Skip to content

Expose absolute start/end time ranges in search_events and search_issues #1215

Open

Description

@giyeol

Summary

Automated MCP callers need deterministic, closed time windows, but the public input schemas for search_events and search_issues currently expose only the relative period parameter.

Please expose optional absolute start and end parameters for both tools.

Current behavior

search_events already has most of the absolute-time plumbing internally:

  • its embedded-agent output accepts either { statsPeriod } or { start, end }
  • the API client can forward start and end
  • the result formatter can report the exact executed absolute range

However, the public tool schema exposes only period. In the structured-query path, an explicitly supplied period is also preferred over the agent's parsed absolute time range. This means a caller cannot make absolute bounds authoritative at the tool boundary.

A generic example is a scheduled checkpoint intended to cover exactly:

[2026-01-01T00:00:00Z, 2026-01-02T00:00:00Z)

The closest public invocation is currently something like:

{
  "organizationSlug": "example-org",
  "dataset": "errors",
  "query": "environment:production timestamp:>=2026-01-01T00:00:00Z timestamp:<2026-01-02T00:00:00Z",
  "fields": ["count()"],
  "sort": "-count()",
  "period": "24h"
}

The embedded agent may extract the timestamp filters into its internal timeRange, but the handler can then retain the explicit relative period. The executed request is therefore relative to execution time rather than the requested fixed window.

search_issues similarly exposes only period and forwards it as statsPeriod. The underlying Sentry issues endpoint supports start and end, so the same fixed-window contract should be available through MCP:

https://docs.sentry.io/api/events/list-an-organizations-issues/

This is related to, but not fixed by, #726 / #1130: those changes exposed a relative period and corrected its default, while fixed absolute ranges remain unavailable.

Proposed behavior

For both tools:

  • Add optional ISO-8601 start and end inputs.
  • Require start and end as a pair.
  • Reject period together with start/end.
  • Validate that start < end.
  • Treat explicitly supplied absolute bounds as authoritative through agent translation and validation/repair.
  • Keep the existing relative-period defaults only when neither absolute bound is supplied.

For search_events, the handler can pass the public values through the existing { start, end } time-parameter path.

For search_issues, extend listIssues to forward start and end instead of statsPeriod when absolute bounds are supplied.

Result provenance

Please also report the executed query, sort, and effective time range in search_issues output, including when the result set is empty. search_events already provides useful executed-search metadata. Without equivalent metadata, a zero-result response cannot prove that the requested fixed window was actually used.

Compatibility and security

  • Existing period calls and defaults remain compatible.
  • No additional OAuth/API scope should be required; these remain read-only event:read operations.
  • Relative periods remain useful for interactive exploration, while absolute bounds enable deterministic scheduled checks and reproducible incident analysis.

Suggested tests

  • Existing period behavior remains unchanged.
  • Paired start/end are forwarded without statsPeriod.
  • Partial, conflicting, or reversed ranges are rejected.
  • Agent translation/repair cannot replace explicit absolute bounds.
  • search_issues reports the effective range for both non-empty and empty results.

Activity

  1. linear-code commented on Jul 30, 2026

    @linear-code
  2. genesiscz commented on Aug 3, 2026

    @genesiscz

    Adding a concrete data point that supports this request from a different direction: the embedded agent's relative time translation is not just imprecise, it frequently emits syntax the issues endpoint rejects outright with a 400. So today there is no reliable way to express a time window at all, relative or absolute.

    This is not a self-hosted quirk. The grammar in getsentry/sentry gives relative-date filters no operator slot at all, so an operator-prefixed relative duration cannot parse on any deployment (details at the end).

    Repro

    @sentry/mcp-server 0.36.0 and 0.37.0, self-hosted Sentry (--host=<internal-host>), embedded agent via --agent-provider=openai against an OpenAI-compatible endpoint.

    Call (0.37.0 tool surface):

    {
      "name": "search_issues",
      "arguments": {
        "organizationSlug": "<org>",
        "query": "regressions from the last 3 days",
        "limit": 2
      }
    }

    Result:

    API error (400): Error parsing search query: last_seen: Invalid date: >-3d.
    Expected +/-duration (e.g. +1h) or ISO 8601-like (e.g. 2026-08-03T22:41:16.91).
    

    Other phrasings fail the same way. Cases where I captured the full error text:

    query argument error from the API
    errors seen in the last 24 hours last_seen: Invalid date: >-24h
    crashes in the last 24 hours affecting the most users last_seen: Invalid date: >-24h
    regressions from the last 3 days last_seen: Invalid date: >-3d

    Feeding the same system prompt to the model directly, outside the server, reproduces the pattern on firstSeen too, for example {"query":"firstSeen:>-7d","sort":"new"} for "new issues from the past week" and {"query":"firstSeen:>-24h"} for "issues first seen since yesterday".

    The agent is prefixing a comparison operator onto a relative duration. Dropping the > makes the identical query succeed, so the filter itself is fine and only the operator is the problem:

    { "organizationSlug": "<org>", "query": "is:unresolved lastSeen:-24h", "limit": 2 }

    returns results normally.

    It is stochastic, not model-specific

    Ran the same six natural-language time queries end to end through the real server, several rounds per model:

    embedded-agent model pass rate
    gpt-5.5 1/6
    gpt-5.6 (variant A) 5/6, then 3/6, then 6/6 across three rounds
    gpt-5.6 (variant B) 6/6, 6/6, 6/6, then 5/6

    No model was reliably clean, and the same query can pass and fail on consecutive runs, which is what you would expect from a prompt ambiguity rather than a defect in one model.

    Likely source

    In packages/mcp-core/src/tools/support/search-issues/config.ts the SYNTAX: block puts these two rules on adjacent lines:

    - Time ranges use relative notation: -24h, -7d, -30d
    - Comparisons: >, <, >=, <=
    

    Nothing states that the comparison operators apply to numeric fields such as timesSeen / userCount and never to the date fields, so the model composes them. The eval suite has one case asserting /lastSeen:-24h/, but no case exercises phrasings like "older than N days" that pull the model toward a comparison operator, so this is not currently caught.

    Why the operator can never work, on any deployment

    From src/sentry/api/event_search.py on master, the PEG productions for date-ish filters:

    date_filter          = search_key sep operator iso_8601_date_format          # L87
    specific_date_filter = search_key sep iso_8601_date_format                   # L90
    rel_date_filter      = search_key sep rel_date_format                        # L93
    duration_filter      = negation? search_key sep operator? duration_format    # L96
    

    rel_date_filter has no operator token, while duration_filter (and the numeric and aggregate variants) carry an optional operator?. The +/- sign is part of rel_date_format itself, which is why lastSeen:-24h parses and lastSeen:>-24h cannot. It then falls through to the generic filter path and hits _handle_basic_filter, which raises the exact string above at L945.

    That production shape explains the failure mode precisely: an LLM that has seen timesSeen:>100 or transaction.duration:>5s generalises > to any value type, and relative dates are one of the few places where that generalisation is invalid.

    Since parsing lives in core sentry rather than in anything SaaS-gated, this reproduces on sentry.io as well, so it is not specific to my deployment.

    This exact pattern was guarded against once, in the sibling prompt

    The search_events prompt used to carry a line naming this bug explicitly. Visible as unchanged context in the diff of #419:

    - IMPORTANT: For relative durations, use format WITHOUT operators (timestamp:-1h NOT timestamp:>-1h)
    

    Searching the repo today for WITHOUT operators returns nothing, so that guard is gone. It was dropped when search_events moved to the structured timeRange parameter, which removed the ambiguity by design rather than by warning, and search_events is correspondingly immune today since time never lives inside its query string.

    search_issues got neither treatment. It still encodes time inline in query, and its prompt has no equivalent guard, which is what leaves this failure open.

    Why this is relevant here

    The TOOL RESPONSE HANDLING section tells the agent it may retry after an error, but that is opportunistic rather than a guaranteed repair loop, so in practice the 400 surfaces to the caller and the call is simply lost.

    The absolute start / end inputs proposed in this issue would let a caller skip agent time translation entirely, which fixes this failure mode as a side effect for automated callers. That said, this is arguably its own bug, since interactive callers passing natural language would still hit it. Happy to open a separate issue for the prompt or eval side if that is preferred.

  3. sentry-junior commented on Nov 10, 2026

    @sentry-junior
    Contributor

    Related path this issue and #1228 do not cover: the caller passes period and absolute timestamp:>= / timestamp:< bounds in a structured query. The embedded agent can move those bounds into an absolute timeRange and drop them from the query, and then the explicit period wins over that range (search.ts:936-938). The search silently runs over the whole period. #2139 fixes that by putting dropped timestamp: bounds back on the repaired query. Absolute start/end inputs are still useful on top of it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions