#
tokens: 49677/50000 181/408 files (page 1/11)
lines: off (toggle) GitHub
raw markdown copy
This is page 1 of 11. Use http://codebase.md/getsentry/sentry-mcp?page={x} to view the full context.

# Directory Structure

```
├── .claude
│   ├── agents
│   │   └── claude-optimizer.md
│   ├── commands
│   │   ├── gh-pr.md
│   │   └── gh-review.md
│   └── settings.json
├── .craft.yml
├── .cursor
│   ├── mcp.json
│   └── rules
├── .env.example
├── .github
│   └── workflows
│       ├── deploy.yml
│       ├── eval.yml
│       ├── merge-jobs.yml
│       ├── release.yml
│       ├── smoke-tests.yml
│       └── test.yml
├── .gitignore
├── .mcp.json
├── .vscode
│   ├── extensions.json
│   ├── mcp.json
│   └── settings.json
├── AGENTS.md
├── bin
│   └── bump-version.sh
├── biome.json
├── CLAUDE.md
├── codecov.yml
├── core
├── docs
│   ├── adding-tools.mdc
│   ├── api-patterns.mdc
│   ├── architecture.mdc
│   ├── cloudflare
│   │   ├── architecture.md
│   │   ├── constraint-do-analysis.md
│   │   ├── deployment.md
│   │   ├── mcpagent-architecture.md
│   │   ├── oauth-architecture.md
│   │   └── overview.md
│   ├── coding-guidelines.mdc
│   ├── common-patterns.mdc
│   ├── cursor.mdc
│   ├── deployment.mdc
│   ├── error-handling.mdc
│   ├── github-actions.mdc
│   ├── llms
│   │   ├── document-scopes.mdc
│   │   ├── documentation-style-guide.mdc
│   │   └── README.md
│   ├── logging.mdc
│   ├── monitoring.mdc
│   ├── permissions-and-scopes.md
│   ├── pr-management.mdc
│   ├── quality-checks.mdc
│   ├── README.md
│   ├── search-events-api-patterns.md
│   ├── security.mdc
│   ├── specs
│   │   ├── README.md
│   │   ├── search-events.md
│   │   └── subpath-constraints.md
│   └── testing.mdc
├── LICENSE.md
├── Makefile
├── package.json
├── packages
│   ├── mcp-cloudflare
│   │   ├── .env.example
│   │   ├── components.json
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── public
│   │   │   ├── favicon.ico
│   │   │   ├── flow-transparent.png
│   │   │   └── flow.jpg
│   │   ├── src
│   │   │   ├── client
│   │   │   │   ├── app.tsx
│   │   │   │   ├── components
│   │   │   │   │   ├── chat
│   │   │   │   │   │   ├── auth-form.tsx
│   │   │   │   │   │   ├── chat-input.tsx
│   │   │   │   │   │   ├── chat-message.tsx
│   │   │   │   │   │   ├── chat-messages.tsx
│   │   │   │   │   │   ├── chat-ui.tsx
│   │   │   │   │   │   ├── chat.tsx
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── tool-invocation.tsx
│   │   │   │   │   │   └── types.ts
│   │   │   │   │   ├── fragments
│   │   │   │   │   │   ├── remote-setup.tsx
│   │   │   │   │   │   ├── setup-guide.tsx
│   │   │   │   │   │   └── stdio-setup.tsx
│   │   │   │   │   └── ui
│   │   │   │   │       ├── accordion.tsx
│   │   │   │   │       ├── backdrop.tsx
│   │   │   │   │       ├── base.tsx
│   │   │   │   │       ├── button.tsx
│   │   │   │   │       ├── code-snippet.tsx
│   │   │   │   │       ├── header.tsx
│   │   │   │   │       ├── icon.tsx
│   │   │   │   │       ├── icons
│   │   │   │   │       │   └── sentry.tsx
│   │   │   │   │       ├── interactive-markdown.tsx
│   │   │   │   │       ├── json-schema-params.tsx
│   │   │   │   │       ├── markdown.tsx
│   │   │   │   │       ├── note.tsx
│   │   │   │   │       ├── prose.tsx
│   │   │   │   │       ├── section.tsx
│   │   │   │   │       ├── slash-command-actions.tsx
│   │   │   │   │       ├── slash-command-text.tsx
│   │   │   │   │       ├── sliding-panel.tsx
│   │   │   │   │       ├── template-vars.tsx
│   │   │   │   │       ├── tool-actions.tsx
│   │   │   │   │       └── typewriter.tsx
│   │   │   │   ├── contexts
│   │   │   │   │   └── auth-context.tsx
│   │   │   │   ├── hooks
│   │   │   │   │   ├── use-mcp-metadata.ts
│   │   │   │   │   ├── use-persisted-chat.ts
│   │   │   │   │   ├── use-scroll-lock.ts
│   │   │   │   │   └── use-streaming-simulation.ts
│   │   │   │   ├── index.css
│   │   │   │   ├── instrument.ts
│   │   │   │   ├── lib
│   │   │   │   │   └── utils.ts
│   │   │   │   ├── main.tsx
│   │   │   │   ├── pages
│   │   │   │   │   └── home.tsx
│   │   │   │   ├── utils
│   │   │   │   │   ├── chat-error-handler.ts
│   │   │   │   │   └── index.ts
│   │   │   │   └── vite-env.d.ts
│   │   │   ├── constants.ts
│   │   │   ├── server
│   │   │   │   ├── app.test.ts
│   │   │   │   ├── app.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── lib
│   │   │   │   │   ├── approval-dialog.test.ts
│   │   │   │   │   ├── approval-dialog.ts
│   │   │   │   │   ├── constraint-utils.test.ts
│   │   │   │   │   ├── constraint-utils.ts
│   │   │   │   │   ├── html-utils.ts
│   │   │   │   │   ├── mcp-agent.ts
│   │   │   │   │   ├── slug-validation.test.ts
│   │   │   │   │   └── slug-validation.ts
│   │   │   │   ├── logging.ts
│   │   │   │   ├── oauth
│   │   │   │   │   ├── authorize.test.ts
│   │   │   │   │   ├── callback.test.ts
│   │   │   │   │   ├── constants.ts
│   │   │   │   │   ├── helpers.test.ts
│   │   │   │   │   ├── helpers.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── routes
│   │   │   │   │   │   ├── authorize.ts
│   │   │   │   │   │   ├── callback.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── state.ts
│   │   │   │   ├── routes
│   │   │   │   │   ├── chat-oauth.ts
│   │   │   │   │   ├── chat.ts
│   │   │   │   │   ├── mcp.ts
│   │   │   │   │   ├── metadata.ts
│   │   │   │   │   ├── search.test.ts
│   │   │   │   │   └── search.ts
│   │   │   │   ├── sentry.config.ts
│   │   │   │   ├── types
│   │   │   │   │   └── chat.ts
│   │   │   │   ├── types.ts
│   │   │   │   └── utils
│   │   │   │       └── auth-errors.ts
│   │   │   └── test-setup.ts
│   │   ├── tsconfig.client.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   ├── tsconfig.server.json
│   │   ├── vite.config.ts
│   │   ├── vitest.config.ts
│   │   ├── worker-configuration.d.ts
│   │   ├── wrangler.canary.jsonc
│   │   └── wrangler.jsonc
│   ├── mcp-server
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── scripts
│   │   │   ├── generate-definitions.ts
│   │   │   └── generate-otel-namespaces.ts
│   │   ├── src
│   │   │   ├── api-client
│   │   │   │   ├── client.test.ts
│   │   │   │   ├── client.ts
│   │   │   │   ├── errors.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── schema.ts
│   │   │   │   └── types.ts
│   │   │   ├── cli
│   │   │   │   ├── parse.test.ts
│   │   │   │   ├── parse.ts
│   │   │   │   ├── resolve.test.ts
│   │   │   │   ├── resolve.ts
│   │   │   │   ├── types.ts
│   │   │   │   └── usage.ts
│   │   │   ├── constants.ts
│   │   │   ├── errors.test.ts
│   │   │   ├── errors.ts
│   │   │   ├── index.ts
│   │   │   ├── internal
│   │   │   │   ├── agents
│   │   │   │   │   ├── callEmbeddedAgent.ts
│   │   │   │   │   ├── openai-provider.ts
│   │   │   │   │   └── tools
│   │   │   │   │       ├── data
│   │   │   │   │       │   ├── __namespaces.json
│   │   │   │   │       │   ├── android.json
│   │   │   │   │       │   ├── app.json
│   │   │   │   │       │   ├── artifact.json
│   │   │   │   │       │   ├── aspnetcore.json
│   │   │   │   │       │   ├── aws.json
│   │   │   │   │       │   ├── azure.json
│   │   │   │   │       │   ├── browser.json
│   │   │   │   │       │   ├── cassandra.json
│   │   │   │   │       │   ├── cicd.json
│   │   │   │   │       │   ├── CLAUDE.md
│   │   │   │   │       │   ├── client.json
│   │   │   │   │       │   ├── cloud.json
│   │   │   │   │       │   ├── cloudevents.json
│   │   │   │   │       │   ├── cloudfoundry.json
│   │   │   │   │       │   ├── code.json
│   │   │   │   │       │   ├── container.json
│   │   │   │   │       │   ├── cpu.json
│   │   │   │   │       │   ├── cpython.json
│   │   │   │   │       │   ├── database.json
│   │   │   │   │       │   ├── db.json
│   │   │   │   │       │   ├── deployment.json
│   │   │   │   │       │   ├── destination.json
│   │   │   │   │       │   ├── device.json
│   │   │   │   │       │   ├── disk.json
│   │   │   │   │       │   ├── dns.json
│   │   │   │   │       │   ├── dotnet.json
│   │   │   │   │       │   ├── elasticsearch.json
│   │   │   │   │       │   ├── enduser.json
│   │   │   │   │       │   ├── error.json
│   │   │   │   │       │   ├── faas.json
│   │   │   │   │       │   ├── feature_flags.json
│   │   │   │   │       │   ├── file.json
│   │   │   │   │       │   ├── gcp.json
│   │   │   │   │       │   ├── gen_ai.json
│   │   │   │   │       │   ├── geo.json
│   │   │   │   │       │   ├── go.json
│   │   │   │   │       │   ├── graphql.json
│   │   │   │   │       │   ├── hardware.json
│   │   │   │   │       │   ├── heroku.json
│   │   │   │   │       │   ├── host.json
│   │   │   │   │       │   ├── http.json
│   │   │   │   │       │   ├── ios.json
│   │   │   │   │       │   ├── jvm.json
│   │   │   │   │       │   ├── k8s.json
│   │   │   │   │       │   ├── linux.json
│   │   │   │   │       │   ├── log.json
│   │   │   │   │       │   ├── mcp.json
│   │   │   │   │       │   ├── messaging.json
│   │   │   │   │       │   ├── network.json
│   │   │   │   │       │   ├── nodejs.json
│   │   │   │   │       │   ├── oci.json
│   │   │   │   │       │   ├── opentracing.json
│   │   │   │   │       │   ├── os.json
│   │   │   │   │       │   ├── otel.json
│   │   │   │   │       │   ├── peer.json
│   │   │   │   │       │   ├── process.json
│   │   │   │   │       │   ├── profile.json
│   │   │   │   │       │   ├── rpc.json
│   │   │   │   │       │   ├── server.json
│   │   │   │   │       │   ├── service.json
│   │   │   │   │       │   ├── session.json
│   │   │   │   │       │   ├── signalr.json
│   │   │   │   │       │   ├── source.json
│   │   │   │   │       │   ├── system.json
│   │   │   │   │       │   ├── telemetry.json
│   │   │   │   │       │   ├── test.json
│   │   │   │   │       │   ├── thread.json
│   │   │   │   │       │   ├── tls.json
│   │   │   │   │       │   ├── url.json
│   │   │   │   │       │   ├── user.json
│   │   │   │   │       │   ├── v8js.json
│   │   │   │   │       │   ├── vcs.json
│   │   │   │   │       │   ├── webengine.json
│   │   │   │   │       │   └── zos.json
│   │   │   │   │       ├── dataset-fields.test.ts
│   │   │   │   │       ├── dataset-fields.ts
│   │   │   │   │       ├── otel-semantics.test.ts
│   │   │   │   │       ├── otel-semantics.ts
│   │   │   │   │       ├── utils.ts
│   │   │   │   │       ├── whoami.test.ts
│   │   │   │   │       └── whoami.ts
│   │   │   │   ├── constraint-helpers.test.ts
│   │   │   │   ├── constraint-helpers.ts
│   │   │   │   ├── error-handling.ts
│   │   │   │   ├── fetch-utils.test.ts
│   │   │   │   ├── fetch-utils.ts
│   │   │   │   ├── formatting.test.ts
│   │   │   │   ├── formatting.ts
│   │   │   │   ├── issue-helpers.test.ts
│   │   │   │   ├── issue-helpers.ts
│   │   │   │   ├── test-fixtures.ts
│   │   │   │   └── tool-helpers
│   │   │   │       ├── api.test.ts
│   │   │   │       ├── api.ts
│   │   │   │       ├── define.ts
│   │   │   │       ├── enhance-error.ts
│   │   │   │       ├── formatting.ts
│   │   │   │       ├── issue.ts
│   │   │   │       ├── seer.test.ts
│   │   │   │       ├── seer.ts
│   │   │   │       ├── validate-region-url.test.ts
│   │   │   │       └── validate-region-url.ts
│   │   │   ├── permissions.parseScopes.test.ts
│   │   │   ├── permissions.ts
│   │   │   ├── schema.ts
│   │   │   ├── server.ts
│   │   │   ├── telem
│   │   │   │   ├── index.ts
│   │   │   │   ├── logging.ts
│   │   │   │   ├── sentry.test.ts
│   │   │   │   └── sentry.ts
│   │   │   ├── test-setup.ts
│   │   │   ├── test-utils
│   │   │   │   └── context.ts
│   │   │   ├── toolDefinitions.ts
│   │   │   ├── tools
│   │   │   │   ├── analyze-issue-with-seer.test.ts
│   │   │   │   ├── analyze-issue-with-seer.ts
│   │   │   │   ├── create-dsn.test.ts
│   │   │   │   ├── create-dsn.ts
│   │   │   │   ├── create-project.test.ts
│   │   │   │   ├── create-project.ts
│   │   │   │   ├── create-team.test.ts
│   │   │   │   ├── create-team.ts
│   │   │   │   ├── find-dsns.test.ts
│   │   │   │   ├── find-dsns.ts
│   │   │   │   ├── find-organizations.test.ts
│   │   │   │   ├── find-organizations.ts
│   │   │   │   ├── find-projects.test.ts
│   │   │   │   ├── find-projects.ts
│   │   │   │   ├── find-releases.test.ts
│   │   │   │   ├── find-releases.ts
│   │   │   │   ├── find-teams.test.ts
│   │   │   │   ├── find-teams.ts
│   │   │   │   ├── get-doc.test.ts
│   │   │   │   ├── get-doc.ts
│   │   │   │   ├── get-event-attachment.test.ts
│   │   │   │   ├── get-event-attachment.ts
│   │   │   │   ├── get-issue-details.test.ts
│   │   │   │   ├── get-issue-details.ts
│   │   │   │   ├── get-trace-details.test.ts
│   │   │   │   ├── get-trace-details.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── search-docs.test.ts
│   │   │   │   ├── search-docs.ts
│   │   │   │   ├── search-events
│   │   │   │   │   ├── agent.ts
│   │   │   │   │   ├── CLAUDE.md
│   │   │   │   │   ├── config.ts
│   │   │   │   │   ├── formatters.ts
│   │   │   │   │   ├── handler.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── utils.test.ts
│   │   │   │   │   └── utils.ts
│   │   │   │   ├── search-events.test.ts
│   │   │   │   ├── search-issues
│   │   │   │   │   ├── agent.ts
│   │   │   │   │   ├── CLAUDE.md
│   │   │   │   │   ├── config.ts
│   │   │   │   │   ├── formatters.ts
│   │   │   │   │   ├── handler.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── README.md
│   │   │   │   ├── tools.test.ts
│   │   │   │   ├── types.ts
│   │   │   │   ├── update-issue.test.ts
│   │   │   │   ├── update-issue.ts
│   │   │   │   ├── update-project.test.ts
│   │   │   │   ├── update-project.ts
│   │   │   │   ├── whoami.test.ts
│   │   │   │   └── whoami.ts
│   │   │   ├── transports
│   │   │   │   └── stdio.ts
│   │   │   ├── types.ts
│   │   │   ├── utils
│   │   │   │   ├── slug-validation.test.ts
│   │   │   │   ├── slug-validation.ts
│   │   │   │   ├── url-utils.test.ts
│   │   │   │   └── url-utils.ts
│   │   │   └── version.ts
│   │   ├── tsconfig.json
│   │   ├── tsdown.config.ts
│   │   └── vitest.config.ts
│   ├── mcp-server-evals
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── bin
│   │   │   │   └── start-mock-stdio.ts
│   │   │   ├── evals
│   │   │   │   ├── autofix.eval.ts
│   │   │   │   ├── create-dsn.eval.ts
│   │   │   │   ├── create-project.eval.ts
│   │   │   │   ├── create-team.eval.ts
│   │   │   │   ├── get-issue.eval.ts
│   │   │   │   ├── get-trace-details.eval.ts
│   │   │   │   ├── list-dsns.eval.ts
│   │   │   │   ├── list-issues.eval.ts
│   │   │   │   ├── list-organizations.eval.ts
│   │   │   │   ├── list-projects.eval.ts
│   │   │   │   ├── list-releases.eval.ts
│   │   │   │   ├── list-tags.eval.ts
│   │   │   │   ├── list-teams.eval.ts
│   │   │   │   ├── search-docs.eval.ts
│   │   │   │   ├── search-events-agent.eval.ts
│   │   │   │   ├── search-events.eval.ts
│   │   │   │   ├── search-issues-agent.eval.ts
│   │   │   │   ├── search-issues.eval.ts
│   │   │   │   ├── update-issue.eval.ts
│   │   │   │   ├── update-project.eval.ts
│   │   │   │   └── utils
│   │   │   │       ├── fixtures.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── runner.ts
│   │   │   │       ├── structuredOutputScorer.ts
│   │   │   │       └── toolPredictionScorer.ts
│   │   │   └── setup-env.ts
│   │   ├── tsconfig.json
│   │   └── vitest.config.ts
│   ├── mcp-server-mocks
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── fixtures
│   │   │   │   ├── autofix-state.json
│   │   │   │   ├── event-attachments.json
│   │   │   │   ├── event.json
│   │   │   │   ├── issue.json
│   │   │   │   ├── performance-event.json
│   │   │   │   ├── project.json
│   │   │   │   ├── tags.json
│   │   │   │   ├── team.json
│   │   │   │   ├── trace-event.json
│   │   │   │   ├── trace-items-attributes-logs-number.json
│   │   │   │   ├── trace-items-attributes-logs-string.json
│   │   │   │   ├── trace-items-attributes-spans-number.json
│   │   │   │   ├── trace-items-attributes-spans-string.json
│   │   │   │   ├── trace-items-attributes.json
│   │   │   │   ├── trace-meta-with-nulls.json
│   │   │   │   ├── trace-meta.json
│   │   │   │   ├── trace-mixed.json
│   │   │   │   └── trace.json
│   │   │   ├── index.ts
│   │   │   └── utils.ts
│   │   ├── tsconfig.json
│   │   └── tsdown.config.ts
│   ├── mcp-server-tsconfig
│   │   ├── package.json
│   │   ├── tsconfig.base.json
│   │   └── tsconfig.vite.json
│   ├── mcp-test-client
│   │   ├── .env.test
│   │   ├── .gitignore
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── agent.ts
│   │   │   ├── auth
│   │   │   │   ├── config.ts
│   │   │   │   └── oauth.ts
│   │   │   ├── constants.ts
│   │   │   ├── index.ts
│   │   │   ├── logger.test.ts
│   │   │   ├── logger.ts
│   │   │   ├── mcp-test-client-remote.ts
│   │   │   ├── mcp-test-client.ts
│   │   │   ├── types.ts
│   │   │   └── version.ts
│   │   ├── tsconfig.json
│   │   ├── tsdown.config.ts
│   │   └── vitest.config.ts
│   └── smoke-tests
│       ├── package.json
│       ├── src
│       │   └── smoke.test.ts
│       └── vitest.config.ts
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── README.md
├── scripts
│   └── check-doc-links.mjs
├── turbo.json
└── vitest.workspace.ts
```

# Files

--------------------------------------------------------------------------------
/.craft.yml:
--------------------------------------------------------------------------------

```yaml
changelogPolicy: none
preReleaseCommand: bash bin/bump-version.sh
targets:
  - name: github
  - name: npm
    id: "@sentry/mcp-server"
    includeNames: /^sentry-mcp-server-\d.*\.tgz$/

```

--------------------------------------------------------------------------------
/packages/mcp-test-client/.env.test:
--------------------------------------------------------------------------------

```
# Test environment file
# Copy this to .env and fill in your actual values

# Dummy values for testing - will fail but show the flow
ANTHROPIC_API_KEY=test-key
SENTRY_ACCESS_TOKEN=test-token
SENTRY_HOST=sentry.io

```

--------------------------------------------------------------------------------
/packages/mcp-test-client/.gitignore:
--------------------------------------------------------------------------------

```
# Dependencies
node_modules/

# Build output
dist/
*.tsbuildinfo

# Environment files
.env
.env.local

# IDE
.idea/
.vscode/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db

# Logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*

# Testing
coverage/
*.junit.xml
```

--------------------------------------------------------------------------------
/.mcp.json:
--------------------------------------------------------------------------------

```json
{
  "mcpServers": {
    "sentry": {
      "type": "http",
      "url": "https://mcp.sentry.dev/mcp/sentry/mcp-server"
    },
    "sentry-dev": {
      "type": "http",
      "url": "http://localhost:5173/mcp/sentry/mcp-server"
    },
    "sentry-spotlight": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@spotlightjs/spotlight", "--stdio-mcp"],
      "env": {}
    }
  }
}

```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# Logs

logs
_.log
npm-debug.log_
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)

report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json

# Runtime data

pids
_.pid
_.seed
*.pid.lock

# Dependency directories

node_modules/
jspm_packages/
.npm
.node_repl_history
*.tgz
.cache
dist
.turbo/
*.tsbuildinfo
.DS_Store

# dotenv environment variable files

.env
.env.development.local
.env.test.local
.env.production.local
.env.local

.vscode-test

.yarn-integrity
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.\*

# wrangler project

.dev.vars
.wrangler/
wrangler.log

*.junit.xml
coverage
*.lcov

# Sentry Config File
.env.sentry-build-plugin

# Generated files
packages/mcp-server/src/toolDefinitions.json

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/.env.example:
--------------------------------------------------------------------------------

```
# Sentry OAuth Application Credentials
# Create an OAuth app at: https://sentry.io/settings/account/api/applications/
# - Homepage URL: http://localhost:5173 (for local dev)
# - Authorized Redirect URIs: http://localhost:5173/oauth/callback (for local dev)
SENTRY_CLIENT_ID=

# Client Secret from your Sentry OAuth application
# Generate this when creating your OAuth app in Sentry
SENTRY_CLIENT_SECRET=

# Cookie encryption secret for session management
# Generate a random string (32+ characters recommended)
# Example: openssl rand -base64 32
COOKIE_SECRET=thisisasecret

# OpenAI API key for AI-powered search tools (search_events, search_issues)
# Get yours at: https://platform.openai.com/api-keys
# Required for natural language query translation features
OPENAI_API_KEY=sk-proj-generate-this

# The URL where your MCP server is hosted
# Local development: http://localhost:5173
# Production: Your deployed URL (e.g., https://your-app.pages.dev)
MCP_HOST=http://localhost:5173

# Enable Spotlight
SENTRY_SPOTLIGHT=1

```

--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------

```
# Root Environment Configuration
# This file provides default environment variables for all packages.
# Individual packages can override these values with their own .env files.

# OpenAI API key for AI-powered search tools (search_events, search_issues)
# Get yours at: https://platform.openai.com/api-keys
# Required for natural language query translation features
OPENAI_API_KEY=sk-proj-agenerate-this

# For mcp-test-client: Anthropic API key for Claude access
# ANTHROPIC_API_KEY=your_anthropic_api_key

# For mcp-test-client: Sentry access token (for stdio transport)
# Get one from: https://sentry.io/settings/account/api/auth-tokens/
# SENTRY_ACCESS_TOKEN=your_sentry_access_token

# Sentry Spotlight - development environment tool for local debugging
# Set to 1 to enable Spotlight integration (recommended for development)
# Learn more: https://spotlightjs.com
SENTRY_SPOTLIGHT=1

# IMPORTANT: For local development, you also need to create:
# - packages/mcp-cloudflare/.env - OAuth configuration (required for authentication)
#   Copy packages/mcp-cloudflare/.env.example to .env and fill in your OAuth credentials

```

--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------

```markdown
# Contributor Docs

This directory contains contributor documentation used by humans and LLMs. To avoid duplication, the canonical documentation map and contributor workflow live in `CLAUDE.md` (also available as `AGENTS.md`).

## Purpose

- Central home for all contributor-focused docs (.mdc files)
- Consumed by tools (e.g., Cursor) via direct file references

## Start Here

- Doc map and workflow: see `CLAUDE.md` / `AGENTS.md`
- Per-topic guides live in this folder (e.g., `adding-tools.mdc`)

## Integration with Tools

- Cursor IDE: this folder is referenced directly as contextual rules
- Other AI tools: reference specific `.mdc` files as needed

## LLM-Specific

- Meta-docs live under `llms/` (e.g., `llms/document-scopes.mdc`)

## Maintenance

Update docs when patterns change, new tools are added, or common issues arise. Keep the index in `CLAUDE.md` authoritative; avoid mirroring it here.

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/README.md:
--------------------------------------------------------------------------------

```markdown
# @sentry/mcp-server-evals

Evaluation helpers and a local mock stdio runner used when developing and validating the Sentry MCP server.

## Mock stdio runner

- Command: `pnpm --filter @sentry/mcp-server-evals start`
- Entry: `src/bin/start-mock-stdio.ts`
- Purpose: Boots the MCP server in-process with MSW mocks enabled for deterministic evals.

### Scopes policy

The mock stdio script grants only the high-level admin scopes that imply all lower permissions via the hierarchy defined in `packages/mcp-server/src/permissions.ts`:

- `org:admin`, `project:admin`, `team:admin`, `member:admin`, `event:admin`
- Plus special non-hierarchical scope: `project:releases`

This keeps permissions minimal and readable while still enabling every tool in eval runs. Avoid enumerating every read/write scope explicitly — rely on the hierarchy to expand implied permissions.

### Notes

- No API keys are logged; MSW handles Sentry API mocking.
- For code changes, ensure `pnpm run tsc && pnpm run lint && pnpm run test` all pass.
- See `docs/adding-tools.mdc` and `docs/testing.mdc` for contribution guidance.

```

--------------------------------------------------------------------------------
/docs/llms/README.md:
--------------------------------------------------------------------------------

```markdown
# LLM-Specific Documentation

This directory contains meta-documentation specifically for LLMs working with the Sentry MCP codebase.

## Contents

### documentation-style-guide.mdc
Guidelines for writing effective documentation that LLMs can consume efficiently. Defines principles like assuming intelligence, being concise, and showing rather than telling.

### document-scopes.mdc  
Defines the specific purpose, content requirements, and line count targets for each documentation file. Helps maintain focus and prevent scope creep.

### documentation-todos.mdc
Specific tasks for improving each document based on the style guide and scope definitions. Tracks the documentation refactoring effort.

## Purpose

These documents help ensure that:
- Documentation remains concise and focused
- LLMs get project-specific information, not general programming knowledge  
- Redundancy is minimized through proper cross-referencing
- Each document has a clear, defined purpose

## For Human Contributors

While these documents are designed for LLM consumption, they also serve as excellent guidelines for human contributors who want to understand:
- How to write documentation for this project
- What belongs in each document
- How to maintain consistency across docs
```

--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/search-issues/README.md:
--------------------------------------------------------------------------------

```markdown
# Search Issues Agent

AI-powered natural language to Sentry issue search translation.

## Overview

The `search_issues` tool uses an embedded AI agent to translate natural language queries into Sentry issue search syntax. It provides intelligent searching for grouped issues/problems rather than individual events.

## Architecture

- **Handler**: `handler.ts` - MCP tool definition and orchestration
- **Agent**: `agent.ts` - AI translation logic
- **Config**: `config.ts` - System prompts and settings
- **Formatters**: `formatters.ts` - Result formatting

## Agent Tools

The AI agent has access to these shared agent tools from `../../agent-tools/`:

1. **issueFields**: Discovers available fields for issue searches using `dataset="search_issues"`
2. **whoami**: Gets current user information to resolve 'me' references

## Natural Language Examples

- "critical bugs from last week" → `level:error is:unresolved lastSeen:-7d`
- "issues assigned to me" → Uses whoami tool → `assignedOrSuggested:[email protected]`
- "affecting 100+ users" → `userCount:>100`
- "production errors" → `environment:production level:error`

## Features

- ✅ Natural language query translation
- ✅ Error feedback loop for self-correction
- ✅ 'Me' reference resolution via whoami tool
- ✅ Field discovery with custom tags
- ✅ Smart sort options (date, freq, new, user)
- ✅ Configurable result limits (1-100, default 10)
- ✅ Project-specific and organization-wide searches

## Usage

```typescript
search_issues({
  organizationSlug: "my-org",
  naturalLanguageQuery: "critical bugs from last week",
  limit: 25,
  includeExplanation: true
})
```
```

--------------------------------------------------------------------------------
/docs/specs/README.md:
--------------------------------------------------------------------------------

```markdown
# Feature Specifications

This directory contains detailed specifications for features in the Sentry MCP server. Each feature has its own subdirectory with related design documents, technical specifications, and implementation guides.


## Purpose

Feature specifications serve to:

1. **Document Design Decisions**: Capture the reasoning behind architectural choices
2. **Define Interfaces**: Specify tool inputs, outputs, and behavior
3. **Guide Implementation**: Provide clear direction for developers
4. **Enable Review**: Allow stakeholders to review and provide feedback
5. **Preserve Knowledge**: Maintain historical context for future reference

## Creating New Specifications

When adding a new feature specification:

1. Create a new directory under `specs/` with a descriptive name
2. Create a **single, concise README.md file** that covers:
   - Problem statement and motivation
   - High-level design approach
   - Interface definitions (with code examples)
   - Key constraints and requirements
   - Migration/compatibility concerns
3. Update this README with a brief description
4. Link to the spec from relevant documentation

**Important Guidelines**:
- Keep specs in a single file (README.md)
- Focus on WHAT and WHY, not HOW
- Include code examples for interfaces and usage
- Document constraints and meta concerns
- Avoid implementation details (no function internals, prompts, etc.)
- Think "contract" not "blueprint"

## Current Specifications

### search-events
A unified event search tool that uses OpenAI GPT-4o to translate natural language queries into Sentry's search syntax. Replaced the separate `find_errors` and `find_transactions` tools with a single, more powerful interface.

- **Status**: ✅ Complete
- **Key Benefits**: Reduces tool count (20→19), improves UX, accessible to non-technical users

## Specification Template

For consistency, new specifications should include:

1. **Overview**: Problem statement and proposed solution
2. **Motivation**: Why this feature is needed
3. **Design**: Technical architecture and approach
4. **Interface**: API/tool definitions
5. **Examples**: Usage scenarios and expected behavior
6. **Implementation**: Step-by-step plan (NO time estimates)
7. **Testing**: Validation strategy
8. **Migration**: If replacing existing functionality
9. **Future Work**: Potential enhancements

**Important**: Do NOT include time windows, deadlines, or duration estimates in specifications. Implementation timing is determined by agents and project priorities, not by the spec.

## Review Process

1. Create specification documents in a feature branch
2. Open PR for review by team members
3. Address feedback and iterate
4. Merge once consensus is reached
5. Update status as implementation progresses
```

--------------------------------------------------------------------------------
/packages/mcp-server/README.md:
--------------------------------------------------------------------------------

```markdown
# sentry-mcp

This is a prototype of an MCP server, acting as a middleware to the upstream Sentry API provider.

This package is primarily for running the `stdio` MCP server. If you do not know what that is, or do not need it, we suggest using the public remote service:

<https://mcp.sentry.dev>

**Note:** Some tools require additional configuration:
- **AI-powered search tools** (`search_events` and `search_issues`): These tools use OpenAI to translate natural language queries into Sentry's query syntax. They require an `OPENAI_API_KEY` environment variable. Without this key, these specific tools will be unavailable, but all other tools will function normally.

## Permissions and Scopes

By default, the MCP server runs with **read-only access** to your Sentry data:
- `org:read`, `project:read`, `team:read`, `event:read`

### Customizing Permissions

You can customize permissions using two different approaches:

- **`--scopes`**: **Override** the default scopes completely (replaces all defaults)
- **`--add-scopes`**: **Add** scopes to the default read-only set (keeps defaults and adds more)

To utilize the `stdio` transport, you'll need to create an User Auth Token in Sentry. The token must have at least read access, but you can grant additional permissions as needed.

### Examples

```shell
# Default read-only access (SaaS)
npx @sentry/mcp-server@latest --access-token=sentry-user-token

# Override with specific scopes only (removes defaults)
npx @sentry/mcp-server@latest --access-token=TOKEN --scopes=org:read,event:read

# Add write permissions to defaults (keeps all defaults)
npx @sentry/mcp-server@latest --access-token=TOKEN --add-scopes=event:write,project:write

# Point at a self-hosted deployment
npx @sentry/mcp-server@latest --access-token=sentry-user-token --host=sentry.example.com

# Override the OpenAI API endpoint for embedded agents (stdio only)
npx @sentry/mcp-server@latest --access-token=TOKEN --openai-base-url=https://proxy.example.com/v1
```

### Environment Variables

You can also use environment variables:

```shell
SENTRY_ACCESS_TOKEN=your-token
# Optional overrides. Leave unset to use the default SaaS host
SENTRY_HOST=sentry.example.com
MCP_SCOPES=org:read,event:read     # Override default scopes (replaces defaults)
MCP_ADD_SCOPES=event:write         # Add to default scopes (keeps defaults)
OPENAI_API_KEY=your-openai-key     # Required for AI-powered search tools (search_events, search_issues)
# No environment variable exists for the OpenAI base URL override; use --openai-base-url instead.
# This restriction prevents unexpected environment overrides that could silently reroute requests to a
# malicious proxy capable of harvesting the OpenAI API key provided at runtime.
```

If `SENTRY_HOST` is not provided, the CLI automatically targets the Sentry SaaS
endpoint.

Configure this variable only when you operate a self-hosted Sentry deployment;
it is not needed for Sentry SaaS.

**Important:** The `MCP_SCOPES` environment variable or `--scopes` flag completely replaces the default scopes. Use `MCP_ADD_SCOPES` or `--add-scopes` if you want to keep the default read-only permissions and add additional ones.

The host configuration accepts two distinct formats:

- **`SENTRY_HOST`**: Hostname only (no protocol)
  - Examples: `sentry.example.com`, `sentry.internal.example.com`, `localhost:8000`

**Note**: Only HTTPS connections are supported for security reasons.

By default we also enable Sentry reporting (traces, errors) upstream to our cloud service. You can disable that, or send it to a different Sentry instance by using the `--sentry-dsn` flag:

```shell
# disable sentry reporting
npx @sentry/mcp-server@latest --sentry-dsn=

# use custom sentry instance
npx @sentry/mcp-server@latest --sentry-dsn=https://[email protected]/...
```

```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
# sentry-mcp

[![codecov](https://codecov.io/gh/getsentry/sentry-mcp/graph/badge.svg?token=khVKvJP5Ig)](https://codecov.io/gh/getsentry/sentry-mcp)

Sentry's MCP service is primarily designed for human-in-the-loop coding agents. Our tool selection and priorities are focused on developer workflows and debugging use cases, rather than providing a general-purpose MCP server for all Sentry functionality.

This remote MCP server acts as middleware to the upstream Sentry API, optimized for coding assistants like Cursor, Claude Code, and similar development tools. It's based on [Cloudflare's work towards remote MCPs](https://blog.cloudflare.com/remote-model-context-protocol-servers-mcp/).

## Getting Started

You'll find everything you need to know by visiting the deployed service in production:

<https://mcp.sentry.dev>

If you're looking to contribute, learn how it works, or to run this for self-hosted Sentry, continue below.

### Stdio vs Remote

While this repository is focused on acting as an MCP service, we also support a `stdio` transport. This is still a work in progress, but is the easiest way to adapt run the MCP against a self-hosted Sentry install.

**Note:** The AI-powered search tools (`search_events` and `search_issues`) require an OpenAI API key. These tools use natural language processing to translate queries into Sentry's query syntax. Without the API key, these specific tools will be unavailable, but all other tools will function normally.

To utilize the `stdio` transport, you'll need to create an User Auth Token in Sentry with the necessary scopes. As of writing this is:

```
org:read
project:read
project:write
team:read
team:write
event:write
```

Launch the transport:

```shell
npx @sentry/mcp-server@latest --access-token=sentry-user-token
```

Need to connect to a self-hosted deployment? Add <code>--host</code> (hostname
only, e.g. <code>--host=sentry.example.com</code>) when you run the command.

Note: You can also use environment variables:

```shell
SENTRY_ACCESS_TOKEN=
# Optional overrides for self-hosted deployments
SENTRY_HOST=
OPENAI_API_KEY=  # Required for AI-powered search tools (search_events, search_issues)
```

If you leave the host variable unset, the CLI automatically targets the Sentry
SaaS service. Only set the override when you operate self-hosted Sentry.

### MCP Inspector

MCP includes an [Inspector](https://modelcontextprotocol.io/docs/tools/inspector), to easily test the service:

```shell
pnpm inspector
```

Enter the MCP server URL (<http://localhost:5173>) and hit connect. This should trigger the authentication flow for you.

Note: If you have issues with your OAuth flow when accessing the inspector on `127.0.0.1`, try using `localhost` instead by visiting `http://localhost:6274`.

## Local Development

To contribute changes, you'll need to set up your local environment:

1. **Set up environment files:**

   ```shell
   make setup-env  # Creates both .env files from examples
   ```

2. **Create an OAuth App in Sentry** (Settings => API => [Applications](https://sentry.io/settings/account/api/applications/)):

   - Homepage URL: `http://localhost:5173`
   - Authorized Redirect URIs: `http://localhost:5173/oauth/callback`
   - Note your Client ID and generate a Client secret

3. **Configure your credentials:**

   - Edit `.env` in the root directory and add your `OPENAI_API_KEY`
   - Edit `packages/mcp-cloudflare/.env` and add:
     - `SENTRY_CLIENT_ID=your_development_sentry_client_id`
     - `SENTRY_CLIENT_SECRET=your_development_sentry_client_secret`
     - `COOKIE_SECRET=my-super-secret-cookie`

4. **Start the development server:**

   ```shell
   pnpm dev
   ```

### Verify

Run the server locally to make it available at `http://localhost:5173`

```shell
pnpm dev
```

To test the local server, enter `http://localhost:5173/mcp` into Inspector and hit connect. Once you follow the prompts, you'll be able to "List Tools".

### Tests

There are two test suites included: basic unit tests, and some evaluations.

Unit tests can be run using:

```shell
pnpm test
```

Evals will require a `.env` file in the project root with some config:

```shell
# .env (in project root)
OPENAI_API_KEY=  # Also required for AI-powered search tools in production
```

Note: The root `.env` file provides defaults for all packages. Individual packages can have their own `.env` files to override these defaults during development.

Once that's done you can run them using:

```shell
pnpm eval
```

## Development Notes

### Automated Code Review

This repository uses automated code review tools (like Cursor BugBot) to help identify potential issues in pull requests. These tools provide helpful feedback and suggestions, but **we do not recommend making these checks required** as the accuracy is still evolving and can produce false positives.

The automated reviews should be treated as:

- ✅ **Helpful suggestions** to consider during code review
- ✅ **Starting points** for discussion and improvement
- ❌ **Not blocking requirements** for merging PRs
- ❌ **Not replacements** for human code review

When addressing automated feedback, focus on the underlying concerns rather than strictly following every suggestion.

### Contributor Documentation

Looking to contribute or explore the full documentation map? See `CLAUDE.md` (also available as `AGENTS.md`) for contributor workflows and the complete docs index. The `docs/` folder contains the per-topic guides and tool-integrated `.mdc` files.

```

--------------------------------------------------------------------------------
/packages/mcp-test-client/README.md:
--------------------------------------------------------------------------------

```markdown
# MCP Client CLI

A simple CLI tool to test the Sentry MCP server using stdio transport with an AI agent powered by Vercel's AI SDK.

## Features

- 🤖 AI-powered interaction with Sentry MCP tools using GPT-4
- 🔧 Full access to all MCP server tools
- 💬 Interactive mode by default when no prompt provided
- 🎨 Colorized output for better readability
- 🔄 Streaming responses for real-time feedback
- 🌐 Remote MCP server support via HTTP streaming (with OAuth)
- 🏠 Local stdio transport for development

## Prerequisites

- Node.js >= 20
- pnpm package manager
- OpenAI API key
- Sentry access token with appropriate permissions

## Installation

From the package directory:

```bash
pnpm install
pnpm build
```

## Configuration

The MCP client supports multiple transport methods and authentication:

### 1. OAuth Authentication (Recommended for Remote Mode)

When using remote mode (default), the MCP client can authenticate via OAuth 2.1 with the MCP server:

```bash
# The client will automatically prompt for OAuth if no token is provided
pnpm mcp-test-client

# Or specify a custom MCP server
pnpm mcp-test-client --mcp-host http://localhost:8787
```

The OAuth flow uses PKCE (Proof Key for Code Exchange) and doesn't require a client secret, making it secure for CLI applications.

### 2. Environment Variables

Create a `.env` file in the package directory:

```env
# Required
OPENAI_API_KEY=your_openai_api_key

# Required - Sentry access token with appropriate permissions
SENTRY_ACCESS_TOKEN=your_sentry_access_token

# Optional (self-hosted only)
# Leave unset to target the SaaS host
SENTRY_HOST=sentry.example.com  # Hostname only
MCP_URL=https://mcp.sentry.dev  # MCP server host (defaults to production)
MCP_MODEL=gpt-4o  # Override default model (GPT-4)

# Optional - Error tracking
SENTRY_DSN=your_sentry_dsn  # Error tracking for the client itself

# OAuth clients are automatically registered via Dynamic Client Registration (RFC 7591)
# No manual client ID configuration needed
```

### 3. Command Line Flags

```bash
pnpm mcp-test-client --access-token=your_token "Your prompt"
```

### Token Priority

The client automatically determines the connection mode:

**Local Mode (stdio transport)**: Used when an access token is provided via:

1. Command-line flag (`--access-token`)
2. Environment variable (`SENTRY_ACCESS_TOKEN`)
3. `.env` file

**Remote Mode (HTTP streaming)**: Used when no access token is provided, prompts for OAuth authentication

### Required Sentry Permissions

Your Sentry access token needs the following scopes:

- `org:read`
- `project:read`
- `project:write`
- `team:read`
- `team:write`
- `event:write`

## Usage

### Remote Mode (Default)

Connect to the remote MCP server via HTTP streaming (uses OAuth for authentication):

```bash
# Connect to production MCP server (uses /mcp endpoint)
pnpm mcp-test-client

# Connect to local development MCP server
pnpm mcp-test-client --mcp-host http://localhost:8787
```

**Note**: Remote mode uses HTTP streaming transport and connects to the `/mcp` endpoint on the MCP server.

### Local Mode

Use the local stdio transport by providing a Sentry access token:

```bash
# Using environment variable
SENTRY_ACCESS_TOKEN=your_token pnpm mcp-test-client

# Using command line flag
pnpm mcp-test-client --access-token your_token
```

### Interactive Mode (Default)

Start an interactive session by running without arguments:

```bash
pnpm mcp-test-client
```

In interactive mode:

- Type your prompts and press Enter
- Type `exit` or `quit` to end the session
- The AI maintains context across prompts

### Single Prompt Mode

Run with a specific prompt:

```bash
pnpm mcp-test-client "List all unresolved issues in my project"
```

### Advanced Options

Use a different AI model:

```bash
pnpm mcp-test-client --model gpt-4-turbo "Analyze my error trends"
```

Connect to a local MCP server:

```bash
pnpm mcp-test-client --mcp-host http://localhost:8787 "List my projects"
```

Use local stdio transport with custom Sentry host:

```bash
SENTRY_HOST=sentry.example.com SENTRY_ACCESS_TOKEN=your_token pnpm mcp-test-client "Show my projects"
```

Only configure `SENTRY_HOST` when you run self-hosted Sentry.

## Development

### Running from Source

```bash
pnpm dev "Your prompt here"
```

### Building

```bash
pnpm build
```

### Type Checking

```bash
pnpm typecheck
```

## Troubleshooting

### Connection Issues

If you see "Failed to connect to MCP server":

1. Ensure the mcp-server package is built
2. Check that your access token is valid
3. Verify the Sentry host URL is correct

### Authentication Errors

If you get authentication errors:

1. Verify your OPENAI_API_KEY is set correctly
2. Check that your SENTRY_ACCESS_TOKEN has the required permissions
3. For self-hosted Sentry, ensure SENTRY_HOST is set

### Tool Errors

If tools fail to execute:

1. Check the error message for missing parameters
2. Ensure your Sentry token has appropriate permissions
3. Verify you have access to the requested resources

## Examples

### Finding and Analyzing Issues

```bash
# List recent issues
pnpm mcp-test-client "Show me issues from the last 24 hours"

# Search for specific errors
pnpm mcp-test-client "Find all TypeError issues in the frontend project"

# Get issue details
pnpm mcp-test-client "Show me details about issue FRONTEND-123"
```

### Project Management

```bash
# List all projects
pnpm mcp-test-client "List all my projects with their platforms"

# Get project settings
pnpm mcp-test-client "Show me the alert settings for my React project"

# View team assignments
pnpm mcp-test-client "Which teams have access to the mobile app project?"
```

### Performance Analysis

```bash
# Check slow transactions
pnpm mcp-test-client "Find the slowest API endpoints in the last hour"

# Analyze performance trends
pnpm mcp-test-client "Show me performance metrics for the checkout flow"
```

## Testing the Installation

After installation, you can verify everything is working:

```bash
# Check CLI is installed
pnpm mcp-test-client --help

# Test basic functionality (no API keys required)
SENTRY_ACCESS_TOKEN=dummy OPENAI_API_KEY=dummy pnpm mcp-test-client --help

# Run the test script (requires valid credentials)
./examples/test-connection.sh
```

## Authentication Methods

### Remote Mode (OAuth)

When connecting to a remote MCP server (default), the client supports OAuth 2.1 with PKCE:

- No client secret required (secure for CLI applications)
- Automatic browser-based authentication flow
- Tokens are securely stored in memory during the session

**Note**: OAuth clients are automatically registered using Dynamic Client Registration (RFC 7591). The client registration is cached in `~/.config/sentry-mcp/config.json` to avoid re-registration on subsequent authentications.

### Local Mode (Access Tokens)

When using local stdio transport (automatic when access token is provided), you must provide a Sentry access token:

- Set `SENTRY_ACCESS_TOKEN` environment variable
- Or use `--access-token` command-line flag
- Tokens need appropriate Sentry permissions (see Required Sentry Permissions section)

## Architecture

The CLI consists of these main components:

1. **MCP Client** (`mcp-test-client.ts`) - Handles connection to the MCP server
2. **AI Agent** (`agent.ts`) - Integrates with Vercel AI SDK for Claude
3. **Auth** (`auth/`) - OAuth flow and secure token storage
4. **CLI Interface** (`index.ts`) - Command-line argument parsing and modes

### Technical Notes

- The client uses `console.log` for all terminal output to maintain compatibility with the logger module
- Error tracking is available via the `SENTRY_DSN` environment variable
- All operations follow OpenTelemetry semantic conventions for observability

## Contributing

When adding new features:

1. Follow the existing code style
2. Add new test scenarios if applicable
3. Update this README with new usage examples
4. Ensure all TypeScript types are properly defined
5. Run quality checks: `pnpm lint:fix && pnpm typecheck && pnpm test`

```

--------------------------------------------------------------------------------
/CLAUDE.md:
--------------------------------------------------------------------------------

```markdown
AGENTS.md
```

--------------------------------------------------------------------------------
/AGENTS.md:
--------------------------------------------------------------------------------

```markdown
# CLAUDE.md

## 🔴 CRITICAL Requirements

**MANDATORY before ANY code:**
1. TypeScript: NEVER use `any`. Use `unknown` or proper types
2. Security: NO API keys in logs. NO vulnerabilities
3. Validation: `pnpm run tsc && pnpm run lint && pnpm run test`
4. Tools limit: ≤20 (hard limit: 25)

**MANDATORY reads:**
- Start here: CLAUDE.md — Contributor doc map
- Tools → @docs/adding-tools.mdc
- Testing → @docs/testing.mdc
- PRs → @docs/pr-management.mdc

## 🟡 MANDATORY Workflow

```bash
# BEFORE coding (parallel execution)
cat docs/[component].mdc & ls -la neighboring-files & git status

# AFTER coding (sequential - fail fast)
pnpm run tsc && pnpm run lint && pnpm run test  # ALL must pass
```

## Repository Map

```
sentry-mcp/
├── packages/
│   ├── mcp-server/          # Main MCP server
│   │   ├── src/
│   │   │   ├── tools/       # 19 tool modules
│   │   │   ├── server.ts    # MCP protocol
│   │   │   ├── api-client/  # Sentry API
│   │   │   └── internal/    # Shared utils
│   │   └── scripts/         # Build scripts
│   ├── mcp-cloudflare/      # Web app
│   ├── mcp-server-evals/    # AI tests
│   ├── mcp-server-mocks/    # MSW mocks
│   └── mcp-test-client/     # Test client
└── docs/                    # All docs
```

## AI-Powered Search Tools

**search_events** (`packages/mcp-server/src/tools/search-events/`):
- Natural language → DiscoverQL queries
- GPT-4o agent with structured outputs
- Tools: `datasetAttributes`, `otelSemantics`, `whoami`
- Requires: `OPENAI_API_KEY`

**search_issues** (`packages/mcp-server/src/tools/search-issues/`):
- Natural language → issue search syntax
- GPT-4o agent with structured outputs
- Tools: `issueFields`, `whoami`
- Requires: `OPENAI_API_KEY`

## 🟢 Key Commands

```bash
# Development
pnpm run dev               # Start development
pnpm run build             # Build all packages
pnpm run generate-otel-namespaces  # Update OpenTelemetry docs

# Quality checks (combine for speed)
pnpm run tsc && pnpm run lint && pnpm run test

# Common workflows
pnpm run build && pnpm run test  # Before PR
grep -r "TODO\|FIXME" src/     # Find tech debt
```

## Quick Reference

**Defaults:**
- Organization: `sentry`
- Project: `mcp-server`
- Transport: stdio
- Auth: access tokens (NOT OAuth)

**Doc Index:**

- Core Guidelines
  - @docs/coding-guidelines.mdc — Code standards and patterns
  - @docs/common-patterns.mdc — Reusable patterns and conventions
  - @docs/quality-checks.mdc — Required checks before changes
  - @docs/error-handling.mdc — Error handling patterns

- API and Tools
  - @docs/adding-tools.mdc — Add new MCP tools
  - @docs/api-patterns.mdc — Sentry API usage
  - @docs/search-events-api-patterns.md — search_events specifics

- Infrastructure and Operations
  - @docs/architecture.mdc — System design
  - @docs/deployment.mdc — Deploy (Cloudflare)
  - @docs/monitoring.mdc — Monitoring/telemetry
  - @docs/security.mdc — Security and authentication
  - @docs/cursor.mdc — Cursor IDE integration

- LLM-Specific
  - @docs/llms/documentation-style-guide.mdc — How to write LLM docs
  - @docs/llms/document-scopes.mdc — Doc scopes and purposes

## Rules

1. **Code**: Follow existing patterns. Check adjacent files
2. **Errors**: Try/catch all async. Log: `console.error('[ERROR]', error.message, error.stack)`
   - Sentry API 429: Retry with exponential backoff
   - Sentry API 401/403: Check token permissions
3. **Docs**: Update when changing functionality
4. **PR**: Follow `docs/pr-management.mdc` for commit/PR guidelines (includes AI attribution)
5. **Tasks**: Use TodoWrite for 3+ steps. Batch tool calls when possible

---
*Optimized for Codex CLI (OpenAI) and Claude Code*

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/search-events/CLAUDE.md:
--------------------------------------------------------------------------------

```markdown
# search_events Tool - Embedded Agent Documentation

This tool embeds an AI agent (GPT-4o) to translate natural language queries into Sentry's event search syntax.

## Architecture Overview

The `search_events` tool uses an "agent-in-tool" pattern:

1. **MCP Tool Handler** (`handler.ts`) - Receives natural language query from calling agent
2. **Embedded AI Agent** (`agent.ts`) - Translates to Sentry search syntax 
3. **API Execution** - Runs the translated query against Sentry's API
4. **Result Formatting** - Returns formatted results to calling agent

## Embedded Agent Behavior

### Available Tools

The embedded agent has access to three tools:

1. **datasetAttributes** - Discovers available fields for the chosen dataset
2. **otelSemantics** - Looks up OpenTelemetry semantic conventions
3. **whoami** - Resolves "me" references to actual user IDs

### Translation Flow

1. Analyzes natural language query to determine dataset (spans/errors/logs)
2. Calls `datasetAttributes` to discover available fields
3. May call `otelSemantics` for standardized field names
4. Generates structured query with fields, sort, and timeRange

### Key Query Patterns

#### Distinct/Unique Values
- "distinct tool names" → `fields: ['mcp.tool.name', 'count()'], sort: '-count()'`
- Always uses aggregate mode with count()

#### Traffic/Volume Queries  
- "how much traffic" → `fields: ['count()'], sort: '-count()'`
- "traffic by X" → `fields: ['X', 'count()'], sort: '-count()'`

#### Mathematical Queries
- "total tokens used" → `fields: ['sum(gen_ai.usage.input_tokens)', 'sum(gen_ai.usage.output_tokens)']`
- Uses spans dataset for OpenTelemetry metrics

#### Time Series (NOT SUPPORTED)
- "X over time" → Returns error: "Time series aggregations are not currently supported."

## Error Handling

The tool follows the MCP philosophy of single-attempt error handling:

1. **Agent generates query** - Using static system prompt
2. **Validation Error** - Returns clear UserInputError to calling agent
3. **Calling agent decides** - Whether to retry with corrections

Common validation errors:
- Missing sort parameter
- Sort field not included in fields array
- Missing fields for aggregate queries
- Invalid field names or syntax

This approach enables better LLM prompt caching and cleaner error boundaries.

## Limitations

1. **No Time Series** - Cannot do "over time" aggregations
2. **Dataset Constraints**:
   - Equations only work in spans dataset
   - Numeric aggregations limited by field types
   - Timestamp filtering differs between datasets
3. **Project Scope** - Fields vary by project based on instrumented data

## Common Issues and Solutions

### Issue: "Sort field not in fields array"
**Cause**: Agent specified sort by a field not included in the fields array
**Solution**: Error message guides agent to include the sort field

### Issue: "Time series not supported"
**Cause**: User asked for data "over time"
**Solution**: Return clear error message, no retry

### Issue: "Invalid aggregate function on non-numeric field"
**Cause**: Using avg(), sum() etc. on string fields
**Solution**: Agent uses field type information from datasetAttributes

## Testing Queries

Test various query patterns:
- Simple counts: "how many errors today"
- Distinct values: "distinct user agents"
- Grouped aggregations: "errors by type"
- Token usage: "total tokens used by model"
- Time-filtered: "errors in the last hour"

## Future Improvements

1. ~~Consider removing retry mechanism - let calling agent handle retries~~ ✅ Done
2. Add support for time bucketing fields (timestamp.to_hour, timestamp.to_day)
3. Extract createOtelLookupTool and createDatasetAttributesTool to shared modules
```

--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------

```markdown
# Functional Source License, Version 1.1, Apache 2.0 Future License

## Abbreviation

FSL-1.1-Apache-2.0

## Notice

Copyright 2008-2024 Functional Software, Inc. dba Sentry

## Terms and Conditions

### Licensor ("We")

The party offering the Software under these Terms and Conditions.

### The Software

The "Software" is each version of the software that we make available under
these Terms and Conditions, as indicated by our inclusion of these Terms and
Conditions with the Software.

### License Grant

Subject to your compliance with this License Grant and the Patents,
Redistribution and Trademark clauses below, we hereby grant you the right to
use, copy, modify, create derivative works, publicly perform, publicly display
and redistribute the Software for any Permitted Purpose identified below.

### Permitted Purpose

A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
means making the Software available to others in a commercial product or
service that:

1. substitutes for the Software;

2. substitutes for any other product or service we offer using the Software
   that exists as of the date we make the Software available; or

3. offers the same or substantially similar functionality as the Software.

Permitted Purposes specifically include using the Software:

1. for your internal use and access;

2. for non-commercial education;

3. for non-commercial research; and

4. in connection with professional services that you provide to a licensee
   using the Software in accordance with these Terms and Conditions.

### Patents

To the extent your use for a Permitted Purpose would necessarily infringe our
patents, the license grant above includes a license under our patents. If you
make a claim against any party that the Software infringes or contributes to
the infringement of any patent, then your patent license to the Software ends
immediately.

### Redistribution

The Terms and Conditions apply to all copies, modifications and derivatives of
the Software.

If you redistribute any copies, modifications or derivatives of the Software,
you must include a copy of or a link to these Terms and Conditions and not
remove any copyright notices provided in or with the Software.

### Disclaimer

THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.

IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.

### Trademarks

Except for displaying the License Details and identifying us as the origin of
the Software, you have no right under these Terms and Conditions to use our
trademarks, trade names, service marks or product names.

## Grant of Future License

We hereby irrevocably grant you an additional license to use the Software under
the Apache License, Version 2.0 that is effective on the second anniversary of
the date we make the Software available. On or after that date, you may use the
Software under the Apache License, Version 2.0, in which case the following
will apply:

Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License.

You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/search-issues/CLAUDE.md:
--------------------------------------------------------------------------------

```markdown
# search_issues Tool - Embedded Agent Documentation

This tool embeds an AI agent (GPT-4o) to translate natural language queries into Sentry's issue search syntax.

## Architecture Overview

The `search_issues` tool uses an "agent-in-tool" pattern similar to `search_events`:

1. **MCP Tool Handler** (`handler.ts`) - Receives natural language query from calling agent
2. **Embedded AI Agent** (`agent.ts`) - Translates to Sentry issue search syntax
3. **API Execution** - Runs the translated query against Sentry's API
4. **Result Formatting** - Returns formatted grouped issues to calling agent

## Key Differences from search_events

### Purpose
- `search_events`: Returns individual events or aggregated statistics
- `search_issues`: Returns grouped issues (problems) with metadata

### Query Syntax
- Uses Sentry's issue search syntax (different from event search)
- No aggregate functions - issues are already grouped
- Special fields like `is:`, `assigned:`, `firstSeen:`, `lastSeen:`

### No Datasets
- Issues are a single unified view across all event types
- No dataset selection required

## Embedded Agent Behavior

### Available Tools

The embedded agent has access to two tools:

1. **discoverDatasetFields** - Discovers available issue fields
2. **whoami** - Resolves "me" references to actual user IDs

### Translation Flow

1. Analyzes natural language query for issue-specific patterns
2. Calls `discoverDatasetFields` to get available issue fields
3. May call `whoami` to resolve "me" references
4. Generates issue search query with proper syntax

### Key Query Patterns

#### Status Queries
- "unresolved issues" → `is:unresolved`
- "ignored bugs" → `is:ignored`
- "resolved yesterday" → `is:resolved` + timeRange

#### Assignment Queries
- "issues assigned to me" → `assigned:me` (or resolved email)
- "unassigned errors" → `is:unassigned`

#### Impact Queries
- "issues affecting 100+ users" → `users:>100`
- "high volume errors" → `events:>1000`

#### Time-based Queries
- "issues from last week" → Uses timeRange parameter
- "errors seen today" → `lastSeen:-24h`

## Error Handling

Follows the same MCP philosophy as search_events:

1. **Agent generates query** - Using static system prompt
2. **Validation Error** - Returns clear UserInputError to calling agent
3. **Calling agent decides** - Whether to retry with corrections

Common validation errors:
- Invalid issue field names
- Incorrect query syntax
- Missing required parameters

This approach enables better LLM prompt caching and cleaner error boundaries.

## Issue-Specific Fields

### Status Fields
- `is:` - resolved, unresolved, ignored, archived
- `assigned:` - user email or "me"
- `bookmarks:` - user email

### Time Fields  
- `firstSeen:` - When issue was first seen
- `lastSeen:` - When issue was last seen
- `age:` - How old the issue is

### Impact Fields
- `users:` - Number of affected users
- `events:` - Total event count
- `level:` - error, warning, info, debug

## Limitations

1. **No Aggregations** - Issues are already grouped, no count()/sum()
2. **Limited Operators** - Simpler query syntax than events
3. **No Custom Fields** - Fixed set of issue attributes

## Common Issues and Solutions

### Issue: "Using event syntax for issues"
**Cause**: Agent tries to use event search patterns
**Solution**: Clear separation in prompt between issue and event search

### Issue: "Me resolution failures"
**Cause**: User not authenticated or API error
**Solution**: Fallback to suggesting user provide email

## Testing Queries

Test various issue query patterns:
- Status filters: "unresolved critical errors"
- Assignment: "my issues", "unassigned bugs"
- Impact: "issues affecting many users"
- Time ranges: "issues from yesterday"
- Combined: "unresolved errors assigned to me from last week"

## Future Improvements

1. ~~Consider removing retry mechanism - let calling agent handle retries~~ ✅ Done
2. Better integration with issue workflow commands (resolve, assign)
3. Extract shared agent tools to common module
```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/CLAUDE.md:
--------------------------------------------------------------------------------

```markdown
# OpenTelemetry Namespace Data

This directory contains JSON files for OpenTelemetry semantic convention namespaces used by the search-events tool's embedded AI agent.

## File Format

Each JSON file represents a namespace and follows this structure:

```json
{
  "namespace": "namespace_name",
  "description": "Description of what this namespace covers",
  "attributes": {
    "attribute.name": {
      "description": "What this attribute represents",
      "type": "string|number|boolean",
      "examples": ["example1", "example2"],
      "note": "Additional notes (optional)",
      "stability": "stable|experimental|deprecated (optional)"
    }
  }
}
```

## Generation Process

### OpenTelemetry Official Namespaces

Most files are automatically generated from the OpenTelemetry semantic conventions repository:

**Source**: https://github.com/open-telemetry/semantic-conventions/tree/main/model

The generation script (`scripts/generate-otel-namespaces.ts`) fetches YAML files from the model directory and converts them to our JSON format.

**Generation Command**: `pnpm run generate-otel-namespaces`

**Caching**: The script caches downloaded YAML files in `.cache/` directory to avoid repeated network requests. Clear the cache to force fresh downloads.

### JSON Import Handling

The JSON files are imported directly in the TypeScript code and bundled by tsdown/rolldown at build time. This approach works seamlessly with Cloudflare Workers since all data is embedded in the JavaScript bundle.

### Custom Namespaces

Some namespaces are maintained manually for attributes not yet in the OpenTelemetry specification:

- **mcp.json** - Model Context Protocol attributes (custom)
- Any file marked with `"custom": true` will be skipped during regeneration

## Usage

The `otel-semantics-lookup.ts` tool reads these JSON files to provide semantic guidance to the embedded AI agent when translating natural language queries.

## Key Namespaces

### Core OpenTelemetry Namespaces

- **gen_ai** - Generative AI operations (models, tokens, conversations)
- **db** - Database operations (queries, connections, systems)
- **http** - HTTP client/server operations (requests, responses, status codes)
- **rpc** - Remote procedure calls (gRPC, etc.)
- **messaging** - Message queue operations (Kafka, RabbitMQ, etc.)
- **faas** - Function as a Service operations (AWS Lambda, etc.)
- **k8s** - Kubernetes operations (pods, services, deployments)
- **cloud** - Cloud provider operations (AWS, Azure, GCP)
- **network** - Network operations (TCP, UDP, protocols)
- **server** - Server-side operations (addresses, ports)
- **service** - Service identification (name, version, instance)
- **error** - Error information (type, message, stack)
- **user** - User identification (id, email, name)

### Custom Namespaces

- **mcp** - Model Context Protocol operations (tool calls, sessions)

## Regeneration Process

1. **Automatic**: Run `pnpm run generate-otel-namespaces` to update all OpenTelemetry namespaces
2. **Manual**: Edit custom namespace files directly (they won't be overwritten)
3. **Selective**: The script only updates files for namespaces that exist in the OpenTelemetry repository

## File Organization

```
data/
├── CLAUDE.md              # This documentation
├── gen_ai.json            # Generative AI attributes
├── db.json                # Database attributes  
├── http.json              # HTTP attributes
├── rpc.json               # RPC attributes
├── messaging.json         # Messaging attributes
├── mcp.json               # MCP attributes (custom)
└── [other-namespaces].json
```

## Maintenance

- **OpenTelemetry files**: Regenerate periodically to stay current with specifications
- **Custom files**: Update manually as needed for new MCP or Sentry-specific attributes
- **Validation**: Ensure all files follow the expected JSON schema format

The embedded AI agent uses these definitions to provide accurate semantic guidance when users query for things like "agent calls" (maps to gen_ai.*) vs "tool calls" (maps to mcp.*).
```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/utils/index.ts:
--------------------------------------------------------------------------------

```typescript
export * from "./chat-error-handler";

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/vite-env.d.ts:
--------------------------------------------------------------------------------

```typescript
/// <reference types="vite/client" />

```

--------------------------------------------------------------------------------
/vitest.workspace.ts:
--------------------------------------------------------------------------------

```typescript
export default ["packages/*", "apps/*"];

```

--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------

```json
{
  "recommendations": ["biomejs.biome"],
  "unwantedRecommendations": []
}

```

--------------------------------------------------------------------------------
/.vscode/mcp.json:
--------------------------------------------------------------------------------

```json
{
  "servers": {
    "sentry": {
      "url": "https://mcp.sentry.dev/mcp"
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/test-setup.ts:
--------------------------------------------------------------------------------

```typescript
import { startMockServer } from "@sentry/mcp-server-mocks";

startMockServer({ ignoreOpenAI: true });

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/api-client/index.ts:
--------------------------------------------------------------------------------

```typescript
export * from "./client";
export * from "./schema";
export * from "./types";
export * from "./errors";

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/version.ts:
--------------------------------------------------------------------------------

```typescript
export const LIB_VERSION =
  (typeof process !== "undefined" && process.env?.npm_package_version) ||
  "0.0.0";

```

--------------------------------------------------------------------------------
/packages/mcp-test-client/src/version.ts:
--------------------------------------------------------------------------------

```typescript
export const LIB_VERSION =
  (typeof process !== "undefined" && process.env?.npm_package_version) ||
  "0.0.0";

```

--------------------------------------------------------------------------------
/.cursor/mcp.json:
--------------------------------------------------------------------------------

```json
{
  "mcpServers": {
    "sentry": {
      "type": "http",
      "url": "https://mcp.sentry.dev/mcp/sentry/mcp-server"
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-tsconfig/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "@sentry/mcp-server-tsconfig",
  "version": "0.18.0",
  "private": true,
  "files": ["tsconfig.base.json", "tsconfig.vite.json"]
}

```

--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------

```yaml
coverage:
  status:
    project:
      default:
        informational: true
    patch:
      default:
        informational: true

comment: false

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/search-events/index.ts:
--------------------------------------------------------------------------------

```typescript
// Export the search-events handler
export { default } from "./handler";

// Export the agent for testing
export { searchEventsAgent } from "./agent";

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/search-issues/index.ts:
--------------------------------------------------------------------------------

```typescript
// Export the search-issues handler
export { default } from "./handler";

// Export the agent for testing
export { searchIssuesAgent } from "./agent";

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "files": [],
  "references": [
    { "path": "./tsconfig.client.json" },
    { "path": "./tsconfig.node.json" },
    { "path": "./tsconfig.server.json" }
  ]
}

```

--------------------------------------------------------------------------------
/packages/mcp-test-client/vitest.config.ts:
--------------------------------------------------------------------------------

```typescript
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    globals: true,
    environment: "node",
    testTimeout: 30000,
  },
});

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/lib/utils.ts:
--------------------------------------------------------------------------------

```typescript
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/utils/index.ts:
--------------------------------------------------------------------------------

```typescript
export { FIXTURES } from "./fixtures";
export { NoOpTaskRunner } from "./runner";
export {
  ToolPredictionScorer,
  type ExpectedToolCall,
} from "./toolPredictionScorer";

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/note.tsx:
--------------------------------------------------------------------------------

```typescript
export default function Note({ children }: { children: React.ReactNode }) {
  return (
    <div className="mb-6">
      <p className="text-slate-300 text-base">{children}</p>
    </div>
  );
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/tool-helpers/define.ts:
--------------------------------------------------------------------------------

```typescript
import type { z } from "zod";
import type { ToolConfig } from "../../tools/types";

export function defineTool<TSchema extends Record<string, z.ZodType>>(
  config: ToolConfig<TSchema>,
) {
  return config;
}

```

--------------------------------------------------------------------------------
/packages/mcp-test-client/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "../mcp-server-tsconfig/tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.test.ts"]
}
```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "@sentry/mcp-server-tsconfig/tsconfig.base.json",
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src"]
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-mocks/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "@sentry/mcp-server-tsconfig/tsconfig.base.json",
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src"]
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "@sentry/mcp-server-tsconfig/tsconfig.base.json",
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src"]
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/tsconfig.server.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "./tsconfig.node.json",
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.server.tsbuildinfo",
    "types": [
      "@cloudflare/workers-types"
    ]
  },
  "include": [
    "src/server"
  ]
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-mocks/tsdown.config.ts:
--------------------------------------------------------------------------------

```typescript
import { defineConfig } from "tsdown";

export default defineConfig({
  entry: ["src/**/*.ts"],
  format: ["cjs", "esm"], // Build for commonJS and ESmodules
  dts: true, // Generate declaration file (.d.ts)
  sourcemap: true,
  clean: true,
});

```

--------------------------------------------------------------------------------
/packages/smoke-tests/vitest.config.ts:
--------------------------------------------------------------------------------

```typescript
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    globals: true,
    environment: "node",
    testTimeout: 30000, // 30 seconds for network requests
    hookTimeout: 60000, // 60 seconds for setup/teardown
  },
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/system.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "system",
  "description": "Describes System attributes",
  "attributes": {
    "system.device": {
      "description": "The device identifier",
      "type": "string",
      "stability": "development",
      "examples": ["(identifier)"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-mocks/src/fixtures/event-attachments.json:
--------------------------------------------------------------------------------

```json
[
  {
    "id": "123",
    "name": "screenshot.png",
    "type": "event.attachment",
    "size": 1024,
    "mimetype": "image/png",
    "dateCreated": "2025-04-08T21:15:04.000Z",
    "sha1": "abc123def456",
    "headers": {
      "Content-Type": "image/png"
    }
  }
]

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/go.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "go",
  "description": "This document defines Go related attributes.\n",
  "attributes": {
    "go.memory.type": {
      "description": "The type of memory.",
      "type": "string",
      "stability": "development",
      "examples": ["stack", "other"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/tsconfig.node.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "@sentry/mcp-server-tsconfig/tsconfig.base.json",
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
    "outDir": "dist",
    "rootDir": "",

    "types": ["@cloudflare/vitest-pool-workers"]
  },
  "include": ["vite.config.ts"]
}

```

--------------------------------------------------------------------------------
/bin/bump-version.sh:
--------------------------------------------------------------------------------

```bash
#!/bin/bash
### Example of a version-bumping script for an NPM project.
### Located at: ./bin/bump-version.sh
set -eux
OLD_VERSION="${1}"
NEW_VERSION="${2}"

# Do not tag and commit changes made by "npm version"
export npm_config_git_tag_version=false
pnpm -r exec npm version "${NEW_VERSION}"

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/nodejs.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "nodejs",
  "description": "Describes Node.js related attributes.",
  "attributes": {
    "nodejs.eventloop.state": {
      "description": "The state of event loop time.",
      "type": "string",
      "stability": "development",
      "examples": ["active", "idle"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/linux.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "linux",
  "description": "Describes Linux Memory attributes",
  "attributes": {
    "linux.memory.slab.state": {
      "description": "The Linux Slab memory state",
      "type": "string",
      "stability": "development",
      "examples": ["reclaimable", "unreclaimable"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/oauth/routes/index.ts:
--------------------------------------------------------------------------------

```typescript
import { Hono } from "hono";
import type { Env } from "../../types";
import authorizeApp from "./authorize";
import callbackApp from "./callback";

// Compose and export the main OAuth Hono app
export default new Hono<{ Bindings: Env }>()
  .route("/authorize", authorizeApp)
  .route("/callback", callbackApp);

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/disk.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "disk",
  "description": "These attributes may be used for any disk related operation.\n",
  "attributes": {
    "disk.io.direction": {
      "description": "The disk IO operation direction.",
      "type": "string",
      "stability": "development",
      "examples": ["read", "write"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/tsconfig.client.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "@sentry/mcp-server-tsconfig/tsconfig.vite.json",
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.client.tsbuildinfo",
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "./src/*"
      ]
    },
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src/client"]
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/constants.ts:
--------------------------------------------------------------------------------

```typescript
// https://docs.sentry.io/api/permissions/
export const SCOPES = {
  "org:read": "Read organization data",
  "project:write": "Write project data",
  "team:write": "Write team data",
  "event:write": "Write event data",
};

export const NPM_PACKAGE_NAME = "@sentry/mcp-server";

export const NPM_REMOTE_NAME = "mcp-remote";

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/cpython.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "cpython",
  "description": "This document defines CPython related attributes.\n",
  "attributes": {
    "cpython.gc.generation": {
      "description": "Value of the garbage collector collection generation.",
      "type": "string",
      "stability": "development",
      "examples": ["0", "1", "2"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/tool-helpers/issue.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Re-export of issue parsing utilities for tool modules.
 * These utilities handle flexible input formats for Sentry issues.
 */
export { parseIssueParams } from "../../internal/issue-helpers";

/**
 * Re-export of issue formatting utilities for tool modules.
 */
export { formatIssueOutput } from "../../internal/formatting";

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/instrument.ts:
--------------------------------------------------------------------------------

```typescript
import * as Sentry from "@sentry/react";
import { sentryBeforeSend } from "@sentry/mcp-server/telem/sentry";

Sentry.init({
  dsn: import.meta.env.VITE_SENTRY_DSN,
  sendDefaultPii: true,
  tracesSampleRate: 1,
  beforeSend: sentryBeforeSend,
  environment:
    import.meta.env.VITE_SENTRY_ENVIRONMENT ?? import.meta.env.NODE_ENV,
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/log.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "log",
  "description": "This document defines log attributes\n",
  "attributes": {
    "log.iostream": {
      "description": "The stream associated with the log. See below for a list of well-known values.\n",
      "type": "string",
      "stability": "development",
      "examples": ["stdout", "stderr"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-tsconfig/tsconfig.vite.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Vite (React) Library",
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "jsx": "react-jsx",
    "target": "ES2020",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "useDefineForClassFields": true,
    "module": "ESNext",
    "types": ["vite/client"]
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/dotnet.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "dotnet",
  "description": "This document defines .NET related attributes.\n",
  "attributes": {
    "dotnet.gc.heap.generation": {
      "description": "Name of the garbage collector managed heap generation.",
      "type": "string",
      "stability": "stable",
      "examples": ["gen0", "gen1", "gen2", "loh", "poh"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/smoke-tests/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "@sentry/mcp-smoke-tests",
  "version": "0.18.0",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "vitest run",
    "test:ci": "vitest run --reporter=default --reporter=junit --outputFile=tests.junit.xml",
    "test:watch": "vitest"
  },
  "devDependencies": {
    "vitest": "catalog:",
    "@types/node": "catalog:"
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-mocks/src/fixtures/trace-items-attributes-logs-number.json:
--------------------------------------------------------------------------------

```json
[
  {
    "key": "severity_number",
    "name": "Severity Number"
  },
  {
    "key": "sentry.observed_timestamp_nanos",
    "name": "Observed Timestamp (Nanos)"
  },
  {
    "key": "timestamp",
    "name": "Timestamp"
  },
  {
    "key": "custom.duration",
    "name": "Custom Duration"
  },
  {
    "key": "custom.bytes",
    "name": "Custom Bytes"
  }
]

```

--------------------------------------------------------------------------------
/packages/mcp-server/vitest.config.ts:
--------------------------------------------------------------------------------

```typescript
/// <reference types="vitest" />
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    include: ["**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
    coverage: {
      provider: "v8",
      reporter: ["text", "json", "html"],
      include: ["**/*.ts"],
    },
    setupFiles: ["dotenv/config", "src/test-setup.ts"],
  },
});

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/prose.tsx:
--------------------------------------------------------------------------------

```typescript
import { cn } from "@/client/lib/utils";

export function Prose({
  children,
  className,
  ...props
}: { children: React.ReactNode } & React.HTMLAttributes<HTMLDivElement>) {
  return (
    <div
      className={cn(
        "prose prose-invert prose-slate max-w-none prose-a:text-violet-300",
        className,
      )}
      {...props}
    >
      {children}
    </div>
  );
}

```

--------------------------------------------------------------------------------
/.claude/commands/gh-review.md:
--------------------------------------------------------------------------------

```markdown
Address feedback and checks in a Pull Request.

We use the GitHub CLI (`gh`) to manage pull requests.

Review the status checks for this PR, and identify any failures from them.

If there are no failures, review the PR feedback.

Do NOT assume feedback is valid. You should always verify that the feedback is truthful (the bug is real, for example), and then attempt to address it.

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/vitest.config.ts:
--------------------------------------------------------------------------------

```typescript
/// <reference types="vitest" />
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    include: ["**/*.eval.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
    reporters: ["vitest-evals/reporter"],
    coverage: {
      provider: "v8",
      reporter: ["text", "json", "html"],
      include: ["**/*.ts"],
    },
    setupFiles: ["./src/setup-env.ts"],
  },
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/elasticsearch.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "elasticsearch",
  "description": "This section defines attributes for Elasticsearch.\n",
  "attributes": {
    "elasticsearch.node.name": {
      "description": "Represents the human-readable identifier of the node/instance to which a request was routed.\n",
      "type": "string",
      "stability": "development",
      "examples": ["instance-0000000001"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/oauth/index.ts:
--------------------------------------------------------------------------------

```typescript
// Re-export the main OAuth Hono app
export { default } from "./routes/index";

// Re-export helper functions and constants for external use
export { tokenExchangeCallback } from "./helpers";
export {
  SENTRY_AUTH_URL,
  SENTRY_TOKEN_URL,
  TokenResponseSchema,
} from "./constants";
export {
  getUpstreamAuthorizeUrl,
  exchangeCodeForAccessToken,
  refreshAccessToken,
} from "./helpers";

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/opentracing.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "opentracing",
  "description": "Attributes used by the OpenTracing Shim layer.",
  "attributes": {
    "opentracing.ref_type": {
      "description": "Parent-child Reference type",
      "type": "string",
      "note": "The causal relationship between a child Span and a parent Span.\n",
      "stability": "development",
      "examples": ["child_of", "follows_from"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/components.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york",
  "rsc": false,
  "tsx": true,
  "tailwind": {
    "config": "",
    "css": "src/client/index.css",
    "baseColor": "neutral",
    "cssVariables": true,
    "prefix": ""
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks"
  },
  "iconLibrary": "lucide"
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/telem/index.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Telemetry and observability utilities.
 *
 * This module provides logging, error tracking, and instrumentation utilities
 * for monitoring and debugging MCP server operations.
 */

// Re-export logging utilities
export {
  getLogger,
  logDebug,
  logInfo,
  logWarn,
  logError,
  logIssue,
  type LogIssueOptions,
} from "./logging";

// Re-export Sentry instrumentation utilities
export { sentryBeforeSend } from "./sentry";

```

--------------------------------------------------------------------------------
/packages/mcp-test-client/src/types.ts:
--------------------------------------------------------------------------------

```typescript
// Shared types for MCP client

export interface MCPConnection {
  client: any; // TODO: Replace with proper type from experimental MCP client
  tools: Map<string, any>;
  disconnect: () => Promise<void>;
  sessionId: string;
  transport: "stdio" | "http";
}

export interface MCPConfig {
  accessToken: string;
  host?: string;
  sentryDsn?: string;
}

export interface RemoteMCPConfig {
  mcpHost?: string;
  accessToken?: string;
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/peer.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "peer",
  "description": "Operations that access some remote service.\n",
  "attributes": {
    "peer.service": {
      "description": "The [`service.name`](/docs/resource/README.md#service) of the remote service. SHOULD be equal to the actual `service.name` resource attribute of the remote service if any.\n",
      "type": "string",
      "stability": "development",
      "examples": ["AuthTokenCache"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/utils/runner.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * A no-op task runner that doesn't execute tools, just returns the input
 * for use with ToolPredictionScorer. This allows tests to focus on predicting
 * which tools would be called without actually executing them.
 */
export function NoOpTaskRunner() {
  return async function NoOpTaskRunner(input: string) {
    // Just return the input as the result, no tool execution
    return {
      result: input,
      toolCalls: [],
    };
  };
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/fragments/setup-guide.tsx:
--------------------------------------------------------------------------------

```typescript
import {
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "../ui/accordion";
import { Prose } from "../ui/prose";

export default function SetupGuide({
  id,
  title,
  children,
}: { id: string; title: string; children: React.ReactNode }) {
  return (
    <AccordionItem value={id}>
      <AccordionTrigger>{title}</AccordionTrigger>
      <AccordionContent>
        <Prose>{children}</Prose>
      </AccordionContent>
    </AccordionItem>
  );
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/toolDefinitions.ts:
--------------------------------------------------------------------------------

```typescript
import toolDefinitionsData from "./toolDefinitions.json";
import type { Scope } from "./permissions";

// Tool definition for UI/external consumption
export interface ToolDefinition {
  name: string;
  description: string;
  // Full JSON Schema object for parameters
  inputSchema: unknown;
  // Sentry API scopes required to use the tool
  requiredScopes: Scope[];
}

const toolDefinitions = toolDefinitionsData as ToolDefinition[];

export default toolDefinitions;

```

--------------------------------------------------------------------------------
/packages/mcp-test-client/src/constants.ts:
--------------------------------------------------------------------------------

```typescript
// Default MCP Server
export const DEFAULT_MCP_URL = "https://mcp.sentry.dev";

// Default AI model - using GPT-4
export const DEFAULT_MODEL = "gpt-4o";

// OAuth configuration
export const OAUTH_REDIRECT_PORT = 8765;
export const OAUTH_REDIRECT_URI = `http://localhost:${OAUTH_REDIRECT_PORT}/callback`;

// Default OAuth scopes
export const DEFAULT_OAUTH_SCOPES = [
  "org:read",
  "project:read",
  "project:write",
  "team:read",
  "team:write",
  "event:write",
];

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/icon.tsx:
--------------------------------------------------------------------------------

```typescript
interface IconProps {
  className?: string;
  path: string;
  viewBox?: string;
  title?: string;
}

export function Icon({
  className,
  path,
  viewBox = "0 0 32 32",
  title = "Icon",
}: IconProps) {
  return (
    <svg
      className={className}
      viewBox={viewBox}
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      aria-labelledby="icon-title"
    >
      <title id="icon-title">{title}</title>
      <path d={path} fill="currentColor" />
    </svg>
  );
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/section.tsx:
--------------------------------------------------------------------------------

```typescript
import type { ReactNode } from "react";
import { Heading } from "./base";
import { cn } from "@/client/lib/utils";

export default function Section({
  heading,
  children,
  className,
  ...props
}: {
  heading?: string | ReactNode;
  children: ReactNode;
  className?: string;
} & React.HTMLAttributes<HTMLDivElement>) {
  return (
    <section className={cn("space-y-4 mb-10", className)} {...props}>
      {heading && <Heading>{heading}</Heading>}
      {children}
    </section>
  );
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-mocks/src/fixtures/trace-items-attributes-spans-number.json:
--------------------------------------------------------------------------------

```json
[
  {
    "key": "span.duration",
    "name": "Span Duration"
  },
  {
    "key": "transaction.duration",
    "name": "Transaction Duration"
  },
  {
    "key": "http.status_code",
    "name": "HTTP Status Code"
  },
  {
    "key": "custom.count",
    "name": "Custom Count"
  },
  {
    "key": "custom.score",
    "name": "Custom Score"
  },
  {
    "key": "custom.latency_ms",
    "name": "Custom Latency (ms)"
  },
  {
    "key": "custom.db.pool_size",
    "name": "Custom DB Pool Size"
  }
]

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/oauth/constants.ts:
--------------------------------------------------------------------------------

```typescript
import { z } from "zod";

// Sentry OAuth endpoints
export const SENTRY_AUTH_URL = "/oauth/authorize/";
export const SENTRY_TOKEN_URL = "/oauth/token/";

export const TokenResponseSchema = z.object({
  access_token: z.string(),
  refresh_token: z.string(),
  token_type: z.string(), // should be "bearer"
  expires_in: z.number(),
  expires_at: z.string().datetime(),
  user: z.object({
    email: z.string().email(),
    id: z.string(),
    name: z.string().nullable(),
  }),
  scope: z.string(),
});

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/list-organizations.eval.ts:
--------------------------------------------------------------------------------

```typescript
import { describeEval } from "vitest-evals";
import { NoOpTaskRunner, ToolPredictionScorer } from "./utils";

describeEval("list-organizations", {
  data: async () => {
    return [
      {
        input: `What organizations do I have access to in Sentry`,
        expectedTools: [
          {
            name: "find_organizations",
            arguments: {},
          },
        ],
      },
    ];
  },
  task: NoOpTaskRunner(),
  scorers: [ToolPredictionScorer()],
  threshold: 0.6,
  timeout: 30000,
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/tool-helpers/formatting.ts:
--------------------------------------------------------------------------------

```typescript
import type { z } from "zod";
import type { AssignedToSchema } from "../../api-client/index";

type AssignedTo = z.infer<typeof AssignedToSchema>;

/**
 * Helper function to format assignedTo field for display
 */
export function formatAssignedTo(assignedTo: AssignedTo): string {
  if (!assignedTo) {
    return "Unassigned";
  }

  if (typeof assignedTo === "string") {
    return assignedTo;
  }

  if (typeof assignedTo === "object" && assignedTo.name) {
    return assignedTo.name;
  }

  return "Unknown";
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/profile.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "profile",
  "description": "Describes the origin of a single frame in a Profile.\n",
  "attributes": {
    "profile.frame.type": {
      "description": "Describes the interpreter or compiler of a single frame.\n",
      "type": "string",
      "stability": "development",
      "examples": [
        "dotnet",
        "jvm",
        "kernel",
        "native",
        "perl",
        "php",
        "cpython",
        "ruby",
        "v8js",
        "beam",
        "go",
        "rust"
      ]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/find-projects.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from "vitest";
import findProjects from "./find-projects.js";
import { getServerContext } from "../test-setup.js";

describe("find_projects", () => {
  it("serializes", async () => {
    const result = await findProjects.handler(
      {
        organizationSlug: "sentry-mcp-evals",
        regionUrl: undefined,
      },
      getServerContext(),
    );
    expect(result).toMatchInlineSnapshot(`
      "# Projects in **sentry-mcp-evals**

      - **cloudflare-mcp**
      "
    `);
  });
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/thread.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "thread",
  "description": "These attributes may be used for any operation to store information about a thread that started a span.\n",
  "attributes": {
    "thread.id": {
      "description": "Current \"managed\" thread ID (as opposed to OS thread ID).\n",
      "type": "number",
      "stability": "development",
      "examples": ["42"]
    },
    "thread.name": {
      "description": "Current thread name.\n",
      "type": "string",
      "stability": "development",
      "examples": ["main"]
    }
  }
}

```

--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------

```json
{
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.biome": "explicit"
  },
  "files.trimTrailingWhitespace": false,
  "files.trimFinalNewlines": false,
  "files.insertFinalNewline": true,
  "cursor.general.enableShadowWorkspace": true,
  "[json]": {
    "editor.tabSize": 2,
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescript]": {
    "editor.tabSize": 2,
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "biomejs.biome"
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/find-teams.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from "vitest";
import findTeams from "./find-teams.js";

describe("find_teams", () => {
  it("serializes", async () => {
    const result = await findTeams.handler(
      {
        organizationSlug: "sentry-mcp-evals",
        regionUrl: undefined,
      },
      {
        constraints: {
          organizationSlug: null,
        },
        accessToken: "access-token",
        userId: "1",
      },
    );
    expect(result).toMatchInlineSnapshot(`
      "# Teams in **sentry-mcp-evals**

      - the-goats
      "
    `);
  });
});

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/vite.config.ts:
--------------------------------------------------------------------------------

```typescript
import { sentryVitePlugin } from "@sentry/vite-plugin";
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { cloudflare } from "@cloudflare/vite-plugin";
import tailwindcss from "@tailwindcss/vite";
import path from "node:path";

export default defineConfig({
  plugins: [
    react(),
    cloudflare(),
    tailwindcss(),
    sentryVitePlugin({
      org: "sentry",
      project: "mcp-server",
    }),
  ],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
  build: {
    sourcemap: true,
  },
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/cpu.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "cpu",
  "description": "Attributes specific to a cpu instance.",
  "attributes": {
    "cpu.mode": {
      "description": "The mode of the CPU",
      "type": "string",
      "stability": "development",
      "examples": [
        "user",
        "system",
        "nice",
        "idle",
        "iowait",
        "interrupt",
        "steal",
        "kernel"
      ]
    },
    "cpu.logical_number": {
      "description": "The logical CPU number [0..n-1]",
      "type": "number",
      "stability": "development",
      "examples": ["1"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-mocks/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "@sentry/mcp-server-mocks",
  "version": "0.18.0",
  "private": true,
  "type": "module",
  "engines": {
    "node": ">=20"
  },
  "license": "FSL-1.1-ALv2",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
    },
    "./utils": {
      "types": "./dist/utils.d.ts",
      "default": "./dist/utils.js"
    }
  },
  "scripts": {
    "build": "tsdown",
    "dev": "tsdown -w"
  },
  "devDependencies": {
    "@sentry/mcp-server-tsconfig": "workspace:*",
    "tsdown": "catalog:"
  },
  "dependencies": {
    "msw": "catalog:"
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/logging.ts:
--------------------------------------------------------------------------------

```typescript
import type { MiddlewareHandler } from "hono";
import { logInfo } from "@sentry/mcp-server/telem/logging";

/**
 * Hono middleware that logs every request once the response is ready.
 */
export function createRequestLogger(
  loggerScope: readonly string[] = ["cloudflare", "http"],
): MiddlewareHandler {
  return async (c, next) => {
    const start = Date.now();
    await next();

    const url = new URL(c.req.url);
    logInfo(`${c.req.method} ${url.pathname}`, {
      loggerScope,
      extra: {
        status: c.res.status,
        duration_ms: Date.now() - start,
      },
    });
  };
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/signalr.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "signalr",
  "description": "SignalR attributes",
  "attributes": {
    "signalr.connection.status": {
      "description": "SignalR HTTP connection closure status.",
      "type": "string",
      "stability": "stable",
      "examples": ["normal_closure", "timeout", "app_shutdown"]
    },
    "signalr.transport": {
      "description": "[SignalR transport type](https://github.com/dotnet/aspnetcore/blob/main/src/SignalR/docs/specs/TransportProtocols.md)",
      "type": "string",
      "stability": "stable",
      "examples": ["server_sent_events", "long_polling", "web_sockets"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/tools.test.ts:
--------------------------------------------------------------------------------

```typescript
import { assert, test } from "vitest";
import * as tools from "./index.js";

// VSCode (via OpenAI) limits to 1024 characters, but its tough to hit that right now,
// so instead lets limit the blast damage and hope that e.g. OpenAI will increase the limit.
const DESCRIPTION_MAX_LENGTH = 2048;

test(`all tool descriptions under maximum length`, () => {
  for (const tool of Object.values(tools.default)) {
    const length = tool.description.length;
    assert(
      length < DESCRIPTION_MAX_LENGTH,
      `${tool.name} description must be less than ${DESCRIPTION_MAX_LENGTH} characters (was ${length})`,
    );
  }
});

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/backdrop.tsx:
--------------------------------------------------------------------------------

```typescript
interface BackdropProps {
  isOpen: boolean;
  onClose: () => void;
}

export function Backdrop({ isOpen, onClose }: BackdropProps) {
  return (
    <div
      className={`fixed inset-0 bg-black/50 backdrop-blur-sm transition-all duration-500 ease-out ${
        isOpen ? "opacity-100" : "opacity-0"
      }`}
      onClick={isOpen ? onClose : undefined}
      onKeyDown={
        isOpen
          ? (e: React.KeyboardEvent) => e.key === "Escape" && onClose()
          : undefined
      }
      role={isOpen ? "button" : undefined}
      tabIndex={isOpen ? 0 : -1}
      aria-label={isOpen ? "Close chat panel" : undefined}
    />
  );
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/zos.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "zos",
  "description": "This document defines attributes of a z/OS resource.\n",
  "attributes": {
    "zos.smf.id": {
      "description": "The System Management Facility (SMF) Identifier uniquely identified a z/OS system within a SYSPLEX or mainframe environment and is used for system and performance analysis.",
      "type": "string",
      "stability": "development",
      "examples": ["SYS1"]
    },
    "zos.sysplex.name": {
      "description": "The name of the SYSPLEX to which the z/OS system belongs too.",
      "type": "string",
      "stability": "development",
      "examples": ["SYSPLEX1"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-test-client/tsdown.config.ts:
--------------------------------------------------------------------------------

```typescript
import { defineConfig } from "tsdown";
import { readFileSync } from "node:fs";

const packageVersion =
  process.env.npm_package_version ??
  JSON.parse(readFileSync("./package.json", "utf-8")).version;

export default defineConfig({
  entry: ["src/index.ts"],
  format: ["esm"],
  clean: true,
  platform: "node",
  minify: false,
  shims: true,
  banner: {
    js: "#!/usr/bin/env node",
  },
  env: {
    DEFAULT_SENTRY_DSN:
      "https://[email protected]/4509062593708032",
    SENTRY_ENVIRONMENT: "mcp-test-client",
    SENTRY_RELEASE: packageVersion,
    npm_package_version: packageVersion,
  },
});

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/vitest.config.ts:
--------------------------------------------------------------------------------

```typescript
/// <reference types="vitest" />
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    // Use thread-based workers to avoid process-kill issues in sandboxed environments
    pool: "threads",
    poolOptions: {
      workers: {
        miniflare: {},
        wrangler: { configPath: "./wrangler.toml" },
      },
    },
    deps: {
      interopDefault: true,
    },
    include: ["**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
    coverage: {
      provider: "v8",
      reporter: ["text", "json", "html"],
      include: ["**/*.ts"],
    },
    setupFiles: ["dotenv/config", "src/test-setup.ts"],
  },
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/ios.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "ios",
  "description": "This group describes iOS-specific attributes.\n",
  "attributes": {
    "ios.app.state": {
      "description": "This attribute represents the state of the application.\n",
      "type": "string",
      "note": "The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate), and from which the `OS terminology` column values are derived.\n",
      "stability": "development",
      "examples": [
        "active",
        "inactive",
        "background",
        "foreground",
        "terminate"
      ]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/list-dsns.eval.ts:
--------------------------------------------------------------------------------

```typescript
import { describeEval } from "vitest-evals";
import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";

describeEval("list-dsns", {
  data: async () => {
    return [
      {
        input: `What is the SENTRY_DSN for ${FIXTURES.organizationSlug}/${FIXTURES.projectSlug}?`,
        expectedTools: [
          {
            name: "find_dsns",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              projectSlug: FIXTURES.projectSlug,
            },
          },
        ],
      },
    ];
  },
  task: NoOpTaskRunner(),
  scorers: [ToolPredictionScorer()],
  threshold: 0.6,
  timeout: 30000,
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/tsdown.config.ts:
--------------------------------------------------------------------------------

```typescript
import { defineConfig } from "tsdown";
import { readFileSync } from "node:fs";

const packageVersion =
  process.env.npm_package_version ??
  JSON.parse(readFileSync("./package.json", "utf-8")).version;

export default defineConfig({
  entry: ["src/**/*.ts", "!src/**/*.test.ts"],
  format: ["cjs", "esm"], // Build for commonJS and ESmodules
  dts: true, // Generate declaration file (.d.ts)
  sourcemap: true,
  clean: true,
  env: {
    DEFAULT_SENTRY_DSN:
      "https://[email protected]/4509062593708032",
    SENTRY_ENVIRONMENT: "stdio",
    SENTRY_RELEASE: packageVersion,
    npm_package_version: packageVersion,
  },
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/gcp.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "gcp",
  "description": "Attributes for Google Cloud client libraries.\n",
  "attributes": {
    "gcp.client.service": {
      "description": "Identifies the Google Cloud service for which the official client library is intended.",
      "type": "string",
      "note": "Intended to be a stable identifier for Google Cloud client libraries that is uniform across implementation languages. The value should be derived from the canonical service domain for the service; for example, 'foo.googleapis.com' should result in a value of 'foo'.\n",
      "stability": "development",
      "examples": ["appengine", "run", "firestore", "alloydb", "spanner"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/chat/index.ts:
--------------------------------------------------------------------------------

```typescript
// Chat components
export { Chat } from "./chat";
export { ChatUI } from "./chat-ui";
export { ChatMessages } from "./chat-messages";
export { ChatInput } from "./chat-input";
export { MessagePart, TextPart, ToolPart } from "./chat-message";
export { ToolContent, ToolInvocation } from "./tool-invocation";

// Auth components
export { AuthForm } from "./auth-form";

// Export types
export type {
  ChatProps,
  ChatUIProps,
  ChatMessagesProps,
  ChatInputProps,
  AuthFormProps,
  MessagePartProps,
  TextPartProps,
  ToolPartProps,
  ToolInvocationProps,
  AuthState,
  AuthActions,
  AuthContextType,
  ChatToolInvocation,
  ToolMessage,
  ProcessedMessagePart,
} from "./types";

```

--------------------------------------------------------------------------------
/.claude/commands/gh-pr.md:
--------------------------------------------------------------------------------

```markdown
Create (or update) a Pull Request.

We use the GitHub CLI (`gh`) to manage pull requests.

If this branch does not already have a pull request, create one:

- If we're on the main branch, switch to a working branch.
- Commit our changes if we haven't already.

If we already have one:

- Verify our changes against the base branch and update the PR title and description to maintain accuracy.

We should never focus on a test plan in the PR, but rather a concise description of the changes (features, breaking changes, major bug fixes, and architectural changes). Only include changes if they're present. We're always contrasting against our base branch when we describe these changes.

```

--------------------------------------------------------------------------------
/packages/mcp-server-mocks/src/fixtures/team.json:
--------------------------------------------------------------------------------

```json
{
  "id": "4509106740854784",
  "slug": "the-goats",
  "name": "the-goats",
  "dateCreated": "2025-04-06T14:11:23.961739Z",
  "isMember": true,
  "teamRole": "admin",
  "flags": { "idp:provisioned": false },
  "access": [
    "team:read",
    "alerts:read",
    "event:write",
    "team:write",
    "team:admin",
    "event:read",
    "org:read",
    "member:read",
    "project:admin",
    "project:write",
    "org:integrations",
    "project:releases",
    "alerts:write",
    "event:admin",
    "project:read"
  ],
  "hasAccess": true,
  "isPending": false,
  "memberCount": 1,
  "avatar": { "avatarType": "letter_avatar", "avatarUuid": null },
  "externalTeams": [],
  "projects": []
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-mocks/src/fixtures/trace-items-attributes-logs-string.json:
--------------------------------------------------------------------------------

```json
[
  {
    "key": "message",
    "name": "Log Message"
  },
  {
    "key": "severity",
    "name": "Log Severity"
  },
  {
    "key": "sentry.item_id",
    "name": "Sentry Item ID"
  },
  {
    "key": "project",
    "name": "Project"
  },
  {
    "key": "environment",
    "name": "Environment"
  },
  {
    "key": "release",
    "name": "Release"
  },
  {
    "key": "trace",
    "name": "Trace ID"
  },
  {
    "key": "level",
    "name": "Log Level"
  },
  {
    "key": "logger",
    "name": "Logger Name"
  },
  {
    "key": "module",
    "name": "Module"
  },
  {
    "key": "custom.service",
    "name": "Service Name"
  },
  {
    "key": "custom.component",
    "name": "Component"
  }
]

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/create-dsn.eval.ts:
--------------------------------------------------------------------------------

```typescript
import { describeEval } from "vitest-evals";
import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";

describeEval("create-dsn", {
  data: async () => {
    return [
      {
        input: `Create a new DSN named "Production" for '${FIXTURES.organizationSlug}/${FIXTURES.projectSlug}'`,
        expectedTools: [
          {
            name: "create_dsn",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              projectSlug: FIXTURES.projectSlug,
              name: "Production",
            },
          },
        ],
      },
    ];
  },
  task: NoOpTaskRunner(),
  scorers: [ToolPredictionScorer()],
  threshold: 0.6,
  timeout: 30000,
});

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/list-tags.eval.ts:
--------------------------------------------------------------------------------

```typescript
import { describeEval } from "vitest-evals";
import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";

describeEval("list-tags", {
  data: async () => {
    return [
      {
        input: `What are common tags in ${FIXTURES.organizationSlug}`,
        expectedTools: [
          {
            name: "find_organizations",
            arguments: {},
          },
          {
            name: "find_tags",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              regionUrl: "https://us.sentry.io",
            },
          },
        ],
      },
    ];
  },
  task: NoOpTaskRunner(),
  scorers: [ToolPredictionScorer()],
  threshold: 0.6,
  timeout: 30000,
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/errors.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Error thrown when user input validation fails.
 * These errors should be returned to the user directly without logging to Sentry.
 */
export class UserInputError extends Error {
  constructor(message: string, options?: ErrorOptions) {
    super(message, options);
    this.name = "UserInputError";
  }
}

/**
 * Error thrown when configuration is invalid or missing.
 * These errors should be returned to the user directly without logging to Sentry.
 * Typically used for environment configuration issues, connection settings, etc.
 */
export class ConfigurationError extends Error {
  constructor(message: string, options?: ErrorOptions) {
    super(message, options);
    this.name = "ConfigurationError";
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/aws.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "aws",
  "description": "This section defines generic attributes for AWS services.\n",
  "attributes": {
    "aws.request_id": {
      "description": "The AWS request ID as returned in the response headers `x-amzn-requestid`, `x-amzn-request-id` or `x-amz-request-id`.",
      "type": "string",
      "stability": "development",
      "examples": ["79b9da39-b7ae-508a-a6bc-864b2829c622", "C9ER4AJX75574TDJ"]
    },
    "aws.extended_request_id": {
      "description": "The AWS extended request ID as returned in the response header `x-amz-id-2`.",
      "type": "string",
      "stability": "development",
      "examples": [
        "wzHcyEWfmOGDIE5QOhTAqFDoDWP3y8IUvpNINCwL9N4TEHbUw0/gZJ+VZTmCNCWR7fezEN3eCiQ="
      ]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/list-projects.eval.ts:
--------------------------------------------------------------------------------

```typescript
import { describeEval } from "vitest-evals";
import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";

describeEval("list-projects", {
  data: async () => {
    return [
      {
        input: `What projects do I have access to in Sentry for '${FIXTURES.organizationSlug}'`,
        expectedTools: [
          {
            name: "find_organizations",
            arguments: {},
          },
          {
            name: "find_projects",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              regionUrl: "https://us.sentry.io",
            },
          },
        ],
      },
    ];
  },
  task: NoOpTaskRunner(),
  scorers: [ToolPredictionScorer()],
  threshold: 0.6,
  timeout: 30000,
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/create-team.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from "vitest";
import createTeam from "./create-team.js";

describe("create_team", () => {
  it("serializes", async () => {
    const result = await createTeam.handler(
      {
        organizationSlug: "sentry-mcp-evals",
        name: "the-goats",
        regionUrl: undefined,
      },
      {
        constraints: {
          organizationSlug: null,
        },
        accessToken: "access-token",
        userId: "1",
      },
    );
    expect(result).toMatchInlineSnapshot(`
      "# New Team in **sentry-mcp-evals**

      **ID**: 4509109078196224
      **Slug**: the-goats
      **Name**: the-goats
      # Using this information

      - You should always inform the user of the Team Slug value.
      "
    `);
  });
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/test-utils/context.ts:
--------------------------------------------------------------------------------

```typescript
import type { ServerContext } from "../types";
import type { Scope } from "../permissions";

/**
 * Create a test context with default values for testing tools
 */
export function createTestContext(
  overrides: Partial<ServerContext> = {},
): ServerContext {
  return {
    accessToken: "test-access-token",
    constraints: {},
    grantedScopes: new Set<Scope>([
      "org:read",
      "project:write",
      "team:write",
      "event:write",
    ]),
    ...overrides,
  };
}

/**
 * Create a test context with specific constraints
 */
export function createTestContextWithConstraints(
  constraints: ServerContext["constraints"],
  overrides: Partial<ServerContext> = {},
): ServerContext {
  return createTestContext({
    constraints,
    ...overrides,
  });
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/app.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from "vitest";
import app from "./app";

describe("app", () => {
  describe("GET /robots.txt", () => {
    it("should return correct robots.txt content", async () => {
      const res = await app.request("/robots.txt");

      expect(res.status).toBe(200);

      const text = await res.text();
      expect(text).toBe(
        ["User-agent: *", "Allow: /$", "Disallow: /"].join("\n"),
      );
    });
  });

  describe("GET /llms.txt", () => {
    it("should return correct llms.txt content", async () => {
      const res = await app.request("/llms.txt");

      expect(res.status).toBe(200);

      const text = await res.text();
      expect(text).toContain("# sentry-mcp");
      expect(text).toContain("Model Context Protocol");
    });
  });
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/v8js.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "v8js",
  "description": "Describes V8 JS Engine Runtime related attributes.",
  "attributes": {
    "v8js.gc.type": {
      "description": "The type of garbage collection.",
      "type": "string",
      "stability": "development",
      "examples": ["major", "minor", "incremental", "weakcb"]
    },
    "v8js.heap.space.name": {
      "description": "The name of the space type of heap memory.",
      "type": "string",
      "note": "Value can be retrieved from value `space_name` of [`v8.getHeapSpaceStatistics()`](https://nodejs.org/api/v8.html#v8getheapspacestatistics)\n",
      "stability": "development",
      "examples": [
        "new_space",
        "old_space",
        "code_space",
        "map_space",
        "large_object_space"
      ]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/setup-env.ts:
--------------------------------------------------------------------------------

```typescript
import { config } from "dotenv";
import path from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = path.dirname(fileURLToPath(import.meta.url));

// Load environment variables from multiple possible locations
// IMPORTANT: Do NOT use override:true as it would overwrite shell/CI environment variables
const rootDir = path.resolve(__dirname, "../../../");

// Load local package .env first (for package-specific overrides)
config({ path: path.resolve(__dirname, "../.env") });

// Load root .env second (for shared defaults - won't override local or shell vars)
config({ path: path.join(rootDir, ".env") });

// Start the shared MSW server for all eval tests
import { startMockServer } from "@sentry/mcp-server-mocks/utils";

startMockServer({ ignoreOpenAI: true });

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/types.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Core type system for MCP tools.
 *
 * Defines TypeScript types derived from tool definitions, handler signatures,
 * and server context. Uses advanced TypeScript patterns for type-safe parameter
 * extraction and handler registration.
 */
import type { Scope } from "./permissions";

/**
 * Constraints that restrict the MCP session scope
 */
export type Constraints = {
  organizationSlug?: string | null;
  projectSlug?: string | null;
  regionUrl?: string | null;
};

export type ServerContext = {
  sentryHost?: string;
  mcpUrl?: string;
  accessToken: string;
  openaiBaseUrl?: string;
  userId?: string | null;
  clientId?: string;
  // Granted scopes for tool access control
  grantedScopes?: Set<Scope> | ReadonlySet<Scope>;
  // URL-based session constraints
  constraints: Constraints;
};

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/heroku.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "heroku",
  "description": "This document defines attributes for the Heroku platform on which application/s are running.\n",
  "attributes": {
    "heroku.release.creation_timestamp": {
      "description": "Time and date the release was created\n",
      "type": "string",
      "stability": "development",
      "examples": ["2022-10-23T18:00:42Z"]
    },
    "heroku.release.commit": {
      "description": "Commit hash for the current release\n",
      "type": "string",
      "stability": "development",
      "examples": ["e6134959463efd8966b20e75b913cafe3f5ec"]
    },
    "heroku.app.id": {
      "description": "Unique identifier for the application\n",
      "type": "string",
      "stability": "development",
      "examples": ["2daa2797-e42b-4624-9322-ec3f968df4da"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/openai-provider.ts:
--------------------------------------------------------------------------------

```typescript
import { createOpenAI, openai as defaultOpenAI } from "@ai-sdk/openai";
import type { LanguageModelV1 } from "ai";

let customFactory: ReturnType<typeof createOpenAI> | null = null;

/**
 * Configure the OpenAI provider factory.
 *
 * When a base URL is provided, the factory will use that endpoint for all
 * subsequent model requests. Passing undefined resets to the default
 * configuration bundled with the SDK.
 */
export function configureOpenAIProvider({
  baseUrl,
}: {
  baseUrl?: string;
}): void {
  if (baseUrl) {
    customFactory = createOpenAI({
      baseURL: baseUrl,
    });
    return;
  }
  customFactory = null;
}

/**
 * Retrieve a configured OpenAI language model.
 */
export function getOpenAIModel(model: string): LanguageModelV1 {
  const factory = customFactory ?? defaultOpenAI;
  return factory(model);
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/graphql.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "graphql",
  "description": "This document defines attributes for GraphQL.",
  "attributes": {
    "graphql.operation.name": {
      "description": "The name of the operation being executed.",
      "type": "string",
      "stability": "development",
      "examples": ["findBookById"]
    },
    "graphql.operation.type": {
      "description": "The type of the operation being executed.",
      "type": "string",
      "stability": "development",
      "examples": ["query", "mutation", "subscription"]
    },
    "graphql.document": {
      "description": "The GraphQL document being executed.",
      "type": "string",
      "note": "The value may be sanitized to exclude sensitive information.",
      "stability": "development",
      "examples": ["query findBookById { bookById(id: ?) { name } }"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/create-team.eval.ts:
--------------------------------------------------------------------------------

```typescript
import { describeEval } from "vitest-evals";
import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";

describeEval("create-team", {
  data: async () => {
    return [
      {
        input: `Create a new team in Sentry for '${FIXTURES.organizationSlug}' called 'the-goats' response with **only** the team slug and no other text.`,
        expectedTools: [
          {
            name: "find_organizations",
            arguments: {},
          },
          {
            name: "create_team",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              name: "the-goats",
              regionUrl: "https://us.sentry.io",
            },
          },
        ],
      },
    ];
  },
  task: NoOpTaskRunner(),
  scorers: [ToolPredictionScorer()],
  threshold: 0.6,
  timeout: 30000,
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/oci.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "oci",
  "description": "An OCI image manifest.\n",
  "attributes": {
    "oci.manifest.digest": {
      "description": "The digest of the OCI image manifest. For container images specifically is the digest by which the container image is known.\n",
      "type": "string",
      "note": "Follows [OCI Image Manifest Specification](https://github.com/opencontainers/image-spec/blob/main/manifest.md), and specifically the [Digest property](https://github.com/opencontainers/image-spec/blob/main/descriptor.md#digests).\nAn example can be found in [Example Image Manifest](https://github.com/opencontainers/image-spec/blob/main/manifest.md#example-image-manifest).\n",
      "stability": "development",
      "examples": [
        "sha256:e4ca62c0d62f3e886e684806dfe9d4e0cda60d54986898173c1083856cfda0f4"
      ]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/base.tsx:
--------------------------------------------------------------------------------

```typescript
import { cn } from "../../lib/utils";

export function Heading({
  children,
  as,
  className,
  ...props
}: {
  children: React.ReactNode;
  as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
} & React.HTMLAttributes<HTMLHeadingElement>) {
  const Tag = as || "h2";
  return (
    <Tag
      className={cn("text-2xl font-bold mb-6 text-white", className)}
      {...props}
    >
      <div className="flex flex-row gap-2">{children}</div>
      <div className="h-[2px] mt-1 bg-violet-300 w-full" />
    </Tag>
  );
}

export function Link({
  children,
  className,
  href,
  ...props
}: {
  children: React.ReactNode;
  href: string;
} & React.HTMLAttributes<HTMLAnchorElement>) {
  return (
    <a
      href={href}
      className={cn("text-violet-300 font-semibold underline", className)}
      {...props}
    >
      {children}
    </a>
  );
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/webengine.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "webengine",
  "description": "This document defines the attributes used to describe the packaged software running the application code.\n",
  "attributes": {
    "webengine.name": {
      "description": "The name of the web engine.\n",
      "type": "string",
      "stability": "development",
      "examples": ["WildFly"]
    },
    "webengine.version": {
      "description": "The version of the web engine.\n",
      "type": "string",
      "stability": "development",
      "examples": ["21.0.0"]
    },
    "webengine.description": {
      "description": "Additional description of the web engine (e.g. detailed version and edition information).\n",
      "type": "string",
      "stability": "development",
      "examples": [
        "WildFly Full 21.0.0.Final (WildFly Core 13.0.1.Final) - 2.2.2.Final"
      ]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "@sentry/mcp-server-evals",
  "version": "0.18.0",
  "private": true,
  "type": "module",
  "engines": {
    "node": ">=20"
  },
  "license": "FSL-1.1-ALv2",
  "scripts": {
    "build": "tsc -b",
    "dev": "tsc -w",
    "start": "tsx src/bin/start-mock-stdio.ts",
    "eval": "vitest --config=vitest.config.ts",
    "eval:ci": "vitest run --coverage --reporter=vitest-evals/reporter --reporter=junit --outputFile=eval.junit.xml"
  },
  "dependencies": {
    "@ai-sdk/openai": "catalog:",
    "@modelcontextprotocol/sdk": "catalog:",
    "@sentry/mcp-server": "workspace:*",
    "@sentry/mcp-server-mocks": "workspace:*",
    "@sentry/mcp-server-tsconfig": "workspace:*",
    "ai": "catalog:",
    "dotenv": "catalog:",
    "msw": "catalog:",
    "typescript": "catalog:",
    "vitest": "catalog:",
    "vitest-evals": "catalog:",
    "zod": "catalog:"
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/dns.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "dns",
  "description": "This document defines the shared attributes used to report a DNS query.\n",
  "attributes": {
    "dns.question.name": {
      "description": "The name being queried.",
      "type": "string",
      "note": "If the name field contains non-printable characters (below 32 or above 126), those characters should be represented as escaped base 10 integers (\\DDD). Back slashes and quotes should be escaped. Tabs, carriage returns, and line feeds should be converted to \\t, \\r, and \\n respectively.\n",
      "stability": "development",
      "examples": ["www.example.com", "opentelemetry.io"]
    },
    "dns.answers": {
      "description": "The list of IPv4 or IPv6 addresses resolved during DNS lookup.",
      "type": "string",
      "stability": "development",
      "examples": ["[\"10.0.0.1\",\"2001:0db8:85a3:0000:0000:8a2e:0370:7334\"]"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/main.tsx:
--------------------------------------------------------------------------------

```typescript
import "./instrument";

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./app";
import { AuthProvider } from "./contexts/auth-context";
import * as Sentry from "@sentry/react";

const container = document.getElementById("root");

const root = createRoot(container!, {
  // Callback called when an error is thrown and not caught by an ErrorBoundary.
  onUncaughtError: Sentry.reactErrorHandler((error, errorInfo) => {
    console.warn("Uncaught error", error, errorInfo.componentStack);
  }),
  // Callback called when React catches an error in an ErrorBoundary.
  onCaughtError: Sentry.reactErrorHandler(),
  // Callback called when React automatically recovers from errors.
  onRecoverableError: Sentry.reactErrorHandler(),
});

root.render(
  <StrictMode>
    <AuthProvider>
      <App />
    </AuthProvider>
  </StrictMode>,
);

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/template-vars.tsx:
--------------------------------------------------------------------------------

```typescript
interface TemplateVarsProps {
  variables?: readonly string[] | null;
  title?: string;
}

/**
 * Renders a standardized Parameters box for template variables.
 */
export default function TemplateVars({
  variables,
  title = "Parameters",
}: TemplateVarsProps) {
  const vars = Array.isArray(variables) ? variables : [];
  if (vars.length === 0) return null;

  return (
    <section className="rounded-md border border-slate-700/60 bg-black/30 p-3">
      <div className="text-xs uppercase tracking-wide text-slate-300/80 mb-2">
        {title}
      </div>
      <div className="flex flex-wrap gap-2">
        {vars.map((v) => (
          <span
            key={v}
            className="inline-flex items-center rounded-full border border-violet-500/40 bg-violet-500/10 px-2 py-0.5 text-xs font-mono text-violet-200"
          >
            {v}
          </span>
        ))}
      </div>
    </section>
  );
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/create-dsn.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from "vitest";
import createDsn from "./create-dsn.js";

describe("create_dsn", () => {
  it("serializes", async () => {
    const result = await createDsn.handler(
      {
        organizationSlug: "sentry-mcp-evals",
        projectSlug: "cloudflare-mcp",
        name: "Default",
        regionUrl: undefined,
      },
      {
        constraints: {
          organizationSlug: null,
          projectSlug: null,
        },
        accessToken: "access-token",
        userId: "1",
      },
    );
    expect(result).toMatchInlineSnapshot(`
      "# New DSN in **sentry-mcp-evals/cloudflare-mcp**

      **DSN**: https://d20df0a1ab5031c7f3c7edca9c02814d@o4509106732793856.ingest.us.sentry.io/4509109104082945
      **Name**: Default

      # Using this information

      - The \`SENTRY_DSN\` value is a URL that you can use to initialize Sentry's SDKs.
      "
    `);
  });
});

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/tool-actions.tsx:
--------------------------------------------------------------------------------

```typescript
/**
 * Component for rendering a readable list of tools
 */

export interface ToolInfo {
  name: string;
  description: string;
}

interface ToolActionsProps {
  tools: ToolInfo[];
}

export function ToolActions({ tools }: ToolActionsProps) {
  if (!tools || tools.length === 0) return null;

  return (
    <div className="mt-4 space-y-3">
      <h4 className="text-sm font-medium text-slate-300 mb-2">Tools</h4>
      <div className="space-y-4">
        {tools.map((tool) => (
          <div key={tool.name} className="space-y-2">
            <div className="inline-block rounded border border-slate-700 bg-slate-900 px-2 py-1 text-[11px] font-mono text-slate-200">
              <code>{tool.name}</code>
            </div>
            {tool.description ? (
              <p className="text-xs text-slate-400 ml-1">{tool.description}</p>
            ) : null}
          </div>
        ))}
      </div>
    </div>
  );
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/find-dsns.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from "vitest";
import findDsns from "./find-dsns.js";

describe("find_dsns", () => {
  it("serializes", async () => {
    const result = await findDsns.handler(
      {
        organizationSlug: "sentry-mcp-evals",
        projectSlug: "cloudflare-mcp",
        regionUrl: undefined,
      },
      {
        constraints: {
          organizationSlug: null,
          projectSlug: null,
        },
        accessToken: "access-token",
        userId: "1",
      },
    );
    expect(result).toMatchInlineSnapshot(`
      "# DSNs in **sentry-mcp-evals/cloudflare-mcp**

      ## Default
      **ID**: d20df0a1ab5031c7f3c7edca9c02814d
      **DSN**: https://d20df0a1ab5031c7f3c7edca9c02814d@o4509106732793856.ingest.us.sentry.io/4509109104082945

      # Using this information

      - The \`SENTRY_DSN\` value is a URL that you can use to initialize Sentry's SDKs.
      "
    `);
  });
});

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/autofix.eval.ts:
--------------------------------------------------------------------------------

```typescript
import { describeEval } from "vitest-evals";
import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";

describeEval("begin-issue-fix", {
  data: async () => {
    return [
      {
        input: `Whats the status on root causing this issue in Sentry?\n${FIXTURES.testIssueUrl}`,
        expectedTools: [
          {
            name: "analyze_issue_with_seer",
            arguments: {
              issueUrl: FIXTURES.testIssueUrl,
            },
          },
        ],
      },
      {
        input: `Can you root cause this issue and retrieve the analysis?\n${FIXTURES.testIssueUrl}`,
        expectedTools: [
          {
            name: "analyze_issue_with_seer",
            arguments: {
              issueUrl: FIXTURES.testIssueUrl,
            },
          },
        ],
      },
    ];
  },
  task: NoOpTaskRunner(),
  scorers: [ToolPredictionScorer()],
  threshold: 0.6,
  timeout: 30000,
});

```

--------------------------------------------------------------------------------
/packages/mcp-server-tsconfig/tsconfig.base.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Default",
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2023"],
    "module": "ESNext",
    "preserveWatchOutput": true,

    /* Bundler mode */
    "moduleResolution": "Bundler",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "allowImportingTsExtensions": false,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": false,

    /* Linting */
    "strict": true,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true,
    "forceConsistentCasingInFileNames": true,

    /* Basic Options */
    "sourceMap": true,
    "composite": false,
    "incremental": true,
    "declaration": true,
    "declarationMap": true,
    "allowJs": true
  },
  "include": [],
  "exclude": ["node_modules"]
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-mocks/src/utils.ts:
--------------------------------------------------------------------------------

```typescript
import { setupServer } from "msw/node";
import type { SetupServer } from "msw/node";

export function setupMockServer(handlers: Array<any> = []): SetupServer {
  return setupServer(...handlers);
}

/**
 * Start the MSW server with common configuration for Sentry MCP tests
 * This helper ensures consistent configuration across all test suites
 */
export function startMockServer(options?: {
  ignoreOpenAI?: boolean;
}): void {
  const { ignoreOpenAI = true } = options || {};

  // Import here to avoid circular dependency
  const { mswServer } = require("./index");

  mswServer.listen({
    onUnhandledRequest: (req: any, print: any) => {
      // Ignore OpenAI requests if specified (default behavior for AI agent tests)
      if (ignoreOpenAI && req.url.startsWith("https://api.openai.com/")) {
        return;
      }

      print.warning();
      throw new Error(`Unhandled request: ${req.method} ${req.url}`);
    },
  });
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/enduser.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "enduser",
  "description": "Describes the end user.\n",
  "attributes": {
    "enduser.id": {
      "description": "Unique identifier of an end user in the system. It maybe a username, email address, or other identifier.",
      "type": "string",
      "note": "Unique identifier of an end user in the system.\n\n> [!Warning]\n> This field contains sensitive (PII) information.\n",
      "stability": "development",
      "examples": ["username"]
    },
    "enduser.pseudo.id": {
      "description": "Pseudonymous identifier of an end user. This identifier should be a random value that is not directly linked or associated with the end user's actual identity.\n",
      "type": "string",
      "note": "Pseudonymous identifier of an end user.\n\n> [!Warning]\n> This field contains sensitive (linkable PII) information.\n",
      "stability": "development",
      "examples": ["QdH5CAWJgqVT4rOr0qtumf"]
    }
  }
}

```

--------------------------------------------------------------------------------
/biome.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
  "organizeImports": {
    "enabled": true
  },
  "files": {
    "ignore": [
      "worker-configuration.d.ts",
      "tsconfig*.json",
      "packages/mcp-server-mocks/src/fixtures/**"
    ]
  },
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "correctness": {
        "noUnusedImports": "warn"
      },
      "suspicious": {
        "noExplicitAny": "off",
        "noDebugger": "off",
        "noConsoleLog": "off",
        "noConfusingVoidType": "off"
      },
      "style": {
        "noNonNullAssertion": "off",
        "noUnusedTemplateLiteral": "off"
      },
      "security": {
        "noDangerouslySetInnerHtml": "off"
      }
    }
  },
  "formatter": {
    "enabled": true,
    "indentWidth": 2,
    "indentStyle": "space"
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/icons/sentry.tsx:
--------------------------------------------------------------------------------

```typescript
import { Icon } from "../icon";

export function SentryIcon({ className }: { className?: string }) {
  return (
    <Icon
      className={className}
      path="M17.48 1.996c.45.26.823.633 1.082 1.083l13.043 22.622a2.962 2.962 0 0 1-2.562 4.44h-3.062c.043-.823.039-1.647 0-2.472h3.052a.488.488 0 0 0 .43-.734L16.418 4.315a.489.489 0 0 0-.845 0L12.582 9.51a23.16 23.16 0 0 1 7.703 8.362 23.19 23.19 0 0 1 2.8 11.024v1.234h-7.882v-1.236a15.284 15.284 0 0 0-6.571-12.543l-1.48 2.567a12.301 12.301 0 0 1 5.105 9.987v1.233h-9.3a2.954 2.954 0 0 1-2.56-1.48A2.963 2.963 0 0 1 .395 25.7l1.864-3.26a6.854 6.854 0 0 1 2.15 1.23l-1.883 3.266a.49.49 0 0 0 .43.734h6.758a9.985 9.985 0 0 0-4.83-7.272l-1.075-.618 3.927-6.835 1.075.615a17.728 17.728 0 0 1 6.164 5.956 17.752 17.752 0 0 1 2.653 8.154h2.959a20.714 20.714 0 0 0-3.05-9.627 20.686 20.686 0 0 0-7.236-7.036l-1.075-.618 4.215-7.309a2.958 2.958 0 0 1 4.038-1.083Z"
      title="Sentry Logo"
    />
  );
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/types.ts:
--------------------------------------------------------------------------------

```typescript
import type { z } from "zod";
import type { ServerContext } from "../types";
import type { Scope } from "../permissions";
import type {
  TextContent,
  ImageContent,
  EmbeddedResource,
} from "@modelcontextprotocol/sdk/types.js";

export interface ToolConfig<
  TSchema extends Record<string, z.ZodType> = Record<string, z.ZodType>,
> {
  name: string;
  description: string;
  inputSchema: TSchema;
  requiredScopes: Scope[];
  annotations: {
    readOnlyHint?: boolean;
    destructiveHint?: boolean;
    idempotentHint?: boolean;
    openWorldHint?: boolean;
  };
  handler: (
    params: z.infer<z.ZodObject<TSchema>>,
    context: ServerContext,
  ) => Promise<string | (TextContent | ImageContent | EmbeddedResource)[]>;
}

/**
 * Response from the search API endpoint
 */
export interface SearchResponse {
  query: string;
  results: Array<{
    id: string;
    url: string;
    snippet: string;
    relevance: number;
  }>;
  error?: string;
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/utils/fixtures.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * IMPORTANT: Keep evaluation tests minimal!
 *
 * Each eval test takes 30+ seconds to run and costs API credits.
 * Only create evaluation tests for the core use cases of each tool:
 * - Primary functionality (e.g., resolving an issue)
 * - Alternative input methods (e.g., using issue URL vs org+issueId)
 * - One complex workflow example if applicable
 *
 * Avoid testing edge cases, error conditions, or minor variations in evals.
 * Use unit tests (tools.test.ts) for comprehensive coverage instead.
 */

export const FIXTURES = {
  organizationSlug: "sentry-mcp-evals",
  teamSlug: "the-goats",
  projectSlug: "cloudflare-mcp",
  issueId: "CLOUDFLARE-MCP-41",
  issueUrl: "https://sentry-mcp-evals.sentry.io/issues/CLOUDFLARE-MCP-41/",
  testIssueUrl: "https://sentry-mcp-evals.sentry.io/issues/PEATED-A8",
  traceId: "a4d1aae7216b47ff8117cf4e09ce9d0a",
  dsn: "https://d20df0a1ab5031c7f3c7edca9c02814d@o4509106732793856.ingest.us.sentry.io/4509109104082945",
};

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/android.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "android",
  "description": "The Android platform on which the Android application is running.\n",
  "attributes": {
    "android.os.api_level": {
      "description": "Uniquely identifies the framework API revision offered by a version (`os.version`) of the android operating system. More information can be found [here](https://developer.android.com/guide/topics/manifest/uses-sdk-element#ApiLevels).\n",
      "type": "string",
      "stability": "development",
      "examples": ["33", "32"]
    },
    "android.app.state": {
      "description": "This attribute represents the state of the application.\n",
      "type": "string",
      "note": "The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n",
      "stability": "development",
      "examples": ["created", "background", "foreground"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-test-client/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "@sentry/mcp-test-client",
  "version": "0.18.0",
  "private": true,
  "type": "module",
  "description": "CLI tool to test the Sentry MCP server",
  "bin": {
    "sentry-mcp-test-client": "./dist/index.js"
  },
  "scripts": {
    "build": "tsdown",
    "start": "node dist/index.js",
    "test-client": "node dist/index.js",
    "test": "vitest run",
    "test:ci": "vitest run --reporter=default --reporter=junit --outputFile=tests.junit.xml",
    "test:watch": "vitest",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "@ai-sdk/openai": "catalog:",
    "@modelcontextprotocol/sdk": "catalog:",
    "@sentry/core": "catalog:",
    "@sentry/mcp-server": "workspace:*",
    "@sentry/node": "catalog:",
    "ai": "catalog:",
    "chalk": "catalog:",
    "commander": "catalog:",
    "dotenv": "catalog:",
    "open": "catalog:"
  },
  "devDependencies": {
    "tsdown": "catalog:",
    "tsx": "catalog:",
    "typescript": "catalog:",
    "vitest": "catalog:"
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/lib/slug-validation.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Validates that a slug is safe and follows expected patterns.
 * Used to validate organization and project slugs from URL paths.
 */
export function isValidSlug(slug: string): boolean {
  // Reject empty strings
  if (!slug || slug.length === 0) {
    return false;
  }

  // Reject excessively long slugs (prevent DOS)
  if (slug.length > 100) {
    return false;
  }

  // Reject path traversal attempts
  if (slug.includes("..") || slug.includes("//")) {
    return false;
  }

  // Reject URLs or suspicious patterns
  if (slug.includes("://") || slug.includes("%")) {
    return false;
  }

  // Must start and end with alphanumeric
  if (!/^[a-zA-Z0-9].*[a-zA-Z0-9]$/.test(slug) && slug.length > 1) {
    return false;
  }

  // Single character must be alphanumeric
  if (slug.length === 1 && !/^[a-zA-Z0-9]$/.test(slug)) {
    return false;
  }

  // Only allow alphanumeric, dots, dashes, and underscores
  if (!/^[a-zA-Z0-9._-]+$/.test(slug)) {
    return false;
  }

  return true;
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/routes/mcp.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Public MCP metadata endpoints under `/.mcp/*` for external documentation sites.
 *
 * Responds with pre-generated JSON payloads from @sentry/mcp-server.
 * Adds permissive CORS for easy cross-origin consumption.
 */
import { Hono } from "hono";
import TOOL_DEFINITIONS from "@sentry/mcp-server/toolDefinitions";

function withCors(json: unknown, status = 200) {
  const body = JSON.stringify(json);
  return new Response(body, {
    status,
    headers: {
      "Content-Type": "application/json; charset=utf-8",
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Methods": "GET, OPTIONS",
      "Access-Control-Allow-Headers": "Content-Type",
      "Cache-Control": "public, max-age=300", // 5 minutes
    },
  });
}

export default new Hono()
  // CORS preflight
  .options("/*", (c) => withCors(null, 204))
  // Index: advertise available endpoints
  .get("/", (c) =>
    withCors({
      endpoints: ["/.mcp/tools.json"],
    }),
  )
  // Tools
  .get("/tools.json", (c) => withCors(TOOL_DEFINITIONS));

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/types.ts:
--------------------------------------------------------------------------------

```typescript
import type { OAuthHelpers } from "@cloudflare/workers-oauth-provider";
import type {
  RateLimit,
  WorkerVersionMetadata,
} from "@cloudflare/workers-types";
import type { ServerContext } from "@sentry/mcp-server/types";

export type WorkerProps = ServerContext & {
  id: string;
  name: string;
  scope: string;
  grantedScopes?: string[]; // Array of scope strings passed from OAuth
  refreshToken?: string; // Refresh token for OAuth token renewal
  accessTokenExpiresAt?: number; // Timestamp when the upstream access token expires
};

export interface Env {
  NODE_ENV: string;
  ASSETS: Fetcher;
  OAUTH_KV: KVNamespace;
  COOKIE_SECRET: string;
  SENTRY_CLIENT_ID: string;
  SENTRY_CLIENT_SECRET: string;
  SENTRY_ENVIRONMENT?: string;
  SENTRY_DSN?: string;
  SENTRY_HOST?: string;
  OPENAI_API_KEY: string;
  MCP_OBJECT: DurableObjectNamespace;
  OAUTH_PROVIDER: OAuthHelpers;
  AI: Ai;
  CF_VERSION_METADATA: WorkerVersionMetadata;
  CHAT_RATE_LIMITER: RateLimit;
  SEARCH_RATE_LIMITER: RateLimit;
  AUTORAG_INDEX_NAME?: string;
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/create-project.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from "vitest";
import createProject from "./create-project.js";

describe("create_project", () => {
  it("serializes", async () => {
    const result = await createProject.handler(
      {
        organizationSlug: "sentry-mcp-evals",
        teamSlug: "the-goats",
        name: "cloudflare-mcp",
        platform: "node",
        regionUrl: undefined,
      },
      {
        constraints: {
          organizationSlug: null,
        },
        accessToken: "access-token",
        userId: "1",
      },
    );
    expect(result).toMatchInlineSnapshot(`
      "# New Project in **sentry-mcp-evals**

      **ID**: 4509109104082945
      **Slug**: cloudflare-mcp
      **Name**: cloudflare-mcp
      **SENTRY_DSN**: https://d20df0a1ab5031c7f3c7edca9c02814d@o4509106732793856.ingest.us.sentry.io/4509109104082945

      # Using this information

      - You can reference the **SENTRY_DSN** value to initialize Sentry's SDKs.
      - You should always inform the user of the **SENTRY_DSN** and Project Slug values.
      "
    `);
  });
});

```

--------------------------------------------------------------------------------
/.claude/settings.json:
--------------------------------------------------------------------------------

```json
{
  "permissions": {
    "allow": [
      "WebFetch(domain:mcp.sentry.dev)",
      "WebFetch(domain:docs.sentry.io)",
      "WebFetch(domain:develop.sentry.dev)",
      "WebFetch(domain:modelcontextprotocol.io)",
      "WebFetch(domain:docs.anthropic.com)",
      "Bash(grep:*)",
      "Bash(jq:*)",
      "Bash(pnpx vitest:*)",
      "Bash(pnpm test:*)",
      "Bash(pnpm run typecheck:*)",
      "Bash(pnpm run check:*)",
      "Bash(pnpm run:*)",
      "Bash(pnpx tsx:*)",
      "Bash(gh pr checks:*)",
      "Bash(gh pr view:*)",
      "Bash(gh run view:*)",
      "Bash(git status:*)"
    ],
    "deny": []
  },
  "hooks": {
    "UserPromptSubmit": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'MANDATORY: If something is unclear, you MUST ask me. ALWAYS reference our docs when they are available for a task, and make a note when they arent.'"
          }
        ]
      }
    ]
  },
  "enableAllProjectMcpServers": true,
  "includeCoAuthoredBy": true,
  "enabledMcpjsonServers": ["sentry"]
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/bin/start-mock-stdio.ts:
--------------------------------------------------------------------------------

```typescript
#!/usr/bin/env node

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { startStdio } from "@sentry/mcp-server/transports/stdio";
import { mswServer } from "@sentry/mcp-server-mocks";
import type { Scope } from "@sentry/mcp-server/permissions";
import { ALL_SCOPES } from "@sentry/mcp-server/permissions";

mswServer.listen({
  onUnhandledRequest: (req, print) => {
    if (req.url.startsWith("https://api.openai.com/")) {
      return;
    }

    print.warning();
    throw new Error(`Unhandled request: ${req.url}`);
  },
  // onUnhandledRequest: "error"
});

const accessToken = "mocked-access-token";

// Grant all available scopes for evals to ensure MSW mocks apply broadly

const server = new McpServer({
  name: "Sentry MCP",
  version: "0.1.0",
});

// Run in-process MCP with all scopes so MSW mocks apply
startStdio(server, {
  accessToken,
  grantedScopes: new Set<Scope>(ALL_SCOPES),
  constraints: {
    organizationSlug: null,
    projectSlug: null,
  },
}).catch((err: unknown) => {
  console.error("Server error:", err);
  process.exit(1);
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/azure.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "azure",
  "description": "This section defines generic attributes used by Azure Client Libraries.\n",
  "attributes": {
    "azure.service.request.id": {
      "description": "The unique identifier of the service request. It's generated by the Azure service and returned with the response.",
      "type": "string",
      "stability": "development",
      "examples": ["00000000-0000-0000-0000-000000000000"]
    },
    "azure.resource_provider.namespace": {
      "description": "[Azure Resource Provider Namespace](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-services-resource-providers) as recognized by the client.\n",
      "type": "string",
      "stability": "development",
      "examples": [
        "Microsoft.Storage",
        "Microsoft.KeyVault",
        "Microsoft.ServiceBus"
      ]
    },
    "azure.client.id": {
      "description": "The unique identifier of the client instance.",
      "type": "string",
      "stability": "development",
      "examples": ["3ba4827d-4422-483f-b59f-85b74211c11d", "storage-client-1"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/cli/usage.ts:
--------------------------------------------------------------------------------

```typescript
import type { Scope } from "../permissions";

export function buildUsage(
  packageName: string,
  defaults: ReadonlyArray<Scope>,
  all: ReadonlyArray<Scope>,
): string {
  return `Usage: ${packageName} --access-token=<token> [--host=<host>]

Required:
  --access-token <token>  Sentry User Auth Token with API access

Common optional flags:
  --host <host>           Change Sentry host (self-hosted)
  --sentry-dsn <dsn>      Override DSN used for telemetry reporting
  --openai-base-url <url> Override OpenAI API base URL for embedded agents

Session constraints:
  --organization-slug <slug>  Force all calls to an organization
  --project-slug <slug>       Optional project constraint

Scope controls:
  --scopes <list>     Override default scopes
  --add-scopes <list> Add scopes to defaults
  --all-scopes        Grant every available scope

Defaults: ${defaults.join(", ")}
All scopes: ${all.join(", ")}

Examples:
  ${packageName} --access-token=TOKEN
  ${packageName} --access-token=TOKEN --host=sentry.example.com
  ${packageName} --access-token=TOKEN --openai-base-url=https://proxy.example.com/v1`;
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/otel.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "otel",
  "description": "Attributes reserved for OpenTelemetry",
  "attributes": {
    "otel.status_code": {
      "description": "Name of the code, either \"OK\" or \"ERROR\". MUST NOT be set if the status code is UNSET.",
      "type": "string",
      "stability": "stable",
      "examples": ["OK", "ERROR"]
    },
    "otel.status_description": {
      "description": "Description of the Status if it has a value, otherwise not set.",
      "type": "string",
      "stability": "stable",
      "examples": ["resource not found"]
    },
    "otel.span.sampling_result": {
      "description": "The result value of the sampler for this span",
      "type": "string",
      "stability": "development",
      "examples": ["DROP", "RECORD_ONLY", "RECORD_AND_SAMPLE"]
    },
    "otel.span.parent.origin": {
      "description": "Determines whether the span has a parent span, and if so, [whether it is a remote parent](https://opentelemetry.io/docs/specs/otel/trace/api/#isremote)",
      "type": "string",
      "stability": "development",
      "examples": ["none", "local", "remote"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/types/chat.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Type definitions for Chat API
 */

// Error response types
export type ErrorName =
  // 400-level errors (client errors)
  | "MISSING_AUTH_TOKEN"
  | "INVALID_AUTH_DATA"
  | "INVALID_MESSAGES_FORMAT"
  // 401-level errors (authentication)
  | "AUTH_EXPIRED"
  | "AI_AUTH_FAILED"
  | "SENTRY_AUTH_INVALID"
  // 403-level errors (authorization)
  | "INSUFFICIENT_PERMISSIONS"
  // 429-level errors (rate limiting)
  | "RATE_LIMIT_EXCEEDED"
  | "AI_RATE_LIMIT"
  // 500-level errors (server errors)
  | "AI_SERVICE_UNAVAILABLE"
  | "RATE_LIMITER_ERROR"
  | "MCP_CONNECTION_FAILED"
  | "METADATA_FETCH_FAILED"
  | "INTERNAL_ERROR";

export interface ErrorResponse {
  error: string;
  name?: ErrorName;
  eventId?: string;
}

// Request types
export interface ChatRequest {
  messages: Array<{
    role: "user" | "assistant" | "system";
    content: string;
    data?: any; // Additional metadata for messages
  }>;
}

// MCP types
export interface MCPTools {
  [toolName: string]: {
    description?: string;
    parameters?: unknown;
  };
}

// Rate limiter types
export interface RateLimitResult {
  success: boolean;
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/tool-helpers/enhance-error.ts:
--------------------------------------------------------------------------------

```typescript
import { ApiNotFoundError } from "../../api-client";

/**
 * Enhances a 404 error with parameter context to help users understand what went wrong.
 * This is optional - tools can use this when they want to provide extra context.
 *
 * @example
 * ```typescript
 * try {
 *   const issue = await apiService.getIssue({ organizationSlug, issueId });
 * } catch (error) {
 *   if (error instanceof ApiNotFoundError) {
 *     throw enhanceNotFoundError(error, { organizationSlug, issueId });
 *   }
 *   throw error;
 * }
 * ```
 */
export function enhanceNotFoundError(
  error: ApiNotFoundError,
  params: Record<string, unknown>,
): ApiNotFoundError {
  const paramsList: string[] = [];

  for (const [key, value] of Object.entries(params)) {
    if (value !== undefined && value !== null && value !== "") {
      paramsList.push(`${key}: '${value}'`);
    }
  }

  if (paramsList.length > 0) {
    const enhancedMessage = `${error.message}\nPlease verify these parameters are correct:\n${paramsList.map((p) => `  - ${p}`).join("\n")}`;
    return new ApiNotFoundError(
      enhancedMessage,
      error.detail,
      error.responseBody,
    );
  }

  return error;
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/whoami.ts:
--------------------------------------------------------------------------------

```typescript
import { z } from "zod";
import type { SentryApiService } from "../../../api-client";
import { agentTool } from "./utils";

export interface WhoamiResult {
  id: string | number;
  name: string | null;
  email: string;
}

/**
 * Get the current authenticated user's information from Sentry API
 */
export async function getCurrentUser(
  apiService: SentryApiService,
): Promise<WhoamiResult> {
  // API client throws ApiClientError/ApiServerError which wrapAgentToolExecute handles
  const user = await apiService.getAuthenticatedUser();
  return {
    id: user.id,
    name: user.name,
    email: user.email,
  };
}

/**
 * Create a tool for getting current user information
 * The tool is pre-bound with the API service configured for the appropriate region
 */
export function createWhoamiTool(options: { apiService: SentryApiService }) {
  const { apiService } = options;
  return agentTool({
    description: "Get the current authenticated user's information",
    parameters: z.object({}),
    execute: async () => {
      const user = await getCurrentUser(apiService);
      return `Current user: ${user.name || "Unknown"} (${user.email}, ID: ${user.id})`;
    },
  });
}

```

--------------------------------------------------------------------------------
/.github/workflows/merge-jobs.yml:
--------------------------------------------------------------------------------

```yaml
name: Post-merge tasks

on:
  push:
    branches: ["main", "release/*"]
  workflow_dispatch:

jobs:
  build-publish:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup pnpm
        uses: pnpm/action-setup@v4

      - name: Set up Node
        uses: actions/setup-node@v4
        with:
          node-version-file: 'package.json'
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm install

      - name: Build
        run: pnpm build

      - name: Run linter
        run: pnpm lint

      - name: Run tests
        run: pnpm test:ci

      - name: Package mcp-server
        working-directory: packages/mcp-server
        run: pnpm pack --pack-destination dist

      - name: Archive artifacts
        uses: actions/upload-artifact@v4
        with:
          name: ${{ github.sha }}
          path: |
            ${{ github.workspace }}/packages/mcp-server/dist/*.tgz

      - name: Publish Test Report
        uses: mikepenz/action-junit-report@cf701569b05ccdd861a76b8607a66d76f6fd4857
        if: ${{ !cancelled() }}
        with:
          report_paths: "**/*.junit.xml"
          comment: false

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/cli/types.ts:
--------------------------------------------------------------------------------

```typescript
import type { Scope } from "../permissions";

export type CliArgs = {
  accessToken?: string;
  host?: string;
  url?: string;
  mcpUrl?: string;
  sentryDsn?: string;
  openaiBaseUrl?: string;
  scopes?: string;
  addScopes?: string;
  allScopes?: boolean;
  organizationSlug?: string;
  projectSlug?: string;
  help?: boolean;
  version?: boolean;
  unknownArgs: string[];
};

export type EnvArgs = {
  accessToken?: string;
  host?: string; // parsed from SENTRY_HOST or SENTRY_URL (raw value)
  url?: string; // raw URL if provided (SENTRY_URL)
  mcpUrl?: string;
  sentryDsn?: string;
  scopes?: string;
  addScopes?: string;
};

export type MergedArgs = {
  accessToken?: string;
  host?: string;
  url?: string;
  mcpUrl?: string;
  sentryDsn?: string;
  openaiBaseUrl?: string;
  scopes?: string;
  addScopes?: string;
  allScopes?: boolean;
  organizationSlug?: string;
  projectSlug?: string;
  help?: boolean;
  version?: boolean;
  unknownArgs: string[];
};

export type ResolvedConfig = {
  accessToken: string;
  sentryHost: string;
  mcpUrl?: string;
  sentryDsn?: string;
  openaiBaseUrl?: string;
  finalScopes?: Set<Scope>;
  organizationSlug?: string;
  projectSlug?: string;
};

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/create-project.eval.ts:
--------------------------------------------------------------------------------

```typescript
import { describeEval } from "vitest-evals";
import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";

describeEval("create-project", {
  data: async () => {
    return [
      {
        input: `Create a new project in Sentry for '${FIXTURES.organizationSlug}' called '${FIXTURES.projectSlug}' with the '${FIXTURES.teamSlug}' team. Output **only** the project slug and the SENTRY_DSN in the format of:\n<PROJECT_SLUG>\n<SENTRY_DSN>`,
        expectedTools: [
          {
            name: "find_organizations",
            arguments: {},
          },
          {
            name: "find_teams",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              regionUrl: "https://us.sentry.io",
            },
          },
          {
            name: "create_project",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              regionUrl: "https://us.sentry.io",
              teamSlug: FIXTURES.teamSlug,
              name: FIXTURES.projectSlug,
            },
          },
        ],
      },
    ];
  },
  task: NoOpTaskRunner(),
  scorers: [ToolPredictionScorer()],
  threshold: 0.6,
  timeout: 30000,
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/session.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "session",
  "description": "Session is defined as the period of time encompassing all activities performed by the application and the actions executed by the end user.\nConsequently, a Session is represented as a collection of Logs, Events, and Spans emitted by the Client Application throughout the Session's duration. Each Session is assigned a unique identifier, which is included as an attribute in the Logs, Events, and Spans generated during the Session's lifecycle.\nWhen a session reaches end of life, typically due to user inactivity or session timeout, a new session identifier will be assigned. The previous session identifier may be provided by the instrumentation so that telemetry backends can link the two sessions.\n",
  "attributes": {
    "session.id": {
      "description": "A unique id to identify a session.",
      "type": "string",
      "stability": "development",
      "examples": ["00112233-4455-6677-8899-aabbccddeeff"]
    },
    "session.previous_id": {
      "description": "The previous `session.id` for this user, when known.",
      "type": "string",
      "stability": "development",
      "examples": ["00112233-4455-6677-8899-aabbccddeeff"]
    }
  }
}

```

--------------------------------------------------------------------------------
/turbo.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "https://turbo.build/schema.json",
  "daemon": false,
  "ui": "stream",
  "tasks": {
    "setup": {
      "dependsOn": ["build"],
      "cache": false
    },
    "dev": {
      "dependsOn": ["^build"],
      "cache": false,
      "persistent": true
    },
    "deploy": {
      "dependsOn": ["^build"],
      "outputs": [],
      "cache": true
    },
    "lint": {
      "dependsOn": ["^build"],
      "cache": true
    },
    "test": {
      "dependsOn": ["^build"],
      "outputs": [],
      "cache": true
    },
    "tsc": {
      "dependsOn": ["^build"],
      "outputs": [],
      "cache": true
    },
    "eval": {
      "dependsOn": ["^build"],
      "outputs": [],
      "cache": true
    },
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**", "dist/**", "*.tsbuildinfo"],
      "cache": true
    },
    "after-build": {
      "dependsOn": ["build"],
      "cache": false
    }
  },
  "globalPassThroughEnv": [
    "NODE_ENV",
    "CI",
    "OPENAI_API_KEY",
    "COOKIE_SECRET",
    "SENTRY_CLIENT_ID",
    "SENTRY_CLIENT_SECRET",
    "SENTRY_AUTH_TOKEN",
    "SENTRY_ACCESS_TOKEN",
    "SENTRY_SPOTLIGHT",
    "VITE_SENTRY_DSN",
    "VITE_SENTRY_ENVIRONMENT"
  ]
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-mocks/src/fixtures/trace-meta-with-nulls.json:
--------------------------------------------------------------------------------

```json
{
  "logs": 0,
  "errors": 2,
  "performance_issues": 0,
  "span_count": 85,
  "transaction_child_count_map": [
    {
      "transaction.event_id": "0daf40dc453a429c8c57e4c215c4e82c",
      "count()": 10.0
    },
    {
      "transaction.event_id": null,
      "count()": 15.0
    },
    {
      "transaction.event_id": "b49a5b53cba046a2bab9323d8f00de96",
      "count()": 7.0
    },
    {
      "transaction.event_id": null,
      "count()": 8.0
    },
    {
      "transaction.event_id": "ee6e7f39107847f980e06119bf116d38",
      "count()": 7.0
    },
    {
      "transaction.event_id": null,
      "count()": 20.0
    },
    {
      "transaction.event_id": "f398bbc635c64e2091d94679dade2957",
      "count()": 3.0
    },
    {
      "transaction.event_id": "f779775e1c6a4f09b62d68818a25d7b5",
      "count()": 15.0
    }
  ],
  "span_count_map": {
    "cache.get": 30.0,
    "middleware.django": 20.0,
    "db": 10.0,
    "function": 5.0,
    "db.redis": 4.0,
    "feature.flagpole.batch_has": 4.0,
    "processor": 2.0,
    "execute": 2.0,
    "fetch_organization_projects": 2.0,
    "other": 1.0,
    "db.clickhouse": 1.0,
    "validator": 1.0,
    "serialize": 1.0,
    "http.client": 1.0,
    "base.paginate.on_results": 1.0
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/whoami.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, vi, beforeEach } from "vitest";
import { getCurrentUser } from "./whoami";
import type { SentryApiService } from "../../../api-client";

describe("whoami agent tool", () => {
  let mockApiService: SentryApiService;

  beforeEach(() => {
    vi.clearAllMocks();
    mockApiService = {
      getAuthenticatedUser: vi.fn(),
    } as unknown as SentryApiService;
  });

  describe("getCurrentUser", () => {
    it("should return current user information", async () => {
      const mockUser = {
        id: "123",
        name: "John Doe",
        email: "[email protected]",
      };

      (mockApiService.getAuthenticatedUser as any).mockResolvedValue(mockUser);

      const result = await getCurrentUser(mockApiService);

      expect(result).toEqual({
        id: "123",
        name: "John Doe",
        email: "[email protected]",
      });

      expect(mockApiService.getAuthenticatedUser).toHaveBeenCalledOnce();
    });

    it("should handle API errors gracefully", async () => {
      (mockApiService.getAuthenticatedUser as any).mockRejectedValue(
        new Error("Unauthorized"),
      );

      await expect(getCurrentUser(mockApiService)).rejects.toThrow(
        "Unauthorized",
      );
    });
  });
});

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/search-docs.eval.ts:
--------------------------------------------------------------------------------

```typescript
import { describeEval } from "vitest-evals";
import { NoOpTaskRunner, ToolPredictionScorer } from "./utils";

describeEval("search-docs", {
  data: async () => {
    return [
      {
        input:
          "I need documentation on how to set up error tracking with Sentry in JavaScript",
        expectedTools: [
          {
            name: "search_docs",
            arguments: {
              query: "set up error tracking JavaScript",
              maxResults: 3,
            },
          },
        ],
      },
      {
        input:
          "I need help configuring Sentry with React components and error boundaries",
        expectedTools: [
          {
            name: "search_docs",
            arguments: {
              query: "React components error boundaries",
              maxResults: 3,
            },
          },
        ],
      },
      {
        input: "What is Sentry's rate limiting and how does it work?",
        expectedTools: [
          {
            name: "search_docs",
            arguments: {
              query: "rate limiting",
              maxResults: 3,
            },
          },
        ],
      },
    ];
  },
  task: NoOpTaskRunner(),
  scorers: [ToolPredictionScorer()],
  threshold: 0.6,
  timeout: 30000,
});

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/get-trace-details.eval.ts:
--------------------------------------------------------------------------------

```typescript
import { describeEval } from "vitest-evals";
import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";

describeEval("get-trace-details", {
  data: async () => {
    return [
      {
        input: `Show me trace ${FIXTURES.traceId} from Sentry in ${FIXTURES.organizationSlug}.`,
        expectedTools: [
          {
            name: "find_organizations",
            arguments: {},
          },
          {
            name: "get_trace_details",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              traceId: FIXTURES.traceId,
              regionUrl: "https://us.sentry.io",
            },
          },
        ],
      },
      {
        input: `Explain trace ${FIXTURES.traceId} in ${FIXTURES.organizationSlug}.`,
        expectedTools: [
          {
            name: "find_organizations",
            arguments: {},
          },
          {
            name: "get_trace_details",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              traceId: FIXTURES.traceId,
              regionUrl: "https://us.sentry.io",
            },
          },
        ],
      },
    ];
  },
  task: NoOpTaskRunner(),
  scorers: [ToolPredictionScorer()],
  threshold: 0.6,
  timeout: 30000,
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/test.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "test",
  "description": "This group describes attributes specific to [software tests](https://wikipedia.org/wiki/Software_testing).\n",
  "attributes": {
    "test.suite.name": {
      "description": "The human readable name of a [test suite](https://wikipedia.org/wiki/Test_suite).\n",
      "type": "string",
      "stability": "development",
      "examples": ["TestSuite1"]
    },
    "test.suite.run.status": {
      "description": "The status of the test suite run.\n",
      "type": "string",
      "stability": "development",
      "examples": [
        "success",
        "failure",
        "skipped",
        "aborted",
        "timed_out",
        "in_progress"
      ]
    },
    "test.case.name": {
      "description": "The fully qualified human readable name of the [test case](https://wikipedia.org/wiki/Test_case).\n",
      "type": "string",
      "stability": "development",
      "examples": [
        "org.example.TestCase1.test1",
        "example/tests/TestCase1.test1",
        "ExampleTestCase1_test1"
      ]
    },
    "test.case.result.status": {
      "description": "The status of the actual test case result from test execution.\n",
      "type": "string",
      "stability": "development",
      "examples": ["pass", "fail"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/source.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "source",
  "description": "These attributes may be used to describe the sender of a network exchange/packet. These should be used when there is no client/server relationship between the two sides, or when that relationship is unknown. This covers low-level network interactions (e.g. packet tracing) where you don't know if there was a connection or which side initiated it. This also covers unidirectional UDP flows and peer-to-peer communication where the \"user-facing\" surface of the protocol / API doesn't expose a clear notion of client and server.\n",
  "attributes": {
    "source.address": {
      "description": "Source address - domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name.",
      "type": "string",
      "note": "When observed from the destination side, and when communicating through an intermediary, `source.address` SHOULD represent the source address behind any intermediaries, for example proxies, if it's available.\n",
      "stability": "development",
      "examples": ["source.example.com", "10.1.2.80", "/tmp/my.sock"]
    },
    "source.port": {
      "description": "Source port number",
      "type": "number",
      "stability": "development",
      "examples": ["3389", "2888"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/get-issue.eval.ts:
--------------------------------------------------------------------------------

```typescript
import { describeEval } from "vitest-evals";
import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";

describeEval("get-issue", {
  data: async () => {
    return [
      {
        input: `Explain CLOUDFLARE-MCP-41 from Sentry in ${FIXTURES.organizationSlug}.`,
        expectedTools: [
          {
            name: "find_organizations",
            arguments: {},
          },
          {
            name: "get_issue_details",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              issueId: "CLOUDFLARE-MCP-41",
              regionUrl: "https://us.sentry.io",
            },
          },
        ],
      },
      {
        input: `Explain the event with ID 7ca573c0f4814912aaa9bdc77d1a7d51 from Sentry in ${FIXTURES.organizationSlug}.`,
        expectedTools: [
          {
            name: "find_organizations",
            arguments: {},
          },
          {
            name: "get_issue_details",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              eventId: "7ca573c0f4814912aaa9bdc77d1a7d51",
              regionUrl: "https://us.sentry.io",
            },
          },
        ],
      },
    ];
  },
  task: NoOpTaskRunner(),
  scorers: [ToolPredictionScorer()],
  threshold: 0.6,
  timeout: 30000,
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/destination.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "destination",
  "description": "These attributes may be used to describe the receiver of a network exchange/packet. These should be used when there is no client/server relationship between the two sides, or when that relationship is unknown. This covers low-level network interactions (e.g. packet tracing) where you don't know if there was a connection or which side initiated it. This also covers unidirectional UDP flows and peer-to-peer communication where the \"user-facing\" surface of the protocol / API doesn't expose a clear notion of client and server.\n",
  "attributes": {
    "destination.address": {
      "description": "Destination address - domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name.",
      "type": "string",
      "note": "When observed from the source side, and when communicating through an intermediary, `destination.address` SHOULD represent the destination address behind any intermediaries, for example proxies, if it's available.\n",
      "stability": "development",
      "examples": ["destination.example.com", "10.1.2.80", "/tmp/my.sock"]
    },
    "destination.port": {
      "description": "Destination port number",
      "type": "number",
      "stability": "development",
      "examples": ["3389", "2888"]
    }
  }
}

```

--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------

```yaml
name: Release

on:
  workflow_dispatch:
    inputs:
      version:
        description: Version to release
        required: true
      force:
        description: Force a release even when there are release-blockers (empty string == false)
        required: false

jobs:
  release:
    runs-on: ubuntu-latest
    name: "Release a new version"
    steps:
      - name: Get auth token
        id: token
        uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0
        with:
          app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }}
          private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }}

      - name: Checkout
        uses: actions/checkout@v4
        with:
          token: ${{ steps.token.outputs.token }}
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"

      # pnpm/action-setup@v4
      - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda
        name: Install pnpm
        with:
          run_install: false

      - name: Prepare release
        uses: getsentry/action-prepare-release@v1
        env:
          GITHUB_TOKEN: ${{ steps.token.outputs.token }}
        with:
          version: ${{ github.event.inputs.version }}
          force: ${{ github.event.inputs.force }}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/user.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "user",
  "description": "Describes information about the user.",
  "attributes": {
    "user.email": {
      "description": "User email address.\n",
      "type": "string",
      "stability": "development",
      "examples": ["[email protected]"]
    },
    "user.full_name": {
      "description": "User's full name\n",
      "type": "string",
      "stability": "development",
      "examples": ["Albert Einstein"]
    },
    "user.hash": {
      "description": "Unique user hash to correlate information for a user in anonymized form.\n",
      "type": "string",
      "note": "Useful if `user.id` or `user.name` contain confidential information and cannot be used.\n",
      "stability": "development",
      "examples": ["364fc68eaf4c8acec74a4e52d7d1feaa"]
    },
    "user.id": {
      "description": "Unique identifier of the user.\n",
      "type": "string",
      "stability": "development",
      "examples": ["S-1-5-21-202424912787-2692429404-2351956786-1000"]
    },
    "user.name": {
      "description": "Short name or login/username of the user.\n",
      "type": "string",
      "stability": "development",
      "examples": ["a.einstein"]
    },
    "user.roles": {
      "description": "Array of user roles at the time of the event.\n",
      "type": "string",
      "stability": "development",
      "examples": ["[\"admin\",\"reporting_user\"]"]
    }
  }
}

```

--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------

```yaml
packages:
  - packages/*
catalog:
  "@ai-sdk/openai": ^1.3.22
  "@ai-sdk/react": ^1.2.12
  "@biomejs/biome": ^1.9.4
  "@cloudflare/vite-plugin": ^1.11.4
  "@cloudflare/vitest-pool-workers": ^0.8.47
  "@cloudflare/workers-oauth-provider": ^0.0.6
  "@cloudflare/workers-types": ^4.20250627.0
  "@modelcontextprotocol/sdk": ^1.17.1
  "@radix-ui/react-accordion": ^1.2.11
  "@radix-ui/react-slot": ^1.2.3
  "@sentry/cloudflare": 9.34.0
  "@sentry/core": 9.34.0
  "@sentry/node": 9.34.0
  "@sentry/react": 9.34.0
  "@sentry/vite-plugin": ^3.5.0
  "@tailwindcss/typography": ^0.5.16
  "@tailwindcss/vite": ^4.1.11
  "@types/node": ^22.15.33
  "@types/react": ^19.1.8
  "@types/react-dom": ^19.1.6
  "@vitejs/plugin-react": ^4.6.0
  "@vitest/coverage-v8": ^3.2.4
  agents: ~0.0.111
  ai: ^4.3.16
  better-sqlite3: ^11.10.0
  chalk: ^5.4.1
  class-variance-authority: ^0.7.1
  clsx: ^2.1.1
  commander: ^14.0.0
  dotenv: ^16.6.1
  dotenv-cli: ^8.0.0
  hono: ^4.9.7
  lint-staged: ^15.5.2
  lucide-react: ^0.503.0
  msw: ^2.10.2
  open: ^10.1.2
  react: ^19.1.0
  react-dom: ^19.1.0
  react-markdown: ^9.1.0
  remark-gfm: ^4.0.1
  simple-git-hooks: ^2.13.0
  tailwind-merge: ^3.3.1
  tailwindcss: ^4.1.11
  tsdown: ^0.12.9
  tsx: ^4.20.3
  turbo: ^2.5.4
  tw-animate-css: ^1.3.4
  typescript: ^5.8.3
  vite: ^6.3.5
  vitest: ^3.2.4
  vitest-evals: ^0.4.0
  workers-mcp: 0.1.0-3
  wrangler: ^4.29.1
  zod: ^3.25.67
  zod-to-json-schema: ^3.24.6

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/list-releases.eval.ts:
--------------------------------------------------------------------------------

```typescript
import { describeEval } from "vitest-evals";
import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";

describeEval("list-releases", {
  data: async () => {
    return [
      {
        input: `Show me the releases in ${FIXTURES.organizationSlug}`,
        expectedTools: [
          {
            name: "find_organizations",
            arguments: {},
          },
          {
            name: "find_releases",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              regionUrl: "https://us.sentry.io",
            },
          },
        ],
      },
      {
        input: `Show me a list of versions in ${FIXTURES.organizationSlug}/${FIXTURES.projectSlug}`,
        expectedTools: [
          {
            name: "find_organizations",
            arguments: {},
          },
          {
            name: "find_projects",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              regionUrl: "https://us.sentry.io",
            },
          },
          {
            name: "find_releases",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              projectSlug: FIXTURES.projectSlug,
              regionUrl: "https://us.sentry.io",
            },
          },
        ],
      },
    ];
  },
  task: NoOpTaskRunner(),
  scorers: [ToolPredictionScorer()],
  threshold: 0.6,
  timeout: 30000,
});

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/deployment.json:
--------------------------------------------------------------------------------

```json
{
  "namespace": "deployment",
  "description": "This document defines attributes for software deployments.\n",
  "attributes": {
    "deployment.name": {
      "description": "The name of the deployment.\n",
      "type": "string",
      "stability": "development",
      "examples": ["deploy my app", "deploy-frontend"]
    },
    "deployment.id": {
      "description": "The id of the deployment.\n",
      "type": "string",
      "stability": "development",
      "examples": ["1208"]
    },
    "deployment.status": {
      "description": "The status of the deployment.\n",
      "type": "string",
      "stability": "development",
      "examples": ["failed", "succeeded"]
    },
    "deployment.environment.name": {
      "description": "Name of the [deployment environment](https://wikipedia.org/wiki/Deployment_environment) (aka deployment tier).\n",
      "type": "string",
      "note": "`deployment.environment.name` does not affect the uniqueness constraints defined through\nthe `service.namespace`, `service.name` and `service.instance.id` resource attributes.\nThis implies that resources carrying the following attribute combinations MUST be\nconsidered to be identifying the same service:\n\n- `service.name=frontend`, `deployment.environment.name=production`\n- `service.name=frontend`, `deployment.environment.name=staging`.\n",
      "stability": "development",
      "examples": ["staging", "production"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/callEmbeddedAgent.ts:
--------------------------------------------------------------------------------

```typescript
import { generateText, Output } from "ai";
import { getOpenAIModel } from "./openai-provider";
import type { z } from "zod";

export type ToolCall = {
  toolName: string;
  args: any;
};

interface EmbeddedAgentResult<T> {
  result: T;
  toolCalls: ToolCall[];
}

/**
 * Call an embedded agent with tool call capture
 * This is the standard way to call embedded AI agents within MCP tools
 *
 * Error handling:
 * - Errors are re-thrown for the calling agent to handle
 * - Each agent can implement its own error handling strategy
 */
export async function callEmbeddedAgent<T>({
  system,
  prompt,
  tools,
  schema,
}: {
  system: string;
  prompt: string;
  tools: Record<string, any>;
  schema: z.ZodSchema<T>;
}): Promise<EmbeddedAgentResult<T>> {
  const capturedToolCalls: ToolCall[] = [];

  const result = await generateText({
    model: getOpenAIModel("gpt-4o"),
    system,
    prompt,
    tools,
    maxSteps: 5,
    experimental_output: Output.object({ schema }),
    onStepFinish: (event) => {
      if (event.toolCalls && event.toolCalls.length > 0) {
        for (const toolCall of event.toolCalls) {
          capturedToolCalls.push({
            toolName: toolCall.toolName,
            args: toolCall.args,
          });
        }
      }
    },
  });

  if (!result.experimental_output) {
    throw new Error("Failed to generate output");
  }

  return {
    result: result.experimental_output as T,
    toolCalls: capturedToolCalls,
  };
}

```

--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/update-project.eval.ts:
--------------------------------------------------------------------------------

```typescript
import { describeEval } from "vitest-evals";
import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";

describeEval("update-project", {
  data: async () => {
    return [
      {
        input: `Update the project '${FIXTURES.projectSlug}' in organization '${FIXTURES.organizationSlug}' to change its name to 'Updated Project Name' and slug to 'updated-project-slug'. Output only the new project slug as plain text without any formatting:\nupdated-project-slug`,
        expectedTools: [
          {
            name: "update_project",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              projectSlug: FIXTURES.projectSlug,
              name: "Updated Project Name",
              slug: "updated-project-slug",
            },
          },
        ],
      },
      {
        input: `Assign the project '${FIXTURES.projectSlug}' in organization '${FIXTURES.organizationSlug}' to the team '${FIXTURES.teamSlug}'. Output only the team slug as plain text without any formatting:\nthe-goats`,
        expectedTools: [
          {
            name: "update_project",
            arguments: {
              organizationSlug: FIXTURES.organizationSlug,
              projectSlug: FIXTURES.projectSlug,
              teamSlug: FIXTURES.teamSlug,
            },
          },
        ],
      },
    ];
  },
  task: NoOpTaskRunner(),
  scorers: [ToolPredictionScorer()],
  threshold: 0.6,
  timeout: 30000,
});

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/header.tsx:
--------------------------------------------------------------------------------

```typescript
import type React from "react";
import { SentryIcon } from "./icons/sentry";
import { Github, LogOut } from "lucide-react";
import { Button } from "./button";

interface HeaderProps {
  isAuthenticated?: boolean;
  onLogout?: () => void;
}

export const Header: React.FC<HeaderProps> = ({
  isAuthenticated,
  onLogout,
}) => {
  return (
    <header className="mb-6 w-full">
      <div className="flex items-center justify-between w-full">
        <div className="flex items-center gap-2 flex-shrink-0">
          <SentryIcon className="h-8 w-8 text-violet-400" />
          <div className="flex items-baseline gap-2">
            <h1 className="text-2xl font-bold whitespace-nowrap">Sentry MCP</h1>
          </div>
        </div>
        <div className="flex items-center gap-2">
          <Button variant="secondary" asChild>
            <a
              href="https://github.com/getsentry/sentry-mcp"
              target="_blank"
              rel="noopener noreferrer"
            >
              <Github className="h-5 w-5" />
              <span>GitHub</span>
            </a>
          </Button>
          {isAuthenticated && onLogout && (
            <Button
              variant="secondary"
              onClick={onLogout}
              className="hidden md:flex cursor-pointer"
            >
              <LogOut className="h-4 w-4" />
              <span>Logout</span>
            </Button>
          )}
        </div>
      </div>
    </header>
  );
};

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/markdown.tsx:
--------------------------------------------------------------------------------

```typescript
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { cn } from "@/client/lib/utils";

interface MarkdownProps {
  children: string;
  className?: string;
}

export function Markdown({ children, className }: MarkdownProps) {
  return (
    <ReactMarkdown
      className={cn(
        "prose prose-invert prose-slate max-w-none",
        "prose-p:my-2 prose-p:leading-relaxed",
        "prose-pre:bg-slate-900 prose-pre:border prose-pre:border-slate-700",
        "prose-code:bg-slate-800 prose-code:px-1 prose-code:py-0.5 prose-code:rounded prose-code:text-sm",
        "prose-code:before:content-none prose-code:after:content-none",
        "prose-strong:text-slate-100",
        "prose-em:text-slate-200",
        "prose-a:text-violet-300",
        "prose-blockquote:border-l-violet-500 prose-blockquote:bg-slate-800/50 prose-blockquote:py-2 prose-blockquote:px-4",
        "prose-h1:text-slate-100 prose-h2:text-slate-100 prose-h3:text-slate-100",
        "prose-h4:text-slate-100 prose-h5:text-slate-100 prose-h6:text-slate-100",
        "prose-ul:my-2 prose-ol:my-2",
        "prose-li:my-1",
        "prose-hr:border-slate-700",
        "prose-table:border-slate-700",
        "prose-th:border-slate-700 prose-td:border-slate-700",
        className,
      )}
      remarkPlugins={[remarkGfm]}
      disallowedElements={["script", "style", "iframe", "object", "embed"]}
      unwrapDisallowed={true}
    >
      {children}
    </ReactMarkdown>
  );
}

```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/sentry.config.ts:
--------------------------------------------------------------------------------

```typescript
import type { Env } from "./types";
import { LIB_VERSION } from "@sentry/mcp-server/version";
import * as Sentry from "@sentry/cloudflare";
import { sentryBeforeSend } from "@sentry/mcp-server/telem/sentry";

type SentryConfig = ReturnType<Parameters<typeof Sentry.withSentry>[0]>;

export default function getSentryConfig(env: Env): SentryConfig {
  const { id: versionId } = env.CF_VERSION_METADATA;

  return {
    dsn: env.SENTRY_DSN,
    tracesSampleRate: 1,
    sendDefaultPii: true,
    beforeSend: sentryBeforeSend,
    initialScope: {
      tags: {
        "mcp.server_version": LIB_VERSION,
        "sentry.host": env.SENTRY_HOST,
      },
    },
    release: versionId,
    environment:
      env.SENTRY_ENVIRONMENT ??
      (process.env.NODE_ENV !== "production" ? "development" : "production"),
    _experiments: {
      enableLogs: true,
    },
    integrations: [
      Sentry.consoleLoggingIntegration(),
      Sentry.zodErrorsIntegration(),
      Sentry.vercelAIIntegration(),
    ],
  };
}

getSentryConfig.partial = (config: Partial<SentryConfig>) => {
  return (env: Env) => {
    const defaultConfig = getSentryConfig(env);
    return {
      ...defaultConfig,
      ...config,
      initialScope: {
        ...defaultConfig.initialScope,
        ...config.initialScope,
        tags: {
          // idk I can't typescript
          ...((defaultConfig.initialScope ?? {}) as any).tags,
          ...((config.initialScope ?? {}) as any).tags,
        },
      },
    };
  };
};

```
Page 1/11FirstPrevNextLast