Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions packages/mcp-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,15 @@
"author": "Sentry",
"description": "Sentry MCP Core - Shared code for MCP transports",
"homepage": "https://github.com/getsentry/sentry-mcp",
"keywords": [
"sentry"
],
"keywords": ["sentry"],
"bugs": {
"url": "https://github.com/getsentry/sentry-mcp/issues"
},
"repository": {
"type": "git",
"url": "git@github.com:getsentry/sentry-mcp.git"
},
"files": [
"./dist/*"
],
"files": ["./dist/*"],
"exports": {
"./api-client": {
"types": "./dist/api-client/index.ts",
Expand Down Expand Up @@ -85,6 +81,10 @@
"types": "./dist/tools/search-issues/index.ts",
"default": "./dist/tools/search-issues/index.js"
},
"./tools/search-issue-events": {
"types": "./dist/tools/search-issue-events/index.ts",
"default": "./dist/tools/search-issue-events/index.js"
},
"./tools/search-events/agent": {
"types": "./dist/tools/search-events/agent.ts",
"default": "./dist/tools/search-events/agent.js"
Expand All @@ -93,6 +93,10 @@
"types": "./dist/tools/search-issues/agent.ts",
"default": "./dist/tools/search-issues/agent.js"
},
"./tools/search-issue-events/agent": {
"types": "./dist/tools/search-issue-events/agent.ts",
"default": "./dist/tools/search-issue-events/agent.js"
},
"./tools/agent-tools": {
"types": "./dist/tools/agent-tools.ts",
"default": "./dist/tools/agent-tools.js"
Expand Down
51 changes: 51 additions & 0 deletions packages/mcp-core/src/api-client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1649,6 +1649,57 @@ export class SentryApiService {
);
}

/**
* Lists events for a specific issue.
* Uses the issue-specific endpoint which already filters by issue ID.
*
* @see https://docs.sentry.io/api/events/list-an-issues-events/
*/
async listEventsForIssue(
{
organizationSlug,
issueId,
query,
limit = 50,
statsPeriod,
start,
end,
full = false,
}: {
organizationSlug: string;
issueId: string;
query?: string;
limit?: number;
statsPeriod?: string;
start?: string;
end?: string;
full?: boolean;
},
opts?: RequestOptions,
) {
const params = new URLSearchParams();

if (query) {
params.append("query", query);
}

params.append("per_page", String(limit));

if (statsPeriod) {
params.append("statsPeriod", statsPeriod);
} else if (start && end) {
params.append("start", start);
params.append("end", end);
}

if (full) {
params.append("full", "true");
}

const apiUrl = `/organizations/${organizationSlug}/issues/${issueId}/events/?${params.toString()}`;
return await this.requestJSON(apiUrl, undefined, opts);
}

async listEventAttachments(
{
organizationSlug,
Expand Down
1 change: 1 addition & 0 deletions packages/mcp-core/src/internal/formatting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1830,5 +1830,6 @@ export function formatIssueOutput({
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`;
output +=
"- The stacktrace includes both first-party application code as well as third-party code, its important to triage to first-party code.\n";
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`;
return output;
}
14 changes: 12 additions & 2 deletions packages/mcp-core/src/skillDefinitions.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"description": "Search for errors, analyze traces, and explore event details",
"defaultEnabled": true,
"order": 1,
"toolCount": 10,
"toolCount": 11,
"tools": [
{
"name": "find_organizations",
Expand Down Expand Up @@ -47,6 +47,11 @@
"description": "Search for events AND perform counts/aggregations - the ONLY tool for statistics and counts.\n\nSupports TWO query types:\n1. AGGREGATIONS (counts, sums, averages): 'how many errors', 'count of issues', 'total tokens'\n2. Individual events with timestamps: 'show me error logs from last hour'\n\nUSE THIS FOR ALL COUNTS/STATISTICS:\n- 'how many errors today' → returns count\n- 'count of database failures' → returns count\n- 'total number of issues' → returns count\n- 'average response time' → returns avg()\n- 'sum of tokens used' → returns sum()\n\nALSO USE FOR INDIVIDUAL EVENTS:\n- 'error logs from last hour' → returns event list\n- 'database errors with timestamps' → returns event list\n- 'trace spans for slow API calls' → returns span list\n\nDataset Selection (AI automatically chooses):\n- errors: Exception/crash events\n- logs: Log entries\n- spans: Performance data, AI/LLM calls, token usage\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', naturalLanguageQuery='count of database failures this week')\nsearch_events(organizationSlug='my-org', naturalLanguageQuery='total tokens used by model')\nsearch_events(organizationSlug='my-org', naturalLanguageQuery='error logs from the last hour')\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</hints>",
"requiredScopes": ["event:read"]
},
{
"name": "search_issue_events",
"description": "Search and filter events within a specific issue using natural language queries.\n\nUse this to filter events by time, environment, release, user, trace ID, or other tags. The tool automatically constrains results to the specified issue.\n\nFor cross-issue searches use search_issues, for single event details use get_issue_details.\n\n<examples>\nsearch_issue_events(issueId='MCP-41', organizationSlug='my-org', naturalLanguageQuery='from last hour')\nsearch_issue_events(issueUrl='https://sentry.io/.../issues/123/', naturalLanguageQuery='production with release v1.0')\n</examples>",
"requiredScopes": ["event:read"]
},
{
"name": "search_issues",
"description": "Search for grouped issues/problems in Sentry - returns a LIST of issues, NOT counts or aggregations.\n\nUses AI to translate natural language queries into Sentry issue search syntax.\nReturns grouped issues with metadata like title, status, and user count.\n\nUSE THIS TOOL WHEN USERS WANT:\n- A LIST of issues: 'show me issues', 'what problems do we have'\n- Filtered issue lists: 'unresolved issues', 'critical bugs'\n- Issues by impact: 'errors affecting more than 100 users'\n- Issues by assignment: 'issues assigned to me'\n\nDO NOT USE FOR COUNTS/AGGREGATIONS:\n- 'how many errors' → use search_events\n- 'count of issues' → use search_events\n- 'total number of errors today' → use search_events\n- 'sum/average/statistics' → use search_events\n\nALSO DO NOT USE FOR:\n- Individual error events with timestamps → use search_events\n- Details about a specific issue ID → use get_issue_details\n\nREMEMBER: This tool returns a LIST of issues, not counts or statistics!\n\n<examples>\nsearch_issues(organizationSlug='my-org', naturalLanguageQuery='critical bugs from last week')\nsearch_issues(organizationSlug='my-org', naturalLanguageQuery='unhandled errors affecting 100+ users')\nsearch_issues(organizationSlug='my-org', naturalLanguageQuery='issues assigned to me')\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>",
Expand Down Expand Up @@ -145,7 +150,7 @@
"description": "Resolve, assign, and update issues",
"defaultEnabled": false,
"order": 4,
"toolCount": 8,
"toolCount": 9,
"tools": [
{
"name": "find_organizations",
Expand All @@ -172,6 +177,11 @@
"description": "Search for events AND perform counts/aggregations - the ONLY tool for statistics and counts.\n\nSupports TWO query types:\n1. AGGREGATIONS (counts, sums, averages): 'how many errors', 'count of issues', 'total tokens'\n2. Individual events with timestamps: 'show me error logs from last hour'\n\nUSE THIS FOR ALL COUNTS/STATISTICS:\n- 'how many errors today' → returns count\n- 'count of database failures' → returns count\n- 'total number of issues' → returns count\n- 'average response time' → returns avg()\n- 'sum of tokens used' → returns sum()\n\nALSO USE FOR INDIVIDUAL EVENTS:\n- 'error logs from last hour' → returns event list\n- 'database errors with timestamps' → returns event list\n- 'trace spans for slow API calls' → returns span list\n\nDataset Selection (AI automatically chooses):\n- errors: Exception/crash events\n- logs: Log entries\n- spans: Performance data, AI/LLM calls, token usage\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', naturalLanguageQuery='count of database failures this week')\nsearch_events(organizationSlug='my-org', naturalLanguageQuery='total tokens used by model')\nsearch_events(organizationSlug='my-org', naturalLanguageQuery='error logs from the last hour')\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</hints>",
"requiredScopes": ["event:read"]
},
{
"name": "search_issue_events",
"description": "Search and filter events within a specific issue using natural language queries.\n\nUse this to filter events by time, environment, release, user, trace ID, or other tags. The tool automatically constrains results to the specified issue.\n\nFor cross-issue searches use search_issues, for single event details use get_issue_details.\n\n<examples>\nsearch_issue_events(issueId='MCP-41', organizationSlug='my-org', naturalLanguageQuery='from last hour')\nsearch_issue_events(issueUrl='https://sentry.io/.../issues/123/', naturalLanguageQuery='production with release v1.0')\n</examples>",
"requiredScopes": ["event:read"]
},
{
"name": "search_issues",
"description": "Search for grouped issues/problems in Sentry - returns a LIST of issues, NOT counts or aggregations.\n\nUses AI to translate natural language queries into Sentry issue search syntax.\nReturns grouped issues with metadata like title, status, and user count.\n\nUSE THIS TOOL WHEN USERS WANT:\n- A LIST of issues: 'show me issues', 'what problems do we have'\n- Filtered issue lists: 'unresolved issues', 'critical bugs'\n- Issues by impact: 'errors affecting more than 100 users'\n- Issues by assignment: 'issues assigned to me'\n\nDO NOT USE FOR COUNTS/AGGREGATIONS:\n- 'how many errors' → use search_events\n- 'count of issues' → use search_events\n- 'total number of errors today' → use search_events\n- 'sum/average/statistics' → use search_events\n\nALSO DO NOT USE FOR:\n- Individual error events with timestamps → use search_events\n- Details about a specific issue ID → use get_issue_details\n\nREMEMBER: This tool returns a LIST of issues, not counts or statistics!\n\n<examples>\nsearch_issues(organizationSlug='my-org', naturalLanguageQuery='critical bugs from last week')\nsearch_issues(organizationSlug='my-org', naturalLanguageQuery='unhandled errors affecting 100+ users')\nsearch_issues(organizationSlug='my-org', naturalLanguageQuery='issues assigned to me')\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>",
Expand Down
78 changes: 78 additions & 0 deletions packages/mcp-core/src/toolDefinitions.json
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,84 @@
},
"requiredScopes": ["event:read"]
},
{
"name": "search_issue_events",
"description": "Search and filter events within a specific issue using natural language queries.\n\nUse this to filter events by time, environment, release, user, trace ID, or other tags. The tool automatically constrains results to the specified issue.\n\nFor cross-issue searches use search_issues, for single event details use get_issue_details.\n\n<examples>\nsearch_issue_events(issueId='MCP-41', organizationSlug='my-org', naturalLanguageQuery='from last hour')\nsearch_issue_events(issueUrl='https://sentry.io/.../issues/123/', naturalLanguageQuery='production with release v1.0')\n</examples>",
"inputSchema": {
"type": "object",
"properties": {
"organizationSlug": {
"anyOf": [
{
"type": "string",
"description": "The organization's slug. You can find a existing list of organizations you have access to using the `find_organizations()` tool."
},
{
"type": "null"
}
],
"description": "Organization slug. Required when using issueId. Not needed when using issueUrl.",
"default": null
},
"issueId": {
"type": "string",
"description": "Issue ID (e.g., 'MCP-41', 'PROJECT-123'). Requires organizationSlug. Alternatively, use issueUrl."
},
"issueUrl": {
"type": "string",
"format": "uri",
"description": "Full Sentry issue URL (e.g., 'https://sentry.io/organizations/my-org/issues/123/'). Includes both organization and issue ID."
},
"naturalLanguageQuery": {
"type": "string",
"minLength": 1,
"description": "Natural language description of what events you want to find within this issue. Examples: 'from last hour', 'production with release v1.0', 'affecting user alice@example.com', 'with trace ID abc123'"
},
"projectSlug": {
"anyOf": [
{
"type": "string",
"description": "The project's slug. You can find a list of existing projects in an organization using the `find_projects()` tool."
},
{
"type": "null"
}
],
"description": "Project slug for better tag discovery. Optional - helps find project-specific tags.",
"default": null
},
"regionUrl": {
"anyOf": [
{
"type": "string",
"description": "The region URL for the organization you're querying, if known. For Sentry's Cloud Service (sentry.io), this is typically the region-specific URL like 'https://us.sentry.io'. For self-hosted Sentry installations, this parameter is usually not needed and should be omitted. You can find the correct regionUrl from the organization details using the `find_organizations()` tool."
},
{
"type": "null"
}
],
"description": "Sentry region URL. Optional - defaults to main region.",
"default": null
},
"limit": {
"type": "number",
"minimum": 1,
"maximum": 100,
"default": 50,
"description": "Maximum number of events to return (1-100, default: 50)"
},
"includeExplanation": {
"type": "boolean",
"default": false,
"description": "Include explanation of how the natural language query was translated to Sentry syntax"
}
},
"required": ["naturalLanguageQuery"],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
},
"requiredScopes": ["event:read"]
},
{
"name": "search_issues",
"description": "Search for grouped issues/problems in Sentry - returns a LIST of issues, NOT counts or aggregations.\n\nUses AI to translate natural language queries into Sentry issue search syntax.\nReturns grouped issues with metadata like title, status, and user count.\n\nUSE THIS TOOL WHEN USERS WANT:\n- A LIST of issues: 'show me issues', 'what problems do we have'\n- Filtered issue lists: 'unresolved issues', 'critical bugs'\n- Issues by impact: 'errors affecting more than 100 users'\n- Issues by assignment: 'issues assigned to me'\n\nDO NOT USE FOR COUNTS/AGGREGATIONS:\n- 'how many errors' → use search_events\n- 'count of issues' → use search_events\n- 'total number of errors today' → use search_events\n- 'sum/average/statistics' → use search_events\n\nALSO DO NOT USE FOR:\n- Individual error events with timestamps → use search_events\n- Details about a specific issue ID → use get_issue_details\n\nREMEMBER: This tool returns a LIST of issues, not counts or statistics!\n\n<examples>\nsearch_issues(organizationSlug='my-org', naturalLanguageQuery='critical bugs from last week')\nsearch_issues(organizationSlug='my-org', naturalLanguageQuery='unhandled errors affecting 100+ users')\nsearch_issues(organizationSlug='my-org', naturalLanguageQuery='issues assigned to me')\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>",
Expand Down
4 changes: 4 additions & 0 deletions packages/mcp-core/src/tools/get-issue-details.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ describe("get_issue_details", () => {

- You can reference the IssueID in commit messages (e.g. \`Fixes CLOUDFLARE-MCP-41\`) to automatically close the issue when the commit is merged.
- The stacktrace includes both first-party application code as well as third-party code, its important to triage to first-party code.
- To search for specific occurrences or filter events within this issue, use \`search_issue_events(organizationSlug='sentry-mcp-evals', issueId='CLOUDFLARE-MCP-41', naturalLanguageQuery='your query')\`
"
`);
});
Expand Down Expand Up @@ -406,6 +407,7 @@ describe("get_issue_details", () => {

- You can reference the IssueID in commit messages (e.g. \`Fixes CLOUDFLARE-MCP-41\`) to automatically close the issue when the commit is merged.
- The stacktrace includes both first-party application code as well as third-party code, its important to triage to first-party code.
- To search for specific occurrences or filter events within this issue, use \`search_issue_events(organizationSlug='sentry-mcp-evals', issueId='CLOUDFLARE-MCP-41', naturalLanguageQuery='your query')\`
"
`);
});
Expand Down Expand Up @@ -682,6 +684,7 @@ describe("get_issue_details", () => {

- You can reference the IssueID in commit messages (e.g. \`Fixes CLOUDFLARE-MCP-41\`) to automatically close the issue when the commit is merged.
- The stacktrace includes both first-party application code as well as third-party code, its important to triage to first-party code.
- To search for specific occurrences or filter events within this issue, use \`search_issue_events(organizationSlug='sentry-mcp-evals', issueId='CLOUDFLARE-MCP-41', naturalLanguageQuery='your query')\`
"
`);
});
Expand Down Expand Up @@ -1257,6 +1260,7 @@ describe("get_issue_details", () => {

- You can reference the IssueID in commit messages (e.g. \`Fixes MCP-SERVER-EQE\`) to automatically close the issue when the commit is merged.
- The stacktrace includes both first-party application code as well as third-party code, its important to triage to first-party code.
- To search for specific occurrences or filter events within this issue, use \`search_issue_events(organizationSlug='sentry-mcp-evals', issueId='MCP-SERVER-EQE', naturalLanguageQuery='your query')\`
"
`);
});
Expand Down
Loading
Loading