Skip to content

feat: adopt @sentry/api SDK for 38 of 40 API call sites#931

Open
MathurAditya724 wants to merge 28 commits into
mainfrom
feat/adopt-sentry-api-sdk
Open

feat: adopt @sentry/api SDK for 38 of 40 API call sites#931
MathurAditya724 wants to merge 28 commits into
mainfrom
feat/adopt-sentry-api-sdk

Conversation

@MathurAditya724

@MathurAditya724 MathurAditya724 commented May 5, 2026

Copy link
Copy Markdown
Member

Adds @sentry/api@^0.175.0 and migrates 38 of 40 API methods in SentryApiService from raw fetch (via requestJSON) to the typed SDK functions. The remaining 2 methods use internal/undocumented endpoints with no SDK equivalent.

What changed

Two helper methods added to SentryApiService:

  • getSdkConfig(opts?) — builds baseUrl + auth headers (including X-Sentry-MCP-Client-* identity headers) per call, supporting multi-region host overrides
  • unwrapSdkResult(result, context) — converts SDK discriminated-union results to the existing MCP error hierarchy (ApiError, ApiNotFoundError, ApiServerError, etc.), using the API detail text as the user-facing message when available

17 direct replacements (no casts)

listOrganizations, getOrganization, listTeams, createTeam, listProjects, getProject, createProject, updateProject, addTeamToProject, createClientKey, listClientKeys, listReleases, listIssues, getEventForIssue, getLatestEventForIssue, listEventsForIssue, startAutofix, getAutofixState

11 replacements with type casts

searchReplays, getIssue, getIssueTagValues, getIssueExternalLinks, getReplayDetails, listReplayIdsForIssue, getReplayRecordingSegments, updateIssue, searchErrors, searchSpans, searchEvents

10 new replacements (from SDK v0.171.0+)

  • listTagslistAnOrganization_sTags (with cast for useCache param)
  • listTraceItemAttributeslistTraceItemAttributes (replaces fetchTraceItemAttributesByType private helper)
  • listEventAttachmentslistAnEvent_sAttachments
  • getEventAttachment — metadata via listEventAttachments; binary download stays on raw request()
  • getTraceMetaretrieveTraceMetadata
  • getTraceretrieveATrace (with cast for limit/project params)
  • getFlamegraphretrieveAFlamegraphForAnOrganization
  • getTransactionProfileretrieveAProfile
  • getProfileChunkretrieveProfileChunksForAnOrganization
  • listReleases (project-level)listAProject_sReleases
  • listIssues (project-level)listAProject_sIssues (with cast for extra query params)

2 methods still on requestJSON

getAuthenticatedUser, regions endpoint — no SDK equivalent exists for these.

Schema improvements

  • TagSchema / TagListSchema rebased on zTagKeyDetailsDict from @sentry/api/zod
  • EventsResponseSchema, ExternalIssueListSchema, AutofixRunSchema use SDK-generated Zod schemas

Preserved behavior

  • Zod validation: All responses still pass through existing Zod schemas after SDK unwrapping
  • Error handling: unwrapSdkResult maps HTTP errors to the existing ApiError/ApiNotFoundError/ApiServerError types, using API detail text as the message
  • Multi-region: getSdkConfig builds per-call base URLs from opts.host overrides
  • Client identity: X-Sentry-MCP-Client-Id/Name/Family headers forwarded through SDK calls

Testing

  • TypeScript: clean (no new errors in client.ts)
  • Full test suite: 1033 tests passed, 4 skipped
  • Lint: clean

Dependencies

  • @sentry/api@^0.175.0 — latest version, includes SDK wrappers for organization tags, trace, profiling, project-level issues/releases, and event attachment endpoints

@MathurAditya724

Copy link
Copy Markdown
Member Author

fix-ci: starting attempt 1/3

@MathurAditya724

Copy link
Copy Markdown
Member Author

fix-ci: result — fixed 7 test failures across 5 test files.

Root causes:

  1. Agent provider conflict: ANTHROPIC_API_KEY env var leaked into tests alongside OPENAI_API_KEY, causing hasAgentProvider() to return false and routing tests through the direct (non-agent) code path. Fixed by clearing the env var in beforeEach/afterEach.
  2. MSW handler assertions: SDK sends limit not per_page for issues, and doesn't expose sort/per_page as query params on issue events. Updated handler assertions.
  3. Path traversal tests: SDK URL-encodes path params, neutralizing traversal attacks. Updated tests to verify the encoding works correctly instead of expecting errors.
  4. addTeamToProject mock: SDK sends POST with no body; removed request.json() call that threw SyntaxError.

All 69 tests in the 5 affected files pass. Client unit tests (72/72) still pass.

@dcramer

dcramer commented May 5, 2026

Copy link
Copy Markdown
Member

One f/u - i was hoping we'd be able to remove a bunch of typed schemas. Im not sure what we need to do to solve it, but it'd be great if @sentry/api had native zod structs that we could use that were either autogenerated or at minimum, we maintain them in one place vs here and cli etc

Comment thread packages/mcp-core/src/api-client/client.ts Outdated
Comment thread packages/mcp-core/src/api-client/client.ts Outdated
Comment thread packages/mcp-core/src/api-client/client.ts
Comment thread packages/mcp-core/src/api-client/client.ts Outdated
Comment thread packages/mcp-core/src/api-client/client.ts
Comment thread packages/mcp-core/src/api-client/client.ts Outdated
Comment thread packages/mcp-core/src/tools/get-issue-tag-values.test.ts Outdated
Comment thread packages/mcp-core/src/api-client/client.ts
Comment thread packages/mcp-core/src/api-client/client.ts Outdated
@MathurAditya724

Copy link
Copy Markdown
Member Author

Bumped @sentry/api to ^0.141.0 — this picks up the new @sentry/api/zod subpath export with auto-generated Zod v3 schemas from the OpenAPI spec (sentry-api-schema#70). These schemas can eventually replace the hand-written ones in packages/mcp-core/src/api-client/schema.ts.

Comment thread packages/mcp-core/src/api-client/client.ts
Comment thread packages/mcp-core/src/api-client/client.ts Outdated
@dcramer dcramer force-pushed the feat/adopt-sentry-api-sdk branch from eef83a3 to 67afdaa Compare May 14, 2026 17:31
MathurAditya724 and others added 27 commits June 11, 2026 16:58
Update 5 test files and 1 mock handler for compatibility with the
@sentry/api SDK's Request-object-based fetch calls:

- search-events, search-issue-events, search-issues: clear
  ANTHROPIC_API_KEY env var in tests to resolve agent provider
  conflicts that caused tests to take the wrong code path. Adjust
  MSW handler assertions for SDK parameter naming (limit vs per_page).

- get-issue-tag-values: path traversal tests now verify that the SDK
  safely URL-encodes path params (../../../admin → ..%2F..%2Fadmin),
  neutralizing the attack vector at the SDK level.

- mcp-server-mocks: remove request.json() call from addTeamToProject
  handler — the SDK sends POST with no body for this endpoint.
Biome's noDelete rule flags `delete process.env.X` as a performance
concern. Use Reflect.deleteProperty() instead — same semantics,
lint-clean.
Cross-referenced with CLI repo's migration patterns and found 3
behavioral regressions where query parameters were dropped during
the SDK migration:

- listTeams: restore per_page=25 and query filter params
- listEventsForIssue: restore per_page (limit) and sort params
- listOrganizations: restore per_page=25 across all 3 SDK call sites

Also improved unwrapSdkResult error detail extraction:
- Use JSON.stringify instead of String() to avoid [object Object]
- Extract detail from nested error objects properly
- Include context and status text in error messages (matching CLI
  pattern from infrastructure.ts throwApiError)
The improved error extraction now includes context and status text
in the error message (getIssue: 404 Not Found) instead of the raw
detail (The requested resource does not exist). Update the inline
snapshot to match.
Snapshot LLM provider env vars after dotenv loads and restore them after each test. This keeps search tool tests from leaking key changes when local Anthropic and OpenAI keys are both set.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Pass replay environment arrays through to the Sentry API so multi-environment replay searches are not silently narrowed to the first environment. Remove duplicated test env restore blocks now that the shared setup restores managed LLM env vars after each test.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Restore replay time range validation when routing through the Sentry API SDK and keep issue event sort serialization covered by tests.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Start managed LLM environment variables unset for each mcp-core test and restore the original process environment after each test. Keep the OpenAI integration test explicit about reusing its captured real key.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Assert invalid issue tag keys are rejected by the declared tool input schema instead of bypassing schema validation through direct handler calls.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Picks up v0.141.0 which adds auto-generated Zod schemas via a new
'@sentry/api/zod' subpath export (getsentry/sentry-api-schema#70).
Replace hand-written Zod schemas with auto-generated ones from
@sentry/api/zod where the generated schemas cover the same response
shapes. Keep custom schemas for internal endpoints, recursive types,
and schemas with transforms/preprocessors.

Replaced:
- AutofixRunSchema -> zAutofixPostResponse.passthrough()
- EventsResponseSchema -> zOrganizationEventsResponseDict
- ExternalIssueSchema/ExternalIssueListSchema -> zGroupExternalIssueResponse
Keep SDK-backed issue event requests aligned with the previous requestJSON behavior by omitting unset query params, preferring statsPeriod over absolute time ranges, and only sending full when requested.

Normalize listProjects pagination to use a numeric per_page value and add focused regression coverage for issue event query serialization.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
…oject error detection

createApiError checks the message param for multi-project access error
patterns, but unwrapSdkResult was passing a generic context string
instead of the actual API error text. This matches the behavior of the
old request() path which passes data.detail as both message and detail.
Inspect API error detail text when classifying known permission failures so SDK-backed requests preserve the multi-project access guidance.

Add regression coverage through an SDK-backed issue event request.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Bump @sentry/api from ^0.141.0 to ^0.171.0 and migrate 9 additional
requestJSON call sites to typed SDK functions:

- listTraceItemAttributes (via listTraceItemAttributes)
- listEventAttachments (via listAnEvent_sAttachments)
- getEventAttachment metadata (reuses listEventAttachments)
- getTraceMeta (via retrieveTraceMetadata)
- getTrace (via retrieveATrace)
- getFlamegraph (via retrieveAFlamegraphForAnOrganization)
- getTransactionProfile (via retrieveAProfile)
- getProfileChunk (via retrieveProfileChunksForAnOrganization)
- listReleases project-level (via listAProject_sReleases)
- listIssues project-level (via listAProject_sIssues)

Also fixes 3 type errors from SDK v0.171.0 type changes:
- issue_id now expects number in getIssue/updateAnIssue
- startAutofix body type narrowed

Only 3 methods remain on requestJSON (no SDK equivalent):
getAuthenticatedUser, regions fetch, listTags.

Co-Authored-By: Claude (claude-opus-4-6)
The outer `as Parameters<typeof sdkFn>[0]` cast already overrides the
entire options type, making the inner `as Record<string, unknown>` on
the query property redundant. Removes 12 unnecessary casts.

Co-Authored-By: Claude (claude-opus-4-6)
Replace the hand-written TagSchema object definition with
zTagKeyDetailsDict.pick({...}).transform(...) from @sentry/api/zod.
This keeps the base schema in sync with the upstream OpenAPI spec
while preserving the local transform that coalesces
totalValues/uniqueValues.

Uses .pick() to select only the 4 fields the transform needs,
avoiding validation of topValues inner elements which have stricter
nullability requirements than what the tags list endpoint returns.

Co-Authored-By: Claude (claude-opus-4-6)
getSdkConfig() was missing X-Sentry-MCP-Client-Id,
X-Sentry-MCP-Client-Name, and X-Sentry-MCP-Client-Family headers
that request() sends. All 37 SDK-migrated endpoints were silently
dropping client identity tracking used for server-side analytics.

Also normalizes searchReplays cast to match the Parameters<typeof>
pattern used everywhere else and removes the now-unused Options type
import.

Co-Authored-By: Claude (claude-opus-4-6)
Bump @sentry/api to ^0.172.0 which exports the SdkResult type from
getsentry/sentry-api-schema#74.

The SDK functions return RequestResult whose conditional generic
encoding (TData[keyof TData]) is not structurally assignable to
SdkResult, so unwrapSdkResult keeps `any` for the parameter type.
Updated the JSDoc to reference SdkResult as the runtime contract
and explain why the type mismatch exists.

Co-Authored-By: Claude (claude-opus-4-6)
Address Warden review findings:

- unwrapSdkResult now uses the API's detail text as the error message
  when available (e.g. 'The requested resource does not exist') instead
  of the internal context label ('getIssue: 404 Not Found'). Falls back
  to the context-prefixed message when no detail is present.

- Remove dead code in listOrganizations: queryParams, queryString, and
  path variables were left over from the pre-SDK migration and are no
  longer referenced.

Co-Authored-By: Claude (claude-opus-4-6)
…ry casts

sentry#116782 fixed issue_id from int to str and added per_page to the
List Organizations spec. With 0.174.0 these casts are no longer needed:
- 8x `issue_id: issueId as unknown as number` → plain issueId
- 3x `as Parameters<typeof sdkListYourOrganizations>[0]` (per_page now declared)
- 1x `as Parameters<typeof sdkListAnIssueSEvents>[0]` (issue_id was the only reason)

returnIds and allowAggregateConditions are now typed as boolean in the spec,
so update the values passed (true/false instead of strings) and strengthen
the remaining casts for project/-1 and useRpc to `as unknown as`.
Bump @sentry/api to ^0.175.0 which adds the organization tags
endpoint to the OpenAPI spec. Migrate listTags from requestJSON
to sdkListAnOrganizationSTags, reducing the remaining requestJSON
methods from 3 to 2 (getAuthenticatedUser and regions endpoint).

Co-Authored-By: Claude (claude-opus-4-6)
The events explore API expects the string '0' to disable aggregate
conditions. A boolean false could be serialized differently by the
SDK's request builder.

Co-Authored-By: Claude (claude-opus-4-6)
Neither param is read by the backend:
- project: "-1" in listReplayIdsForIssue — not in ReplayCountQueryParamsValidator
- useRpc: "1" in searchSpans — not referenced anywhere in organization_events.py

Removing them also drops the two remaining as-unknown-as casts on those call sites.
…s to requestJSON

searchReplays was building a Record<string,unknown> query object and casting
the entire SDK call. All replay params are already in the spec so the cast
was only needed because of the dynamic object construction. Inline the query
directly — the only remaining targeted cast is for field[], which the spec
types as a strict enum but the API accepts arbitrary strings at runtime.

Also reverts listTags to requestJSON. sdkListAnOrganizationSTags was removed
from the public spec in @sentry/api ≥0.175.0, so the SDK function no longer
exists. The endpoint has no SDK equivalent; requestJSON is the right fallback.
project is processed by OrganizationEventsEndpointBase.get_snuba_params(),
not by the endpoint's own validator. -1 is the all-accessible-projects
sentinel — without it the API narrows to membership-only projects, which
misses replays for issues in projects the caller can access but isn't a
member of.
Handle SDK response shapes and replay query validation after rebasing the API SDK branch onto main. Keep API detail messages in tests and preserve multi-environment replay queries.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
@dcramer dcramer force-pushed the feat/adopt-sentry-api-sdk branch from b52d182 to 950be09 Compare June 12, 2026 00:16

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 950be09. Configure here.

queryParams.statsPeriod = statsPeriod;
} else if (start && end) {
queryParams.start = start;
queryParams.end = end;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trace attributes skip time validation

Medium Severity

fetchTraceItemAttributesByType no longer calls applyTimeParams before the SDK request. Conflicting statsPeriod with start/end, or a lone start or end, is ignored instead of raising ApiValidationError, unlike searchReplays and other callers updated in this PR.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 950be09. Configure here.

query: sentryQuery.join(" "),
allowAggregateConditions: false,
},
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

searchSpans drops useRpc flag

Medium Severity

The searchSpans SDK migration stopped sending the useRpc=1 query parameter that the prior requestJSON implementation always included for the spans explore query, which may change which backend serves results.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 950be09. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants