Skip to content

ref(mcp): Send SentryApiService requests through a shared request core - #1737

Merged
BYK merged 2 commits into
mainfrom
feat/shared-api-client-core
Oct 29, 2026
Merged

BYK merged 2 commits into
mainfrom
feat/shared-api-client-core

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Adds the shared request core in toolkit-core/src/api-client/core.ts and switches SentryApiService onto it. This is the first slice of #1669 task 8.4. #1736 has merged, so this PR now targets main.

8.4 as written covers the request core and every domain's endpoint wrappers. SentryApiService is about 6,000 lines with about 100 endpoint methods, so I'm splitting 8.4 into the core first, then domain PRs on top. This PR is the core.

What changes

  • createApiClientCore (toolkit-core, browser-portable). The host injects its transport, per-request headers, and logger. request(origin, path, init, { allowStatuses }):

    • sends to <origin>/api/0<path> with Content-Type: application/json plus the host's headers (they replace any the caller passes, as before);
    • turns network failures into Unable to connect to <url> - …, as a ConfigurationError for ENOTFOUND, EAI_AGAIN, ECONNREFUSED, ETIMEDOUT, and connect timeouts;
    • rethrows the caller's abort unchanged;
    • maps an error response to the status's ApiError through readErrorResponse, with the same three warnings as before.

    requestJson also parses the body with readJsonResponse.

  • SentryApiService. request and requestJSON keep their signatures and delegate to the core, so no endpoint method changes. SentryApiService supplies User-Agent, Authorization (still a ConfigurationError for a malformed token, before anything is sent), the X-Sentry-MCP-* attribution headers, the existing shared transport, and logWarn under the api.client scope. Its copies of the network error table and the error-response mapping are deleted.

  • Still in mcp-core: sdkClient, which now goes through the core via request, and sdkListPage.

    • Moving sdkClient means toolkit-core depends on @sentry/api. Today that resolves a second @sentry/api copy, because toolkit-core pins TypeScript through the ^5.8.3 catalog while mcp-core resolves 5.9.3. The domain-wrapper PRs will fix that skew first.
    • sdkListPage stays because its rules differ from the shared paginate: an exact per_page, and an error on extra rows or a repeated cursor. Merging them would change behavior, so that waits for the merge step.
  • Docs: the toolkit-core README's API client section and api-patterns.md describe the core.

Behavior changes

  • Warning host field. The three error-response warnings (HTML page, unparseable JSON, no string detail) now log the host the request actually went to. Before, they logged the service's default host even when a call overrode it, e.g. a regional host. Messages, error classes, detail, responseBody, and retryAfterMs don't change.

This PR does not touch packages/mcp-server, packages/cli/src/lib/mcp.ts, or the evals stdio entry. The @sentry/mcp-server retirement PR owns those.

Commits

Both commits are hand-written. No codemod.

  1. 5710b8e8d Add createApiClientCore with unit tests
  2. fc6aa0875 Switch SentryApiService onto it, plus docs

Verification

  • pnpm run tsc (including toolkit-core's browser typecheck), pnpm run lint, and node scripts/check-doc-links.mjs pass.
  • toolkit-core: 319 passed, including 13 new core.test.ts cases covering headers, header errors, detail mapping, allowed statuses, rate-limit wait, HTML and unreadable bodies, network errors, abort, and requestJson.
  • mcp-core: 1881 passed, 6 skipped. The existing client.test.ts MSW suites cover the delegated path unchanged.
  • mcp-server: 87 passed. mcp-cloudflare: 443 passed.
  • The CLI is untouched in this PR; its turn is 8.5.

--

View Junior Session in Sentry

@vercel

vercel Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
sentry-local Ready Ready Preview Oct 29, 2026 9:30pm UTC

Request Review

@github-actions github-actions Bot added the risk: medium PR risk score: medium label Oct 29, 2026
Base automatically changed from feat/shared-api-client-layout to main October 29, 2026 21:23
createApiClientCore sends a request through the host's transport with
the host's headers, turns network failures into readable errors
(ConfigurationError for an unreachable host), maps error responses to
the status's ApiError through readErrorResponse, and parses JSON bodies.
The transport, headers, and logger are injected, so it stays
browser-portable. It is the MCP's request path, moved as is; the next
commit switches SentryApiService onto it.
request and requestJSON keep their signatures and delegate to
createApiClientCore, so no endpoint method changes. SentryApiService
supplies its headers (User-Agent, Authorization, MCP attribution), the
shared transport, and logWarn under the api.client scope. Its copies of
the network error messages and the error-response mapping are deleted.

The one difference: the error-response warnings now log the host the
request went to, rather than the service's default host, when a call
overrides the host.
@sentry-junior
sentry-junior Bot force-pushed the feat/shared-api-client-core branch from 31cc0f4 to fc6aa08 Compare October 29, 2026 21:27
@BYK
BYK merged commit 6a267d9 into main Oct 29, 2026
32 of 36 checks passed
@BYK
BYK deleted the feat/shared-api-client-core branch October 29, 2026 21:44
sentry-junior Bot added a commit that referenced this pull request Oct 29, 2026
main gained #1737 as a squash commit whose tree matches this branch's
copy of the request core (fc6aa08), so every conflict resolves to this
branch's side and the merged tree is unchanged.
BYK pushed a commit that referenced this pull request Oct 29, 2026
…1741)

Task 8.4, part 2 of the shared API client stack
([#1669](#1669)). It used to be
stacked on #1737, which has merged, so it now targets `main`.

This adds the first shared endpoint wrappers to `toolkit-core`'s
`api-client/`, and the MCP's `SentryApiService` now calls them. The code
moves as is, so it can go to `@sentry/api` later without changes.

**Changes**
- `endpoints/organizations` adds `getAuthenticatedUser`,
`listOrganizations` and `getOrganization`. Each one takes an `ApiTarget`
(the request core plus an origin) and a Standard Schema from the host,
and returns that schema's output. `toolkit-core` doesn't depend on Zod
or valibot when the code runs.
- The request core gains `sdkClient`, which sends one GET to an expected
path and rejects any other path or method, and `listPage`, which walks a
list endpoint up to a limit and validates each page. These are the MCP's
`sdkClient` and `sdkListPage`, moved as is. The only change is that
validation now uses Standard Schema.
- `SentryApiService` still decides which host to call: the control host
for the current user and for the organization list on public SaaS. Its
own `sdkClient` and `sdkListPage` copies are deleted, and the teams and
projects lists use the shared ones.
- `toolkit-core` now depends on `@sentry/api`. To keep a single
TypeScript copy, the pnpm catalog's TypeScript moves from `^5.8.3` to
`^5.9.3`, and `toolkit-core` and the CLI use `catalog:` instead of
pinning their own version. Every workspace package now resolves
TypeScript 5.9.3, and 5.8.3 drops out of the lockfile. The cache policy
changes one type to match TypeScript 5.9's DOM `BodyInit`. Nothing
changes at runtime.

**One change in behaviour:** if a response fails its schema in these
calls, the error is now the shared `ApiResponseValidationError` instead
of a `ZodError`. Both still reach the tool error handler as unexpected
errors.

<!-- junior-session-footer:start -->
<!-- junior-conversation-id:local%3Aweb%3A0ab4fc2bd5a2e23f2c25efcf -->

--

[View Junior Session in
Sentry](https://sentry.sentry.io/explore/conversations/local%3Aweb%3A0ab4fc2bd5a2e23f2c25efcf/?project=4510944073809921)

<!-- junior-session-footer:end -->

---------

Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
sentry-junior Bot added a commit that referenced this pull request Oct 30, 2026
main moved response parsing into toolkit-core's readJsonResponse
(#1732, #1737), which still throws a plain Error for an empty or
non-JSON body. validateEvents is the only caller that lets a 400 reach
that parser, so classify its non-JSON 400s there with createApiError.
Successful non-JSON responses stay reportable.

This branch was successfully deployed

1 active deployment
Preview — fc6aa087 Deployed Oct 29, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: medium PR risk score: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant