Sentry MCP Server

repository·main·Indexed 21 days ago

https://github.com/getsentry/sentry-mcp

A Model Context Protocol (MCP) server that acts as a middleware to the Sentry API, allowing AI agents to interact with Sentry data via stdio or HTTP transport. It features a skills-based authorization system (inspect, seer, triage, project-management) and AI-powered tools like search_issues and search_events that translate natural language into Sentry query syntax using OpenAI or OpenRouter.

Tokens
52.4K
Snippets
122
Records
231
Agent score
73%

What's inside sentry-mcp

  1. Overview of the Claude Code Plugin structure

    main

    The Claude Code plugin registers a sentry-mcp subagent. When a user asks about Sentry errors, issues, traces, or performance, Claude Code automatically delegates the request to this subagent. The subagent connects to a remote MCP server and has access to Sentry tools.

    There are two published variants:

    PluginMCP URLPurpose
    sentry-mcphttps://mcp.sentry.dev/mcpDefault catalog gateway surface
    sentry-mcp-experimentalhttps://mcp.sentry.dev/mcp?experimental=1Forward-looking feature flags
  2. Understand the Sentry MCP Architecture

    main

    Sentry MCP is a Model Context Protocol (MCP) server that exposes Sentry's error tracking and performance monitoring capabilities to AI assistants (like Claude or Cursor).

    Core Components

    • @sentry/mcp-server: The primary package used by end-users. It provides the stdio transport and is published to npm. It bundles the core logic into a self-contained package.
    • mcp-core: A private workspace package containing the actual MCP implementation, Sentry API client, and tool definitions. It is not published to npm.
    • mcp-test-client: An interactive CLI tool for testing the MCP server with an AI agent.

    Data Flow

    1. An LLM makes a tool call.
    2. The MCP server receives the request.
    3. The tool handler validates parameters.
    4. The Sentry API client executes the request against Sentry.
    5. The response is formatted for the LLM and sent back.
  3. Understand Sentry MCP CI/CD Workflows

    main

    The Sentry MCP project uses GitHub Actions for continuous integration and deployment. There are three primary workflows:

    • test.yml: Triggered on all pushes to main and pull requests. It handles building, linting, unit testing, and code coverage reporting.
    • deploy.yml: Triggered after tests pass on the main branch. It follows a canary-to-production pipeline: deploys to the canary worker, runs smoke tests, and only proceeds to production deployment if canary tests pass. It includes automatic rollback capabilities.
    • eval.yml: Runs evaluation tests against the MCP server.
  4. URL State Management for IDE and Transport

    main

    The integration uses URL parameters to persist the user's selected IDE and transport mode. This allows for deep-linking and state preservation when switching between Cloud and Stdio modes.

    URL Parameters

    • ide: The ID of the selected IDE (e.g., claude-code, cursor). Defaults to claude-code.
    • transport: The setup mode, either cloud or stdio. Defaults to cloud.

    Example URLs

    • ?ide=claude-code&transport=cloud: Cloud instructions for Claude Code.
    • ?ide=cursor&transport=stdio: Stdio instructions for Cursor.
  5. Understand Sentry MCP Telemetry Attribute Namespaces

    main

    Sentry MCP uses specific namespaces for telemetry attributes to ensure compatibility and avoid data scrubbing issues:

    • http.*, network.*, and gen_ai.*: Follow OpenTelemetry semantic conventions.
    • mcp.*: Reserved for OpenTelemetry MCP semantic attributes (e.g., mcp.method.name, mcp.protocol.version, mcp.resource.uri, mcp.session.id).
    • app.*: Sentry MCP application-owned attributes for product-specific concepts (e.g., OAuth outcomes, route groups, constraints, and local response reasons).
    • gen_ai.tool.call.arguments.<key>: Extends GenAI semantic conventions with per-key tool arguments.

    Important Note on High Cardinality:

    • gen_ai.tool.call.result contains the full JSON tool result payload. It is high-cardinality and should be used for targeted inspection only, not for group-bys or metrics.
    • gen_ai.tool.call.result.count is a span-level integer. Do not use this in metrics dimensions.
  6. Understand the MCP OAuth token lifecycle

    main

    The remote MCP server (mcp.sentry.dev) uses a two-tier token system to manage authentication:

    1. Upstream (Sentry): Sentry issues a 30-day access token and a rotating refresh token via the /oauth/authorize flow. The MCP server reuses this cached upstream token for its full 30-day lifetime.
    2. MCP Wrapper: The @cloudflare/workers-oauth-provider issues a shorter-lived wrapper access token (default 1h).

    Token Refresh Flow: When an MCP client refreshes its wrapper token via /oauth/token, the tokenExchangeCallback performs the following logic:

    • If the local expiry is in the future (> 2 min), it returns a cached_valid_local token.
    • If the local expiry has passed, it probes the upstream Sentry API (/api/0/auth/):
      • 200 OK: The token is cached_valid_probed and the wrapper expiry is extended by 2h.
      • 4xx Error: The token is upstream_rejected and marked invalid.
      • 5xx/Timeout: The state is verification_indeterminate (the grant stays alive).

    Tool Call Flow: When a client makes a tool call to /mcp, the mcp-handler executes the tool via SentryApiService. If the upstream Sentry API returns a 401, the onUpstreamUnauthorized callback is triggered, revoking the grant to prevent a 'death-spiral' of invalid refreshes.

  7. How MCP Permissions and Scopes Work

    main

    Permissions in Sentry MCP are managed through two different layers that serve different purposes:

    1. Upstream Sentry Scopes: These are the coarse-grained permissions requested from Sentry (e.g., org:read project:write team:write event:write). This token is a server-side capability used to interact with the Sentry REST API.
    2. Downstream MCP Restrictions: This is the actual permission boundary for the client. It is composed of:
      • Granted MCP skills: The primary authorization mechanism. Tools are only exposed if their required skills are enabled in the session.
      • Resource constraints: Restrictions on specific organizations or projects (e.g., via /mcp/:org or /mcp/:org/:project paths). A token minted for a specific project cannot be used to access other projects.
      • OAuth scope: A legacy/transitional field representing the downstream grant.
  8. SSRF Protection via Region URL Validation

    main

    To prevent Server-Side Request Forgery (SSRF), the MCP server validates regionUrl parameters. A URL is only considered valid if it meets these criteria:

    1. It matches the base host (e.g., sentry.io).
    2. It is explicitly listed in the SENTRY_ALLOWED_REGION_DOMAINS allowlist (e.g., us.sentry.io, de.sentry.io).
    3. It uses the https protocol.

    Requests to unauthorized domains or non-HTTPS endpoints are rejected.

    // Example validation logic
    validateRegionUrl("https://sentry.io", "sentry.io"); // ✅ Base host match
    validateRegionUrl("https://us.sentry.io", "sentry.io"); // ✅ In allowlist
    validateRegionUrl("https://evil.com", "sentry.io"); // ❌ Not in allowlist
    validateRegionUrl("http://us.sentry.io", "sentry.io"); // ❌ Must use HTTPS
  9. Observability Architecture for Sentry MCP

    main

    The Sentry MCP project uses different Sentry SDKs depending on the execution environment to ensure proper observability:

    • Core server: Uses @sentry/core (platform-agnostic).
    • Cloudflare Workers: Uses @sentry/cloudflare.
    • Node.js stdio: Uses @sentry/node.
    • React client: Uses @sentry/react.
  10. Manage Sentry projects using Project Management Tools

    main

    Project management tools allow for the creation and updating of Sentry projects, teams, project DSNs, and project team access.

    Important Usage Note: These tools are not top-level MCP tools. They are part of a searchable catalog. To use them, you must first discover them using search_sentry_tools and then execute them using execute_sentry_tool. Access to these tools is only granted if the project-management skill is enabled.

  11. Stdio Transport Invariant: Logs MUST Go to Stderr

    main

    When running in MCP stdio mode, the stdout stream is strictly reserved for JSON-RPC frames. Writing any non-JSON-RPC data to stdout will cause the client to fail framing and close the transport.

    Critical Rules for Developers:

    • All log output must go to stderr. This includes every level and every sink that writes to a console.
    • Do not call console.log, console.info, or console.debug in code reachable from the stdio entry point. Use the provided log helpers instead.
    • Do not introduce new LogTape sinks that write to stdout.
    • Do not modify STDERR_CONSOLE_LEVEL_MAP to map any level to a non-stderr method (e.g., mapping info to console.info).
  12. How OAuth grant revocation works

    main

    The system is designed to prevent a "death spiral" where a client attempts to use a dead upstream token that has been invalidated by Sentry (e.g., via SSO or password change).

    The Revocation Flow

    1. Detection: When a tool call results in a 401 error, handleApiError re-throws an unwrapped ApiAuthenticationError.
    2. Trigger: The server.ts tool-handler catches this error and invokes context.onUpstreamUnauthorized.
    3. Invalidation: The transport layer (e.g., Cloudflare) calls env.OAUTH_PROVIDER.revokeGrant.
    4. Cleanup: Because tokens are stored in KV under token:userId:grantId:*, revoking the grant invalidates all outstanding wrapper tokens.
    5. User Experience: The formatErrorForUser function returns a clear "Authorization Expired — please re-authorize" message instead of a generic error.

    Concurrent Session Behavior

    To prevent one active session from killing all other sessions for the same user (a common issue with tools like Claude Code that persist client_id across processes), the system now allows multiple grants for the same (userId, clientId) to coexist. Each grant lives independently until its own refreshTokenTTL (30 days) expires or it is explicitly revoked.