diff --git a/packages/mcp-core/src/internal/url-helpers.test.ts b/packages/mcp-core/src/internal/url-helpers.test.ts index 5d2ac3057..01dca5c0f 100644 --- a/packages/mcp-core/src/internal/url-helpers.test.ts +++ b/packages/mcp-core/src/internal/url-helpers.test.ts @@ -543,6 +543,54 @@ describe("parseSentryUrl", () => { }); }); + describe("dashboard URLs", () => { + it("parses dashboard URL with numeric ID (subdomain)", () => { + expect( + parseSentryUrl("https://my-org.sentry.io/dashboard/542438/"), + ).toMatchInlineSnapshot(` + { + "dashboardId": "542438", + "organizationSlug": "my-org", + "type": "dashboard", + } + `); + }); + + it("parses dashboard URL with organizations path", () => { + expect( + parseSentryUrl("https://sentry.io/organizations/my-org/dashboard/101/"), + ).toMatchInlineSnapshot(` + { + "dashboardId": "101", + "organizationSlug": "my-org", + "type": "dashboard", + } + `); + }); + + it("parses dashboard URL with path-based org", () => { + expect( + parseSentryUrl("https://sentry.io/my-org/dashboard/101/"), + ).toMatchInlineSnapshot(` + { + "dashboardId": "101", + "organizationSlug": "my-org", + "type": "dashboard", + } + `); + }); + + it("returns unknown for /dashboard/new/ (non-numeric ID)", () => { + const result = parseSentryUrl("https://my-org.sentry.io/dashboard/new/"); + expect(result.type).toBe("unknown"); + }); + + it("returns unknown for /dashboards/ list URL (plural, no ID)", () => { + const result = parseSentryUrl("https://my-org.sentry.io/dashboards/"); + expect(result.type).toBe("unknown"); + }); + }); + describe("performance summary URLs", () => { it("extracts transaction from performance summary URL", () => { expect( diff --git a/packages/mcp-core/src/internal/url-helpers.ts b/packages/mcp-core/src/internal/url-helpers.ts index 1546b3d5d..164f20c1e 100644 --- a/packages/mcp-core/src/internal/url-helpers.ts +++ b/packages/mcp-core/src/internal/url-helpers.ts @@ -2,7 +2,7 @@ * Unified URL parsing utilities for Sentry resources. * * Parses Sentry URLs to identify resource types and extract relevant identifiers. - * Supports issue, trace, profile, event, replay, and monitor URLs across different + * Supports issue, trace, profile, event, replay, monitor, and dashboard URLs across different * Sentry URL formats (subdomain, path-based organization, self-hosted). */ @@ -21,6 +21,7 @@ export type SentryResourceType = | "monitor" | "release" | "snapshot" + | "dashboard" | "unknown"; /** @@ -64,6 +65,8 @@ export interface ParsedSentryUrl { snapshotId?: string; /** Selected snapshot image name (from ?selectedSnapshot= query param) */ selectedSnapshot?: string; + /** Dashboard numeric ID (for dashboard URLs) */ + dashboardId?: string; } /** @@ -79,6 +82,7 @@ export interface ParsedSentryUrl { * - Replay: `/explore/replays/{replayId}/` or `/replays/{replayId}/` * - Monitor: `/crons/{monitorSlug}/` or `/monitors/{monitorSlug}/` * - Release: `/releases/{version}/` + * - Dashboard: `/dashboard/{dashboardId}/` * * Organization slug is extracted from: * 1. Subdomain (e.g., `my-org.sentry.io`) @@ -164,6 +168,7 @@ function extractOrganizationSlug(parsedUrl: URL, pathParts: string[]): string { "monitors", "alerts", "feedback", + "dashboard", "dashboards", "discover", "insights", @@ -398,6 +403,20 @@ function identifyResource( } } + // Dashboard URL: /dashboard/{dashboardId}/ + // Dashboard IDs are always numeric integers. + const dashboardIndex = pathParts.indexOf("dashboard"); + if (dashboardIndex !== -1) { + const dashboardId = pathParts[dashboardIndex + 1]; + if (dashboardId && /^\d+$/.test(dashboardId)) { + return { + type: "dashboard", + organizationSlug, + dashboardId, + }; + } + } + // Snapshot URL: /preprod/snapshots/{snapshotId}/ const preprodIndex = pathParts.indexOf("preprod"); if (preprodIndex !== -1 && pathParts[preprodIndex + 1] === "snapshots") { diff --git a/packages/mcp-core/src/skillDefinitions.json b/packages/mcp-core/src/skillDefinitions.json index 4addc7972..d20356c7b 100644 --- a/packages/mcp-core/src/skillDefinitions.json +++ b/packages/mcp-core/src/skillDefinitions.json @@ -124,7 +124,7 @@ }, { "name": "get_sentry_resource", - "description": "Fetch a Sentry resource by URL, or by resourceType plus resourceId.\nPass a Sentry URL directly when possible; the resource type is auto-detected.\n\nSupports issues, events, traces, spans, AI conversations, breadcrumbs, replays, monitors, preprod snapshots, and snapshot images.\nTrace lookups return a condensed overview by default.\n\nAI Conversations: A conversation is a set of spans sharing the same gen_ai.conversation.id. Use resourceType='ai_conversation' with a conversation ID, or pass a Sentry conversation URL, to fetch the transcript/details. To discover or list conversations, use search_ai_conversations. Conversations are NOT issues — do not use search_issues for conversation queries.\n\nFor preprod snapshot URLs (matching 'sentry.io/preprod/snapshots/'):\n- Without ?selectedSnapshot=: returns the snapshot diff summary (changed, added, removed images)\n- With ?selectedSnapshot=: returns the image preview and metadata. Use the Sentry tool `get_snapshot_image` for full-resolution image bytes.\n\nResource IDs:\n- span: :\n- monitor: \n- snapshot: \n- snapshotImage: :\n\n\nget_sentry_resource(url='https://sentry.io/issues/PROJECT-123/')\nget_sentry_resource(resourceType='issue', organizationSlug='my-org', resourceId='PROJECT-123')\nget_sentry_resource(resourceType='span', organizationSlug='my-org', resourceId=':')\nget_sentry_resource(resourceType='ai_conversation', organizationSlug='my-org', resourceId='conversation-123')\nget_sentry_resource(url='https://sentry.sentry.io/preprod/snapshots/123/')\nget_sentry_resource(url='https://sentry.sentry.io/preprod/snapshots/123/?selectedSnapshot=login_screen.png')\n", + "description": "Fetch a Sentry resource by URL, or by resourceType plus resourceId.\nPass a Sentry URL directly when possible; the resource type is auto-detected.\n\nSupports issues, events, traces, spans, AI conversations, breadcrumbs, replays, monitors, dashboards, preprod snapshots, and snapshot images.\nTrace lookups return a condensed overview by default.\n\nAI Conversations: A conversation is a set of spans sharing the same gen_ai.conversation.id. Use resourceType='ai_conversation' with a conversation ID, or pass a Sentry conversation URL, to fetch the transcript/details. To discover or list conversations, use search_ai_conversations. Conversations are NOT issues — do not use search_issues for conversation queries.\n\nFor preprod snapshot URLs (matching 'sentry.io/preprod/snapshots/'):\n- Without ?selectedSnapshot=: returns the snapshot diff summary (changed, added, removed images)\n- With ?selectedSnapshot=: returns the image preview and metadata. Use the Sentry tool `get_snapshot_image` for full-resolution image bytes.\n\nResource IDs:\n- span: :\n- monitor: \n- dashboard: \n- snapshot: \n- snapshotImage: :\n\n\nget_sentry_resource(url='https://sentry.io/issues/PROJECT-123/')\nget_sentry_resource(resourceType='issue', organizationSlug='my-org', resourceId='PROJECT-123')\nget_sentry_resource(resourceType='span', organizationSlug='my-org', resourceId=':')\nget_sentry_resource(resourceType='ai_conversation', organizationSlug='my-org', resourceId='conversation-123')\nget_sentry_resource(url='https://sentry.sentry.io/dashboard/542438/')\nget_sentry_resource(url='https://sentry.sentry.io/preprod/snapshots/123/')\nget_sentry_resource(url='https://sentry.sentry.io/preprod/snapshots/123/?selectedSnapshot=login_screen.png')\n", "requiredScopes": ["event:read", "project:read"] }, { diff --git a/packages/mcp-core/src/toolDefinitions.json b/packages/mcp-core/src/toolDefinitions.json index 94c2b045a..298c469c4 100644 --- a/packages/mcp-core/src/toolDefinitions.json +++ b/packages/mcp-core/src/toolDefinitions.json @@ -2015,7 +2015,7 @@ }, { "name": "get_sentry_resource", - "description": "Fetch a Sentry resource by URL, or by resourceType plus resourceId.\nPass a Sentry URL directly when possible; the resource type is auto-detected.\n\nSupports issues, events, traces, spans, AI conversations, breadcrumbs, replays, monitors, preprod snapshots, and snapshot images.\nTrace lookups return a condensed overview by default.\n\nAI Conversations: A conversation is a set of spans sharing the same gen_ai.conversation.id. Use resourceType='ai_conversation' with a conversation ID, or pass a Sentry conversation URL, to fetch the transcript/details. To discover or list conversations, use search_ai_conversations. Conversations are NOT issues — do not use search_issues for conversation queries.\n\nFor preprod snapshot URLs (matching 'sentry.io/preprod/snapshots/'):\n- Without ?selectedSnapshot=: returns the snapshot diff summary (changed, added, removed images)\n- With ?selectedSnapshot=: returns the image preview and metadata. Use the Sentry tool `get_snapshot_image` for full-resolution image bytes.\n\nResource IDs:\n- span: :\n- monitor: \n- snapshot: \n- snapshotImage: :\n\n\nget_sentry_resource(url='https://sentry.io/issues/PROJECT-123/')\nget_sentry_resource(resourceType='issue', organizationSlug='my-org', resourceId='PROJECT-123')\nget_sentry_resource(resourceType='span', organizationSlug='my-org', resourceId=':')\nget_sentry_resource(resourceType='ai_conversation', organizationSlug='my-org', resourceId='conversation-123')\nget_sentry_resource(url='https://sentry.sentry.io/preprod/snapshots/123/')\nget_sentry_resource(url='https://sentry.sentry.io/preprod/snapshots/123/?selectedSnapshot=login_screen.png')\n", + "description": "Fetch a Sentry resource by URL, or by resourceType plus resourceId.\nPass a Sentry URL directly when possible; the resource type is auto-detected.\n\nSupports issues, events, traces, spans, AI conversations, breadcrumbs, replays, monitors, dashboards, preprod snapshots, and snapshot images.\nTrace lookups return a condensed overview by default.\n\nAI Conversations: A conversation is a set of spans sharing the same gen_ai.conversation.id. Use resourceType='ai_conversation' with a conversation ID, or pass a Sentry conversation URL, to fetch the transcript/details. To discover or list conversations, use search_ai_conversations. Conversations are NOT issues — do not use search_issues for conversation queries.\n\nFor preprod snapshot URLs (matching 'sentry.io/preprod/snapshots/'):\n- Without ?selectedSnapshot=: returns the snapshot diff summary (changed, added, removed images)\n- With ?selectedSnapshot=: returns the image preview and metadata. Use the Sentry tool `get_snapshot_image` for full-resolution image bytes.\n\nResource IDs:\n- span: :\n- monitor: \n- dashboard: \n- snapshot: \n- snapshotImage: :\n\n\nget_sentry_resource(url='https://sentry.io/issues/PROJECT-123/')\nget_sentry_resource(resourceType='issue', organizationSlug='my-org', resourceId='PROJECT-123')\nget_sentry_resource(resourceType='span', organizationSlug='my-org', resourceId=':')\nget_sentry_resource(resourceType='ai_conversation', organizationSlug='my-org', resourceId='conversation-123')\nget_sentry_resource(url='https://sentry.sentry.io/dashboard/542438/')\nget_sentry_resource(url='https://sentry.sentry.io/preprod/snapshots/123/')\nget_sentry_resource(url='https://sentry.sentry.io/preprod/snapshots/123/?selectedSnapshot=login_screen.png')\n", "inputSchema": { "type": "object", "properties": { @@ -2036,13 +2036,14 @@ "replay", "monitor", "snapshot", - "snapshotImage" + "snapshotImage", + "dashboard" ], - "description": "Resource type. With a URL, can override the auto-detected type for breadcrumbs on an issue/event URL or for `trace` on a span-focused trace URL. Use `monitor` with a monitor slug only when inspect monitor tools are available, `snapshot` with a snapshot artifact ID, or `snapshotImage` with `:`." + "description": "Resource type. With a URL, can override the auto-detected type for breadcrumbs on an issue/event URL or for `trace` on a span-focused trace URL. Use `monitor` with a monitor slug only when inspect monitor tools are available, `snapshot` with a snapshot artifact ID, `snapshotImage` with `:`, or `dashboard` with a dashboard ID or exact title when inspect dashboard tools are available." }, "resourceId": { "type": "string", - "description": "Resource identifier: issue shortId (e.g., 'PROJECT-123'), event ID, trace ID, AI conversation ID, replay ID, monitor slug when inspect monitor tools are available, snapshot artifact ID, `:` for snapshot image resources, or `traceId:spanId` for span resources. Required when not using a URL." + "description": "Resource identifier: issue shortId (e.g., 'PROJECT-123'), event ID, trace ID, AI conversation ID, replay ID, monitor slug when inspect monitor tools are available, dashboard ID or title when inspect dashboard tools are available, snapshot artifact ID, `:` for snapshot image resources, or `traceId:spanId` for span resources. Required when not using a URL." }, "organizationSlug": { "type": "string", diff --git a/packages/mcp-core/src/tools/catalog/get-sentry-resource.test.ts b/packages/mcp-core/src/tools/catalog/get-sentry-resource.test.ts index 604d53b4b..d412463ad 100644 --- a/packages/mcp-core/src/tools/catalog/get-sentry-resource.test.ts +++ b/packages/mcp-core/src/tools/catalog/get-sentry-resource.test.ts @@ -12,6 +12,7 @@ import { encode as encodePng } from "fast-png"; import { http, HttpResponse } from "msw"; import { afterAll, beforeEach, describe, expect, it } from "vitest"; import getSentryResource from "./get-sentry-resource.js"; +import { resolveDescription } from "../../tools/types.js"; const originalOpenAIApiKey = process.env.OPENAI_API_KEY; const originalAnthropicApiKey = process.env.ANTHROPIC_API_KEY; @@ -51,7 +52,8 @@ function callHandler(params: { | "replay" | "monitor" | "snapshot" - | "snapshotImage"; + | "snapshotImage" + | "dashboard"; resourceId?: string; organizationSlug?: string; }) { @@ -739,6 +741,56 @@ describe("get_sentry_resource", () => { }); }); + // ─── URL mode: dashboard URLs ────────────────────────────────────────────── + describe("URL mode — dashboard URLs", () => { + it("dispatches dashboard URL to get_dashboard_details", async () => { + const result = await callHandler({ + url: "https://sentry-mcp-evals.sentry.io/dashboard/101/", + }); + expect(result).toContain( + "# Dashboard Errors Overview in **sentry-mcp-evals**", + ); + expect(result).toContain("**ID**: 101"); + expect(result).toContain("[Open Dashboard]"); + }); + + it("dispatches explicit dashboard resourceType to get_dashboard_details by ID", async () => { + const result = await callHandler({ + resourceType: "dashboard", + resourceId: "101", + organizationSlug: "sentry-mcp-evals", + }); + expect(result).toContain( + "# Dashboard Errors Overview in **sentry-mcp-evals**", + ); + expect(result).toContain("**ID**: 101"); + }); + + it("dispatches explicit dashboard resourceType to get_dashboard_details by title", async () => { + const result = await callHandler({ + resourceType: "dashboard", + resourceId: "Errors Overview", + organizationSlug: "sentry-mcp-evals", + }); + expect(result).toContain( + "# Dashboard Errors Overview in **sentry-mcp-evals**", + ); + expect(result).toContain("**ID**: 101"); + }); + + it("rejects dashboard URL when get_dashboard_details is not available", async () => { + await expect( + getSentryResource.handler( + { url: "https://sentry-mcp-evals.sentry.io/dashboard/101/" }, + { + ...baseContext, + availableToolNames: new Set(["get_sentry_resource"]), + }, + ), + ).rejects.toThrow("Dashboard resources require the inspect skill"); + }); + }); + // ─── URL mode: error cases ──────────────────────────────────────────────── describe("URL mode — error cases", () => { it("throws for unsupported URL path (settings)", async () => { @@ -1471,5 +1523,43 @@ describe("get_sentry_resource", () => { "organizationSlug", ]); }); + + it("omits dashboard hints when get_dashboard_details is unavailable", () => { + const desc = resolveDescription(getSentryResource.description, { + experimentalMode: false, + availableToolNames: new Set([ + "get_sentry_resource", + "get_monitor_details", + ]), + }); + expect(desc).not.toContain("dashboard"); + expect(desc).toContain("monitor"); + }); + + it("includes dashboard hints when get_dashboard_details is available", () => { + const desc = resolveDescription(getSentryResource.description, { + experimentalMode: false, + availableToolNames: new Set([ + "get_sentry_resource", + "get_monitor_details", + "get_dashboard_details", + ]), + }); + expect(desc).toContain("dashboards"); + expect(desc).toContain("dashboard: "); + expect(desc).toContain("/dashboard/542438/"); + }); + + it("omits monitor hints when get_monitor_details is unavailable", () => { + const desc = resolveDescription(getSentryResource.description, { + experimentalMode: false, + availableToolNames: new Set([ + "get_sentry_resource", + "get_dashboard_details", + ]), + }); + expect(desc).not.toContain("monitor"); + expect(desc).toContain("dashboard"); + }); }); }); diff --git a/packages/mcp-core/src/tools/catalog/get-sentry-resource.ts b/packages/mcp-core/src/tools/catalog/get-sentry-resource.ts index 527903b61..a7a5997cd 100644 --- a/packages/mcp-core/src/tools/catalog/get-sentry-resource.ts +++ b/packages/mcp-core/src/tools/catalog/get-sentry-resource.ts @@ -24,6 +24,7 @@ import { fetchSnapshotSummary, } from "../support/snapshots/handlers"; import getAIConversationDetails from "./get-ai-conversation-details"; +import getDashboardDetails from "./get-dashboard-details"; import getIssueDetails from "./get-issue-details"; import getMonitorDetails from "./get-monitor-details"; import getProfileDetails from "./get-profile-details"; @@ -42,6 +43,7 @@ export const FULLY_SUPPORTED_TYPES = [ "monitor", "snapshot", "snapshotImage", + "dashboard", ] as const; export type FullySupportedType = (typeof FULLY_SUPPORTED_TYPES)[number]; @@ -80,6 +82,8 @@ export interface ResolvedResourceParams { // Snapshot params snapshotId?: string; selectedSnapshot?: string; + // Dashboard params + dashboardIdOrTitle?: string; } export function resolveResourceParams(params: { @@ -203,6 +207,13 @@ export function resolveResourceParams(params: { selectedSnapshot: imageName, }; } + + case "dashboard": + return { + type: "dashboard", + organizationSlug, + dashboardIdOrTitle: resourceId, + }; } } @@ -234,7 +245,7 @@ function resolveFromParsedUrl( } throw new UserInputError( "Could not determine resource type from URL. " + - "Supported URL patterns: issues, events, traces, AI conversations, profiles, replays, monitors, and releases.", + "Supported URL patterns: issues, events, traces, AI conversations, profiles, replays, monitors, dashboards, and releases.", ); } @@ -402,6 +413,16 @@ function resolveFromParsedUrl( snapshotId: parsed.snapshotId, selectedSnapshot: parsed.selectedSnapshot, }; + + case "dashboard": + if (!parsed.dashboardId) { + throw new UserInputError("Could not extract dashboard ID from URL."); + } + return { + type: "dashboard", + organizationSlug, + dashboardIdOrTitle: parsed.dashboardId, + }; } } @@ -514,6 +535,14 @@ export default defineTool({ "get_monitor_details", availableToolNames, ); + // Monitors and dashboards both delegate to inspect-only catalog tools. + // Only advertise them when their backing tools are available in this session. + // The URL parser still recognises /crons/ and /dashboard/{id}/ unconditionally; + // non-inspect sessions get a clear "requires the inspect skill" error at runtime. + const dashboardResourcesAvailable = isToolAvailable( + "get_dashboard_details", + availableToolNames, + ); const fullResolutionInstruction = formatToolCallInstruction({ toolName: "get_snapshot_image", arguments: { @@ -529,12 +558,20 @@ export default defineTool({ "Full-resolution snapshot image bytes are not available in this session", purpose: "for full-resolution image bytes", }); - const supportedResources = monitorResourcesAvailable - ? "issues, events, traces, spans, AI conversations, breadcrumbs, replays, monitors, preprod snapshots, and snapshot images." - : "issues, events, traces, spans, AI conversations, breadcrumbs, replays, preprod snapshots, and snapshot images."; + const extraResources = [ + ...(monitorResourcesAvailable ? ["monitors"] : []), + ...(dashboardResourcesAvailable ? ["dashboards"] : []), + ]; + const supportedResources = + extraResources.length > 0 + ? `issues, events, traces, spans, AI conversations, breadcrumbs, replays, ${extraResources.join(", ")}, preprod snapshots, and snapshot images.` + : "issues, events, traces, spans, AI conversations, breadcrumbs, replays, preprod snapshots, and snapshot images."; const resourceIds = [ "- span: :", ...(monitorResourcesAvailable ? ["- monitor: "] : []), + ...(dashboardResourcesAvailable + ? ["- dashboard: "] + : []), "- snapshot: ", "- snapshotImage: :", ]; @@ -560,6 +597,11 @@ export default defineTool({ "get_sentry_resource(resourceType='issue', organizationSlug='my-org', resourceId='PROJECT-123')", "get_sentry_resource(resourceType='span', organizationSlug='my-org', resourceId=':')", "get_sentry_resource(resourceType='ai_conversation', organizationSlug='my-org', resourceId='conversation-123')", + ...(dashboardResourcesAvailable + ? [ + "get_sentry_resource(url='https://sentry.sentry.io/dashboard/542438/')", + ] + : []), "get_sentry_resource(url='https://sentry.sentry.io/preprod/snapshots/123/')", "get_sentry_resource(url='https://sentry.sentry.io/preprod/snapshots/123/?selectedSnapshot=login_screen.png')", "", @@ -587,10 +629,11 @@ export default defineTool({ "monitor", "snapshot", "snapshotImage", + "dashboard", ]) .optional() .describe( - "Resource type. With a URL, can override the auto-detected type for breadcrumbs on an issue/event URL or for `trace` on a span-focused trace URL. Use `monitor` with a monitor slug only when inspect monitor tools are available, `snapshot` with a snapshot artifact ID, or `snapshotImage` with `:`.", + "Resource type. With a URL, can override the auto-detected type for breadcrumbs on an issue/event URL or for `trace` on a span-focused trace URL. Use `monitor` with a monitor slug only when inspect monitor tools are available, `snapshot` with a snapshot artifact ID, `snapshotImage` with `:`, or `dashboard` with a dashboard ID or exact title when inspect dashboard tools are available.", ), resourceId: z @@ -598,7 +641,7 @@ export default defineTool({ .trim() .optional() .describe( - "Resource identifier: issue shortId (e.g., 'PROJECT-123'), event ID, trace ID, AI conversation ID, replay ID, monitor slug when inspect monitor tools are available, snapshot artifact ID, `:` for snapshot image resources, or `traceId:spanId` for span resources. Required when not using a URL.", + "Resource identifier: issue shortId (e.g., 'PROJECT-123'), event ID, trace ID, AI conversation ID, replay ID, monitor slug when inspect monitor tools are available, dashboard ID or title when inspect dashboard tools are available, snapshot artifact ID, `:` for snapshot image resources, or `traceId:spanId` for span resources. Required when not using a URL.", ), organizationSlug: ParamOrganizationSlug.optional(), @@ -767,6 +810,21 @@ export default defineTool({ context, ); + case "dashboard": + assertCatalogToolAvailable( + context, + "get_dashboard_details", + "Dashboard", + ); + return getDashboardDetails.handler( + { + organizationSlug: resolved.organizationSlug, + dashboardIdOrTitle: resolved.dashboardIdOrTitle!, + regionUrl: context.constraints.regionUrl ?? null, + }, + context, + ); + case "snapshot": case "snapshotImage": { const apiService = apiServiceFromContext(context, { diff --git a/packages/mcp-server-evals/src/evals/get-sentry-resource.eval.ts b/packages/mcp-server-evals/src/evals/get-sentry-resource.eval.ts index 42437788e..48ac823ec 100644 --- a/packages/mcp-server-evals/src/evals/get-sentry-resource.eval.ts +++ b/packages/mcp-server-evals/src/evals/get-sentry-resource.eval.ts @@ -51,6 +51,17 @@ describeEval("get-sentry-resource", { }, ], }, + { + input: `What widgets are on this dashboard? ${FIXTURES.dashboardUrl}`, + expectedTools: [ + { + name: "get_sentry_resource", + arguments: { + url: FIXTURES.dashboardUrl, + }, + }, + ], + }, ]; }, task: NoOpTaskRunner(), diff --git a/packages/mcp-server-evals/src/evals/utils/fixtures.ts b/packages/mcp-server-evals/src/evals/utils/fixtures.ts index 82758ab35..073d692d6 100644 --- a/packages/mcp-server-evals/src/evals/utils/fixtures.ts +++ b/packages/mcp-server-evals/src/evals/utils/fixtures.ts @@ -22,4 +22,5 @@ export const FIXTURES = { traceUrl: "https://sentry-mcp-evals.sentry.io/explore/traces/trace/a4d1aae7216b47ff8117cf4e09ce9d0a/", dsn: "https://d20df0a1ab5031c7f3c7edca9c02814d@o4509106732793856.ingest.us.sentry.io/4509109104082945", + dashboardUrl: "https://sentry-mcp-evals.sentry.io/dashboard/101/", };