diff --git a/packages/mcp-core/src/api-client/client.ts b/packages/mcp-core/src/api-client/client.ts index c067f5afc..6c503c45b 100644 --- a/packages/mcp-core/src/api-client/client.ts +++ b/packages/mcp-core/src/api-client/client.ts @@ -3259,7 +3259,7 @@ export class SentryApiService { opts?: RequestOptions, ): Promise { const body = await this.requestJSON( - `/organizations/${organizationSlug}/issues/${issueId}/events/${eventId}/`, + `/organizations/${encodeURIComponent(organizationSlug)}/issues/${encodeURIComponent(issueId)}/events/${encodeURIComponent(eventId)}/`, undefined, opts, ); diff --git a/packages/mcp-core/src/internal/tool-helpers/breadcrumbs.ts b/packages/mcp-core/src/internal/tool-helpers/breadcrumbs.ts index 42aa71fd1..0bb7f8bdf 100644 --- a/packages/mcp-core/src/internal/tool-helpers/breadcrumbs.ts +++ b/packages/mcp-core/src/internal/tool-helpers/breadcrumbs.ts @@ -1,16 +1,19 @@ import type { SentryApiService } from "../../api-client/index"; /** - * Fetches breadcrumbs from the latest event for an issue and formats them. + * Fetches breadcrumbs from an issue event and formats them. + * Defaults to the latest event when eventId is omitted. */ export async function fetchAndFormatBreadcrumbs( apiService: SentryApiService, organizationSlug: string, issueId: string, + eventId: string = "latest", ): Promise { - const event = await apiService.getLatestEventForIssue({ + const event = await apiService.getEventForIssue({ organizationSlug, issueId, + eventId, }); const breadcrumbEntry = event.entries.find((e) => e.type === "breadcrumbs"); @@ -40,7 +43,7 @@ export function formatBreadcrumbs( "", `**Event ID**: ${eventId}`, "", - "No breadcrumbs found in the latest event for this issue.", + "No breadcrumbs found in this event for the issue.", ].join("\n"); } diff --git a/packages/mcp-core/src/schema.ts b/packages/mcp-core/src/schema.ts index d14305b7f..f856f9483 100644 --- a/packages/mcp-core/src/schema.ts +++ b/packages/mcp-core/src/schema.ts @@ -237,7 +237,23 @@ export const ParamSentryGuide = z "Use either a platform (e.g., 'javascript', 'python') or platform/guide combination (e.g., 'javascript/nextjs', 'python/django').", ); -export const ParamEventId = z.string().trim().describe("The ID of the event."); +export const ParamEventId = z + .string() + .trim() + .regex( + /^[0-9a-fA-F]{32}$/, + "Event ID must be a 32-character hexadecimal string", + ) + .describe("The ID of the event. e.g. `c49541c747cb4d8aa3efb70ca5aba243`"); + +/** + * Issue-scoped event selector used by tools that can target either a concrete + * event or the issue's latest event. + */ +export const ParamEventIdOrLatest = z + .union([z.literal("latest"), ParamEventId]) + .default("latest") + .describe("The event ID for the issue, or `latest`. Defaults to `latest`."); export const ParamAttachmentId = z .string() diff --git a/packages/mcp-core/src/skillDefinitions.json b/packages/mcp-core/src/skillDefinitions.json index 1c5cc4f7f..8f4eed553 100644 --- a/packages/mcp-core/src/skillDefinitions.json +++ b/packages/mcp-core/src/skillDefinitions.json @@ -69,7 +69,7 @@ }, { "name": "get_event_stacktrace", - "description": "Get a full thread stacktrace from a specific Sentry event.\n\nUse this tool when you need to:\n- Fetch the full stacktrace for a thread listed in issue details\n- Inspect a non-crashed thread from an event with multiple threads\n- Get Sentry's default selected thread stacktrace when no thread is specified\n\n\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123')\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', eventId='abc123', thread=259)\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', thread='main')\n\n\n\n- `thread` is optional. If omitted, this returns the same default thread Sentry selects: first crashed thread, then first thread with a stacktrace, then first thread.\n- Pass `thread` as a numeric Thread ID or exact thread Name from the issue details thread list.\n- If the issue details show only one useful thread, omit `thread`.\n", + "description": "Get a full thread stacktrace from a specific Sentry event.\n\nUse this tool when you need to:\n- Fetch the full stacktrace for a thread listed in issue details\n- Inspect a non-crashed thread from an event with multiple threads\n- Get Sentry's default selected thread stacktrace when no thread is specified\n\n\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123')\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', eventId='c49541c747cb4d8aa3efb70ca5aba243', thread=259)\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', thread='main')\n\n\n\n- `thread` is optional. If omitted, this returns the same default thread Sentry selects: first crashed thread, then first thread with a stacktrace, then first thread.\n- Pass `thread` as a numeric Thread ID or exact thread Name from the issue details thread list.\n- If the issue details show only one useful thread, omit `thread`.\n", "requiredScopes": ["event:read"] }, { @@ -79,7 +79,7 @@ }, { "name": "get_issue_breadcrumbs", - "description": "Get the breadcrumb trail from the latest event for a Sentry issue.\n\nUse this tool when you need to:\n- See the user and application actions leading up to an error\n- Inspect navigation, console, HTTP, and other breadcrumb events\n- Reconstruct the immediate context before an issue occurred\n\n\nget_issue_breadcrumbs(organizationSlug='my-org', issueId='PROJECT-123')\nget_issue_breadcrumbs(issueUrl='https://my-org.sentry.io/issues/PROJECT-123/')\n", + "description": "Get the breadcrumb trail from a Sentry issue event.\nDefaults to the latest event when eventId is omitted.\n\nUse this tool when you need to:\n- See the user and application actions leading up to an error\n- Inspect navigation, console, HTTP, and other breadcrumb events\n- Reconstruct the immediate context before an issue occurred\n- Compare breadcrumb trails across multiple events in the same issue\n\n\nget_issue_breadcrumbs(organizationSlug='my-org', issueId='PROJECT-123')\nget_issue_breadcrumbs(organizationSlug='my-org', issueId='PROJECT-123', eventId='c49541c747cb4d8aa3efb70ca5aba243')\nget_issue_breadcrumbs(issueUrl='https://my-org.sentry.io/issues/PROJECT-123/')\n", "requiredScopes": ["event:read"] }, { @@ -214,7 +214,7 @@ }, { "name": "get_event_stacktrace", - "description": "Get a full thread stacktrace from a specific Sentry event.\n\nUse this tool when you need to:\n- Fetch the full stacktrace for a thread listed in issue details\n- Inspect a non-crashed thread from an event with multiple threads\n- Get Sentry's default selected thread stacktrace when no thread is specified\n\n\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123')\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', eventId='abc123', thread=259)\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', thread='main')\n\n\n\n- `thread` is optional. If omitted, this returns the same default thread Sentry selects: first crashed thread, then first thread with a stacktrace, then first thread.\n- Pass `thread` as a numeric Thread ID or exact thread Name from the issue details thread list.\n- If the issue details show only one useful thread, omit `thread`.\n", + "description": "Get a full thread stacktrace from a specific Sentry event.\n\nUse this tool when you need to:\n- Fetch the full stacktrace for a thread listed in issue details\n- Inspect a non-crashed thread from an event with multiple threads\n- Get Sentry's default selected thread stacktrace when no thread is specified\n\n\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123')\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', eventId='c49541c747cb4d8aa3efb70ca5aba243', thread=259)\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', thread='main')\n\n\n\n- `thread` is optional. If omitted, this returns the same default thread Sentry selects: first crashed thread, then first thread with a stacktrace, then first thread.\n- Pass `thread` as a numeric Thread ID or exact thread Name from the issue details thread list.\n- If the issue details show only one useful thread, omit `thread`.\n", "requiredScopes": ["event:read"] }, { @@ -320,7 +320,7 @@ }, { "name": "get_event_stacktrace", - "description": "Get a full thread stacktrace from a specific Sentry event.\n\nUse this tool when you need to:\n- Fetch the full stacktrace for a thread listed in issue details\n- Inspect a non-crashed thread from an event with multiple threads\n- Get Sentry's default selected thread stacktrace when no thread is specified\n\n\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123')\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', eventId='abc123', thread=259)\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', thread='main')\n\n\n\n- `thread` is optional. If omitted, this returns the same default thread Sentry selects: first crashed thread, then first thread with a stacktrace, then first thread.\n- Pass `thread` as a numeric Thread ID or exact thread Name from the issue details thread list.\n- If the issue details show only one useful thread, omit `thread`.\n", + "description": "Get a full thread stacktrace from a specific Sentry event.\n\nUse this tool when you need to:\n- Fetch the full stacktrace for a thread listed in issue details\n- Inspect a non-crashed thread from an event with multiple threads\n- Get Sentry's default selected thread stacktrace when no thread is specified\n\n\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123')\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', eventId='c49541c747cb4d8aa3efb70ca5aba243', thread=259)\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', thread='main')\n\n\n\n- `thread` is optional. If omitted, this returns the same default thread Sentry selects: first crashed thread, then first thread with a stacktrace, then first thread.\n- Pass `thread` as a numeric Thread ID or exact thread Name from the issue details thread list.\n- If the issue details show only one useful thread, omit `thread`.\n", "requiredScopes": ["event:read"] }, { @@ -330,7 +330,7 @@ }, { "name": "get_issue_breadcrumbs", - "description": "Get the breadcrumb trail from the latest event for a Sentry issue.\n\nUse this tool when you need to:\n- See the user and application actions leading up to an error\n- Inspect navigation, console, HTTP, and other breadcrumb events\n- Reconstruct the immediate context before an issue occurred\n\n\nget_issue_breadcrumbs(organizationSlug='my-org', issueId='PROJECT-123')\nget_issue_breadcrumbs(issueUrl='https://my-org.sentry.io/issues/PROJECT-123/')\n", + "description": "Get the breadcrumb trail from a Sentry issue event.\nDefaults to the latest event when eventId is omitted.\n\nUse this tool when you need to:\n- See the user and application actions leading up to an error\n- Inspect navigation, console, HTTP, and other breadcrumb events\n- Reconstruct the immediate context before an issue occurred\n- Compare breadcrumb trails across multiple events in the same issue\n\n\nget_issue_breadcrumbs(organizationSlug='my-org', issueId='PROJECT-123')\nget_issue_breadcrumbs(organizationSlug='my-org', issueId='PROJECT-123', eventId='c49541c747cb4d8aa3efb70ca5aba243')\nget_issue_breadcrumbs(issueUrl='https://my-org.sentry.io/issues/PROJECT-123/')\n", "requiredScopes": ["event:read"] }, { diff --git a/packages/mcp-core/src/toolDefinitions.json b/packages/mcp-core/src/toolDefinitions.json index 039a0ea42..2770a2d38 100644 --- a/packages/mcp-core/src/toolDefinitions.json +++ b/packages/mcp-core/src/toolDefinitions.json @@ -2321,7 +2321,8 @@ }, "eventId": { "type": "string", - "description": "The ID of the event." + "pattern": "^[0-9a-fA-F]{32}$", + "description": "The ID of the event. e.g. `c49541c747cb4d8aa3efb70ca5aba243`" }, "attachmentId": { "default": null, @@ -2356,7 +2357,7 @@ }, { "name": "get_event_stacktrace", - "description": "Get a full thread stacktrace from a specific Sentry event.\n\nUse this tool when you need to:\n- Fetch the full stacktrace for a thread listed in issue details\n- Inspect a non-crashed thread from an event with multiple threads\n- Get Sentry's default selected thread stacktrace when no thread is specified\n\n\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123')\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', eventId='abc123', thread=259)\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', thread='main')\n\n\n\n- `thread` is optional. If omitted, this returns the same default thread Sentry selects: first crashed thread, then first thread with a stacktrace, then first thread.\n- Pass `thread` as a numeric Thread ID or exact thread Name from the issue details thread list.\n- If the issue details show only one useful thread, omit `thread`.\n", + "description": "Get a full thread stacktrace from a specific Sentry event.\n\nUse this tool when you need to:\n- Fetch the full stacktrace for a thread listed in issue details\n- Inspect a non-crashed thread from an event with multiple threads\n- Get Sentry's default selected thread stacktrace when no thread is specified\n\n\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123')\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', eventId='c49541c747cb4d8aa3efb70ca5aba243', thread=259)\nget_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', thread='main')\n\n\n\n- `thread` is optional. If omitted, this returns the same default thread Sentry selects: first crashed thread, then first thread with a stacktrace, then first thread.\n- Pass `thread` as a numeric Thread ID or exact thread Name from the issue details thread list.\n- If the issue details show only one useful thread, omit `thread`.\n", "inputSchema": { "type": "object", "properties": { @@ -2382,8 +2383,18 @@ }, "eventId": { "default": "latest", - "description": "The event ID for the issue. Defaults to `latest`.", - "type": "string" + "description": "The event ID for the issue, or `latest`. Defaults to `latest`.", + "anyOf": [ + { + "type": "string", + "const": "latest" + }, + { + "type": "string", + "pattern": "^[0-9a-fA-F]{32}$", + "description": "The ID of the event. e.g. `c49541c747cb4d8aa3efb70ca5aba243`" + } + ] }, "thread": { "description": "Optional thread selector. Pass a numeric thread ID, or an exact thread name string. If omitted, returns the same default thread Sentry selects: first crashed thread, then first thread with a stacktrace, then first thread.", @@ -2455,7 +2466,7 @@ }, { "name": "get_issue_breadcrumbs", - "description": "Get the breadcrumb trail from the latest event for a Sentry issue.\n\nUse this tool when you need to:\n- See the user and application actions leading up to an error\n- Inspect navigation, console, HTTP, and other breadcrumb events\n- Reconstruct the immediate context before an issue occurred\n\n\nget_issue_breadcrumbs(organizationSlug='my-org', issueId='PROJECT-123')\nget_issue_breadcrumbs(issueUrl='https://my-org.sentry.io/issues/PROJECT-123/')\n", + "description": "Get the breadcrumb trail from a Sentry issue event.\nDefaults to the latest event when eventId is omitted.\n\nUse this tool when you need to:\n- See the user and application actions leading up to an error\n- Inspect navigation, console, HTTP, and other breadcrumb events\n- Reconstruct the immediate context before an issue occurred\n- Compare breadcrumb trails across multiple events in the same issue\n\n\nget_issue_breadcrumbs(organizationSlug='my-org', issueId='PROJECT-123')\nget_issue_breadcrumbs(organizationSlug='my-org', issueId='PROJECT-123', eventId='c49541c747cb4d8aa3efb70ca5aba243')\nget_issue_breadcrumbs(issueUrl='https://my-org.sentry.io/issues/PROJECT-123/')\n", "inputSchema": { "type": "object", "properties": { @@ -2483,6 +2494,21 @@ "type": "string", "format": "uri", "description": "The URL of the issue. e.g. https://my-organization.sentry.io/issues/PROJECT-1Z43" + }, + "eventId": { + "default": "latest", + "description": "The event ID for the issue, or `latest`. Defaults to `latest`.", + "anyOf": [ + { + "type": "string", + "const": "latest" + }, + { + "type": "string", + "pattern": "^[0-9a-fA-F]{32}$", + "description": "The ID of the event. e.g. `c49541c747cb4d8aa3efb70ca5aba243`" + } + ] } } }, @@ -2518,7 +2544,8 @@ }, "eventId": { "type": "string", - "description": "The ID of the event." + "pattern": "^[0-9a-fA-F]{32}$", + "description": "The ID of the event. e.g. `c49541c747cb4d8aa3efb70ca5aba243`" }, "issueUrl": { "type": "string", diff --git a/packages/mcp-core/src/tools/catalog/get-event-attachment.test.ts b/packages/mcp-core/src/tools/catalog/get-event-attachment.test.ts index 18485a467..b1b9b9ebe 100644 --- a/packages/mcp-core/src/tools/catalog/get-event-attachment.test.ts +++ b/packages/mcp-core/src/tools/catalog/get-event-attachment.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect } from "vitest"; +import { describe, expect, it } from "vitest"; import getEventAttachment from "./get-event-attachment.js"; describe("get_event_attachment", () => { @@ -110,7 +110,7 @@ describe("get_event_attachment", () => { { organizationSlug: "sentry-mcp-evals", projectSlug: "cloudflare-mcp", - eventId: "octet-stream-event-id", + eventId: "d49541c747cb4d8aa3efb70ca5aba244", attachmentId: "456", regionUrl: null, }, diff --git a/packages/mcp-core/src/tools/catalog/get-event-stacktrace.ts b/packages/mcp-core/src/tools/catalog/get-event-stacktrace.ts index 897414755..6e8f4e53e 100644 --- a/packages/mcp-core/src/tools/catalog/get-event-stacktrace.ts +++ b/packages/mcp-core/src/tools/catalog/get-event-stacktrace.ts @@ -6,6 +6,7 @@ import { defineTool } from "../../internal/tool-helpers/define"; import { enhanceNotFoundError } from "../../internal/tool-helpers/enhance-error"; import { ensureIssueWithinProjectConstraint } from "../../internal/tool-helpers/issue"; import { + ParamEventIdOrLatest, ParamIssueShortId, ParamOrganizationSlug, ParamRegionUrl, @@ -27,7 +28,7 @@ export default defineTool({ "", "", "get_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123')", - "get_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', eventId='abc123', thread=259)", + "get_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', eventId='c49541c747cb4d8aa3efb70ca5aba243', thread=259)", "get_event_stacktrace(organizationSlug='my-org', issueId='PROJECT-123', thread='main')", "", "", @@ -41,11 +42,7 @@ export default defineTool({ organizationSlug: ParamOrganizationSlug, regionUrl: ParamRegionUrl.nullable().default(null), issueId: ParamIssueShortId, - eventId: z - .string() - .trim() - .default("latest") - .describe("The event ID for the issue. Defaults to `latest`."), + eventId: ParamEventIdOrLatest, thread: z .union([z.number().int(), z.string().trim().min(1)]) .optional() diff --git a/packages/mcp-core/src/tools/catalog/get-issue-breadcrumbs.test.ts b/packages/mcp-core/src/tools/catalog/get-issue-breadcrumbs.test.ts index d1a3170bb..61f78842e 100644 --- a/packages/mcp-core/src/tools/catalog/get-issue-breadcrumbs.test.ts +++ b/packages/mcp-core/src/tools/catalog/get-issue-breadcrumbs.test.ts @@ -1,5 +1,5 @@ import { eventFixture, mswServer } from "@sentry/mcp-server-mocks"; -import { http, HttpResponse } from "msw"; +import { HttpResponse, http } from "msw"; import { afterEach, describe, expect, it } from "vitest"; import getIssueBreadcrumbs from "./get-issue-breadcrumbs.js"; @@ -20,6 +20,7 @@ describe("get_issue_breadcrumbs", () => { organizationSlug: "sentry-mcp-evals", regionUrl: null, issueId: "CLOUDFLARE-MCP-41", + eventId: "latest", }, context, ); @@ -48,6 +49,7 @@ describe("get_issue_breadcrumbs", () => { issueUrl: "https://sentry-mcp-evals.sentry.io/issues/CLOUDFLARE-MCP-41/", regionUrl: null, + eventId: "latest", }, context, ); @@ -62,6 +64,7 @@ describe("get_issue_breadcrumbs", () => { organizationSlug: "sentry-mcp-evals", issueId: "CLOUDFLARE-MCP-41", regionUrl: null, + eventId: "latest", }, { ...context, @@ -96,12 +99,40 @@ describe("get_issue_breadcrumbs", () => { organizationSlug: "sentry-mcp-evals", regionUrl: null, issueId: "CLOUDFLARE-MCP-41", + eventId: "latest", }, context, ); expect(result).toContain( - "No breadcrumbs found in the latest event for this issue.", + "No breadcrumbs found in this event for the issue.", ); }); + + it("returns breadcrumbs for an explicit event ID", async () => { + mswServer.use( + http.get( + "https://sentry.io/api/0/organizations/sentry-mcp-evals/issues/CLOUDFLARE-MCP-41/events/c49541c747cb4d8aa3efb70ca5aba243/", + () => + HttpResponse.json({ + ...eventFixture, + id: "c49541c747cb4d8aa3efb70ca5aba243", + }), + { once: true }, + ), + ); + + const result = await getIssueBreadcrumbs.handler( + { + organizationSlug: "sentry-mcp-evals", + regionUrl: null, + issueId: "CLOUDFLARE-MCP-41", + eventId: "c49541c747cb4d8aa3efb70ca5aba243", + }, + context, + ); + + expect(result).toContain("# Breadcrumbs for CLOUDFLARE-MCP-41"); + expect(result).toContain("**Event ID**: c49541c747cb4d8aa3efb70ca5aba243"); + }); }); diff --git a/packages/mcp-core/src/tools/catalog/get-issue-breadcrumbs.ts b/packages/mcp-core/src/tools/catalog/get-issue-breadcrumbs.ts index 8984b7379..7bc49cbee 100644 --- a/packages/mcp-core/src/tools/catalog/get-issue-breadcrumbs.ts +++ b/packages/mcp-core/src/tools/catalog/get-issue-breadcrumbs.ts @@ -9,6 +9,7 @@ import { parseIssueParams, } from "../../internal/tool-helpers/issue"; import { + ParamEventIdOrLatest, ParamIssueShortId, ParamIssueUrl, ParamOrganizationSlug, @@ -21,15 +22,18 @@ export default defineTool({ skills: ["inspect", "triage"], requiredScopes: ["event:read"], description: [ - "Get the breadcrumb trail from the latest event for a Sentry issue.", + "Get the breadcrumb trail from a Sentry issue event.", + "Defaults to the latest event when eventId is omitted.", "", "Use this tool when you need to:", "- See the user and application actions leading up to an error", "- Inspect navigation, console, HTTP, and other breadcrumb events", "- Reconstruct the immediate context before an issue occurred", + "- Compare breadcrumb trails across multiple events in the same issue", "", "", "get_issue_breadcrumbs(organizationSlug='my-org', issueId='PROJECT-123')", + "get_issue_breadcrumbs(organizationSlug='my-org', issueId='PROJECT-123', eventId='c49541c747cb4d8aa3efb70ca5aba243')", "get_issue_breadcrumbs(issueUrl='https://my-org.sentry.io/issues/PROJECT-123/')", "", ].join("\n"), @@ -38,6 +42,7 @@ export default defineTool({ regionUrl: ParamRegionUrl.nullable().default(null), issueId: ParamIssueShortId.optional(), issueUrl: ParamIssueUrl.optional(), + eventId: ParamEventIdOrLatest, }, annotations: { readOnlyHint: true, @@ -69,12 +74,14 @@ export default defineTool({ apiService, parsed.organizationSlug, parsed.issueId, + params.eventId, ); } catch (error) { if (error instanceof ApiNotFoundError) { throw enhanceNotFoundError(error, { organizationSlug: parsed.organizationSlug, issueId: parsed.issueId, + eventId: params.eventId, }); } throw error; diff --git a/packages/mcp-core/src/tools/catalog/get-issue-details.ts b/packages/mcp-core/src/tools/catalog/get-issue-details.ts index 1060db499..d2f069de4 100644 --- a/packages/mcp-core/src/tools/catalog/get-issue-details.ts +++ b/packages/mcp-core/src/tools/catalog/get-issue-details.ts @@ -1,7 +1,6 @@ import { setTag } from "@sentry/core"; -import { z } from "zod"; -import { ApiNotFoundError } from "../../api-client"; import type { SentryApiService } from "../../api-client"; +import { ApiNotFoundError } from "../../api-client"; import type { AutofixRunState, DefaultEvent, @@ -27,6 +26,7 @@ import { parseIssueParams, } from "../../internal/tool-helpers/issue"; import { + ParamEventId, ParamIssueShortId, ParamIssueUrl, ParamOrganizationSlug, @@ -88,7 +88,7 @@ export default defineTool({ organizationSlug: ParamOrganizationSlug.optional(), regionUrl: ParamRegionUrl.nullable().default(null), issueId: ParamIssueShortId.optional(), - eventId: z.string().trim().describe("The ID of the event.").optional(), + eventId: ParamEventId.optional(), issueUrl: ParamIssueUrl.optional(), }, annotations: { diff --git a/packages/mcp-server-mocks/src/index.ts b/packages/mcp-server-mocks/src/index.ts index 64a5c5aed..1794b834c 100644 --- a/packages/mcp-server-mocks/src/index.ts +++ b/packages/mcp-server-mocks/src/index.ts @@ -1507,7 +1507,7 @@ export const restHandlers = buildHandlers([ // Step 1 (metadata), so the attachment is rendered as an image not a blob. { method: "get", - path: "/api/0/projects/sentry-mcp-evals/cloudflare-mcp/events/octet-stream-event-id/attachments/", + path: "/api/0/projects/sentry-mcp-evals/cloudflare-mcp/events/d49541c747cb4d8aa3efb70ca5aba244/attachments/", fetch: () => HttpResponse.json([ { @@ -1524,7 +1524,7 @@ export const restHandlers = buildHandlers([ }, { method: "get", - path: "/api/0/projects/sentry-mcp-evals/cloudflare-mcp/events/octet-stream-event-id/attachments/456/", + path: "/api/0/projects/sentry-mcp-evals/cloudflare-mcp/events/d49541c747cb4d8aa3efb70ca5aba244/attachments/456/", fetch: () => { const mockBlob = new Blob(["fake image data"], { type: "image/png" }); return new HttpResponse(mockBlob, {