Skip to main content
Glama

Sentry MCP

Official
by getsentry
security.mdc6.06 kB
# Security Authentication and security patterns for the Sentry MCP server. ## OAuth Architecture The MCP server acts as an OAuth proxy between clients and Sentry: ``` MCP Client → MCP Server → Sentry OAuth → Sentry API ``` ### Key Components 1. **OAuth Provider** (Cloudflare Durable Object) - Manages client authorization - Stores tokens securely - Handles state management 2. **Client Approval** - First-time clients require user approval - Approved clients stored in signed cookies - Per-organization access control 3. **Token Management** - Access tokens encrypted in KV storage - Tokens scoped to organizations ## Implementation Patterns ### OAuth Flow Handler See implementation: `packages/mcp-cloudflare/src/server/oauth/authorize.ts` and `packages/mcp-cloudflare/src/server/oauth/callback.ts` Key endpoints: - `/authorize` - Client approval and redirect to Sentry - `/callback` - Handle Sentry callback, store tokens - `/approve` - Process user approval ### Required OAuth Scopes ```typescript const REQUIRED_SCOPES = [ "org:read", "project:read", "issue:read", "issue:write" ]; ``` ### Security Context ```typescript interface ServerContext { host: string; accessToken: string; organizationSlug?: string; } ``` Context propagated through: - Tool handlers - API client initialization - Error messages (sanitized) ## Security Measures ### SSRF Protection The MCP server validates `regionUrl` parameters to prevent Server-Side Request Forgery (SSRF) attacks: ```typescript // Region URL validation rules: // 1. By default, only the base host itself is allowed as regionUrl // 2. Additional domains must be in SENTRY_ALLOWED_REGION_DOMAINS allowlist // 3. Must use HTTPS protocol for security // 4. Empty/undefined regionUrl means use the base host // Base host always allowed validateRegionUrl("https://sentry.io", "sentry.io"); // ✅ Base host match validateRegionUrl("https://mycompany.com", "mycompany.com"); // ✅ Base host match // Allowlist domains (sentry.io, us.sentry.io, de.sentry.io) validateRegionUrl("https://us.sentry.io", "sentry.io"); // ✅ In allowlist validateRegionUrl("https://de.sentry.io", "mycompany.com"); // ✅ In allowlist validateRegionUrl("https://sentry.io", "mycompany.com"); // ✅ In allowlist // Rejected domains validateRegionUrl("https://evil.com", "sentry.io"); // ❌ Not in allowlist validateRegionUrl("http://us.sentry.io", "sentry.io"); // ❌ Must use HTTPS validateRegionUrl("https://eu.sentry.io", "sentry.io"); // ❌ Not in allowlist validateRegionUrl("https://sub.mycompany.com", "mycompany.com"); // ❌ Not base host or allowlist ``` Implementation: `packages/mcp-server/src/internal/tool-helpers/validate-region-url.ts` ### Prompt Injection Protection Tools that accept user input are vulnerable to prompt injection attacks. Key mitigations: 1. **Parameter Validation**: All tool inputs validated with Zod schemas 2. **URL Validation**: URLs parsed and validated before use 3. **Region Constraints**: Region URLs restricted to known Sentry domains 4. **No Direct Command Execution**: Tools don't execute user-provided commands Example protection in tools: ```typescript // URLs must be valid and from expected domains if (!issueUrl.includes('sentry.io')) { throw new UserInputError("Invalid Sentry URL"); } // Region URLs validated against base host const validatedHost = validateRegionUrl(regionUrl, baseHost); ``` ### State Parameter Protection The OAuth `state` is a compact HMAC-signed payload with a 10‑minute expiry: ```typescript // Payload contains only what's needed on callback type OAuthState = { clientId: string; redirectUri: string; // must be a valid URL scope: string[]; // from OAuth provider parseAuthRequest permissions?: string[]; // user selections from approval iat: number; // issued at (ms) exp: number; // expires at (ms) }; // Sign: `${hex(hmacSHA256(json))}.${btoa(json)}` using COOKIE_SECRET const signed = `${signatureHex}.${btoa(JSON.stringify(state))}`; // On callback: split, verify signature, parse, check exp > Date.now() ``` Implementation: `packages/mcp-cloudflare/src/server/oauth/state.ts` ### Input Validation All user inputs sanitized: - HTML content escaped - URLs validated - OAuth parameters verified ### Cookie Security ```typescript // Signed cookie for approved clients const cookie = await signCookie( `approved_clients=${JSON.stringify(approvedClients)}`, COOKIE_SECRET ); // Cookie attributes "HttpOnly; Secure; SameSite=Lax; Max-Age=2592000" // 30 days ``` ## Error Handling Security-aware error responses: - No token/secret exposure in errors - Generic messages for auth failures - Detailed logging server-side only ```typescript catch (error) { if (error.message.includes("token")) { return new Response("Authentication failed", { status: 401 }); } // Log full error server-side console.error("OAuth error:", error); return new Response("An error occurred", { status: 500 }); } ``` ## Multi-Tenant Security ### Organization Isolation - Tokens scoped to organizations - Users can switch organizations - Each organization requires separate approval ### Access Control ```typescript // Verify organization access const orgs = await apiService.listOrganizations(); if (!orgs.find(org => org.slug === requestedOrg)) { throw new UserInputError("No access to organization"); } ``` ## Environment Variables Required for OAuth: ```bash SENTRY_CLIENT_ID=your_oauth_app_id SENTRY_CLIENT_SECRET=your_oauth_app_secret COOKIE_SECRET=random_32_char_string ``` ## CORS Configuration ```typescript // Allowed origins for OAuth flow const ALLOWED_ORIGINS = [ "https://sentry.io", "https://*.sentry.io" ]; ``` ## References - OAuth implementation: `packages/mcp-cloudflare/src/server/oauth/*` - Cookie utilities: `packages/mcp-cloudflare/src/server/utils/cookies.ts` - OAuth Provider: `packages/mcp-cloudflare/src/server/bindings.ts` - Sentry OAuth docs: <https://docs.sentry.io/api/guides/oauth/>

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/getsentry/sentry-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server