API Patterns
June 25, 2026 ยท View on GitHub
Sentry API client usage, mocking, and testing patterns.
API Client Usage
Verify Endpoint Contracts
When adding or changing Sentry API endpoint usage in MCP tools, validate the
request parameters and response shape against the Sentry source tree in
~/src/sentry before implementing schemas or handlers. Treat API docs,
frontend call sites, and existing MCP types as helpful context, not authority.
Check the relevant Sentry endpoint, serializer, URL registration, and tests. For example:
rg -n "class OrganizationAIConversations|ai-conversations" ~/src/sentry/src ~/src/sentry/tests
Use the verified source contract to define Zod schemas, query parameters, pagination behavior, feature-gate handling, and test fixtures.
Client Creation
// Standard usage with context helper
const apiService = apiServiceFromContext(context, {
regionUrl: params.regionUrl
});
// Direct instantiation
const api = new SentryApiService({
host: "sentry.io",
accessToken: token
});
See packages/mcp-server/src/api-utils.ts and
adding-tools.md for usage in
tools.
Common Operations
// List with filtering
const issues = await api.issues.list({
organizationSlug: "org",
query: "is:unresolved",
sort: "date"
});
// Get specific resource
const project = await api.projects.get({
organizationSlug: "org",
projectIdOrSlug: "frontend"
});
// Create/update
await api.issues.update({
issueId: "123",
status: "resolved"
});
Multi-Region Support
Sentry uses region-specific URLs:
// Auto-detect from organization
const orgs = await api.organizations.list();
// Returns: { region_url: "https://us.sentry.io" }
// Use region URL
const api = apiServiceFromContext(context, {
regionUrl: org.region_url
});
Schema Patterns
Flexible Sentry Models
// Support ID variations
const IssueIdSchema = z.union([
z.string(), // "PROJ-123"
z.number() // 123456789
]);
// Partial with passthrough for unknowns
const FlexibleSchema = BaseSchema
.partial()
.passthrough();
// Nullable handling
z.union([DateSchema, z.null()])
See Zod patterns in common-patterns.md.
Type Safety
For testing API patterns, see ../testing/overview.md.
// Derive types from schemas
export type Issue = z.infer<typeof IssueSchema>;
// Runtime validation
const issues = IssueListSchema.parse(response);
Mock Patterns
MSW Handler Structure
export const handlers = [
{
method: "get",
path: "/api/0/organizations/:org/issues/",
fetch: async ({ request, params }) => {
// Validate parameters
if (!params.org) {
return HttpResponse.json("Invalid org", { status: 400 });
}
// Return fixture
return HttpResponse.json(issueListFixture);
}
}
];
See: packages/mcp-server-mocks/src/handlers/
Request Validation
fetch: async ({ request }) => {
const url = new URL(request.url);
const query = url.searchParams.get("query");
// Validate query parameters
if (query && !isValidQuery(query)) {
return HttpResponse.json("Invalid query", { status: 400 });
}
// Filter based on query
const filtered = fixtures.filter(item =>
matchesQuery(item, query)
);
return HttpResponse.json(filtered);
}
Dynamic Responses
// Support pagination
const limit = parseInt(url.searchParams.get("limit") || "100");
const cursor = url.searchParams.get("cursor");
const start = cursor ? parseInt(cursor) : 0;
const page = fixtures.slice(start, start + limit);
return HttpResponse.json(page, {
headers: {
"Link": `<...?cursor=${start + limit}>; rel="next"`
}
});
Testing with Mocks
Setup Pattern
import { setupMockServer } from "@sentry-mcp/mocks";
const server = setupMockServer();
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Override Handlers
it("handles errors", async () => {
server.use(
http.get("*/issues/", () =>
HttpResponse.json({ error: "Server error" }, { status: 500 })
)
);
await expect(api.issues.list(params))
.rejects.toThrow(ApiError);
});
Error Patterns
ApiError Handling
try {
const data = await api.issues.list(params);
} catch (error) {
if (error instanceof ApiError) {
// Handle specific status codes
if (error.status === 404) {
throw new UserInputError("Organization not found");
}
}
throw error;
}
See error patterns in common-patterns.md.
Best Practices
- Always use context helper when in tools/prompts
- Handle region URLs for multi-region support
- Validate schemas at API boundaries
- Mock realistically in tests
- Transform errors for LLM consumption
References
- API Client:
packages/mcp-server/src/api-client/ - Mock handlers:
packages/mcp-server-mocks/src/handlers/ - Fixtures:
packages/mcp-server-mocks/src/fixtures/ - API Utils:
packages/mcp-server/src/api-utils.ts