Repository navigation
feat(mcp-core): Add get_profile_details tool and fix profile schemas #870
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
dcramer
merged 5 commits into
main
from
dcramer/feat/profile-resource-schemas-discoverability
Mar 27, 2026
Merged
Changes from 3 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
31485d3
feat(mcp-core): Add profile as first-class resource type in get_sentr…
dcramer ac3d042
ref(mcp-core): Wire up get_profile_details as standalone tool, revert…
dcramer d2a7155
ref(mcp-core): Hide get_profile_details in experimental mode
dcramer 0f465f1
fix(mcp-core): Resolve project slug to numeric ID in get_profile_details
dcramer 56ae7ef
ref(mcp-core): Remove unreachable profilerId validation in get_profil…
dcramer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| import { describe, it, expect } from "vitest"; | ||
| import getProfileDetails from "./get-profile-details"; | ||
|
|
||
| const baseContext = { | ||
| constraints: { | ||
| organizationSlug: null, | ||
| }, | ||
| accessToken: "access-token", | ||
| userId: "1", | ||
| }; | ||
|
|
||
| function callHandler(params: { | ||
| organizationSlug: string; | ||
| projectSlugOrId: string | number; | ||
| profilerId: string; | ||
| start: string; | ||
| end: string; | ||
| regionUrl?: string | null; | ||
| focusOnUserCode?: boolean; | ||
| }) { | ||
| return getProfileDetails.handler( | ||
| { regionUrl: null, focusOnUserCode: true, ...params }, | ||
| baseContext, | ||
| ); | ||
| } | ||
|
|
||
| describe("get_profile_details", () => { | ||
| describe("handler", () => { | ||
| it("fetches and formats a profile chunk", async () => { | ||
| const result = await callHandler({ | ||
| organizationSlug: "sentry-mcp-evals", | ||
| projectSlugOrId: "backend", | ||
| profilerId: "041bde57b9844e36b8b7e5734efae5f7", | ||
| start: "2024-01-01T00:00:00", | ||
| end: "2024-01-01T01:00:00", | ||
| }); | ||
|
|
||
| expect(result).toContain("# Profile Chunk Details"); | ||
| expect(result).toContain("## Metadata"); | ||
| expect(result).toContain("## Sample Summary"); | ||
| expect(result).toContain("## Thread Information"); | ||
| expect(result).toContain("## Top Frames by Occurrence"); | ||
| }); | ||
|
|
||
| it("respects focusOnUserCode option", async () => { | ||
| const resultAll = await callHandler({ | ||
| organizationSlug: "sentry-mcp-evals", | ||
| projectSlugOrId: "backend", | ||
| profilerId: "041bde57b9844e36b8b7e5734efae5f7", | ||
| start: "2024-01-01T00:00:00", | ||
| end: "2024-01-01T01:00:00", | ||
| focusOnUserCode: false, | ||
| }); | ||
|
|
||
| // With focusOnUserCode false, should include library frames | ||
| expect(resultAll).toContain("Library"); | ||
| }); | ||
| }); | ||
|
|
||
| describe("tool definition", () => { | ||
| it("has read-only annotation", () => { | ||
| expect(getProfileDetails.annotations.readOnlyHint).toBe(true); | ||
| }); | ||
|
|
||
| it("belongs to inspect skill", () => { | ||
| expect(getProfileDetails.skills).toContain("inspect"); | ||
| }); | ||
|
|
||
| it("requires profiles capability", () => { | ||
| expect(getProfileDetails.requiredCapabilities).toContain("profiles"); | ||
| }); | ||
|
|
||
| it("has expected params", () => { | ||
| const schemaKeys = Object.keys(getProfileDetails.inputSchema); | ||
| expect(schemaKeys).toEqual([ | ||
| "organizationSlug", | ||
| "regionUrl", | ||
| "projectSlugOrId", | ||
| "profilerId", | ||
| "start", | ||
| "end", | ||
| "focusOnUserCode", | ||
| ]); | ||
| }); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| import { setTag } from "@sentry/core"; | ||
| import { z } from "zod"; | ||
| import { defineTool } from "../internal/tool-helpers/define"; | ||
| import { apiServiceFromContext } from "../internal/tool-helpers/api"; | ||
| import { UserInputError } from "../errors"; | ||
| import type { ServerContext } from "../types"; | ||
| import { ParamOrganizationSlug, ParamRegionUrl } from "../schema"; | ||
| import { formatProfileChunkAnalysis } from "./profile/formatter"; | ||
|
|
||
| export default defineTool({ | ||
| name: "get_profile_details", | ||
| skills: ["inspect"], | ||
| requiredScopes: ["event:read"], | ||
| requiredCapabilities: ["profiles"], | ||
| hideInExperimentalMode: true, | ||
|
|
||
| description: [ | ||
| "Retrieve raw profile chunk data to inspect individual function calls, threads, and stack traces.", | ||
| "", | ||
| "USE THIS TOOL WHEN:", | ||
| "- User wants to inspect raw profiling samples for a specific profiler session", | ||
| "- User needs to see individual thread activity and stack traces", | ||
| "- User wants detailed frame-level data (function names, file locations, call counts)", | ||
| "", | ||
| "RETURNS:", | ||
| "- Profile chunk metadata (platform, release, environment)", | ||
| "- Per-thread sample counts and names", | ||
| "- Top frames by occurrence with file locations", | ||
| "- User code vs library code breakdown", | ||
| "", | ||
| "NOTE: This tool requires a `profilerId` which identifies a specific profiling session.", | ||
| "Use `get_profile` for aggregated flamegraph analysis by transaction name.", | ||
| "", | ||
| "<examples>", | ||
| "### Inspect a profiler session", | ||
| "```", | ||
| "get_profile_details(", | ||
| " organizationSlug='my-org',", | ||
| " projectSlugOrId='backend',", | ||
| " profilerId='041bde57b9844e36b8b7e5734efae5f7',", | ||
| " start='2024-01-01T00:00:00',", | ||
| " end='2024-01-01T01:00:00'", | ||
| ")", | ||
| "```", | ||
| "</examples>", | ||
| "", | ||
| "<hints>", | ||
| "- Use `focusOnUserCode: true` (default) to filter out library/system frames", | ||
| "- The profilerId can be found in Sentry profile URLs or event data", | ||
| "</hints>", | ||
| ].join("\n"), | ||
|
|
||
| inputSchema: { | ||
| organizationSlug: ParamOrganizationSlug, | ||
| regionUrl: ParamRegionUrl.nullable().default(null), | ||
| projectSlugOrId: z | ||
| .union([z.string(), z.number()]) | ||
| .describe("Project slug or numeric ID"), | ||
| profilerId: z | ||
| .string() | ||
| .trim() | ||
| .describe("Profiler session ID (UUID from Sentry profile data)"), | ||
| start: z | ||
| .string() | ||
| .trim() | ||
| .describe( | ||
| "Start time for the profile chunk query (ISO 8601 format, e.g., '2024-01-01T00:00:00')", | ||
| ), | ||
| end: z | ||
| .string() | ||
| .trim() | ||
| .describe( | ||
| "End time for the profile chunk query (ISO 8601 format, e.g., '2024-01-01T01:00:00')", | ||
| ), | ||
| focusOnUserCode: z | ||
| .boolean() | ||
| .default(true) | ||
| .describe( | ||
| "Show only user code (in_app: true). Set to false to include library code.", | ||
| ), | ||
| }, | ||
|
|
||
| annotations: { readOnlyHint: true, openWorldHint: false }, | ||
|
|
||
| async handler(params, context: ServerContext) { | ||
| const apiService = apiServiceFromContext(context, { | ||
| regionUrl: params.regionUrl ?? undefined, | ||
| }); | ||
|
|
||
| const { | ||
| organizationSlug, | ||
| projectSlugOrId, | ||
| profilerId, | ||
| start, | ||
| end, | ||
| focusOnUserCode, | ||
| } = params; | ||
|
|
||
| if (!profilerId) { | ||
| throw new UserInputError( | ||
| "profilerId is required. This is the profiler session UUID found in Sentry profile URLs or event data.", | ||
| ); | ||
| } | ||
|
|
||
| setTag("organization.slug", organizationSlug); | ||
| setTag("profiler.id", profilerId); | ||
|
|
||
| const chunk = await apiService.getProfileChunk({ | ||
| organizationSlug, | ||
| profilerId, | ||
| projectId: projectSlugOrId, | ||
| start, | ||
| end, | ||
| }); | ||
|
cursor[bot] marked this conversation as resolved.
|
||
|
|
||
| return formatProfileChunkAnalysis(chunk, { focusOnUserCode }); | ||
| }, | ||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.