Skip to content

fix(mcp): Rewrite AND/OR in search_issues queries before calling Sentry - #1671

Merged
BYK merged 4 commits into
mainfrom
fix/mcp-issue-search-boolean-rewrite
Oct 26, 2026
Merged

BYK merged 4 commits into
mainfrom
fix/mcp-issue-search-boolean-rewrite

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

search_issues was sending AND/OR to the issues endpoint, which rejects them with Boolean statements containing "OR" or "AND" are not supported in this search. That's the top search_issues failure in sentry/mcp-server: about 93K a week across many users, mostly is:X OR is:Y.

Two things in MCP let them through:

  • The repair prompt (search-issues/config.ts) listed AND, OR, NOT as valid syntax and told the agent to keep explicit tokens.
  • With no agent provider configured, queries went to the API unchecked.

What changes

  • The CLI sanitizer moves to @sentry/toolkit-core/search-query. rewriteSearchQuery returns { query, notes } and throws SearchQueryError. Each product decides how to report: the CLI wrapper (cli/src/lib/search-query.ts) keeps its stderr warning and ValidationError, and MCP throws UserInputError. CLI behavior is unchanged except one error line, which now reads key:[val1,val2] instead of --query "key:[val1,val2]".
  • search_issues runs it after the optional agent repair, right before listIssues, so it covers the no-provider path too. When it rewrites a query, the result says so and shows the query it ran. Queries it can't rewrite fail with a UserInputError that lists alternatives, before any API call.
  • New issueSearch option (MCP only for now):
    • is:A OR is:B becomes status:[A,B] or substatus:[A,B]. is: rejects in-lists, but the status and substatus filters it maps to accept them.
    • Substatus lists must share one parent status, because the endpoint adds a status filter for the first substatus only (expand_substatus_query_values). So is:ongoing OR is:archived_forever is still rejected.
    • Parentheses that reduce to plain terms are unwrapped: is:unresolved (is:regressed OR is:escalating) becomes is:unresolved substatus:[regressed,escalating].
  • The agent prompt and tool description now say there's no AND/OR/NOT or parentheses, and give the in-list, status:, and substatus: forms instead.

Checked against the live API (sentry org, junior project, 14d, X-Hits):

  • status:[unresolved,resolved] returned 165, which is 159 (is:unresolved) + 6 (is:resolved).
  • substatus:[new,ongoing] returned 159, which is 53 (is:new) + 106 (is:ongoing).
  • substatus:[ongoing,archived_forever] returned only unresolved issues, and [archived_forever,ongoing] returned none. That's the first-substatus behavior the parent-status check guards against.
  • (is:unresolved) returned [] and NOT is:resolved returned [] (NOT is searched as free text), both with a 200. That's why the prompt now says ! instead of NOT, and why parentheses get unwrapped.
  • is:[unresolved,resolved] returned a 400: "in" syntax invalid for "is" search.

Reviewing the move

Git shows the core file as new, because the CLI path still holds the wrapper. To see only what changed in the moved code:

git diff main:packages/cli/src/lib/search-query.ts HEAD:packages/toolkit-core/src/search-query.ts

Not in this PR

Checks

  • pnpm run tsc and pnpm run lint pass.
  • Tests pass for toolkit-core (356), mcp-core (1833), and the CLI search-query, issue, log, span, and replay tests (532).
  • The full CLI test/lib + test/commands run has 6 failures in filesystem-permission tests (completions, upgrade lock, code scanner, file-changes). The completions and upgrade-lock failures also happen on main in this sandbox, so they look environment-specific.

via @BYK.

--

View Junior Session [Sentry]

The issues endpoint rejects AND/OR ("Boolean statements containing OR or
AND are not supported"), but the search_issues repair prompt listed them as
valid syntax and told the agent to keep explicit tokens. Without an agent
provider, queries went to the API unchecked.

Move the CLI's query sanitizer into toolkit-core as rewriteSearchQuery and
run it in search_issues after the optional agent repair. It strips AND,
turns same-key OR into in-lists, and throws a UserInputError with
alternatives for anything it can't rewrite. The CLI keeps a thin wrapper
for its stderr warning and ValidationError.

A new issueSearch option covers the most common failure, is:X OR is:Y.
is: rejects in-lists, but the status and substatus filters it maps to
accept them, so it rewrites to status:[...] or substatus:[...]. Substatus
lists must share one parent status, because the endpoint adds a status
filter for the first substatus only. It also unwraps parentheses that
reduce to plain terms, since issue search silently matches nothing for
grouped queries.

Fix the agent prompt and tool description to match.

Co-Authored-By: Burak Yigit Kaya <126780+BYK@users.noreply.github.com>
Co-Authored-By: Andrew Liu <andrew.liu@sentry.io>
@vercel

vercel Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
sentry-local Skipped Skipped Oct 26, 2026 9:47pm UTC

Request Review

@github-actions github-actions Bot added the risk: medium PR risk score: medium label Oct 26, 2026

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread packages/toolkit-core/src/search-query.ts
(is:unresolved OR is:resolved) OR is:ignored threw, because the paren group
became status:[...] first and the is: merge only accepted is: operands.
Accept status/substatus in-lists as operands when the merged field matches.
Comment thread packages/toolkit-core/src/search-query.ts Outdated
substatus:[new] OR substatus:[archived_forever] failed the is: merge and fell
through to the generic same-key merge, producing a cross-parent substatus
list the endpoint silently narrows to the first value's status. In issue
search, route every OR group with an is:, status:, or substatus: operand
through the status merge only.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 35e618e. Configure here.

Comment thread packages/toolkit-core/src/search-query.ts
Substatus:[new] OR substatus:[archived_forever] skipped the parent-status
check because the guard matched keys exactly, then the case-insensitive
generic merge combined them. Lowercase keys in the guard to match.
@BYK
BYK merged commit 37c7193 into main Oct 26, 2026
37 checks passed
@BYK
BYK deleted the fix/mcp-issue-search-boolean-rewrite branch October 26, 2026 22:48

This branch was successfully deployed

1 active and 1 inactive deployments
Actions — ed8bb74e Deployed Oct 26, 2026 by sentry-junior[bot] via eval #1369
Preview — ed8bb74e Deployed Oct 26, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: medium PR risk score: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant