Skip to content

Commit 05559a9

Browse files
dcramercodex
andcommitted
fix(search): Use query for agent-assisted search
Collapse natural language search input into the existing query parameter and run configured agent providers as a repair pass over query, dataset, fields, sort, and time hints. Update generated definitions, docs, evals, and tests so search tools expose query as the single input for both natural language and direct Sentry syntax. Co-Authored-By: Codex GPT-5 <codex@openai.com>
1 parent 5c8fa84 commit 05559a9

24 files changed

Lines changed: 315 additions & 386 deletions

‎docs/adding-tools.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ Some tools (`search_events` and `search_issues`) embed AI agents to handle compl
294294
// Tool handler delegates to embedded agent
295295
async handler(params, context) {
296296
// 1. Embedded agent translates natural language
297-
const translated = await translateQuery(params.naturalLanguageQuery, ...);
297+
const translated = await translateQuery(params.query, ...);
298298

299299
// 2. Tool executes the translated query
300300
const results = await apiService.searchEvents(translated.query, ...);

‎docs/architecture.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ Some tools (`search_events` and `search_issues`) implement a two-tier agent patt
279279
```
280280
1. User: "Show me errors from yesterday"
281281
↓
282-
2. Claude: Calls search_events(naturalLanguageQuery="errors from yesterday")
282+
2. Claude: Calls search_events(query="errors from yesterday")
283283
↓
284284
3. MCP Tool Handler: Receives request
285285
↓

‎docs/specs/search-events.md‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ A unified search tool that accepts natural language queries and translates them
1515
```typescript
1616
interface SearchEventsParams {
1717
organizationSlug: string; // Required
18-
naturalLanguageQuery: string; // Natural language search description
18+
query: string; // Natural language search description
1919
dataset?: "spans" | "errors" | "logs" | "metrics"; // Dataset to search (default: "errors")
2020
projectSlug?: string; // Optional - limit to specific project
2121
regionUrl?: string;
@@ -30,28 +30,28 @@ interface SearchEventsParams {
3030
// Find errors (errors dataset is default)
3131
search_events({
3232
organizationSlug: "my-org",
33-
naturalLanguageQuery: "database timeouts in checkout flow from last hour"
33+
query: "database timeouts in checkout flow from last hour"
3434
})
3535

3636
// Find slow transactions
3737
search_events({
3838
organizationSlug: "my-org",
39-
naturalLanguageQuery: "API calls taking over 5 seconds",
39+
query: "API calls taking over 5 seconds",
4040
projectSlug: "backend",
4141
dataset: "spans"
4242
})
4343

4444
// Find logs
4545
search_events({
4646
organizationSlug: "my-org",
47-
naturalLanguageQuery: "warning logs about memory usage",
47+
query: "warning logs about memory usage",
4848
dataset: "logs"
4949
})
5050

5151
// Find request duration metrics
5252
search_events({
5353
organizationSlug: "my-org",
54-
naturalLanguageQuery: "p95 request duration by transaction this week",
54+
query: "p95 request duration by transaction this week",
5555
dataset: "metrics"
5656
})
5757
```
@@ -125,7 +125,7 @@ find_errors({
125125
// After
126126
search_events({
127127
organizationSlug: "sentry",
128-
naturalLanguageQuery: "unresolved errors in checkout.js"
128+
query: "unresolved errors in checkout.js"
129129
})
130130
```
131131

‎docs/testing-remote.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ Opens at `http://localhost:6274`
343343
// Test search_events with AI
344344
{
345345
"organizationSlug": "your-org",
346-
"naturalLanguageQuery": "errors in the last hour",
346+
"query": "errors in the last hour",
347347
"dataset": "errors"
348348
}
349349
```

‎docs/testing-stdio.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ This opens the MCP Inspector at `http://localhost:6274`
198198
1. **List Tools** - Verify expected tools appear
199199
2. **Call a tool** - Start with `whoami` (no parameters required)
200200
3. **Test with parameters** - Try `find_organizations()`
201-
4. **Test complex operations** - Try `search_events(naturalLanguageQuery="errors in the last hour")`
201+
4. **Test complex operations** - Try `search_events(query="errors in the last hour")`
202202

203203
**Example test sequence:**
204204
```
@@ -207,7 +207,7 @@ This opens the MCP Inspector at `http://localhost:6274`
207207
3. find_projects(organizationSlug="your-org")
208208
4. search_events(
209209
organizationSlug="your-org",
210-
naturalLanguageQuery="errors from yesterday"
210+
query="errors from yesterday"
211211
)
212212
```
213213

@@ -485,8 +485,8 @@ OPENAI_API_KEY=your-key pnpm start --access-token=TOKEN
485485

486486
# Test search_events and search_issues work
487487
# In MCP Inspector:
488-
# - Call search_events(naturalLanguageQuery="errors in production")
489-
# - Call search_issues(naturalLanguageQuery="unresolved crashes")
488+
# - Call search_events(query="errors in production")
489+
# - Call search_issues(query="unresolved crashes")
490490
```
491491

492492
### 5. Test Agent Mode

‎packages/mcp-core/src/internal/formatting.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1929,7 +1929,7 @@ export function formatIssueOutput({
19291929
output += `- You can reference the IssueID in commit messages (e.g. \`Fixes ${issue.shortId}\`) to automatically close the issue when the commit is merged.\n`;
19301930
output +=
19311931
"- The stacktrace includes both first-party application code as well as third-party code, its important to triage to first-party code.\n";
1932-
output += `- To search for specific occurrences or filter events within this issue, use \`search_issue_events(organizationSlug='${organizationSlug}', issueId='${issue.shortId}', naturalLanguageQuery='your query')\`\n`;
1932+
output += `- To search for specific occurrences or filter events within this issue, use \`search_issue_events(organizationSlug='${organizationSlug}', issueId='${issue.shortId}', query='your query')\`\n`;
19331933
if (experimentalMode) {
19341934
output += `- To see the trail of events leading up to this error, use \`get_sentry_resource(url='${apiService.getIssueUrl(organizationSlug, issue.shortId)}', resourceType='breadcrumbs')\`\n`;
19351935
}

‎packages/mcp-core/src/skillDefinitions.json‎

Lines changed: 8 additions & 8 deletions
Large diffs are not rendered by default.

‎packages/mcp-core/src/toolDefinitions.json‎

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -772,27 +772,22 @@
772772
},
773773
{
774774
"name": "search_events",
775-
"description": "Search Sentry events and replays. This is the ONLY tool for counts/statistics on event datasets.\n\nProvide `naturalLanguageQuery` to let an embedded agent determine dataset, query, fields, and sort,\nor provide these directly with Sentry search syntax.\n\nSupports TWO query types:\n1. AGGREGATIONS (counts, sums, averages): 'how many errors', 'total tokens'\n2. Individual events with timestamps: 'error logs from last hour'\n\nDatasets:\n- errors: Exception/crash events with stack traces, usually grouped into issues\n- logs: Application log entries, including error-severity log messages\n- spans: Raw trace/span events for performance, AI/LLM calls, requests, and operations\n- metrics: Metric rows and aggregates, including counters, gauges, distributions, and metric values\n- profiles: Transaction and continuous profile results, profile IDs, and profiled transactions\n- replays: Session replay results such as rage clicks, dead clicks, visited pages, and replay users\nIf the user says logs, log messages, error logs, or warning logs, choose logs instead of errors.\n\nReplay searches on this tool return replay lists only. Replay count()/avg()/sum() aggregations are not supported.\n\nDO NOT USE for grouped issue lists → use search_issues\n\n<examples>\nsearch_events(organizationSlug='my-org', naturalLanguageQuery='how many errors today')\nsearch_events(organizationSlug='my-org', dataset='errors', query='level:error')\nsearch_events(organizationSlug='my-org', dataset='errors', fields=['issue', 'count()'], sort='-count()')\nsearch_events(organizationSlug='my-org', dataset='spans', query='span.op:db', sort='-span.duration')\nsearch_events(organizationSlug='my-org', dataset='replays', query='count_errors:>0', sort='-count_errors')\n</examples>\n\n<hints>\n- If the user passes a parameter in the form of name/otherName, it's likely in the format of <organizationSlug>/<projectSlug>.\n- Parse org/project notation directly without calling find_organizations or find_projects.\n- Use fields with aggregate functions like count(), avg(), sum() for statistics\n- Sort by -count() for most common, -timestamp for newest\n</hints>",
775+
"description": "Search Sentry events and replays. Use for event counts/statistics.\n\n`query` can be natural language or Sentry search syntax. With an agent configured, it fixes dataset, query, fields, and sort before running.\n\nSupports TWO query types:\n1. AGGREGATIONS (counts, sums, averages): 'how many errors', 'total tokens'\n2. Individual events with timestamps: 'error logs from last hour'\n\nDatasets:\n- errors: Exception/crash events with stack traces, usually grouped into issues\n- logs: Application log entries, including error-severity log messages\n- spans: Raw trace/span events for performance, AI/LLM calls, requests, and operations\n- metrics: Metric rows and aggregates: counters, gauges, distributions, values\n- profiles: Transaction/continuous profile results, profile IDs, profiled transactions\n- replays: Session replay results: rage clicks, dead clicks, visited pages, replay users\nIf the user says logs, log messages, error logs, or warning logs, choose logs instead of errors.\n\nReplay searches return replay lists only; replay count()/avg()/sum() are not supported.\n\nDO NOT USE for grouped issue lists → use search_issues\n\n<examples>\nsearch_events(organizationSlug='my-org', query='how many errors today')\nsearch_events(organizationSlug='my-org', dataset='errors', query='level:error')\nsearch_events(organizationSlug='my-org', dataset='errors', fields=['issue', 'count()'], sort='-count()')\nsearch_events(organizationSlug='my-org', dataset='spans', query='span.op:db', sort='-span.duration')\nsearch_events(organizationSlug='my-org', dataset='replays', query='count_errors:>0', sort='-count_errors')\n</examples>\n\n<hints>\n- If the user passes a parameter in the form of name/otherName, it's likely in the format of <organizationSlug>/<projectSlug>.\n- Parse org/project notation directly without calling find_organizations or find_projects.\n- Use fields with aggregate functions like count(), avg(), sum() for statistics\n- Sort by -count() for most common, -timestamp for newest\n</hints>",
776776
"inputSchema": {
777777
"type": "object",
778778
"properties": {
779779
"organizationSlug": {
780780
"type": "string",
781781
"description": "The organization's slug. You can find a existing list of organizations you have access to using the `find_organizations()` tool."
782782
},
783-
"naturalLanguageQuery": {
784-
"type": "string",
785-
"minLength": 1,
786-
"description": "Natural language description of what you want to search for. When provided, an embedded agent determines the dataset, query, fields, and sort."
787-
},
788783
"dataset": {
789784
"type": "string",
790785
"enum": ["spans", "errors", "logs", "metrics", "profiles", "replays"],
791-
"description": "Dataset to query when naturalLanguageQuery is not provided: errors, logs, spans, metrics, profiles, or replays."
786+
"description": "Initial dataset hint: errors, logs, spans, metrics, profiles, or replays. The agent may correct this when configured."
792787
},
793788
"query": {
794789
"type": "string",
795-
"description": "Sentry event search query syntax. Used when naturalLanguageQuery is not provided."
790+
"description": "Natural language or Sentry event search query syntax."
796791
},
797792
"fields": {
798793
"anyOf": [
@@ -858,7 +853,7 @@
858853
},
859854
"statsPeriod": {
860855
"type": "string",
861-
"description": "Time period: 1h, 24h, 7d, 14d, 30d, etc. Used when naturalLanguageQuery is not provided."
856+
"description": "Initial time period hint: 1h, 24h, 7d, 14d, 30d, etc."
862857
},
863858
"regionUrl": {
864859
"anyOf": [
@@ -883,7 +878,7 @@
883878
"includeExplanation": {
884879
"type": "boolean",
885880
"default": false,
886-
"description": "Include explanation of how the query was translated (only applies with naturalLanguageQuery)"
881+
"description": "Include explanation of how the query was translated or repaired"
887882
}
888883
},
889884
"required": ["organizationSlug"],
@@ -894,7 +889,7 @@
894889
},
895890
{
896891
"name": "search_issue_events",
897-
"description": "Search and filter events within a specific issue.\n\nProvide `naturalLanguageQuery` to let an embedded agent determine the correct filters,\nor use `query` and `sort` directly with Sentry search syntax.\n\nThe tool automatically constrains results to the specified issue.\n\nCommon Query Filters:\n- environment:production - Filter by environment\n- release:1.0.0 - Filter by release version\n- user.email:alice@example.com - Filter by user\n- trace:TRACE_ID - Filter by trace ID\n\nFor cross-issue searches use search_issues. For single issue or event details use get_sentry_resource.\n\n<examples>\nsearch_issue_events(issueId='MCP-41', organizationSlug='my-org', naturalLanguageQuery='from last hour')\nsearch_issue_events(issueId='MCP-41', organizationSlug='my-org', query='environment:production')\nsearch_issue_events(issueUrl='https://sentry.io/.../issues/123/', query='release:v1.0.0', statsPeriod='7d')\n</examples>",
892+
"description": "Search and filter events within a specific issue.\n\nProvide `query` as natural language or Sentry event search syntax. When an embedded agent is configured, it fixes filters, fields, sort, and time range before running.\n\nThe tool automatically constrains results to the specified issue.\n\nCommon Query Filters:\n- environment:production - Filter by environment\n- release:1.0.0 - Filter by release version\n- user.email:alice@example.com - Filter by user\n- trace:TRACE_ID - Filter by trace ID\n\nFor cross-issue searches use search_issues. For single issue or event details use get_sentry_resource.\n\n<examples>\nsearch_issue_events(issueId='MCP-41', organizationSlug='my-org', query='from last hour')\nsearch_issue_events(issueId='MCP-41', organizationSlug='my-org', query='environment:production')\nsearch_issue_events(issueUrl='https://sentry.io/.../issues/123/', query='release:v1.0.0', statsPeriod='7d')\n</examples>",
898893
"inputSchema": {
899894
"type": "object",
900895
"properties": {
@@ -920,22 +915,17 @@
920915
"format": "uri",
921916
"description": "Full Sentry issue URL (e.g., 'https://sentry.io/organizations/my-org/issues/123/'). Includes both organization and issue ID."
922917
},
923-
"naturalLanguageQuery": {
924-
"type": "string",
925-
"minLength": 1,
926-
"description": "Natural language description of what events to find within this issue. When provided, an embedded agent determines the correct filters, fields, sort, and time range."
927-
},
928918
"query": {
929919
"type": "string",
930-
"description": "Sentry event search query syntax for filtering within the issue. Used when naturalLanguageQuery is not provided."
920+
"description": "Natural language or Sentry event search query syntax for filtering within the issue."
931921
},
932922
"sort": {
933923
"type": "string",
934924
"description": "Sort field (prefix with - for descending). Default: -timestamp"
935925
},
936926
"statsPeriod": {
937927
"type": "string",
938-
"description": "Time period: 1h, 24h, 7d, 14d, 30d, etc. Used when naturalLanguageQuery is not provided."
928+
"description": "Initial time period hint: 1h, 24h, 7d, 14d, 30d, etc."
939929
},
940930
"projectSlug": {
941931
"anyOf": [
@@ -973,7 +963,7 @@
973963
"includeExplanation": {
974964
"type": "boolean",
975965
"default": false,
976-
"description": "Include explanation of how the query was translated (only applies with naturalLanguageQuery)"
966+
"description": "Include explanation of how the query was translated or repaired"
977967
}
978968
},
979969
"additionalProperties": false,
@@ -983,23 +973,18 @@
983973
},
984974
{
985975
"name": "search_issues",
986-
"description": "Search for grouped issues/problems in Sentry - returns a LIST of issues, NOT counts or aggregations.\n\nProvide `naturalLanguageQuery` to let an embedded agent determine the correct query and sort params,\nor use `query` and `sort` directly with Sentry search syntax.\n\nReturns grouped issues with metadata like title, status, and user count.\n\nCommon Query Syntax:\n- is:unresolved / is:resolved / is:ignored\n- level:error / level:warning\n- firstSeen:-24h / lastSeen:-7d\n- assigned:me / assignedOrSuggested:me\n- issueCategory:feedback\n- environment:production\n- userCount:>100\n\nDO NOT USE FOR COUNTS/AGGREGATIONS → use search_events\nDO NOT USE FOR individual events with timestamps → use search_events\nDO NOT USE FOR details about a specific issue → use get_sentry_resource\n\n<examples>\nsearch_issues(organizationSlug='my-org', naturalLanguageQuery='critical bugs from last week')\nsearch_issues(organizationSlug='my-org', query='is:unresolved is:unassigned', sort='freq')\nsearch_issues(organizationSlug='my-org', query='level:error firstSeen:-24h', projectSlugOrId='my-project')\n</examples>\n\n<hints>\n- If the user passes a parameter in the form of name/otherName, it's likely in the format of <organizationSlug>/<projectSlugOrId>.\n- Parse org/project notation directly without calling find_organizations or find_projects.\n- The projectSlugOrId parameter accepts both project slugs (e.g., 'my-project') and numeric IDs (e.g., '123456').\n</hints>",
976+
"description": "Search for grouped issues/problems in Sentry - returns a LIST of issues, NOT counts or aggregations.\n\nProvide `query` as natural language or Sentry issue search syntax. When an embedded agent is configured, it fixes query and sort before running.\n\nReturns grouped issues with metadata like title, status, and user count.\n\nCommon Query Syntax:\n- is:unresolved / is:resolved / is:ignored\n- level:error / level:warning\n- firstSeen:-24h / lastSeen:-7d\n- assigned:me / assignedOrSuggested:me\n- issueCategory:feedback\n- environment:production\n- userCount:>100\n\nDO NOT USE FOR COUNTS/AGGREGATIONS → use search_events\nDO NOT USE FOR individual events with timestamps → use search_events\nDO NOT USE FOR details about a specific issue → use get_sentry_resource\n\n<examples>\nsearch_issues(organizationSlug='my-org', query='critical bugs from last week')\nsearch_issues(organizationSlug='my-org', query='is:unresolved is:unassigned', sort='freq')\nsearch_issues(organizationSlug='my-org', query='level:error firstSeen:-24h', projectSlugOrId='my-project')\n</examples>\n\n<hints>\n- If the user passes a parameter in the form of name/otherName, it's likely in the format of <organizationSlug>/<projectSlugOrId>.\n- Parse org/project notation directly without calling find_organizations or find_projects.\n- The projectSlugOrId parameter accepts both project slugs (e.g., 'my-project') and numeric IDs (e.g., '123456').\n</hints>",
987977
"inputSchema": {
988978
"type": "object",
989979
"properties": {
990980
"organizationSlug": {
991981
"type": "string",
992982
"description": "The organization's slug. You can find a existing list of organizations you have access to using the `find_organizations()` tool."
993983
},
994-
"naturalLanguageQuery": {
995-
"type": "string",
996-
"minLength": 1,
997-
"description": "Natural language description of issues to search for. When provided, an embedded agent translates this into the correct query and sort params."
998-
},
999984
"query": {
1000985
"type": "string",
1001986
"default": "is:unresolved",
1002-
"description": "Sentry issue search query syntax. Used when naturalLanguageQuery is not provided."
987+
"description": "Natural language or Sentry issue search query syntax."
1003988
},
1004989
"sort": {
1005990
"type": "string",
@@ -1042,7 +1027,7 @@
10421027
"includeExplanation": {
10431028
"type": "boolean",
10441029
"default": false,
1045-
"description": "Include explanation of how the query was translated (only applies with naturalLanguageQuery)"
1030+
"description": "Include explanation of how the query was translated or repaired"
10461031
}
10471032
},
10481033
"required": ["organizationSlug"],

0 commit comments

Comments
 (0)