This is page 1 of 15. Use http://codebase.md/getsentry/sentry-mcp?lines=true&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
1 | changelogPolicy: none
2 | preReleaseCommand: bash bin/bump-version.sh
3 | targets:
4 | - name: github
5 | - name: npm
6 | id: "@sentry/mcp-server"
7 | includeNames: /^sentry-mcp-server-\d.*\.tgz$/
8 |
```
--------------------------------------------------------------------------------
/packages/mcp-test-client/.env.test:
--------------------------------------------------------------------------------
```
1 | # Test environment file
2 | # Copy this to .env and fill in your actual values
3 |
4 | # Dummy values for testing - will fail but show the flow
5 | ANTHROPIC_API_KEY=test-key
6 | SENTRY_ACCESS_TOKEN=test-token
7 | SENTRY_HOST=sentry.io
8 |
```
--------------------------------------------------------------------------------
/packages/mcp-test-client/.gitignore:
--------------------------------------------------------------------------------
```
1 | # Dependencies
2 | node_modules/
3 |
4 | # Build output
5 | dist/
6 | *.tsbuildinfo
7 |
8 | # Environment files
9 | .env
10 | .env.local
11 |
12 | # IDE
13 | .idea/
14 | .vscode/
15 | *.swp
16 | *.swo
17 |
18 | # OS
19 | .DS_Store
20 | Thumbs.db
21 |
22 | # Logs
23 | *.log
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 | pnpm-debug.log*
28 |
29 | # Testing
30 | coverage/
31 | *.junit.xml
```
--------------------------------------------------------------------------------
/.mcp.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "mcpServers": {
3 | "sentry": {
4 | "type": "http",
5 | "url": "https://mcp.sentry.dev/mcp/sentry/mcp-server"
6 | },
7 | "sentry-dev": {
8 | "type": "http",
9 | "url": "http://localhost:5173/mcp/sentry/mcp-server"
10 | },
11 | "sentry-spotlight": {
12 | "type": "stdio",
13 | "command": "npx",
14 | "args": ["-y", "@spotlightjs/spotlight", "--stdio-mcp"],
15 | "env": {}
16 | }
17 | }
18 | }
19 |
```
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
1 | # Logs
2 |
3 | logs
4 | _.log
5 | npm-debug.log_
6 | yarn-debug.log*
7 | yarn-error.log*
8 | lerna-debug.log*
9 | .pnpm-debug.log*
10 |
11 | # Diagnostic reports (https://nodejs.org/api/report.html)
12 |
13 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
14 |
15 | # Runtime data
16 |
17 | pids
18 | _.pid
19 | _.seed
20 | *.pid.lock
21 |
22 | # Dependency directories
23 |
24 | node_modules/
25 | jspm_packages/
26 | .npm
27 | .node_repl_history
28 | *.tgz
29 | .cache
30 | dist
31 | .turbo/
32 | *.tsbuildinfo
33 | .DS_Store
34 |
35 | # dotenv environment variable files
36 |
37 | .env
38 | .env.development.local
39 | .env.test.local
40 | .env.production.local
41 | .env.local
42 |
43 | .vscode-test
44 |
45 | .yarn-integrity
46 | .yarn/cache
47 | .yarn/unplugged
48 | .yarn/build-state.yml
49 | .yarn/install-state.gz
50 | .pnp.\*
51 |
52 | # wrangler project
53 |
54 | .dev.vars
55 | .wrangler/
56 | wrangler.log
57 |
58 | *.junit.xml
59 | coverage
60 | *.lcov
61 |
62 | # Sentry Config File
63 | .env.sentry-build-plugin
64 |
65 | # Generated files
66 | packages/mcp-server/src/toolDefinitions.json
67 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/.env.example:
--------------------------------------------------------------------------------
```
1 | # Sentry OAuth Application Credentials
2 | # Create an OAuth app at: https://sentry.io/settings/account/api/applications/
3 | # - Homepage URL: http://localhost:5173 (for local dev)
4 | # - Authorized Redirect URIs: http://localhost:5173/oauth/callback (for local dev)
5 | SENTRY_CLIENT_ID=
6 |
7 | # Client Secret from your Sentry OAuth application
8 | # Generate this when creating your OAuth app in Sentry
9 | SENTRY_CLIENT_SECRET=
10 |
11 | # Cookie encryption secret for session management
12 | # Generate a random string (32+ characters recommended)
13 | # Example: openssl rand -base64 32
14 | COOKIE_SECRET=thisisasecret
15 |
16 | # OpenAI API key for AI-powered search tools (search_events, search_issues)
17 | # Get yours at: https://platform.openai.com/api-keys
18 | # Required for natural language query translation features
19 | OPENAI_API_KEY=sk-proj-generate-this
20 |
21 | # The URL where your MCP server is hosted
22 | # Local development: http://localhost:5173
23 | # Production: Your deployed URL (e.g., https://your-app.pages.dev)
24 | MCP_HOST=http://localhost:5173
25 |
26 | # Enable Spotlight
27 | SENTRY_SPOTLIGHT=1
28 |
```
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
```
1 | # Root Environment Configuration
2 | # This file provides default environment variables for all packages.
3 | # Individual packages can override these values with their own .env files.
4 |
5 | # OpenAI API key for AI-powered search tools (search_events, search_issues)
6 | # Get yours at: https://platform.openai.com/api-keys
7 | # Required for natural language query translation features
8 | OPENAI_API_KEY=sk-proj-agenerate-this
9 |
10 | # For mcp-test-client: Anthropic API key for Claude access
11 | # ANTHROPIC_API_KEY=your_anthropic_api_key
12 |
13 | # For mcp-test-client: Sentry access token (for stdio transport)
14 | # Get one from: https://sentry.io/settings/account/api/auth-tokens/
15 | # SENTRY_ACCESS_TOKEN=your_sentry_access_token
16 |
17 | # Sentry Spotlight - development environment tool for local debugging
18 | # Set to 1 to enable Spotlight integration (recommended for development)
19 | # Learn more: https://spotlightjs.com
20 | SENTRY_SPOTLIGHT=1
21 |
22 | # IMPORTANT: For local development, you also need to create:
23 | # - packages/mcp-cloudflare/.env - OAuth configuration (required for authentication)
24 | # Copy packages/mcp-cloudflare/.env.example to .env and fill in your OAuth credentials
25 |
```
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # Contributor Docs
2 |
3 | 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`).
4 |
5 | ## Purpose
6 |
7 | - Central home for all contributor-focused docs (.mdc files)
8 | - Consumed by tools (e.g., Cursor) via direct file references
9 |
10 | ## Start Here
11 |
12 | - Doc map and workflow: see `CLAUDE.md` / `AGENTS.md`
13 | - Per-topic guides live in this folder (e.g., `adding-tools.mdc`)
14 |
15 | ## Integration with Tools
16 |
17 | - Cursor IDE: this folder is referenced directly as contextual rules
18 | - Other AI tools: reference specific `.mdc` files as needed
19 |
20 | ## LLM-Specific
21 |
22 | - Meta-docs live under `llms/` (e.g., `llms/document-scopes.mdc`)
23 |
24 | ## Maintenance
25 |
26 | Update docs when patterns change, new tools are added, or common issues arise. Keep the index in `CLAUDE.md` authoritative; avoid mirroring it here.
27 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-evals/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # @sentry/mcp-server-evals
2 |
3 | Evaluation helpers and a local mock stdio runner used when developing and validating the Sentry MCP server.
4 |
5 | ## Mock stdio runner
6 |
7 | - Command: `pnpm --filter @sentry/mcp-server-evals start`
8 | - Entry: `src/bin/start-mock-stdio.ts`
9 | - Purpose: Boots the MCP server in-process with MSW mocks enabled for deterministic evals.
10 |
11 | ### Scopes policy
12 |
13 | 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`:
14 |
15 | - `org:admin`, `project:admin`, `team:admin`, `member:admin`, `event:admin`
16 | - Plus special non-hierarchical scope: `project:releases`
17 |
18 | 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.
19 |
20 | ### Notes
21 |
22 | - No API keys are logged; MSW handles Sentry API mocking.
23 | - For code changes, ensure `pnpm run tsc && pnpm run lint && pnpm run test` all pass.
24 | - See `docs/adding-tools.mdc` and `docs/testing.mdc` for contribution guidance.
25 |
```
--------------------------------------------------------------------------------
/docs/llms/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # LLM-Specific Documentation
2 |
3 | This directory contains meta-documentation specifically for LLMs working with the Sentry MCP codebase.
4 |
5 | ## Contents
6 |
7 | ### documentation-style-guide.mdc
8 | Guidelines for writing effective documentation that LLMs can consume efficiently. Defines principles like assuming intelligence, being concise, and showing rather than telling.
9 |
10 | ### document-scopes.mdc
11 | Defines the specific purpose, content requirements, and line count targets for each documentation file. Helps maintain focus and prevent scope creep.
12 |
13 | ### documentation-todos.mdc
14 | Specific tasks for improving each document based on the style guide and scope definitions. Tracks the documentation refactoring effort.
15 |
16 | ## Purpose
17 |
18 | These documents help ensure that:
19 | - Documentation remains concise and focused
20 | - LLMs get project-specific information, not general programming knowledge
21 | - Redundancy is minimized through proper cross-referencing
22 | - Each document has a clear, defined purpose
23 |
24 | ## For Human Contributors
25 |
26 | While these documents are designed for LLM consumption, they also serve as excellent guidelines for human contributors who want to understand:
27 | - How to write documentation for this project
28 | - What belongs in each document
29 | - How to maintain consistency across docs
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/search-issues/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # Search Issues Agent
2 |
3 | AI-powered natural language to Sentry issue search translation.
4 |
5 | ## Overview
6 |
7 | 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.
8 |
9 | ## Architecture
10 |
11 | - **Handler**: `handler.ts` - MCP tool definition and orchestration
12 | - **Agent**: `agent.ts` - AI translation logic
13 | - **Config**: `config.ts` - System prompts and settings
14 | - **Formatters**: `formatters.ts` - Result formatting
15 |
16 | ## Agent Tools
17 |
18 | The AI agent has access to these shared agent tools from `../../agent-tools/`:
19 |
20 | 1. **issueFields**: Discovers available fields for issue searches using `dataset="search_issues"`
21 | 2. **whoami**: Gets current user information to resolve 'me' references
22 |
23 | ## Natural Language Examples
24 |
25 | - "critical bugs from last week" → `level:error is:unresolved lastSeen:-7d`
26 | - "issues assigned to me" → Uses whoami tool → `assignedOrSuggested:[email protected]`
27 | - "affecting 100+ users" → `userCount:>100`
28 | - "production errors" → `environment:production level:error`
29 |
30 | ## Features
31 |
32 | - ✅ Natural language query translation
33 | - ✅ Error feedback loop for self-correction
34 | - ✅ 'Me' reference resolution via whoami tool
35 | - ✅ Field discovery with custom tags
36 | - ✅ Smart sort options (date, freq, new, user)
37 | - ✅ Configurable result limits (1-100, default 10)
38 | - ✅ Project-specific and organization-wide searches
39 |
40 | ## Usage
41 |
42 | ```typescript
43 | search_issues({
44 | organizationSlug: "my-org",
45 | naturalLanguageQuery: "critical bugs from last week",
46 | limit: 25,
47 | includeExplanation: true
48 | })
49 | ```
```
--------------------------------------------------------------------------------
/docs/specs/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # Feature Specifications
2 |
3 | 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.
4 |
5 |
6 | ## Purpose
7 |
8 | Feature specifications serve to:
9 |
10 | 1. **Document Design Decisions**: Capture the reasoning behind architectural choices
11 | 2. **Define Interfaces**: Specify tool inputs, outputs, and behavior
12 | 3. **Guide Implementation**: Provide clear direction for developers
13 | 4. **Enable Review**: Allow stakeholders to review and provide feedback
14 | 5. **Preserve Knowledge**: Maintain historical context for future reference
15 |
16 | ## Creating New Specifications
17 |
18 | When adding a new feature specification:
19 |
20 | 1. Create a new directory under `specs/` with a descriptive name
21 | 2. Create a **single, concise README.md file** that covers:
22 | - Problem statement and motivation
23 | - High-level design approach
24 | - Interface definitions (with code examples)
25 | - Key constraints and requirements
26 | - Migration/compatibility concerns
27 | 3. Update this README with a brief description
28 | 4. Link to the spec from relevant documentation
29 |
30 | **Important Guidelines**:
31 | - Keep specs in a single file (README.md)
32 | - Focus on WHAT and WHY, not HOW
33 | - Include code examples for interfaces and usage
34 | - Document constraints and meta concerns
35 | - Avoid implementation details (no function internals, prompts, etc.)
36 | - Think "contract" not "blueprint"
37 |
38 | ## Current Specifications
39 |
40 | ### search-events
41 | 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.
42 |
43 | - **Status**: ✅ Complete
44 | - **Key Benefits**: Reduces tool count (20→19), improves UX, accessible to non-technical users
45 |
46 | ## Specification Template
47 |
48 | For consistency, new specifications should include:
49 |
50 | 1. **Overview**: Problem statement and proposed solution
51 | 2. **Motivation**: Why this feature is needed
52 | 3. **Design**: Technical architecture and approach
53 | 4. **Interface**: API/tool definitions
54 | 5. **Examples**: Usage scenarios and expected behavior
55 | 6. **Implementation**: Step-by-step plan (NO time estimates)
56 | 7. **Testing**: Validation strategy
57 | 8. **Migration**: If replacing existing functionality
58 | 9. **Future Work**: Potential enhancements
59 |
60 | **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.
61 |
62 | ## Review Process
63 |
64 | 1. Create specification documents in a feature branch
65 | 2. Open PR for review by team members
66 | 3. Address feedback and iterate
67 | 4. Merge once consensus is reached
68 | 5. Update status as implementation progresses
```
--------------------------------------------------------------------------------
/packages/mcp-server/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # sentry-mcp
2 |
3 | This is a prototype of an MCP server, acting as a middleware to the upstream Sentry API provider.
4 |
5 | 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:
6 |
7 | <https://mcp.sentry.dev>
8 |
9 | **Note:** Some tools require additional configuration:
10 | - **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.
11 |
12 | ## Permissions and Scopes
13 |
14 | By default, the MCP server runs with **read-only access** to your Sentry data:
15 | - `org:read`, `project:read`, `team:read`, `event:read`
16 |
17 | ### Customizing Permissions
18 |
19 | You can customize permissions using two different approaches:
20 |
21 | - **`--scopes`**: **Override** the default scopes completely (replaces all defaults)
22 | - **`--add-scopes`**: **Add** scopes to the default read-only set (keeps defaults and adds more)
23 |
24 | 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.
25 |
26 | ### Examples
27 |
28 | ```shell
29 | # Default read-only access (SaaS)
30 | npx @sentry/mcp-server@latest --access-token=sentry-user-token
31 |
32 | # Override with specific scopes only (removes defaults)
33 | npx @sentry/mcp-server@latest --access-token=TOKEN --scopes=org:read,event:read
34 |
35 | # Add write permissions to defaults (keeps all defaults)
36 | npx @sentry/mcp-server@latest --access-token=TOKEN --add-scopes=event:write,project:write
37 |
38 | # Point at a self-hosted deployment
39 | npx @sentry/mcp-server@latest --access-token=sentry-user-token --host=sentry.example.com
40 |
41 | # Override the OpenAI API endpoint for embedded agents (stdio only)
42 | npx @sentry/mcp-server@latest --access-token=TOKEN --openai-base-url=https://proxy.example.com/v1
43 | ```
44 |
45 | ### Environment Variables
46 |
47 | You can also use environment variables:
48 |
49 | ```shell
50 | SENTRY_ACCESS_TOKEN=your-token
51 | # Optional overrides. Leave unset to use the default SaaS host
52 | SENTRY_HOST=sentry.example.com
53 | MCP_SCOPES=org:read,event:read # Override default scopes (replaces defaults)
54 | MCP_ADD_SCOPES=event:write # Add to default scopes (keeps defaults)
55 | OPENAI_API_KEY=your-openai-key # Required for AI-powered search tools (search_events, search_issues)
56 | # No environment variable exists for the OpenAI base URL override; use --openai-base-url instead.
57 | # This restriction prevents unexpected environment overrides that could silently reroute requests to a
58 | # malicious proxy capable of harvesting the OpenAI API key provided at runtime.
59 | ```
60 |
61 | If `SENTRY_HOST` is not provided, the CLI automatically targets the Sentry SaaS
62 | endpoint.
63 |
64 | Configure this variable only when you operate a self-hosted Sentry deployment;
65 | it is not needed for Sentry SaaS.
66 |
67 | **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.
68 |
69 | The host configuration accepts two distinct formats:
70 |
71 | - **`SENTRY_HOST`**: Hostname only (no protocol)
72 | - Examples: `sentry.example.com`, `sentry.internal.example.com`, `localhost:8000`
73 |
74 | **Note**: Only HTTPS connections are supported for security reasons.
75 |
76 | 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:
77 |
78 | ```shell
79 | # disable sentry reporting
80 | npx @sentry/mcp-server@latest --sentry-dsn=
81 |
82 | # use custom sentry instance
83 | npx @sentry/mcp-server@latest --sentry-dsn=https://[email protected]/...
84 | ```
85 |
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # sentry-mcp
2 |
3 | [](https://codecov.io/gh/getsentry/sentry-mcp)
4 |
5 | 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.
6 |
7 | 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/).
8 |
9 | ## Getting Started
10 |
11 | You'll find everything you need to know by visiting the deployed service in production:
12 |
13 | <https://mcp.sentry.dev>
14 |
15 | If you're looking to contribute, learn how it works, or to run this for self-hosted Sentry, continue below.
16 |
17 | ### Stdio vs Remote
18 |
19 | 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.
20 |
21 | **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.
22 |
23 | 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:
24 |
25 | ```
26 | org:read
27 | project:read
28 | project:write
29 | team:read
30 | team:write
31 | event:write
32 | ```
33 |
34 | Launch the transport:
35 |
36 | ```shell
37 | npx @sentry/mcp-server@latest --access-token=sentry-user-token
38 | ```
39 |
40 | Need to connect to a self-hosted deployment? Add <code>--host</code> (hostname
41 | only, e.g. <code>--host=sentry.example.com</code>) when you run the command.
42 |
43 | Note: You can also use environment variables:
44 |
45 | ```shell
46 | SENTRY_ACCESS_TOKEN=
47 | # Optional overrides for self-hosted deployments
48 | SENTRY_HOST=
49 | OPENAI_API_KEY= # Required for AI-powered search tools (search_events, search_issues)
50 | ```
51 |
52 | If you leave the host variable unset, the CLI automatically targets the Sentry
53 | SaaS service. Only set the override when you operate self-hosted Sentry.
54 |
55 | ### MCP Inspector
56 |
57 | MCP includes an [Inspector](https://modelcontextprotocol.io/docs/tools/inspector), to easily test the service:
58 |
59 | ```shell
60 | pnpm inspector
61 | ```
62 |
63 | Enter the MCP server URL (<http://localhost:5173>) and hit connect. This should trigger the authentication flow for you.
64 |
65 | 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`.
66 |
67 | ## Local Development
68 |
69 | To contribute changes, you'll need to set up your local environment:
70 |
71 | 1. **Set up environment files:**
72 |
73 | ```shell
74 | make setup-env # Creates both .env files from examples
75 | ```
76 |
77 | 2. **Create an OAuth App in Sentry** (Settings => API => [Applications](https://sentry.io/settings/account/api/applications/)):
78 |
79 | - Homepage URL: `http://localhost:5173`
80 | - Authorized Redirect URIs: `http://localhost:5173/oauth/callback`
81 | - Note your Client ID and generate a Client secret
82 |
83 | 3. **Configure your credentials:**
84 |
85 | - Edit `.env` in the root directory and add your `OPENAI_API_KEY`
86 | - Edit `packages/mcp-cloudflare/.env` and add:
87 | - `SENTRY_CLIENT_ID=your_development_sentry_client_id`
88 | - `SENTRY_CLIENT_SECRET=your_development_sentry_client_secret`
89 | - `COOKIE_SECRET=my-super-secret-cookie`
90 |
91 | 4. **Start the development server:**
92 |
93 | ```shell
94 | pnpm dev
95 | ```
96 |
97 | ### Verify
98 |
99 | Run the server locally to make it available at `http://localhost:5173`
100 |
101 | ```shell
102 | pnpm dev
103 | ```
104 |
105 | 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".
106 |
107 | ### Tests
108 |
109 | There are two test suites included: basic unit tests, and some evaluations.
110 |
111 | Unit tests can be run using:
112 |
113 | ```shell
114 | pnpm test
115 | ```
116 |
117 | Evals will require a `.env` file in the project root with some config:
118 |
119 | ```shell
120 | # .env (in project root)
121 | OPENAI_API_KEY= # Also required for AI-powered search tools in production
122 | ```
123 |
124 | Note: The root `.env` file provides defaults for all packages. Individual packages can have their own `.env` files to override these defaults during development.
125 |
126 | Once that's done you can run them using:
127 |
128 | ```shell
129 | pnpm eval
130 | ```
131 |
132 | ## Development Notes
133 |
134 | ### Automated Code Review
135 |
136 | 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.
137 |
138 | The automated reviews should be treated as:
139 |
140 | - ✅ **Helpful suggestions** to consider during code review
141 | - ✅ **Starting points** for discussion and improvement
142 | - ❌ **Not blocking requirements** for merging PRs
143 | - ❌ **Not replacements** for human code review
144 |
145 | When addressing automated feedback, focus on the underlying concerns rather than strictly following every suggestion.
146 |
147 | ### Contributor Documentation
148 |
149 | 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.
150 |
```
--------------------------------------------------------------------------------
/packages/mcp-test-client/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # MCP Client CLI
2 |
3 | A simple CLI tool to test the Sentry MCP server using stdio transport with an AI agent powered by Vercel's AI SDK.
4 |
5 | ## Features
6 |
7 | - 🤖 AI-powered interaction with Sentry MCP tools using GPT-4
8 | - 🔧 Full access to all MCP server tools
9 | - 💬 Interactive mode by default when no prompt provided
10 | - 🎨 Colorized output for better readability
11 | - 🔄 Streaming responses for real-time feedback
12 | - 🌐 Remote MCP server support via HTTP streaming (with OAuth)
13 | - 🏠 Local stdio transport for development
14 |
15 | ## Prerequisites
16 |
17 | - Node.js >= 20
18 | - pnpm package manager
19 | - OpenAI API key
20 | - Sentry access token with appropriate permissions
21 |
22 | ## Installation
23 |
24 | From the package directory:
25 |
26 | ```bash
27 | pnpm install
28 | pnpm build
29 | ```
30 |
31 | ## Configuration
32 |
33 | The MCP client supports multiple transport methods and authentication:
34 |
35 | ### 1. OAuth Authentication (Recommended for Remote Mode)
36 |
37 | When using remote mode (default), the MCP client can authenticate via OAuth 2.1 with the MCP server:
38 |
39 | ```bash
40 | # The client will automatically prompt for OAuth if no token is provided
41 | pnpm mcp-test-client
42 |
43 | # Or specify a custom MCP server
44 | pnpm mcp-test-client --mcp-host http://localhost:8787
45 | ```
46 |
47 | The OAuth flow uses PKCE (Proof Key for Code Exchange) and doesn't require a client secret, making it secure for CLI applications.
48 |
49 | ### 2. Environment Variables
50 |
51 | Create a `.env` file in the package directory:
52 |
53 | ```env
54 | # Required
55 | OPENAI_API_KEY=your_openai_api_key
56 |
57 | # Required - Sentry access token with appropriate permissions
58 | SENTRY_ACCESS_TOKEN=your_sentry_access_token
59 |
60 | # Optional (self-hosted only)
61 | # Leave unset to target the SaaS host
62 | SENTRY_HOST=sentry.example.com # Hostname only
63 | MCP_URL=https://mcp.sentry.dev # MCP server host (defaults to production)
64 | MCP_MODEL=gpt-4o # Override default model (GPT-4)
65 |
66 | # Optional - Error tracking
67 | SENTRY_DSN=your_sentry_dsn # Error tracking for the client itself
68 |
69 | # OAuth clients are automatically registered via Dynamic Client Registration (RFC 7591)
70 | # No manual client ID configuration needed
71 | ```
72 |
73 | ### 3. Command Line Flags
74 |
75 | ```bash
76 | pnpm mcp-test-client --access-token=your_token "Your prompt"
77 | ```
78 |
79 | ### Token Priority
80 |
81 | The client automatically determines the connection mode:
82 |
83 | **Local Mode (stdio transport)**: Used when an access token is provided via:
84 |
85 | 1. Command-line flag (`--access-token`)
86 | 2. Environment variable (`SENTRY_ACCESS_TOKEN`)
87 | 3. `.env` file
88 |
89 | **Remote Mode (HTTP streaming)**: Used when no access token is provided, prompts for OAuth authentication
90 |
91 | ### Required Sentry Permissions
92 |
93 | Your Sentry access token needs the following scopes:
94 |
95 | - `org:read`
96 | - `project:read`
97 | - `project:write`
98 | - `team:read`
99 | - `team:write`
100 | - `event:write`
101 |
102 | ## Usage
103 |
104 | ### Remote Mode (Default)
105 |
106 | Connect to the remote MCP server via HTTP streaming (uses OAuth for authentication):
107 |
108 | ```bash
109 | # Connect to production MCP server (uses /mcp endpoint)
110 | pnpm mcp-test-client
111 |
112 | # Connect to local development MCP server
113 | pnpm mcp-test-client --mcp-host http://localhost:8787
114 | ```
115 |
116 | **Note**: Remote mode uses HTTP streaming transport and connects to the `/mcp` endpoint on the MCP server.
117 |
118 | ### Local Mode
119 |
120 | Use the local stdio transport by providing a Sentry access token:
121 |
122 | ```bash
123 | # Using environment variable
124 | SENTRY_ACCESS_TOKEN=your_token pnpm mcp-test-client
125 |
126 | # Using command line flag
127 | pnpm mcp-test-client --access-token your_token
128 | ```
129 |
130 | ### Interactive Mode (Default)
131 |
132 | Start an interactive session by running without arguments:
133 |
134 | ```bash
135 | pnpm mcp-test-client
136 | ```
137 |
138 | In interactive mode:
139 |
140 | - Type your prompts and press Enter
141 | - Type `exit` or `quit` to end the session
142 | - The AI maintains context across prompts
143 |
144 | ### Single Prompt Mode
145 |
146 | Run with a specific prompt:
147 |
148 | ```bash
149 | pnpm mcp-test-client "List all unresolved issues in my project"
150 | ```
151 |
152 | ### Advanced Options
153 |
154 | Use a different AI model:
155 |
156 | ```bash
157 | pnpm mcp-test-client --model gpt-4-turbo "Analyze my error trends"
158 | ```
159 |
160 | Connect to a local MCP server:
161 |
162 | ```bash
163 | pnpm mcp-test-client --mcp-host http://localhost:8787 "List my projects"
164 | ```
165 |
166 | Use local stdio transport with custom Sentry host:
167 |
168 | ```bash
169 | SENTRY_HOST=sentry.example.com SENTRY_ACCESS_TOKEN=your_token pnpm mcp-test-client "Show my projects"
170 | ```
171 |
172 | Only configure `SENTRY_HOST` when you run self-hosted Sentry.
173 |
174 | ## Development
175 |
176 | ### Running from Source
177 |
178 | ```bash
179 | pnpm dev "Your prompt here"
180 | ```
181 |
182 | ### Building
183 |
184 | ```bash
185 | pnpm build
186 | ```
187 |
188 | ### Type Checking
189 |
190 | ```bash
191 | pnpm typecheck
192 | ```
193 |
194 | ## Troubleshooting
195 |
196 | ### Connection Issues
197 |
198 | If you see "Failed to connect to MCP server":
199 |
200 | 1. Ensure the mcp-server package is built
201 | 2. Check that your access token is valid
202 | 3. Verify the Sentry host URL is correct
203 |
204 | ### Authentication Errors
205 |
206 | If you get authentication errors:
207 |
208 | 1. Verify your OPENAI_API_KEY is set correctly
209 | 2. Check that your SENTRY_ACCESS_TOKEN has the required permissions
210 | 3. For self-hosted Sentry, ensure SENTRY_HOST is set
211 |
212 | ### Tool Errors
213 |
214 | If tools fail to execute:
215 |
216 | 1. Check the error message for missing parameters
217 | 2. Ensure your Sentry token has appropriate permissions
218 | 3. Verify you have access to the requested resources
219 |
220 | ## Examples
221 |
222 | ### Finding and Analyzing Issues
223 |
224 | ```bash
225 | # List recent issues
226 | pnpm mcp-test-client "Show me issues from the last 24 hours"
227 |
228 | # Search for specific errors
229 | pnpm mcp-test-client "Find all TypeError issues in the frontend project"
230 |
231 | # Get issue details
232 | pnpm mcp-test-client "Show me details about issue FRONTEND-123"
233 | ```
234 |
235 | ### Project Management
236 |
237 | ```bash
238 | # List all projects
239 | pnpm mcp-test-client "List all my projects with their platforms"
240 |
241 | # Get project settings
242 | pnpm mcp-test-client "Show me the alert settings for my React project"
243 |
244 | # View team assignments
245 | pnpm mcp-test-client "Which teams have access to the mobile app project?"
246 | ```
247 |
248 | ### Performance Analysis
249 |
250 | ```bash
251 | # Check slow transactions
252 | pnpm mcp-test-client "Find the slowest API endpoints in the last hour"
253 |
254 | # Analyze performance trends
255 | pnpm mcp-test-client "Show me performance metrics for the checkout flow"
256 | ```
257 |
258 | ## Testing the Installation
259 |
260 | After installation, you can verify everything is working:
261 |
262 | ```bash
263 | # Check CLI is installed
264 | pnpm mcp-test-client --help
265 |
266 | # Test basic functionality (no API keys required)
267 | SENTRY_ACCESS_TOKEN=dummy OPENAI_API_KEY=dummy pnpm mcp-test-client --help
268 |
269 | # Run the test script (requires valid credentials)
270 | ./examples/test-connection.sh
271 | ```
272 |
273 | ## Authentication Methods
274 |
275 | ### Remote Mode (OAuth)
276 |
277 | When connecting to a remote MCP server (default), the client supports OAuth 2.1 with PKCE:
278 |
279 | - No client secret required (secure for CLI applications)
280 | - Automatic browser-based authentication flow
281 | - Tokens are securely stored in memory during the session
282 |
283 | **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.
284 |
285 | ### Local Mode (Access Tokens)
286 |
287 | When using local stdio transport (automatic when access token is provided), you must provide a Sentry access token:
288 |
289 | - Set `SENTRY_ACCESS_TOKEN` environment variable
290 | - Or use `--access-token` command-line flag
291 | - Tokens need appropriate Sentry permissions (see Required Sentry Permissions section)
292 |
293 | ## Architecture
294 |
295 | The CLI consists of these main components:
296 |
297 | 1. **MCP Client** (`mcp-test-client.ts`) - Handles connection to the MCP server
298 | 2. **AI Agent** (`agent.ts`) - Integrates with Vercel AI SDK for Claude
299 | 3. **Auth** (`auth/`) - OAuth flow and secure token storage
300 | 4. **CLI Interface** (`index.ts`) - Command-line argument parsing and modes
301 |
302 | ### Technical Notes
303 |
304 | - The client uses `console.log` for all terminal output to maintain compatibility with the logger module
305 | - Error tracking is available via the `SENTRY_DSN` environment variable
306 | - All operations follow OpenTelemetry semantic conventions for observability
307 |
308 | ## Contributing
309 |
310 | When adding new features:
311 |
312 | 1. Follow the existing code style
313 | 2. Add new test scenarios if applicable
314 | 3. Update this README with new usage examples
315 | 4. Ensure all TypeScript types are properly defined
316 | 5. Run quality checks: `pnpm lint:fix && pnpm typecheck && pnpm test`
317 |
```
--------------------------------------------------------------------------------
/CLAUDE.md:
--------------------------------------------------------------------------------
```markdown
1 | AGENTS.md
```
--------------------------------------------------------------------------------
/AGENTS.md:
--------------------------------------------------------------------------------
```markdown
1 | # CLAUDE.md
2 |
3 | ## 🔴 CRITICAL Requirements
4 |
5 | **MANDATORY before ANY code:**
6 | 1. TypeScript: NEVER use `any`. Use `unknown` or proper types
7 | 2. Security: NO API keys in logs. NO vulnerabilities
8 | 3. Validation: `pnpm run tsc && pnpm run lint && pnpm run test`
9 | 4. Tools limit: ≤20 (hard limit: 25)
10 |
11 | **MANDATORY reads:**
12 | - Start here: CLAUDE.md — Contributor doc map
13 | - Tools → @docs/adding-tools.mdc
14 | - Testing → @docs/testing.mdc
15 | - PRs → @docs/pr-management.mdc
16 |
17 | ## 🟡 MANDATORY Workflow
18 |
19 | ```bash
20 | # BEFORE coding (parallel execution)
21 | cat docs/[component].mdc & ls -la neighboring-files & git status
22 |
23 | # AFTER coding (sequential - fail fast)
24 | pnpm run tsc && pnpm run lint && pnpm run test # ALL must pass
25 | ```
26 |
27 | ## Repository Map
28 |
29 | ```
30 | sentry-mcp/
31 | ├── packages/
32 | │ ├── mcp-server/ # Main MCP server
33 | │ │ ├── src/
34 | │ │ │ ├── tools/ # 19 tool modules
35 | │ │ │ ├── server.ts # MCP protocol
36 | │ │ │ ├── api-client/ # Sentry API
37 | │ │ │ └── internal/ # Shared utils
38 | │ │ └── scripts/ # Build scripts
39 | │ ├── mcp-cloudflare/ # Web app
40 | │ ├── mcp-server-evals/ # AI tests
41 | │ ├── mcp-server-mocks/ # MSW mocks
42 | │ └── mcp-test-client/ # Test client
43 | └── docs/ # All docs
44 | ```
45 |
46 | ## AI-Powered Search Tools
47 |
48 | **search_events** (`packages/mcp-server/src/tools/search-events/`):
49 | - Natural language → DiscoverQL queries
50 | - GPT-4o agent with structured outputs
51 | - Tools: `datasetAttributes`, `otelSemantics`, `whoami`
52 | - Requires: `OPENAI_API_KEY`
53 |
54 | **search_issues** (`packages/mcp-server/src/tools/search-issues/`):
55 | - Natural language → issue search syntax
56 | - GPT-4o agent with structured outputs
57 | - Tools: `issueFields`, `whoami`
58 | - Requires: `OPENAI_API_KEY`
59 |
60 | ## 🟢 Key Commands
61 |
62 | ```bash
63 | # Development
64 | pnpm run dev # Start development
65 | pnpm run build # Build all packages
66 | pnpm run generate-otel-namespaces # Update OpenTelemetry docs
67 |
68 | # Quality checks (combine for speed)
69 | pnpm run tsc && pnpm run lint && pnpm run test
70 |
71 | # Common workflows
72 | pnpm run build && pnpm run test # Before PR
73 | grep -r "TODO\|FIXME" src/ # Find tech debt
74 | ```
75 |
76 | ## Quick Reference
77 |
78 | **Defaults:**
79 | - Organization: `sentry`
80 | - Project: `mcp-server`
81 | - Transport: stdio
82 | - Auth: access tokens (NOT OAuth)
83 |
84 | **Doc Index:**
85 |
86 | - Core Guidelines
87 | - @docs/coding-guidelines.mdc — Code standards and patterns
88 | - @docs/common-patterns.mdc — Reusable patterns and conventions
89 | - @docs/quality-checks.mdc — Required checks before changes
90 | - @docs/error-handling.mdc — Error handling patterns
91 |
92 | - API and Tools
93 | - @docs/adding-tools.mdc — Add new MCP tools
94 | - @docs/api-patterns.mdc — Sentry API usage
95 | - @docs/search-events-api-patterns.md — search_events specifics
96 |
97 | - Infrastructure and Operations
98 | - @docs/architecture.mdc — System design
99 | - @docs/deployment.mdc — Deploy (Cloudflare)
100 | - @docs/monitoring.mdc — Monitoring/telemetry
101 | - @docs/security.mdc — Security and authentication
102 | - @docs/cursor.mdc — Cursor IDE integration
103 |
104 | - LLM-Specific
105 | - @docs/llms/documentation-style-guide.mdc — How to write LLM docs
106 | - @docs/llms/document-scopes.mdc — Doc scopes and purposes
107 |
108 | ## Rules
109 |
110 | 1. **Code**: Follow existing patterns. Check adjacent files
111 | 2. **Errors**: Try/catch all async. Log: `console.error('[ERROR]', error.message, error.stack)`
112 | - Sentry API 429: Retry with exponential backoff
113 | - Sentry API 401/403: Check token permissions
114 | 3. **Docs**: Update when changing functionality
115 | 4. **PR**: Follow `docs/pr-management.mdc` for commit/PR guidelines (includes AI attribution)
116 | 5. **Tasks**: Use TodoWrite for 3+ steps. Batch tool calls when possible
117 |
118 | ---
119 | *Optimized for Codex CLI (OpenAI) and Claude Code*
120 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/search-events/CLAUDE.md:
--------------------------------------------------------------------------------
```markdown
1 | # search_events Tool - Embedded Agent Documentation
2 |
3 | This tool embeds an AI agent (GPT-4o) to translate natural language queries into Sentry's event search syntax.
4 |
5 | ## Architecture Overview
6 |
7 | The `search_events` tool uses an "agent-in-tool" pattern:
8 |
9 | 1. **MCP Tool Handler** (`handler.ts`) - Receives natural language query from calling agent
10 | 2. **Embedded AI Agent** (`agent.ts`) - Translates to Sentry search syntax
11 | 3. **API Execution** - Runs the translated query against Sentry's API
12 | 4. **Result Formatting** - Returns formatted results to calling agent
13 |
14 | ## Embedded Agent Behavior
15 |
16 | ### Available Tools
17 |
18 | The embedded agent has access to three tools:
19 |
20 | 1. **datasetAttributes** - Discovers available fields for the chosen dataset
21 | 2. **otelSemantics** - Looks up OpenTelemetry semantic conventions
22 | 3. **whoami** - Resolves "me" references to actual user IDs
23 |
24 | ### Translation Flow
25 |
26 | 1. Analyzes natural language query to determine dataset (spans/errors/logs)
27 | 2. Calls `datasetAttributes` to discover available fields
28 | 3. May call `otelSemantics` for standardized field names
29 | 4. Generates structured query with fields, sort, and timeRange
30 |
31 | ### Key Query Patterns
32 |
33 | #### Distinct/Unique Values
34 | - "distinct tool names" → `fields: ['mcp.tool.name', 'count()'], sort: '-count()'`
35 | - Always uses aggregate mode with count()
36 |
37 | #### Traffic/Volume Queries
38 | - "how much traffic" → `fields: ['count()'], sort: '-count()'`
39 | - "traffic by X" → `fields: ['X', 'count()'], sort: '-count()'`
40 |
41 | #### Mathematical Queries
42 | - "total tokens used" → `fields: ['sum(gen_ai.usage.input_tokens)', 'sum(gen_ai.usage.output_tokens)']`
43 | - Uses spans dataset for OpenTelemetry metrics
44 |
45 | #### Time Series (NOT SUPPORTED)
46 | - "X over time" → Returns error: "Time series aggregations are not currently supported."
47 |
48 | ## Error Handling
49 |
50 | The tool follows the MCP philosophy of single-attempt error handling:
51 |
52 | 1. **Agent generates query** - Using static system prompt
53 | 2. **Validation Error** - Returns clear UserInputError to calling agent
54 | 3. **Calling agent decides** - Whether to retry with corrections
55 |
56 | Common validation errors:
57 | - Missing sort parameter
58 | - Sort field not included in fields array
59 | - Missing fields for aggregate queries
60 | - Invalid field names or syntax
61 |
62 | This approach enables better LLM prompt caching and cleaner error boundaries.
63 |
64 | ## Limitations
65 |
66 | 1. **No Time Series** - Cannot do "over time" aggregations
67 | 2. **Dataset Constraints**:
68 | - Equations only work in spans dataset
69 | - Numeric aggregations limited by field types
70 | - Timestamp filtering differs between datasets
71 | 3. **Project Scope** - Fields vary by project based on instrumented data
72 |
73 | ## Common Issues and Solutions
74 |
75 | ### Issue: "Sort field not in fields array"
76 | **Cause**: Agent specified sort by a field not included in the fields array
77 | **Solution**: Error message guides agent to include the sort field
78 |
79 | ### Issue: "Time series not supported"
80 | **Cause**: User asked for data "over time"
81 | **Solution**: Return clear error message, no retry
82 |
83 | ### Issue: "Invalid aggregate function on non-numeric field"
84 | **Cause**: Using avg(), sum() etc. on string fields
85 | **Solution**: Agent uses field type information from datasetAttributes
86 |
87 | ## Testing Queries
88 |
89 | Test various query patterns:
90 | - Simple counts: "how many errors today"
91 | - Distinct values: "distinct user agents"
92 | - Grouped aggregations: "errors by type"
93 | - Token usage: "total tokens used by model"
94 | - Time-filtered: "errors in the last hour"
95 |
96 | ## Future Improvements
97 |
98 | 1. ~~Consider removing retry mechanism - let calling agent handle retries~~ ✅ Done
99 | 2. Add support for time bucketing fields (timestamp.to_hour, timestamp.to_day)
100 | 3. Extract createOtelLookupTool and createDatasetAttributesTool to shared modules
```
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
```markdown
1 | # Functional Source License, Version 1.1, Apache 2.0 Future License
2 |
3 | ## Abbreviation
4 |
5 | FSL-1.1-Apache-2.0
6 |
7 | ## Notice
8 |
9 | Copyright 2008-2024 Functional Software, Inc. dba Sentry
10 |
11 | ## Terms and Conditions
12 |
13 | ### Licensor ("We")
14 |
15 | The party offering the Software under these Terms and Conditions.
16 |
17 | ### The Software
18 |
19 | The "Software" is each version of the software that we make available under
20 | these Terms and Conditions, as indicated by our inclusion of these Terms and
21 | Conditions with the Software.
22 |
23 | ### License Grant
24 |
25 | Subject to your compliance with this License Grant and the Patents,
26 | Redistribution and Trademark clauses below, we hereby grant you the right to
27 | use, copy, modify, create derivative works, publicly perform, publicly display
28 | and redistribute the Software for any Permitted Purpose identified below.
29 |
30 | ### Permitted Purpose
31 |
32 | A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
33 | means making the Software available to others in a commercial product or
34 | service that:
35 |
36 | 1. substitutes for the Software;
37 |
38 | 2. substitutes for any other product or service we offer using the Software
39 | that exists as of the date we make the Software available; or
40 |
41 | 3. offers the same or substantially similar functionality as the Software.
42 |
43 | Permitted Purposes specifically include using the Software:
44 |
45 | 1. for your internal use and access;
46 |
47 | 2. for non-commercial education;
48 |
49 | 3. for non-commercial research; and
50 |
51 | 4. in connection with professional services that you provide to a licensee
52 | using the Software in accordance with these Terms and Conditions.
53 |
54 | ### Patents
55 |
56 | To the extent your use for a Permitted Purpose would necessarily infringe our
57 | patents, the license grant above includes a license under our patents. If you
58 | make a claim against any party that the Software infringes or contributes to
59 | the infringement of any patent, then your patent license to the Software ends
60 | immediately.
61 |
62 | ### Redistribution
63 |
64 | The Terms and Conditions apply to all copies, modifications and derivatives of
65 | the Software.
66 |
67 | If you redistribute any copies, modifications or derivatives of the Software,
68 | you must include a copy of or a link to these Terms and Conditions and not
69 | remove any copyright notices provided in or with the Software.
70 |
71 | ### Disclaimer
72 |
73 | THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74 | IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75 | PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
76 |
77 | IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
78 | SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
79 | EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
80 |
81 | ### Trademarks
82 |
83 | Except for displaying the License Details and identifying us as the origin of
84 | the Software, you have no right under these Terms and Conditions to use our
85 | trademarks, trade names, service marks or product names.
86 |
87 | ## Grant of Future License
88 |
89 | We hereby irrevocably grant you an additional license to use the Software under
90 | the Apache License, Version 2.0 that is effective on the second anniversary of
91 | the date we make the Software available. On or after that date, you may use the
92 | Software under the Apache License, Version 2.0, in which case the following
93 | will apply:
94 |
95 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use
96 | this file except in compliance with the License.
97 |
98 | You may obtain a copy of the License at
99 |
100 | http://www.apache.org/licenses/LICENSE-2.0
101 |
102 | Unless required by applicable law or agreed to in writing, software distributed
103 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104 | CONDITIONS OF ANY KIND, either express or implied. See the License for the
105 | specific language governing permissions and limitations under the License.
106 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/search-issues/CLAUDE.md:
--------------------------------------------------------------------------------
```markdown
1 | # search_issues Tool - Embedded Agent Documentation
2 |
3 | This tool embeds an AI agent (GPT-4o) to translate natural language queries into Sentry's issue search syntax.
4 |
5 | ## Architecture Overview
6 |
7 | The `search_issues` tool uses an "agent-in-tool" pattern similar to `search_events`:
8 |
9 | 1. **MCP Tool Handler** (`handler.ts`) - Receives natural language query from calling agent
10 | 2. **Embedded AI Agent** (`agent.ts`) - Translates to Sentry issue search syntax
11 | 3. **API Execution** - Runs the translated query against Sentry's API
12 | 4. **Result Formatting** - Returns formatted grouped issues to calling agent
13 |
14 | ## Key Differences from search_events
15 |
16 | ### Purpose
17 | - `search_events`: Returns individual events or aggregated statistics
18 | - `search_issues`: Returns grouped issues (problems) with metadata
19 |
20 | ### Query Syntax
21 | - Uses Sentry's issue search syntax (different from event search)
22 | - No aggregate functions - issues are already grouped
23 | - Special fields like `is:`, `assigned:`, `firstSeen:`, `lastSeen:`
24 |
25 | ### No Datasets
26 | - Issues are a single unified view across all event types
27 | - No dataset selection required
28 |
29 | ## Embedded Agent Behavior
30 |
31 | ### Available Tools
32 |
33 | The embedded agent has access to two tools:
34 |
35 | 1. **discoverDatasetFields** - Discovers available issue fields
36 | 2. **whoami** - Resolves "me" references to actual user IDs
37 |
38 | ### Translation Flow
39 |
40 | 1. Analyzes natural language query for issue-specific patterns
41 | 2. Calls `discoverDatasetFields` to get available issue fields
42 | 3. May call `whoami` to resolve "me" references
43 | 4. Generates issue search query with proper syntax
44 |
45 | ### Key Query Patterns
46 |
47 | #### Status Queries
48 | - "unresolved issues" → `is:unresolved`
49 | - "ignored bugs" → `is:ignored`
50 | - "resolved yesterday" → `is:resolved` + timeRange
51 |
52 | #### Assignment Queries
53 | - "issues assigned to me" → `assigned:me` (or resolved email)
54 | - "unassigned errors" → `is:unassigned`
55 |
56 | #### Impact Queries
57 | - "issues affecting 100+ users" → `users:>100`
58 | - "high volume errors" → `events:>1000`
59 |
60 | #### Time-based Queries
61 | - "issues from last week" → Uses timeRange parameter
62 | - "errors seen today" → `lastSeen:-24h`
63 |
64 | ## Error Handling
65 |
66 | Follows the same MCP philosophy as search_events:
67 |
68 | 1. **Agent generates query** - Using static system prompt
69 | 2. **Validation Error** - Returns clear UserInputError to calling agent
70 | 3. **Calling agent decides** - Whether to retry with corrections
71 |
72 | Common validation errors:
73 | - Invalid issue field names
74 | - Incorrect query syntax
75 | - Missing required parameters
76 |
77 | This approach enables better LLM prompt caching and cleaner error boundaries.
78 |
79 | ## Issue-Specific Fields
80 |
81 | ### Status Fields
82 | - `is:` - resolved, unresolved, ignored, archived
83 | - `assigned:` - user email or "me"
84 | - `bookmarks:` - user email
85 |
86 | ### Time Fields
87 | - `firstSeen:` - When issue was first seen
88 | - `lastSeen:` - When issue was last seen
89 | - `age:` - How old the issue is
90 |
91 | ### Impact Fields
92 | - `users:` - Number of affected users
93 | - `events:` - Total event count
94 | - `level:` - error, warning, info, debug
95 |
96 | ## Limitations
97 |
98 | 1. **No Aggregations** - Issues are already grouped, no count()/sum()
99 | 2. **Limited Operators** - Simpler query syntax than events
100 | 3. **No Custom Fields** - Fixed set of issue attributes
101 |
102 | ## Common Issues and Solutions
103 |
104 | ### Issue: "Using event syntax for issues"
105 | **Cause**: Agent tries to use event search patterns
106 | **Solution**: Clear separation in prompt between issue and event search
107 |
108 | ### Issue: "Me resolution failures"
109 | **Cause**: User not authenticated or API error
110 | **Solution**: Fallback to suggesting user provide email
111 |
112 | ## Testing Queries
113 |
114 | Test various issue query patterns:
115 | - Status filters: "unresolved critical errors"
116 | - Assignment: "my issues", "unassigned bugs"
117 | - Impact: "issues affecting many users"
118 | - Time ranges: "issues from yesterday"
119 | - Combined: "unresolved errors assigned to me from last week"
120 |
121 | ## Future Improvements
122 |
123 | 1. ~~Consider removing retry mechanism - let calling agent handle retries~~ ✅ Done
124 | 2. Better integration with issue workflow commands (resolve, assign)
125 | 3. Extract shared agent tools to common module
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/CLAUDE.md:
--------------------------------------------------------------------------------
```markdown
1 | # OpenTelemetry Namespace Data
2 |
3 | This directory contains JSON files for OpenTelemetry semantic convention namespaces used by the search-events tool's embedded AI agent.
4 |
5 | ## File Format
6 |
7 | Each JSON file represents a namespace and follows this structure:
8 |
9 | ```json
10 | {
11 | "namespace": "namespace_name",
12 | "description": "Description of what this namespace covers",
13 | "attributes": {
14 | "attribute.name": {
15 | "description": "What this attribute represents",
16 | "type": "string|number|boolean",
17 | "examples": ["example1", "example2"],
18 | "note": "Additional notes (optional)",
19 | "stability": "stable|experimental|deprecated (optional)"
20 | }
21 | }
22 | }
23 | ```
24 |
25 | ## Generation Process
26 |
27 | ### OpenTelemetry Official Namespaces
28 |
29 | Most files are automatically generated from the OpenTelemetry semantic conventions repository:
30 |
31 | **Source**: https://github.com/open-telemetry/semantic-conventions/tree/main/model
32 |
33 | The generation script (`scripts/generate-otel-namespaces.ts`) fetches YAML files from the model directory and converts them to our JSON format.
34 |
35 | **Generation Command**: `pnpm run generate-otel-namespaces`
36 |
37 | **Caching**: The script caches downloaded YAML files in `.cache/` directory to avoid repeated network requests. Clear the cache to force fresh downloads.
38 |
39 | ### JSON Import Handling
40 |
41 | 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.
42 |
43 | ### Custom Namespaces
44 |
45 | Some namespaces are maintained manually for attributes not yet in the OpenTelemetry specification:
46 |
47 | - **mcp.json** - Model Context Protocol attributes (custom)
48 | - Any file marked with `"custom": true` will be skipped during regeneration
49 |
50 | ## Usage
51 |
52 | The `otel-semantics-lookup.ts` tool reads these JSON files to provide semantic guidance to the embedded AI agent when translating natural language queries.
53 |
54 | ## Key Namespaces
55 |
56 | ### Core OpenTelemetry Namespaces
57 |
58 | - **gen_ai** - Generative AI operations (models, tokens, conversations)
59 | - **db** - Database operations (queries, connections, systems)
60 | - **http** - HTTP client/server operations (requests, responses, status codes)
61 | - **rpc** - Remote procedure calls (gRPC, etc.)
62 | - **messaging** - Message queue operations (Kafka, RabbitMQ, etc.)
63 | - **faas** - Function as a Service operations (AWS Lambda, etc.)
64 | - **k8s** - Kubernetes operations (pods, services, deployments)
65 | - **cloud** - Cloud provider operations (AWS, Azure, GCP)
66 | - **network** - Network operations (TCP, UDP, protocols)
67 | - **server** - Server-side operations (addresses, ports)
68 | - **service** - Service identification (name, version, instance)
69 | - **error** - Error information (type, message, stack)
70 | - **user** - User identification (id, email, name)
71 |
72 | ### Custom Namespaces
73 |
74 | - **mcp** - Model Context Protocol operations (tool calls, sessions)
75 |
76 | ## Regeneration Process
77 |
78 | 1. **Automatic**: Run `pnpm run generate-otel-namespaces` to update all OpenTelemetry namespaces
79 | 2. **Manual**: Edit custom namespace files directly (they won't be overwritten)
80 | 3. **Selective**: The script only updates files for namespaces that exist in the OpenTelemetry repository
81 |
82 | ## File Organization
83 |
84 | ```
85 | data/
86 | ├── CLAUDE.md # This documentation
87 | ├── gen_ai.json # Generative AI attributes
88 | ├── db.json # Database attributes
89 | ├── http.json # HTTP attributes
90 | ├── rpc.json # RPC attributes
91 | ├── messaging.json # Messaging attributes
92 | ├── mcp.json # MCP attributes (custom)
93 | └── [other-namespaces].json
94 | ```
95 |
96 | ## Maintenance
97 |
98 | - **OpenTelemetry files**: Regenerate periodically to stay current with specifications
99 | - **Custom files**: Update manually as needed for new MCP or Sentry-specific attributes
100 | - **Validation**: Ensure all files follow the expected JSON schema format
101 |
102 | 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
1 | export * from "./chat-error-handler";
2 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/vite-env.d.ts:
--------------------------------------------------------------------------------
```typescript
1 | /// <reference types="vite/client" />
2 |
```
--------------------------------------------------------------------------------
/vitest.workspace.ts:
--------------------------------------------------------------------------------
```typescript
1 | export default ["packages/*", "apps/*"];
2 |
```
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "recommendations": ["biomejs.biome"],
3 | "unwantedRecommendations": []
4 | }
5 |
```
--------------------------------------------------------------------------------
/.vscode/mcp.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "servers": {
3 | "sentry": {
4 | "url": "https://mcp.sentry.dev/mcp"
5 | }
6 | }
7 | }
8 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/test-setup.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { startMockServer } from "@sentry/mcp-server-mocks";
2 |
3 | startMockServer({ ignoreOpenAI: true });
4 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/api-client/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | export * from "./client";
2 | export * from "./schema";
3 | export * from "./types";
4 | export * from "./errors";
5 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/version.ts:
--------------------------------------------------------------------------------
```typescript
1 | export const LIB_VERSION =
2 | (typeof process !== "undefined" && process.env?.npm_package_version) ||
3 | "0.0.0";
4 |
```
--------------------------------------------------------------------------------
/packages/mcp-test-client/src/version.ts:
--------------------------------------------------------------------------------
```typescript
1 | export const LIB_VERSION =
2 | (typeof process !== "undefined" && process.env?.npm_package_version) ||
3 | "0.0.0";
4 |
```
--------------------------------------------------------------------------------
/.cursor/mcp.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "mcpServers": {
3 | "sentry": {
4 | "type": "http",
5 | "url": "https://mcp.sentry.dev/mcp/sentry/mcp-server"
6 | }
7 | }
8 | }
9 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-tsconfig/package.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "name": "@sentry/mcp-server-tsconfig",
3 | "version": "0.18.0",
4 | "private": true,
5 | "files": ["tsconfig.base.json", "tsconfig.vite.json"]
6 | }
7 |
```
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
```yaml
1 | coverage:
2 | status:
3 | project:
4 | default:
5 | informational: true
6 | patch:
7 | default:
8 | informational: true
9 |
10 | comment: false
11 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/search-events/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | // Export the search-events handler
2 | export { default } from "./handler";
3 |
4 | // Export the agent for testing
5 | export { searchEventsAgent } from "./agent";
6 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/search-issues/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | // Export the search-issues handler
2 | export { default } from "./handler";
3 |
4 | // Export the agent for testing
5 | export { searchIssuesAgent } from "./agent";
6 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/tsconfig.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "files": [],
3 | "references": [
4 | { "path": "./tsconfig.client.json" },
5 | { "path": "./tsconfig.node.json" },
6 | { "path": "./tsconfig.server.json" }
7 | ]
8 | }
9 |
```
--------------------------------------------------------------------------------
/packages/mcp-test-client/vitest.config.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { defineConfig } from "vitest/config";
2 |
3 | export default defineConfig({
4 | test: {
5 | globals: true,
6 | environment: "node",
7 | testTimeout: 30000,
8 | },
9 | });
10 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/lib/utils.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { clsx, type ClassValue } from "clsx";
2 | import { twMerge } from "tailwind-merge";
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs));
6 | }
7 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/utils/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | export { FIXTURES } from "./fixtures";
2 | export { NoOpTaskRunner } from "./runner";
3 | export {
4 | ToolPredictionScorer,
5 | type ExpectedToolCall,
6 | } from "./toolPredictionScorer";
7 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/note.tsx:
--------------------------------------------------------------------------------
```typescript
1 | export default function Note({ children }: { children: React.ReactNode }) {
2 | return (
3 | <div className="mb-6">
4 | <p className="text-slate-300 text-base">{children}</p>
5 | </div>
6 | );
7 | }
8 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/tool-helpers/define.ts:
--------------------------------------------------------------------------------
```typescript
1 | import type { z } from "zod";
2 | import type { ToolConfig } from "../../tools/types";
3 |
4 | export function defineTool<TSchema extends Record<string, z.ZodType>>(
5 | config: ToolConfig<TSchema>,
6 | ) {
7 | return config;
8 | }
9 |
```
--------------------------------------------------------------------------------
/packages/mcp-test-client/tsconfig.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "extends": "../mcp-server-tsconfig/tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src"
6 | },
7 | "include": ["src/**/*"],
8 | "exclude": ["node_modules", "dist", "**/*.test.ts"]
9 | }
```
--------------------------------------------------------------------------------
/packages/mcp-server-evals/tsconfig.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "extends": "@sentry/mcp-server-tsconfig/tsconfig.base.json",
3 | "compilerOptions": {
4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
5 | "outDir": "dist",
6 | "rootDir": "src"
7 | },
8 | "include": ["src"]
9 | }
10 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-mocks/tsconfig.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "extends": "@sentry/mcp-server-tsconfig/tsconfig.base.json",
3 | "compilerOptions": {
4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
5 | "outDir": "dist",
6 | "rootDir": "src"
7 | },
8 | "include": ["src"]
9 | }
10 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/tsconfig.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "extends": "@sentry/mcp-server-tsconfig/tsconfig.base.json",
3 | "compilerOptions": {
4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
5 | "outDir": "dist",
6 | "rootDir": "src"
7 | },
8 | "include": ["src"]
9 | }
10 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/tsconfig.server.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "extends": "./tsconfig.node.json",
3 | "compilerOptions": {
4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.server.tsbuildinfo",
5 | "types": [
6 | "@cloudflare/workers-types"
7 | ]
8 | },
9 | "include": [
10 | "src/server"
11 | ]
12 | }
13 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-mocks/tsdown.config.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { defineConfig } from "tsdown";
2 |
3 | export default defineConfig({
4 | entry: ["src/**/*.ts"],
5 | format: ["cjs", "esm"], // Build for commonJS and ESmodules
6 | dts: true, // Generate declaration file (.d.ts)
7 | sourcemap: true,
8 | clean: true,
9 | });
10 |
```
--------------------------------------------------------------------------------
/packages/smoke-tests/vitest.config.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { defineConfig } from "vitest/config";
2 |
3 | export default defineConfig({
4 | test: {
5 | globals: true,
6 | environment: "node",
7 | testTimeout: 30000, // 30 seconds for network requests
8 | hookTimeout: 60000, // 60 seconds for setup/teardown
9 | },
10 | });
11 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/system.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "system",
3 | "description": "Describes System attributes",
4 | "attributes": {
5 | "system.device": {
6 | "description": "The device identifier",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["(identifier)"]
10 | }
11 | }
12 | }
13 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-mocks/src/fixtures/event-attachments.json:
--------------------------------------------------------------------------------
```json
1 | [
2 | {
3 | "id": "123",
4 | "name": "screenshot.png",
5 | "type": "event.attachment",
6 | "size": 1024,
7 | "mimetype": "image/png",
8 | "dateCreated": "2025-04-08T21:15:04.000Z",
9 | "sha1": "abc123def456",
10 | "headers": {
11 | "Content-Type": "image/png"
12 | }
13 | }
14 | ]
15 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/go.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "go",
3 | "description": "This document defines Go related attributes.\n",
4 | "attributes": {
5 | "go.memory.type": {
6 | "description": "The type of memory.",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["stack", "other"]
10 | }
11 | }
12 | }
13 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/tsconfig.node.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "extends": "@sentry/mcp-server-tsconfig/tsconfig.base.json",
3 | "compilerOptions": {
4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
5 | "outDir": "dist",
6 | "rootDir": "",
7 |
8 | "types": ["@cloudflare/vitest-pool-workers"]
9 | },
10 | "include": ["vite.config.ts"]
11 | }
12 |
```
--------------------------------------------------------------------------------
/bin/bump-version.sh:
--------------------------------------------------------------------------------
```bash
1 | #!/bin/bash
2 | ### Example of a version-bumping script for an NPM project.
3 | ### Located at: ./bin/bump-version.sh
4 | set -eux
5 | OLD_VERSION="${1}"
6 | NEW_VERSION="${2}"
7 |
8 | # Do not tag and commit changes made by "npm version"
9 | export npm_config_git_tag_version=false
10 | pnpm -r exec npm version "${NEW_VERSION}"
11 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/nodejs.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "nodejs",
3 | "description": "Describes Node.js related attributes.",
4 | "attributes": {
5 | "nodejs.eventloop.state": {
6 | "description": "The state of event loop time.",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["active", "idle"]
10 | }
11 | }
12 | }
13 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/linux.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "linux",
3 | "description": "Describes Linux Memory attributes",
4 | "attributes": {
5 | "linux.memory.slab.state": {
6 | "description": "The Linux Slab memory state",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["reclaimable", "unreclaimable"]
10 | }
11 | }
12 | }
13 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/oauth/routes/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { Hono } from "hono";
2 | import type { Env } from "../../types";
3 | import authorizeApp from "./authorize";
4 | import callbackApp from "./callback";
5 |
6 | // Compose and export the main OAuth Hono app
7 | export default new Hono<{ Bindings: Env }>()
8 | .route("/authorize", authorizeApp)
9 | .route("/callback", callbackApp);
10 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/disk.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "disk",
3 | "description": "These attributes may be used for any disk related operation.\n",
4 | "attributes": {
5 | "disk.io.direction": {
6 | "description": "The disk IO operation direction.",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["read", "write"]
10 | }
11 | }
12 | }
13 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/tsconfig.client.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "extends": "@sentry/mcp-server-tsconfig/tsconfig.vite.json",
3 | "compilerOptions": {
4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.client.tsbuildinfo",
5 | "baseUrl": ".",
6 | "paths": {
7 | "@/*": [
8 | "./src/*"
9 | ]
10 | },
11 | "outDir": "dist",
12 | "rootDir": "src"
13 | },
14 | "include": ["src/client"]
15 | }
16 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/constants.ts:
--------------------------------------------------------------------------------
```typescript
1 | // https://docs.sentry.io/api/permissions/
2 | export const SCOPES = {
3 | "org:read": "Read organization data",
4 | "project:write": "Write project data",
5 | "team:write": "Write team data",
6 | "event:write": "Write event data",
7 | };
8 |
9 | export const NPM_PACKAGE_NAME = "@sentry/mcp-server";
10 |
11 | export const NPM_REMOTE_NAME = "mcp-remote";
12 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/cpython.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "cpython",
3 | "description": "This document defines CPython related attributes.\n",
4 | "attributes": {
5 | "cpython.gc.generation": {
6 | "description": "Value of the garbage collector collection generation.",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["0", "1", "2"]
10 | }
11 | }
12 | }
13 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/tool-helpers/issue.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * Re-export of issue parsing utilities for tool modules.
3 | * These utilities handle flexible input formats for Sentry issues.
4 | */
5 | export { parseIssueParams } from "../../internal/issue-helpers";
6 |
7 | /**
8 | * Re-export of issue formatting utilities for tool modules.
9 | */
10 | export { formatIssueOutput } from "../../internal/formatting";
11 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/instrument.ts:
--------------------------------------------------------------------------------
```typescript
1 | import * as Sentry from "@sentry/react";
2 | import { sentryBeforeSend } from "@sentry/mcp-server/telem/sentry";
3 |
4 | Sentry.init({
5 | dsn: import.meta.env.VITE_SENTRY_DSN,
6 | sendDefaultPii: true,
7 | tracesSampleRate: 1,
8 | beforeSend: sentryBeforeSend,
9 | environment:
10 | import.meta.env.VITE_SENTRY_ENVIRONMENT ?? import.meta.env.NODE_ENV,
11 | });
12 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/log.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "log",
3 | "description": "This document defines log attributes\n",
4 | "attributes": {
5 | "log.iostream": {
6 | "description": "The stream associated with the log. See below for a list of well-known values.\n",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["stdout", "stderr"]
10 | }
11 | }
12 | }
13 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-tsconfig/tsconfig.vite.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "display": "Vite (React) Library",
4 | "extends": "./tsconfig.base.json",
5 | "compilerOptions": {
6 | "jsx": "react-jsx",
7 | "target": "ES2020",
8 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
9 | "useDefineForClassFields": true,
10 | "module": "ESNext",
11 | "types": ["vite/client"]
12 | }
13 | }
14 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/dotnet.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "dotnet",
3 | "description": "This document defines .NET related attributes.\n",
4 | "attributes": {
5 | "dotnet.gc.heap.generation": {
6 | "description": "Name of the garbage collector managed heap generation.",
7 | "type": "string",
8 | "stability": "stable",
9 | "examples": ["gen0", "gen1", "gen2", "loh", "poh"]
10 | }
11 | }
12 | }
13 |
```
--------------------------------------------------------------------------------
/packages/smoke-tests/package.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "name": "@sentry/mcp-smoke-tests",
3 | "version": "0.18.0",
4 | "private": true,
5 | "type": "module",
6 | "scripts": {
7 | "test": "vitest run",
8 | "test:ci": "vitest run --reporter=default --reporter=junit --outputFile=tests.junit.xml",
9 | "test:watch": "vitest"
10 | },
11 | "devDependencies": {
12 | "vitest": "catalog:",
13 | "@types/node": "catalog:"
14 | }
15 | }
16 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-mocks/src/fixtures/trace-items-attributes-logs-number.json:
--------------------------------------------------------------------------------
```json
1 | [
2 | {
3 | "key": "severity_number",
4 | "name": "Severity Number"
5 | },
6 | {
7 | "key": "sentry.observed_timestamp_nanos",
8 | "name": "Observed Timestamp (Nanos)"
9 | },
10 | {
11 | "key": "timestamp",
12 | "name": "Timestamp"
13 | },
14 | {
15 | "key": "custom.duration",
16 | "name": "Custom Duration"
17 | },
18 | {
19 | "key": "custom.bytes",
20 | "name": "Custom Bytes"
21 | }
22 | ]
23 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/vitest.config.ts:
--------------------------------------------------------------------------------
```typescript
1 | /// <reference types="vitest" />
2 | import { defineConfig } from "vitest/config";
3 |
4 | export default defineConfig({
5 | test: {
6 | include: ["**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
7 | coverage: {
8 | provider: "v8",
9 | reporter: ["text", "json", "html"],
10 | include: ["**/*.ts"],
11 | },
12 | setupFiles: ["dotenv/config", "src/test-setup.ts"],
13 | },
14 | });
15 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/prose.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { cn } from "@/client/lib/utils";
2 |
3 | export function Prose({
4 | children,
5 | className,
6 | ...props
7 | }: { children: React.ReactNode } & React.HTMLAttributes<HTMLDivElement>) {
8 | return (
9 | <div
10 | className={cn(
11 | "prose prose-invert prose-slate max-w-none prose-a:text-violet-300",
12 | className,
13 | )}
14 | {...props}
15 | >
16 | {children}
17 | </div>
18 | );
19 | }
20 |
```
--------------------------------------------------------------------------------
/.claude/commands/gh-review.md:
--------------------------------------------------------------------------------
```markdown
1 | Address feedback and checks in a Pull Request.
2 |
3 | We use the GitHub CLI (`gh`) to manage pull requests.
4 |
5 | Review the status checks for this PR, and identify any failures from them.
6 |
7 | If there are no failures, review the PR feedback.
8 |
9 | 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.
10 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-evals/vitest.config.ts:
--------------------------------------------------------------------------------
```typescript
1 | /// <reference types="vitest" />
2 | import { defineConfig } from "vitest/config";
3 |
4 | export default defineConfig({
5 | test: {
6 | include: ["**/*.eval.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
7 | reporters: ["vitest-evals/reporter"],
8 | coverage: {
9 | provider: "v8",
10 | reporter: ["text", "json", "html"],
11 | include: ["**/*.ts"],
12 | },
13 | setupFiles: ["./src/setup-env.ts"],
14 | },
15 | });
16 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/elasticsearch.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "elasticsearch",
3 | "description": "This section defines attributes for Elasticsearch.\n",
4 | "attributes": {
5 | "elasticsearch.node.name": {
6 | "description": "Represents the human-readable identifier of the node/instance to which a request was routed.\n",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["instance-0000000001"]
10 | }
11 | }
12 | }
13 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/oauth/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | // Re-export the main OAuth Hono app
2 | export { default } from "./routes/index";
3 |
4 | // Re-export helper functions and constants for external use
5 | export { tokenExchangeCallback } from "./helpers";
6 | export {
7 | SENTRY_AUTH_URL,
8 | SENTRY_TOKEN_URL,
9 | TokenResponseSchema,
10 | } from "./constants";
11 | export {
12 | getUpstreamAuthorizeUrl,
13 | exchangeCodeForAccessToken,
14 | refreshAccessToken,
15 | } from "./helpers";
16 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/opentracing.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "opentracing",
3 | "description": "Attributes used by the OpenTracing Shim layer.",
4 | "attributes": {
5 | "opentracing.ref_type": {
6 | "description": "Parent-child Reference type",
7 | "type": "string",
8 | "note": "The causal relationship between a child Span and a parent Span.\n",
9 | "stability": "development",
10 | "examples": ["child_of", "follows_from"]
11 | }
12 | }
13 | }
14 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/components.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "new-york",
4 | "rsc": false,
5 | "tsx": true,
6 | "tailwind": {
7 | "config": "",
8 | "css": "src/client/index.css",
9 | "baseColor": "neutral",
10 | "cssVariables": true,
11 | "prefix": ""
12 | },
13 | "aliases": {
14 | "components": "@/components",
15 | "utils": "@/lib/utils",
16 | "ui": "@/components/ui",
17 | "lib": "@/lib",
18 | "hooks": "@/hooks"
19 | },
20 | "iconLibrary": "lucide"
21 | }
22 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/telem/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * Telemetry and observability utilities.
3 | *
4 | * This module provides logging, error tracking, and instrumentation utilities
5 | * for monitoring and debugging MCP server operations.
6 | */
7 |
8 | // Re-export logging utilities
9 | export {
10 | getLogger,
11 | logDebug,
12 | logInfo,
13 | logWarn,
14 | logError,
15 | logIssue,
16 | type LogIssueOptions,
17 | } from "./logging";
18 |
19 | // Re-export Sentry instrumentation utilities
20 | export { sentryBeforeSend } from "./sentry";
21 |
```
--------------------------------------------------------------------------------
/packages/mcp-test-client/src/types.ts:
--------------------------------------------------------------------------------
```typescript
1 | // Shared types for MCP client
2 |
3 | export interface MCPConnection {
4 | client: any; // TODO: Replace with proper type from experimental MCP client
5 | tools: Map<string, any>;
6 | disconnect: () => Promise<void>;
7 | sessionId: string;
8 | transport: "stdio" | "http";
9 | }
10 |
11 | export interface MCPConfig {
12 | accessToken: string;
13 | host?: string;
14 | sentryDsn?: string;
15 | }
16 |
17 | export interface RemoteMCPConfig {
18 | mcpHost?: string;
19 | accessToken?: string;
20 | }
21 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/peer.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "peer",
3 | "description": "Operations that access some remote service.\n",
4 | "attributes": {
5 | "peer.service": {
6 | "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",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["AuthTokenCache"]
10 | }
11 | }
12 | }
13 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/utils/runner.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * A no-op task runner that doesn't execute tools, just returns the input
3 | * for use with ToolPredictionScorer. This allows tests to focus on predicting
4 | * which tools would be called without actually executing them.
5 | */
6 | export function NoOpTaskRunner() {
7 | return async function NoOpTaskRunner(input: string) {
8 | // Just return the input as the result, no tool execution
9 | return {
10 | result: input,
11 | toolCalls: [],
12 | };
13 | };
14 | }
15 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/fragments/setup-guide.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import {
2 | AccordionContent,
3 | AccordionItem,
4 | AccordionTrigger,
5 | } from "../ui/accordion";
6 | import { Prose } from "../ui/prose";
7 |
8 | export default function SetupGuide({
9 | id,
10 | title,
11 | children,
12 | }: { id: string; title: string; children: React.ReactNode }) {
13 | return (
14 | <AccordionItem value={id}>
15 | <AccordionTrigger>{title}</AccordionTrigger>
16 | <AccordionContent>
17 | <Prose>{children}</Prose>
18 | </AccordionContent>
19 | </AccordionItem>
20 | );
21 | }
22 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/toolDefinitions.ts:
--------------------------------------------------------------------------------
```typescript
1 | import toolDefinitionsData from "./toolDefinitions.json";
2 | import type { Scope } from "./permissions";
3 |
4 | // Tool definition for UI/external consumption
5 | export interface ToolDefinition {
6 | name: string;
7 | description: string;
8 | // Full JSON Schema object for parameters
9 | inputSchema: unknown;
10 | // Sentry API scopes required to use the tool
11 | requiredScopes: Scope[];
12 | }
13 |
14 | const toolDefinitions = toolDefinitionsData as ToolDefinition[];
15 |
16 | export default toolDefinitions;
17 |
```
--------------------------------------------------------------------------------
/packages/mcp-test-client/src/constants.ts:
--------------------------------------------------------------------------------
```typescript
1 | // Default MCP Server
2 | export const DEFAULT_MCP_URL = "https://mcp.sentry.dev";
3 |
4 | // Default AI model - using GPT-4
5 | export const DEFAULT_MODEL = "gpt-4o";
6 |
7 | // OAuth configuration
8 | export const OAUTH_REDIRECT_PORT = 8765;
9 | export const OAUTH_REDIRECT_URI = `http://localhost:${OAUTH_REDIRECT_PORT}/callback`;
10 |
11 | // Default OAuth scopes
12 | export const DEFAULT_OAUTH_SCOPES = [
13 | "org:read",
14 | "project:read",
15 | "project:write",
16 | "team:read",
17 | "team:write",
18 | "event:write",
19 | ];
20 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/icon.tsx:
--------------------------------------------------------------------------------
```typescript
1 | interface IconProps {
2 | className?: string;
3 | path: string;
4 | viewBox?: string;
5 | title?: string;
6 | }
7 |
8 | export function Icon({
9 | className,
10 | path,
11 | viewBox = "0 0 32 32",
12 | title = "Icon",
13 | }: IconProps) {
14 | return (
15 | <svg
16 | className={className}
17 | viewBox={viewBox}
18 | fill="none"
19 | xmlns="http://www.w3.org/2000/svg"
20 | aria-labelledby="icon-title"
21 | >
22 | <title id="icon-title">{title}</title>
23 | <path d={path} fill="currentColor" />
24 | </svg>
25 | );
26 | }
27 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/section.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import type { ReactNode } from "react";
2 | import { Heading } from "./base";
3 | import { cn } from "@/client/lib/utils";
4 |
5 | export default function Section({
6 | heading,
7 | children,
8 | className,
9 | ...props
10 | }: {
11 | heading?: string | ReactNode;
12 | children: ReactNode;
13 | className?: string;
14 | } & React.HTMLAttributes<HTMLDivElement>) {
15 | return (
16 | <section className={cn("space-y-4 mb-10", className)} {...props}>
17 | {heading && <Heading>{heading}</Heading>}
18 | {children}
19 | </section>
20 | );
21 | }
22 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-mocks/src/fixtures/trace-items-attributes-spans-number.json:
--------------------------------------------------------------------------------
```json
1 | [
2 | {
3 | "key": "span.duration",
4 | "name": "Span Duration"
5 | },
6 | {
7 | "key": "transaction.duration",
8 | "name": "Transaction Duration"
9 | },
10 | {
11 | "key": "http.status_code",
12 | "name": "HTTP Status Code"
13 | },
14 | {
15 | "key": "custom.count",
16 | "name": "Custom Count"
17 | },
18 | {
19 | "key": "custom.score",
20 | "name": "Custom Score"
21 | },
22 | {
23 | "key": "custom.latency_ms",
24 | "name": "Custom Latency (ms)"
25 | },
26 | {
27 | "key": "custom.db.pool_size",
28 | "name": "Custom DB Pool Size"
29 | }
30 | ]
31 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/oauth/constants.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { z } from "zod";
2 |
3 | // Sentry OAuth endpoints
4 | export const SENTRY_AUTH_URL = "/oauth/authorize/";
5 | export const SENTRY_TOKEN_URL = "/oauth/token/";
6 |
7 | export const TokenResponseSchema = z.object({
8 | access_token: z.string(),
9 | refresh_token: z.string(),
10 | token_type: z.string(), // should be "bearer"
11 | expires_in: z.number(),
12 | expires_at: z.string().datetime(),
13 | user: z.object({
14 | email: z.string().email(),
15 | id: z.string(),
16 | name: z.string().nullable(),
17 | }),
18 | scope: z.string(),
19 | });
20 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/list-organizations.eval.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describeEval } from "vitest-evals";
2 | import { NoOpTaskRunner, ToolPredictionScorer } from "./utils";
3 |
4 | describeEval("list-organizations", {
5 | data: async () => {
6 | return [
7 | {
8 | input: `What organizations do I have access to in Sentry`,
9 | expectedTools: [
10 | {
11 | name: "find_organizations",
12 | arguments: {},
13 | },
14 | ],
15 | },
16 | ];
17 | },
18 | task: NoOpTaskRunner(),
19 | scorers: [ToolPredictionScorer()],
20 | threshold: 0.6,
21 | timeout: 30000,
22 | });
23 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/tool-helpers/formatting.ts:
--------------------------------------------------------------------------------
```typescript
1 | import type { z } from "zod";
2 | import type { AssignedToSchema } from "../../api-client/index";
3 |
4 | type AssignedTo = z.infer<typeof AssignedToSchema>;
5 |
6 | /**
7 | * Helper function to format assignedTo field for display
8 | */
9 | export function formatAssignedTo(assignedTo: AssignedTo): string {
10 | if (!assignedTo) {
11 | return "Unassigned";
12 | }
13 |
14 | if (typeof assignedTo === "string") {
15 | return assignedTo;
16 | }
17 |
18 | if (typeof assignedTo === "object" && assignedTo.name) {
19 | return assignedTo.name;
20 | }
21 |
22 | return "Unknown";
23 | }
24 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/profile.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "profile",
3 | "description": "Describes the origin of a single frame in a Profile.\n",
4 | "attributes": {
5 | "profile.frame.type": {
6 | "description": "Describes the interpreter or compiler of a single frame.\n",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": [
10 | "dotnet",
11 | "jvm",
12 | "kernel",
13 | "native",
14 | "perl",
15 | "php",
16 | "cpython",
17 | "ruby",
18 | "v8js",
19 | "beam",
20 | "go",
21 | "rust"
22 | ]
23 | }
24 | }
25 | }
26 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/find-projects.test.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describe, it, expect } from "vitest";
2 | import findProjects from "./find-projects.js";
3 | import { getServerContext } from "../test-setup.js";
4 |
5 | describe("find_projects", () => {
6 | it("serializes", async () => {
7 | const result = await findProjects.handler(
8 | {
9 | organizationSlug: "sentry-mcp-evals",
10 | regionUrl: undefined,
11 | },
12 | getServerContext(),
13 | );
14 | expect(result).toMatchInlineSnapshot(`
15 | "# Projects in **sentry-mcp-evals**
16 |
17 | - **cloudflare-mcp**
18 | "
19 | `);
20 | });
21 | });
22 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/thread.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "thread",
3 | "description": "These attributes may be used for any operation to store information about a thread that started a span.\n",
4 | "attributes": {
5 | "thread.id": {
6 | "description": "Current \"managed\" thread ID (as opposed to OS thread ID).\n",
7 | "type": "number",
8 | "stability": "development",
9 | "examples": ["42"]
10 | },
11 | "thread.name": {
12 | "description": "Current thread name.\n",
13 | "type": "string",
14 | "stability": "development",
15 | "examples": ["main"]
16 | }
17 | }
18 | }
19 |
```
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "editor.formatOnSave": true,
3 | "editor.codeActionsOnSave": {
4 | "source.fixAll.biome": "explicit"
5 | },
6 | "files.trimTrailingWhitespace": false,
7 | "files.trimFinalNewlines": false,
8 | "files.insertFinalNewline": true,
9 | "cursor.general.enableShadowWorkspace": true,
10 | "[json]": {
11 | "editor.tabSize": 2,
12 | "editor.defaultFormatter": "biomejs.biome"
13 | },
14 | "[typescript]": {
15 | "editor.tabSize": 2,
16 | "editor.defaultFormatter": "biomejs.biome"
17 | },
18 | "[typescriptreact]": {
19 | "editor.defaultFormatter": "biomejs.biome"
20 | }
21 | }
22 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/find-teams.test.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describe, it, expect } from "vitest";
2 | import findTeams from "./find-teams.js";
3 |
4 | describe("find_teams", () => {
5 | it("serializes", async () => {
6 | const result = await findTeams.handler(
7 | {
8 | organizationSlug: "sentry-mcp-evals",
9 | regionUrl: undefined,
10 | },
11 | {
12 | constraints: {
13 | organizationSlug: null,
14 | },
15 | accessToken: "access-token",
16 | userId: "1",
17 | },
18 | );
19 | expect(result).toMatchInlineSnapshot(`
20 | "# Teams in **sentry-mcp-evals**
21 |
22 | - the-goats
23 | "
24 | `);
25 | });
26 | });
27 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/vite.config.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { sentryVitePlugin } from "@sentry/vite-plugin";
2 | import { defineConfig } from "vite";
3 | import react from "@vitejs/plugin-react";
4 | import { cloudflare } from "@cloudflare/vite-plugin";
5 | import tailwindcss from "@tailwindcss/vite";
6 | import path from "node:path";
7 |
8 | export default defineConfig({
9 | plugins: [
10 | react(),
11 | cloudflare(),
12 | tailwindcss(),
13 | sentryVitePlugin({
14 | org: "sentry",
15 | project: "mcp-server",
16 | }),
17 | ],
18 | resolve: {
19 | alias: {
20 | "@": path.resolve(__dirname, "./src"),
21 | },
22 | },
23 | build: {
24 | sourcemap: true,
25 | },
26 | });
27 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/cpu.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "cpu",
3 | "description": "Attributes specific to a cpu instance.",
4 | "attributes": {
5 | "cpu.mode": {
6 | "description": "The mode of the CPU",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": [
10 | "user",
11 | "system",
12 | "nice",
13 | "idle",
14 | "iowait",
15 | "interrupt",
16 | "steal",
17 | "kernel"
18 | ]
19 | },
20 | "cpu.logical_number": {
21 | "description": "The logical CPU number [0..n-1]",
22 | "type": "number",
23 | "stability": "development",
24 | "examples": ["1"]
25 | }
26 | }
27 | }
28 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-mocks/package.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "name": "@sentry/mcp-server-mocks",
3 | "version": "0.18.0",
4 | "private": true,
5 | "type": "module",
6 | "engines": {
7 | "node": ">=20"
8 | },
9 | "license": "FSL-1.1-ALv2",
10 | "exports": {
11 | ".": {
12 | "types": "./dist/index.d.ts",
13 | "default": "./dist/index.js"
14 | },
15 | "./utils": {
16 | "types": "./dist/utils.d.ts",
17 | "default": "./dist/utils.js"
18 | }
19 | },
20 | "scripts": {
21 | "build": "tsdown",
22 | "dev": "tsdown -w"
23 | },
24 | "devDependencies": {
25 | "@sentry/mcp-server-tsconfig": "workspace:*",
26 | "tsdown": "catalog:"
27 | },
28 | "dependencies": {
29 | "msw": "catalog:"
30 | }
31 | }
32 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/logging.ts:
--------------------------------------------------------------------------------
```typescript
1 | import type { MiddlewareHandler } from "hono";
2 | import { logInfo } from "@sentry/mcp-server/telem/logging";
3 |
4 | /**
5 | * Hono middleware that logs every request once the response is ready.
6 | */
7 | export function createRequestLogger(
8 | loggerScope: readonly string[] = ["cloudflare", "http"],
9 | ): MiddlewareHandler {
10 | return async (c, next) => {
11 | const start = Date.now();
12 | await next();
13 |
14 | const url = new URL(c.req.url);
15 | logInfo(`${c.req.method} ${url.pathname}`, {
16 | loggerScope,
17 | extra: {
18 | status: c.res.status,
19 | duration_ms: Date.now() - start,
20 | },
21 | });
22 | };
23 | }
24 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/signalr.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "signalr",
3 | "description": "SignalR attributes",
4 | "attributes": {
5 | "signalr.connection.status": {
6 | "description": "SignalR HTTP connection closure status.",
7 | "type": "string",
8 | "stability": "stable",
9 | "examples": ["normal_closure", "timeout", "app_shutdown"]
10 | },
11 | "signalr.transport": {
12 | "description": "[SignalR transport type](https://github.com/dotnet/aspnetcore/blob/main/src/SignalR/docs/specs/TransportProtocols.md)",
13 | "type": "string",
14 | "stability": "stable",
15 | "examples": ["server_sent_events", "long_polling", "web_sockets"]
16 | }
17 | }
18 | }
19 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/tools.test.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { assert, test } from "vitest";
2 | import * as tools from "./index.js";
3 |
4 | // VSCode (via OpenAI) limits to 1024 characters, but its tough to hit that right now,
5 | // so instead lets limit the blast damage and hope that e.g. OpenAI will increase the limit.
6 | const DESCRIPTION_MAX_LENGTH = 2048;
7 |
8 | test(`all tool descriptions under maximum length`, () => {
9 | for (const tool of Object.values(tools.default)) {
10 | const length = tool.description.length;
11 | assert(
12 | length < DESCRIPTION_MAX_LENGTH,
13 | `${tool.name} description must be less than ${DESCRIPTION_MAX_LENGTH} characters (was ${length})`,
14 | );
15 | }
16 | });
17 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/backdrop.tsx:
--------------------------------------------------------------------------------
```typescript
1 | interface BackdropProps {
2 | isOpen: boolean;
3 | onClose: () => void;
4 | }
5 |
6 | export function Backdrop({ isOpen, onClose }: BackdropProps) {
7 | return (
8 | <div
9 | className={`fixed inset-0 bg-black/50 backdrop-blur-sm transition-all duration-500 ease-out ${
10 | isOpen ? "opacity-100" : "opacity-0"
11 | }`}
12 | onClick={isOpen ? onClose : undefined}
13 | onKeyDown={
14 | isOpen
15 | ? (e: React.KeyboardEvent) => e.key === "Escape" && onClose()
16 | : undefined
17 | }
18 | role={isOpen ? "button" : undefined}
19 | tabIndex={isOpen ? 0 : -1}
20 | aria-label={isOpen ? "Close chat panel" : undefined}
21 | />
22 | );
23 | }
24 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/zos.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "zos",
3 | "description": "This document defines attributes of a z/OS resource.\n",
4 | "attributes": {
5 | "zos.smf.id": {
6 | "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.",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["SYS1"]
10 | },
11 | "zos.sysplex.name": {
12 | "description": "The name of the SYSPLEX to which the z/OS system belongs too.",
13 | "type": "string",
14 | "stability": "development",
15 | "examples": ["SYSPLEX1"]
16 | }
17 | }
18 | }
19 |
```
--------------------------------------------------------------------------------
/packages/mcp-test-client/tsdown.config.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { defineConfig } from "tsdown";
2 | import { readFileSync } from "node:fs";
3 |
4 | const packageVersion =
5 | process.env.npm_package_version ??
6 | JSON.parse(readFileSync("./package.json", "utf-8")).version;
7 |
8 | export default defineConfig({
9 | entry: ["src/index.ts"],
10 | format: ["esm"],
11 | clean: true,
12 | platform: "node",
13 | minify: false,
14 | shims: true,
15 | banner: {
16 | js: "#!/usr/bin/env node",
17 | },
18 | env: {
19 | DEFAULT_SENTRY_DSN:
20 | "https://[email protected]/4509062593708032",
21 | SENTRY_ENVIRONMENT: "mcp-test-client",
22 | SENTRY_RELEASE: packageVersion,
23 | npm_package_version: packageVersion,
24 | },
25 | });
26 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/vitest.config.ts:
--------------------------------------------------------------------------------
```typescript
1 | /// <reference types="vitest" />
2 | import { defineConfig } from "vitest/config";
3 |
4 | export default defineConfig({
5 | test: {
6 | // Use thread-based workers to avoid process-kill issues in sandboxed environments
7 | pool: "threads",
8 | poolOptions: {
9 | workers: {
10 | miniflare: {},
11 | wrangler: { configPath: "./wrangler.toml" },
12 | },
13 | },
14 | deps: {
15 | interopDefault: true,
16 | },
17 | include: ["**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
18 | coverage: {
19 | provider: "v8",
20 | reporter: ["text", "json", "html"],
21 | include: ["**/*.ts"],
22 | },
23 | setupFiles: ["dotenv/config", "src/test-setup.ts"],
24 | },
25 | });
26 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/ios.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "ios",
3 | "description": "This group describes iOS-specific attributes.\n",
4 | "attributes": {
5 | "ios.app.state": {
6 | "description": "This attribute represents the state of the application.\n",
7 | "type": "string",
8 | "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",
9 | "stability": "development",
10 | "examples": [
11 | "active",
12 | "inactive",
13 | "background",
14 | "foreground",
15 | "terminate"
16 | ]
17 | }
18 | }
19 | }
20 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/list-dsns.eval.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describeEval } from "vitest-evals";
2 | import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";
3 |
4 | describeEval("list-dsns", {
5 | data: async () => {
6 | return [
7 | {
8 | input: `What is the SENTRY_DSN for ${FIXTURES.organizationSlug}/${FIXTURES.projectSlug}?`,
9 | expectedTools: [
10 | {
11 | name: "find_dsns",
12 | arguments: {
13 | organizationSlug: FIXTURES.organizationSlug,
14 | projectSlug: FIXTURES.projectSlug,
15 | },
16 | },
17 | ],
18 | },
19 | ];
20 | },
21 | task: NoOpTaskRunner(),
22 | scorers: [ToolPredictionScorer()],
23 | threshold: 0.6,
24 | timeout: 30000,
25 | });
26 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/tsdown.config.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { defineConfig } from "tsdown";
2 | import { readFileSync } from "node:fs";
3 |
4 | const packageVersion =
5 | process.env.npm_package_version ??
6 | JSON.parse(readFileSync("./package.json", "utf-8")).version;
7 |
8 | export default defineConfig({
9 | entry: ["src/**/*.ts", "!src/**/*.test.ts"],
10 | format: ["cjs", "esm"], // Build for commonJS and ESmodules
11 | dts: true, // Generate declaration file (.d.ts)
12 | sourcemap: true,
13 | clean: true,
14 | env: {
15 | DEFAULT_SENTRY_DSN:
16 | "https://[email protected]/4509062593708032",
17 | SENTRY_ENVIRONMENT: "stdio",
18 | SENTRY_RELEASE: packageVersion,
19 | npm_package_version: packageVersion,
20 | },
21 | });
22 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/gcp.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "gcp",
3 | "description": "Attributes for Google Cloud client libraries.\n",
4 | "attributes": {
5 | "gcp.client.service": {
6 | "description": "Identifies the Google Cloud service for which the official client library is intended.",
7 | "type": "string",
8 | "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",
9 | "stability": "development",
10 | "examples": ["appengine", "run", "firestore", "alloydb", "spanner"]
11 | }
12 | }
13 | }
14 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/chat/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | // Chat components
2 | export { Chat } from "./chat";
3 | export { ChatUI } from "./chat-ui";
4 | export { ChatMessages } from "./chat-messages";
5 | export { ChatInput } from "./chat-input";
6 | export { MessagePart, TextPart, ToolPart } from "./chat-message";
7 | export { ToolContent, ToolInvocation } from "./tool-invocation";
8 |
9 | // Auth components
10 | export { AuthForm } from "./auth-form";
11 |
12 | // Export types
13 | export type {
14 | ChatProps,
15 | ChatUIProps,
16 | ChatMessagesProps,
17 | ChatInputProps,
18 | AuthFormProps,
19 | MessagePartProps,
20 | TextPartProps,
21 | ToolPartProps,
22 | ToolInvocationProps,
23 | AuthState,
24 | AuthActions,
25 | AuthContextType,
26 | ChatToolInvocation,
27 | ToolMessage,
28 | ProcessedMessagePart,
29 | } from "./types";
30 |
```
--------------------------------------------------------------------------------
/.claude/commands/gh-pr.md:
--------------------------------------------------------------------------------
```markdown
1 | Create (or update) a Pull Request.
2 |
3 | We use the GitHub CLI (`gh`) to manage pull requests.
4 |
5 | If this branch does not already have a pull request, create one:
6 |
7 | - If we're on the main branch, switch to a working branch.
8 | - Commit our changes if we haven't already.
9 |
10 | If we already have one:
11 |
12 | - Verify our changes against the base branch and update the PR title and description to maintain accuracy.
13 |
14 | 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.
15 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-mocks/src/fixtures/team.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "id": "4509106740854784",
3 | "slug": "the-goats",
4 | "name": "the-goats",
5 | "dateCreated": "2025-04-06T14:11:23.961739Z",
6 | "isMember": true,
7 | "teamRole": "admin",
8 | "flags": { "idp:provisioned": false },
9 | "access": [
10 | "team:read",
11 | "alerts:read",
12 | "event:write",
13 | "team:write",
14 | "team:admin",
15 | "event:read",
16 | "org:read",
17 | "member:read",
18 | "project:admin",
19 | "project:write",
20 | "org:integrations",
21 | "project:releases",
22 | "alerts:write",
23 | "event:admin",
24 | "project:read"
25 | ],
26 | "hasAccess": true,
27 | "isPending": false,
28 | "memberCount": 1,
29 | "avatar": { "avatarType": "letter_avatar", "avatarUuid": null },
30 | "externalTeams": [],
31 | "projects": []
32 | }
33 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-mocks/src/fixtures/trace-items-attributes-logs-string.json:
--------------------------------------------------------------------------------
```json
1 | [
2 | {
3 | "key": "message",
4 | "name": "Log Message"
5 | },
6 | {
7 | "key": "severity",
8 | "name": "Log Severity"
9 | },
10 | {
11 | "key": "sentry.item_id",
12 | "name": "Sentry Item ID"
13 | },
14 | {
15 | "key": "project",
16 | "name": "Project"
17 | },
18 | {
19 | "key": "environment",
20 | "name": "Environment"
21 | },
22 | {
23 | "key": "release",
24 | "name": "Release"
25 | },
26 | {
27 | "key": "trace",
28 | "name": "Trace ID"
29 | },
30 | {
31 | "key": "level",
32 | "name": "Log Level"
33 | },
34 | {
35 | "key": "logger",
36 | "name": "Logger Name"
37 | },
38 | {
39 | "key": "module",
40 | "name": "Module"
41 | },
42 | {
43 | "key": "custom.service",
44 | "name": "Service Name"
45 | },
46 | {
47 | "key": "custom.component",
48 | "name": "Component"
49 | }
50 | ]
51 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/create-dsn.eval.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describeEval } from "vitest-evals";
2 | import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";
3 |
4 | describeEval("create-dsn", {
5 | data: async () => {
6 | return [
7 | {
8 | input: `Create a new DSN named "Production" for '${FIXTURES.organizationSlug}/${FIXTURES.projectSlug}'`,
9 | expectedTools: [
10 | {
11 | name: "create_dsn",
12 | arguments: {
13 | organizationSlug: FIXTURES.organizationSlug,
14 | projectSlug: FIXTURES.projectSlug,
15 | name: "Production",
16 | },
17 | },
18 | ],
19 | },
20 | ];
21 | },
22 | task: NoOpTaskRunner(),
23 | scorers: [ToolPredictionScorer()],
24 | threshold: 0.6,
25 | timeout: 30000,
26 | });
27 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/list-tags.eval.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describeEval } from "vitest-evals";
2 | import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";
3 |
4 | describeEval("list-tags", {
5 | data: async () => {
6 | return [
7 | {
8 | input: `What are common tags in ${FIXTURES.organizationSlug}`,
9 | expectedTools: [
10 | {
11 | name: "find_organizations",
12 | arguments: {},
13 | },
14 | {
15 | name: "find_tags",
16 | arguments: {
17 | organizationSlug: FIXTURES.organizationSlug,
18 | regionUrl: "https://us.sentry.io",
19 | },
20 | },
21 | ],
22 | },
23 | ];
24 | },
25 | task: NoOpTaskRunner(),
26 | scorers: [ToolPredictionScorer()],
27 | threshold: 0.6,
28 | timeout: 30000,
29 | });
30 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/errors.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * Error thrown when user input validation fails.
3 | * These errors should be returned to the user directly without logging to Sentry.
4 | */
5 | export class UserInputError extends Error {
6 | constructor(message: string, options?: ErrorOptions) {
7 | super(message, options);
8 | this.name = "UserInputError";
9 | }
10 | }
11 |
12 | /**
13 | * Error thrown when configuration is invalid or missing.
14 | * These errors should be returned to the user directly without logging to Sentry.
15 | * Typically used for environment configuration issues, connection settings, etc.
16 | */
17 | export class ConfigurationError extends Error {
18 | constructor(message: string, options?: ErrorOptions) {
19 | super(message, options);
20 | this.name = "ConfigurationError";
21 | }
22 | }
23 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/aws.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "aws",
3 | "description": "This section defines generic attributes for AWS services.\n",
4 | "attributes": {
5 | "aws.request_id": {
6 | "description": "The AWS request ID as returned in the response headers `x-amzn-requestid`, `x-amzn-request-id` or `x-amz-request-id`.",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["79b9da39-b7ae-508a-a6bc-864b2829c622", "C9ER4AJX75574TDJ"]
10 | },
11 | "aws.extended_request_id": {
12 | "description": "The AWS extended request ID as returned in the response header `x-amz-id-2`.",
13 | "type": "string",
14 | "stability": "development",
15 | "examples": [
16 | "wzHcyEWfmOGDIE5QOhTAqFDoDWP3y8IUvpNINCwL9N4TEHbUw0/gZJ+VZTmCNCWR7fezEN3eCiQ="
17 | ]
18 | }
19 | }
20 | }
21 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/list-projects.eval.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describeEval } from "vitest-evals";
2 | import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";
3 |
4 | describeEval("list-projects", {
5 | data: async () => {
6 | return [
7 | {
8 | input: `What projects do I have access to in Sentry for '${FIXTURES.organizationSlug}'`,
9 | expectedTools: [
10 | {
11 | name: "find_organizations",
12 | arguments: {},
13 | },
14 | {
15 | name: "find_projects",
16 | arguments: {
17 | organizationSlug: FIXTURES.organizationSlug,
18 | regionUrl: "https://us.sentry.io",
19 | },
20 | },
21 | ],
22 | },
23 | ];
24 | },
25 | task: NoOpTaskRunner(),
26 | scorers: [ToolPredictionScorer()],
27 | threshold: 0.6,
28 | timeout: 30000,
29 | });
30 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/create-team.test.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describe, it, expect } from "vitest";
2 | import createTeam from "./create-team.js";
3 |
4 | describe("create_team", () => {
5 | it("serializes", async () => {
6 | const result = await createTeam.handler(
7 | {
8 | organizationSlug: "sentry-mcp-evals",
9 | name: "the-goats",
10 | regionUrl: undefined,
11 | },
12 | {
13 | constraints: {
14 | organizationSlug: null,
15 | },
16 | accessToken: "access-token",
17 | userId: "1",
18 | },
19 | );
20 | expect(result).toMatchInlineSnapshot(`
21 | "# New Team in **sentry-mcp-evals**
22 |
23 | **ID**: 4509109078196224
24 | **Slug**: the-goats
25 | **Name**: the-goats
26 | # Using this information
27 |
28 | - You should always inform the user of the Team Slug value.
29 | "
30 | `);
31 | });
32 | });
33 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/test-utils/context.ts:
--------------------------------------------------------------------------------
```typescript
1 | import type { ServerContext } from "../types";
2 | import type { Scope } from "../permissions";
3 |
4 | /**
5 | * Create a test context with default values for testing tools
6 | */
7 | export function createTestContext(
8 | overrides: Partial<ServerContext> = {},
9 | ): ServerContext {
10 | return {
11 | accessToken: "test-access-token",
12 | constraints: {},
13 | grantedScopes: new Set<Scope>([
14 | "org:read",
15 | "project:write",
16 | "team:write",
17 | "event:write",
18 | ]),
19 | ...overrides,
20 | };
21 | }
22 |
23 | /**
24 | * Create a test context with specific constraints
25 | */
26 | export function createTestContextWithConstraints(
27 | constraints: ServerContext["constraints"],
28 | overrides: Partial<ServerContext> = {},
29 | ): ServerContext {
30 | return createTestContext({
31 | constraints,
32 | ...overrides,
33 | });
34 | }
35 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/app.test.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describe, it, expect } from "vitest";
2 | import app from "./app";
3 |
4 | describe("app", () => {
5 | describe("GET /robots.txt", () => {
6 | it("should return correct robots.txt content", async () => {
7 | const res = await app.request("/robots.txt");
8 |
9 | expect(res.status).toBe(200);
10 |
11 | const text = await res.text();
12 | expect(text).toBe(
13 | ["User-agent: *", "Allow: /$", "Disallow: /"].join("\n"),
14 | );
15 | });
16 | });
17 |
18 | describe("GET /llms.txt", () => {
19 | it("should return correct llms.txt content", async () => {
20 | const res = await app.request("/llms.txt");
21 |
22 | expect(res.status).toBe(200);
23 |
24 | const text = await res.text();
25 | expect(text).toContain("# sentry-mcp");
26 | expect(text).toContain("Model Context Protocol");
27 | });
28 | });
29 | });
30 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/v8js.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "v8js",
3 | "description": "Describes V8 JS Engine Runtime related attributes.",
4 | "attributes": {
5 | "v8js.gc.type": {
6 | "description": "The type of garbage collection.",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["major", "minor", "incremental", "weakcb"]
10 | },
11 | "v8js.heap.space.name": {
12 | "description": "The name of the space type of heap memory.",
13 | "type": "string",
14 | "note": "Value can be retrieved from value `space_name` of [`v8.getHeapSpaceStatistics()`](https://nodejs.org/api/v8.html#v8getheapspacestatistics)\n",
15 | "stability": "development",
16 | "examples": [
17 | "new_space",
18 | "old_space",
19 | "code_space",
20 | "map_space",
21 | "large_object_space"
22 | ]
23 | }
24 | }
25 | }
26 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/setup-env.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { config } from "dotenv";
2 | import path from "node:path";
3 | import { fileURLToPath } from "node:url";
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url));
6 |
7 | // Load environment variables from multiple possible locations
8 | // IMPORTANT: Do NOT use override:true as it would overwrite shell/CI environment variables
9 | const rootDir = path.resolve(__dirname, "../../../");
10 |
11 | // Load local package .env first (for package-specific overrides)
12 | config({ path: path.resolve(__dirname, "../.env") });
13 |
14 | // Load root .env second (for shared defaults - won't override local or shell vars)
15 | config({ path: path.join(rootDir, ".env") });
16 |
17 | // Start the shared MSW server for all eval tests
18 | import { startMockServer } from "@sentry/mcp-server-mocks/utils";
19 |
20 | startMockServer({ ignoreOpenAI: true });
21 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/types.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * Core type system for MCP tools.
3 | *
4 | * Defines TypeScript types derived from tool definitions, handler signatures,
5 | * and server context. Uses advanced TypeScript patterns for type-safe parameter
6 | * extraction and handler registration.
7 | */
8 | import type { Scope } from "./permissions";
9 |
10 | /**
11 | * Constraints that restrict the MCP session scope
12 | */
13 | export type Constraints = {
14 | organizationSlug?: string | null;
15 | projectSlug?: string | null;
16 | regionUrl?: string | null;
17 | };
18 |
19 | export type ServerContext = {
20 | sentryHost?: string;
21 | mcpUrl?: string;
22 | accessToken: string;
23 | openaiBaseUrl?: string;
24 | userId?: string | null;
25 | clientId?: string;
26 | // Granted scopes for tool access control
27 | grantedScopes?: Set<Scope> | ReadonlySet<Scope>;
28 | // URL-based session constraints
29 | constraints: Constraints;
30 | };
31 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/heroku.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "heroku",
3 | "description": "This document defines attributes for the Heroku platform on which application/s are running.\n",
4 | "attributes": {
5 | "heroku.release.creation_timestamp": {
6 | "description": "Time and date the release was created\n",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["2022-10-23T18:00:42Z"]
10 | },
11 | "heroku.release.commit": {
12 | "description": "Commit hash for the current release\n",
13 | "type": "string",
14 | "stability": "development",
15 | "examples": ["e6134959463efd8966b20e75b913cafe3f5ec"]
16 | },
17 | "heroku.app.id": {
18 | "description": "Unique identifier for the application\n",
19 | "type": "string",
20 | "stability": "development",
21 | "examples": ["2daa2797-e42b-4624-9322-ec3f968df4da"]
22 | }
23 | }
24 | }
25 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/openai-provider.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { createOpenAI, openai as defaultOpenAI } from "@ai-sdk/openai";
2 | import type { LanguageModelV1 } from "ai";
3 |
4 | let customFactory: ReturnType<typeof createOpenAI> | null = null;
5 |
6 | /**
7 | * Configure the OpenAI provider factory.
8 | *
9 | * When a base URL is provided, the factory will use that endpoint for all
10 | * subsequent model requests. Passing undefined resets to the default
11 | * configuration bundled with the SDK.
12 | */
13 | export function configureOpenAIProvider({
14 | baseUrl,
15 | }: {
16 | baseUrl?: string;
17 | }): void {
18 | if (baseUrl) {
19 | customFactory = createOpenAI({
20 | baseURL: baseUrl,
21 | });
22 | return;
23 | }
24 | customFactory = null;
25 | }
26 |
27 | /**
28 | * Retrieve a configured OpenAI language model.
29 | */
30 | export function getOpenAIModel(model: string): LanguageModelV1 {
31 | const factory = customFactory ?? defaultOpenAI;
32 | return factory(model);
33 | }
34 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/graphql.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "graphql",
3 | "description": "This document defines attributes for GraphQL.",
4 | "attributes": {
5 | "graphql.operation.name": {
6 | "description": "The name of the operation being executed.",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["findBookById"]
10 | },
11 | "graphql.operation.type": {
12 | "description": "The type of the operation being executed.",
13 | "type": "string",
14 | "stability": "development",
15 | "examples": ["query", "mutation", "subscription"]
16 | },
17 | "graphql.document": {
18 | "description": "The GraphQL document being executed.",
19 | "type": "string",
20 | "note": "The value may be sanitized to exclude sensitive information.",
21 | "stability": "development",
22 | "examples": ["query findBookById { bookById(id: ?) { name } }"]
23 | }
24 | }
25 | }
26 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/create-team.eval.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describeEval } from "vitest-evals";
2 | import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";
3 |
4 | describeEval("create-team", {
5 | data: async () => {
6 | return [
7 | {
8 | input: `Create a new team in Sentry for '${FIXTURES.organizationSlug}' called 'the-goats' response with **only** the team slug and no other text.`,
9 | expectedTools: [
10 | {
11 | name: "find_organizations",
12 | arguments: {},
13 | },
14 | {
15 | name: "create_team",
16 | arguments: {
17 | organizationSlug: FIXTURES.organizationSlug,
18 | name: "the-goats",
19 | regionUrl: "https://us.sentry.io",
20 | },
21 | },
22 | ],
23 | },
24 | ];
25 | },
26 | task: NoOpTaskRunner(),
27 | scorers: [ToolPredictionScorer()],
28 | threshold: 0.6,
29 | timeout: 30000,
30 | });
31 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/oci.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "oci",
3 | "description": "An OCI image manifest.\n",
4 | "attributes": {
5 | "oci.manifest.digest": {
6 | "description": "The digest of the OCI image manifest. For container images specifically is the digest by which the container image is known.\n",
7 | "type": "string",
8 | "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",
9 | "stability": "development",
10 | "examples": [
11 | "sha256:e4ca62c0d62f3e886e684806dfe9d4e0cda60d54986898173c1083856cfda0f4"
12 | ]
13 | }
14 | }
15 | }
16 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/base.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { cn } from "../../lib/utils";
2 |
3 | export function Heading({
4 | children,
5 | as,
6 | className,
7 | ...props
8 | }: {
9 | children: React.ReactNode;
10 | as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
11 | } & React.HTMLAttributes<HTMLHeadingElement>) {
12 | const Tag = as || "h2";
13 | return (
14 | <Tag
15 | className={cn("text-2xl font-bold mb-6 text-white", className)}
16 | {...props}
17 | >
18 | <div className="flex flex-row gap-2">{children}</div>
19 | <div className="h-[2px] mt-1 bg-violet-300 w-full" />
20 | </Tag>
21 | );
22 | }
23 |
24 | export function Link({
25 | children,
26 | className,
27 | href,
28 | ...props
29 | }: {
30 | children: React.ReactNode;
31 | href: string;
32 | } & React.HTMLAttributes<HTMLAnchorElement>) {
33 | return (
34 | <a
35 | href={href}
36 | className={cn("text-violet-300 font-semibold underline", className)}
37 | {...props}
38 | >
39 | {children}
40 | </a>
41 | );
42 | }
43 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/webengine.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "webengine",
3 | "description": "This document defines the attributes used to describe the packaged software running the application code.\n",
4 | "attributes": {
5 | "webengine.name": {
6 | "description": "The name of the web engine.\n",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["WildFly"]
10 | },
11 | "webengine.version": {
12 | "description": "The version of the web engine.\n",
13 | "type": "string",
14 | "stability": "development",
15 | "examples": ["21.0.0"]
16 | },
17 | "webengine.description": {
18 | "description": "Additional description of the web engine (e.g. detailed version and edition information).\n",
19 | "type": "string",
20 | "stability": "development",
21 | "examples": [
22 | "WildFly Full 21.0.0.Final (WildFly Core 13.0.1.Final) - 2.2.2.Final"
23 | ]
24 | }
25 | }
26 | }
27 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-evals/package.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "name": "@sentry/mcp-server-evals",
3 | "version": "0.18.0",
4 | "private": true,
5 | "type": "module",
6 | "engines": {
7 | "node": ">=20"
8 | },
9 | "license": "FSL-1.1-ALv2",
10 | "scripts": {
11 | "build": "tsc -b",
12 | "dev": "tsc -w",
13 | "start": "tsx src/bin/start-mock-stdio.ts",
14 | "eval": "vitest --config=vitest.config.ts",
15 | "eval:ci": "vitest run --coverage --reporter=vitest-evals/reporter --reporter=junit --outputFile=eval.junit.xml"
16 | },
17 | "dependencies": {
18 | "@ai-sdk/openai": "catalog:",
19 | "@modelcontextprotocol/sdk": "catalog:",
20 | "@sentry/mcp-server": "workspace:*",
21 | "@sentry/mcp-server-mocks": "workspace:*",
22 | "@sentry/mcp-server-tsconfig": "workspace:*",
23 | "ai": "catalog:",
24 | "dotenv": "catalog:",
25 | "msw": "catalog:",
26 | "typescript": "catalog:",
27 | "vitest": "catalog:",
28 | "vitest-evals": "catalog:",
29 | "zod": "catalog:"
30 | }
31 | }
32 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/dns.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "dns",
3 | "description": "This document defines the shared attributes used to report a DNS query.\n",
4 | "attributes": {
5 | "dns.question.name": {
6 | "description": "The name being queried.",
7 | "type": "string",
8 | "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",
9 | "stability": "development",
10 | "examples": ["www.example.com", "opentelemetry.io"]
11 | },
12 | "dns.answers": {
13 | "description": "The list of IPv4 or IPv6 addresses resolved during DNS lookup.",
14 | "type": "string",
15 | "stability": "development",
16 | "examples": ["[\"10.0.0.1\",\"2001:0db8:85a3:0000:0000:8a2e:0370:7334\"]"]
17 | }
18 | }
19 | }
20 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/main.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import "./instrument";
2 |
3 | import { StrictMode } from "react";
4 | import { createRoot } from "react-dom/client";
5 | import "./index.css";
6 | import App from "./app";
7 | import { AuthProvider } from "./contexts/auth-context";
8 | import * as Sentry from "@sentry/react";
9 |
10 | const container = document.getElementById("root");
11 |
12 | const root = createRoot(container!, {
13 | // Callback called when an error is thrown and not caught by an ErrorBoundary.
14 | onUncaughtError: Sentry.reactErrorHandler((error, errorInfo) => {
15 | console.warn("Uncaught error", error, errorInfo.componentStack);
16 | }),
17 | // Callback called when React catches an error in an ErrorBoundary.
18 | onCaughtError: Sentry.reactErrorHandler(),
19 | // Callback called when React automatically recovers from errors.
20 | onRecoverableError: Sentry.reactErrorHandler(),
21 | });
22 |
23 | root.render(
24 | <StrictMode>
25 | <AuthProvider>
26 | <App />
27 | </AuthProvider>
28 | </StrictMode>,
29 | );
30 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/template-vars.tsx:
--------------------------------------------------------------------------------
```typescript
1 | interface TemplateVarsProps {
2 | variables?: readonly string[] | null;
3 | title?: string;
4 | }
5 |
6 | /**
7 | * Renders a standardized Parameters box for template variables.
8 | */
9 | export default function TemplateVars({
10 | variables,
11 | title = "Parameters",
12 | }: TemplateVarsProps) {
13 | const vars = Array.isArray(variables) ? variables : [];
14 | if (vars.length === 0) return null;
15 |
16 | return (
17 | <section className="rounded-md border border-slate-700/60 bg-black/30 p-3">
18 | <div className="text-xs uppercase tracking-wide text-slate-300/80 mb-2">
19 | {title}
20 | </div>
21 | <div className="flex flex-wrap gap-2">
22 | {vars.map((v) => (
23 | <span
24 | key={v}
25 | 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"
26 | >
27 | {v}
28 | </span>
29 | ))}
30 | </div>
31 | </section>
32 | );
33 | }
34 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/create-dsn.test.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describe, it, expect } from "vitest";
2 | import createDsn from "./create-dsn.js";
3 |
4 | describe("create_dsn", () => {
5 | it("serializes", async () => {
6 | const result = await createDsn.handler(
7 | {
8 | organizationSlug: "sentry-mcp-evals",
9 | projectSlug: "cloudflare-mcp",
10 | name: "Default",
11 | regionUrl: undefined,
12 | },
13 | {
14 | constraints: {
15 | organizationSlug: null,
16 | projectSlug: null,
17 | },
18 | accessToken: "access-token",
19 | userId: "1",
20 | },
21 | );
22 | expect(result).toMatchInlineSnapshot(`
23 | "# New DSN in **sentry-mcp-evals/cloudflare-mcp**
24 |
25 | **DSN**: https://d20df0a1ab5031c7f3c7edca9c02814d@o4509106732793856.ingest.us.sentry.io/4509109104082945
26 | **Name**: Default
27 |
28 | # Using this information
29 |
30 | - The \`SENTRY_DSN\` value is a URL that you can use to initialize Sentry's SDKs.
31 | "
32 | `);
33 | });
34 | });
35 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/tool-actions.tsx:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * Component for rendering a readable list of tools
3 | */
4 |
5 | export interface ToolInfo {
6 | name: string;
7 | description: string;
8 | }
9 |
10 | interface ToolActionsProps {
11 | tools: ToolInfo[];
12 | }
13 |
14 | export function ToolActions({ tools }: ToolActionsProps) {
15 | if (!tools || tools.length === 0) return null;
16 |
17 | return (
18 | <div className="mt-4 space-y-3">
19 | <h4 className="text-sm font-medium text-slate-300 mb-2">Tools</h4>
20 | <div className="space-y-4">
21 | {tools.map((tool) => (
22 | <div key={tool.name} className="space-y-2">
23 | <div className="inline-block rounded border border-slate-700 bg-slate-900 px-2 py-1 text-[11px] font-mono text-slate-200">
24 | <code>{tool.name}</code>
25 | </div>
26 | {tool.description ? (
27 | <p className="text-xs text-slate-400 ml-1">{tool.description}</p>
28 | ) : null}
29 | </div>
30 | ))}
31 | </div>
32 | </div>
33 | );
34 | }
35 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/find-dsns.test.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describe, it, expect } from "vitest";
2 | import findDsns from "./find-dsns.js";
3 |
4 | describe("find_dsns", () => {
5 | it("serializes", async () => {
6 | const result = await findDsns.handler(
7 | {
8 | organizationSlug: "sentry-mcp-evals",
9 | projectSlug: "cloudflare-mcp",
10 | regionUrl: undefined,
11 | },
12 | {
13 | constraints: {
14 | organizationSlug: null,
15 | projectSlug: null,
16 | },
17 | accessToken: "access-token",
18 | userId: "1",
19 | },
20 | );
21 | expect(result).toMatchInlineSnapshot(`
22 | "# DSNs in **sentry-mcp-evals/cloudflare-mcp**
23 |
24 | ## Default
25 | **ID**: d20df0a1ab5031c7f3c7edca9c02814d
26 | **DSN**: https://d20df0a1ab5031c7f3c7edca9c02814d@o4509106732793856.ingest.us.sentry.io/4509109104082945
27 |
28 | # Using this information
29 |
30 | - The \`SENTRY_DSN\` value is a URL that you can use to initialize Sentry's SDKs.
31 | "
32 | `);
33 | });
34 | });
35 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/autofix.eval.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describeEval } from "vitest-evals";
2 | import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";
3 |
4 | describeEval("begin-issue-fix", {
5 | data: async () => {
6 | return [
7 | {
8 | input: `Whats the status on root causing this issue in Sentry?\n${FIXTURES.testIssueUrl}`,
9 | expectedTools: [
10 | {
11 | name: "analyze_issue_with_seer",
12 | arguments: {
13 | issueUrl: FIXTURES.testIssueUrl,
14 | },
15 | },
16 | ],
17 | },
18 | {
19 | input: `Can you root cause this issue and retrieve the analysis?\n${FIXTURES.testIssueUrl}`,
20 | expectedTools: [
21 | {
22 | name: "analyze_issue_with_seer",
23 | arguments: {
24 | issueUrl: FIXTURES.testIssueUrl,
25 | },
26 | },
27 | ],
28 | },
29 | ];
30 | },
31 | task: NoOpTaskRunner(),
32 | scorers: [ToolPredictionScorer()],
33 | threshold: 0.6,
34 | timeout: 30000,
35 | });
36 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-tsconfig/tsconfig.base.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "display": "Default",
4 | "compilerOptions": {
5 | "target": "ES2022",
6 | "lib": ["ES2023"],
7 | "module": "ESNext",
8 | "preserveWatchOutput": true,
9 |
10 | /* Bundler mode */
11 | "moduleResolution": "Bundler",
12 | "esModuleInterop": true,
13 | "skipLibCheck": true,
14 | "allowImportingTsExtensions": false,
15 | "resolveJsonModule": true,
16 | "isolatedModules": true,
17 | "moduleDetection": "force",
18 | "noEmit": false,
19 |
20 | /* Linting */
21 | "strict": true,
22 | "noUnusedLocals": false,
23 | "noUnusedParameters": false,
24 | "noFallthroughCasesInSwitch": true,
25 | "noUncheckedSideEffectImports": true,
26 | "forceConsistentCasingInFileNames": true,
27 |
28 | /* Basic Options */
29 | "sourceMap": true,
30 | "composite": false,
31 | "incremental": true,
32 | "declaration": true,
33 | "declarationMap": true,
34 | "allowJs": true
35 | },
36 | "include": [],
37 | "exclude": ["node_modules"]
38 | }
39 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-mocks/src/utils.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { setupServer } from "msw/node";
2 | import type { SetupServer } from "msw/node";
3 |
4 | export function setupMockServer(handlers: Array<any> = []): SetupServer {
5 | return setupServer(...handlers);
6 | }
7 |
8 | /**
9 | * Start the MSW server with common configuration for Sentry MCP tests
10 | * This helper ensures consistent configuration across all test suites
11 | */
12 | export function startMockServer(options?: {
13 | ignoreOpenAI?: boolean;
14 | }): void {
15 | const { ignoreOpenAI = true } = options || {};
16 |
17 | // Import here to avoid circular dependency
18 | const { mswServer } = require("./index");
19 |
20 | mswServer.listen({
21 | onUnhandledRequest: (req: any, print: any) => {
22 | // Ignore OpenAI requests if specified (default behavior for AI agent tests)
23 | if (ignoreOpenAI && req.url.startsWith("https://api.openai.com/")) {
24 | return;
25 | }
26 |
27 | print.warning();
28 | throw new Error(`Unhandled request: ${req.method} ${req.url}`);
29 | },
30 | });
31 | }
32 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/enduser.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "enduser",
3 | "description": "Describes the end user.\n",
4 | "attributes": {
5 | "enduser.id": {
6 | "description": "Unique identifier of an end user in the system. It maybe a username, email address, or other identifier.",
7 | "type": "string",
8 | "note": "Unique identifier of an end user in the system.\n\n> [!Warning]\n> This field contains sensitive (PII) information.\n",
9 | "stability": "development",
10 | "examples": ["username"]
11 | },
12 | "enduser.pseudo.id": {
13 | "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",
14 | "type": "string",
15 | "note": "Pseudonymous identifier of an end user.\n\n> [!Warning]\n> This field contains sensitive (linkable PII) information.\n",
16 | "stability": "development",
17 | "examples": ["QdH5CAWJgqVT4rOr0qtumf"]
18 | }
19 | }
20 | }
21 |
```
--------------------------------------------------------------------------------
/biome.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
3 | "organizeImports": {
4 | "enabled": true
5 | },
6 | "files": {
7 | "ignore": [
8 | "worker-configuration.d.ts",
9 | "tsconfig*.json",
10 | "packages/mcp-server-mocks/src/fixtures/**"
11 | ]
12 | },
13 | "vcs": {
14 | "enabled": true,
15 | "clientKind": "git",
16 | "useIgnoreFile": true
17 | },
18 | "linter": {
19 | "enabled": true,
20 | "rules": {
21 | "recommended": true,
22 | "correctness": {
23 | "noUnusedImports": "warn"
24 | },
25 | "suspicious": {
26 | "noExplicitAny": "off",
27 | "noDebugger": "off",
28 | "noConsoleLog": "off",
29 | "noConfusingVoidType": "off"
30 | },
31 | "style": {
32 | "noNonNullAssertion": "off",
33 | "noUnusedTemplateLiteral": "off"
34 | },
35 | "security": {
36 | "noDangerouslySetInnerHtml": "off"
37 | }
38 | }
39 | },
40 | "formatter": {
41 | "enabled": true,
42 | "indentWidth": 2,
43 | "indentStyle": "space"
44 | }
45 | }
46 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/icons/sentry.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { Icon } from "../icon";
2 |
3 | export function SentryIcon({ className }: { className?: string }) {
4 | return (
5 | <Icon
6 | className={className}
7 | 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"
8 | title="Sentry Logo"
9 | />
10 | );
11 | }
12 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/types.ts:
--------------------------------------------------------------------------------
```typescript
1 | import type { z } from "zod";
2 | import type { ServerContext } from "../types";
3 | import type { Scope } from "../permissions";
4 | import type {
5 | TextContent,
6 | ImageContent,
7 | EmbeddedResource,
8 | } from "@modelcontextprotocol/sdk/types.js";
9 |
10 | export interface ToolConfig<
11 | TSchema extends Record<string, z.ZodType> = Record<string, z.ZodType>,
12 | > {
13 | name: string;
14 | description: string;
15 | inputSchema: TSchema;
16 | requiredScopes: Scope[];
17 | annotations: {
18 | readOnlyHint?: boolean;
19 | destructiveHint?: boolean;
20 | idempotentHint?: boolean;
21 | openWorldHint?: boolean;
22 | };
23 | handler: (
24 | params: z.infer<z.ZodObject<TSchema>>,
25 | context: ServerContext,
26 | ) => Promise<string | (TextContent | ImageContent | EmbeddedResource)[]>;
27 | }
28 |
29 | /**
30 | * Response from the search API endpoint
31 | */
32 | export interface SearchResponse {
33 | query: string;
34 | results: Array<{
35 | id: string;
36 | url: string;
37 | snippet: string;
38 | relevance: number;
39 | }>;
40 | error?: string;
41 | }
42 |
```
--------------------------------------------------------------------------------
/packages/mcp-server-evals/src/evals/utils/fixtures.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * IMPORTANT: Keep evaluation tests minimal!
3 | *
4 | * Each eval test takes 30+ seconds to run and costs API credits.
5 | * Only create evaluation tests for the core use cases of each tool:
6 | * - Primary functionality (e.g., resolving an issue)
7 | * - Alternative input methods (e.g., using issue URL vs org+issueId)
8 | * - One complex workflow example if applicable
9 | *
10 | * Avoid testing edge cases, error conditions, or minor variations in evals.
11 | * Use unit tests (tools.test.ts) for comprehensive coverage instead.
12 | */
13 |
14 | export const FIXTURES = {
15 | organizationSlug: "sentry-mcp-evals",
16 | teamSlug: "the-goats",
17 | projectSlug: "cloudflare-mcp",
18 | issueId: "CLOUDFLARE-MCP-41",
19 | issueUrl: "https://sentry-mcp-evals.sentry.io/issues/CLOUDFLARE-MCP-41/",
20 | testIssueUrl: "https://sentry-mcp-evals.sentry.io/issues/PEATED-A8",
21 | traceId: "a4d1aae7216b47ff8117cf4e09ce9d0a",
22 | dsn: "https://d20df0a1ab5031c7f3c7edca9c02814d@o4509106732793856.ingest.us.sentry.io/4509109104082945",
23 | };
24 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/agents/tools/data/android.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "namespace": "android",
3 | "description": "The Android platform on which the Android application is running.\n",
4 | "attributes": {
5 | "android.os.api_level": {
6 | "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",
7 | "type": "string",
8 | "stability": "development",
9 | "examples": ["33", "32"]
10 | },
11 | "android.app.state": {
12 | "description": "This attribute represents the state of the application.\n",
13 | "type": "string",
14 | "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",
15 | "stability": "development",
16 | "examples": ["created", "background", "foreground"]
17 | }
18 | }
19 | }
20 |
```
--------------------------------------------------------------------------------
/packages/mcp-test-client/package.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "name": "@sentry/mcp-test-client",
3 | "version": "0.18.0",
4 | "private": true,
5 | "type": "module",
6 | "description": "CLI tool to test the Sentry MCP server",
7 | "bin": {
8 | "sentry-mcp-test-client": "./dist/index.js"
9 | },
10 | "scripts": {
11 | "build": "tsdown",
12 | "start": "node dist/index.js",
13 | "test-client": "node dist/index.js",
14 | "test": "vitest run",
15 | "test:ci": "vitest run --reporter=default --reporter=junit --outputFile=tests.junit.xml",
16 | "test:watch": "vitest",
17 | "typecheck": "tsc --noEmit"
18 | },
19 | "dependencies": {
20 | "@ai-sdk/openai": "catalog:",
21 | "@modelcontextprotocol/sdk": "catalog:",
22 | "@sentry/core": "catalog:",
23 | "@sentry/mcp-server": "workspace:*",
24 | "@sentry/node": "catalog:",
25 | "ai": "catalog:",
26 | "chalk": "catalog:",
27 | "commander": "catalog:",
28 | "dotenv": "catalog:",
29 | "open": "catalog:"
30 | },
31 | "devDependencies": {
32 | "tsdown": "catalog:",
33 | "tsx": "catalog:",
34 | "typescript": "catalog:",
35 | "vitest": "catalog:"
36 | }
37 | }
38 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/lib/slug-validation.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * Validates that a slug is safe and follows expected patterns.
3 | * Used to validate organization and project slugs from URL paths.
4 | */
5 | export function isValidSlug(slug: string): boolean {
6 | // Reject empty strings
7 | if (!slug || slug.length === 0) {
8 | return false;
9 | }
10 |
11 | // Reject excessively long slugs (prevent DOS)
12 | if (slug.length > 100) {
13 | return false;
14 | }
15 |
16 | // Reject path traversal attempts
17 | if (slug.includes("..") || slug.includes("//")) {
18 | return false;
19 | }
20 |
21 | // Reject URLs or suspicious patterns
22 | if (slug.includes("://") || slug.includes("%")) {
23 | return false;
24 | }
25 |
26 | // Must start and end with alphanumeric
27 | if (!/^[a-zA-Z0-9].*[a-zA-Z0-9]$/.test(slug) && slug.length > 1) {
28 | return false;
29 | }
30 |
31 | // Single character must be alphanumeric
32 | if (slug.length === 1 && !/^[a-zA-Z0-9]$/.test(slug)) {
33 | return false;
34 | }
35 |
36 | // Only allow alphanumeric, dots, dashes, and underscores
37 | if (!/^[a-zA-Z0-9._-]+$/.test(slug)) {
38 | return false;
39 | }
40 |
41 | return true;
42 | }
43 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/routes/mcp.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * Public MCP metadata endpoints under `/.mcp/*` for external documentation sites.
3 | *
4 | * Responds with pre-generated JSON payloads from @sentry/mcp-server.
5 | * Adds permissive CORS for easy cross-origin consumption.
6 | */
7 | import { Hono } from "hono";
8 | import TOOL_DEFINITIONS from "@sentry/mcp-server/toolDefinitions";
9 |
10 | function withCors(json: unknown, status = 200) {
11 | const body = JSON.stringify(json);
12 | return new Response(body, {
13 | status,
14 | headers: {
15 | "Content-Type": "application/json; charset=utf-8",
16 | "Access-Control-Allow-Origin": "*",
17 | "Access-Control-Allow-Methods": "GET, OPTIONS",
18 | "Access-Control-Allow-Headers": "Content-Type",
19 | "Cache-Control": "public, max-age=300", // 5 minutes
20 | },
21 | });
22 | }
23 |
24 | export default new Hono()
25 | // CORS preflight
26 | .options("/*", (c) => withCors(null, 204))
27 | // Index: advertise available endpoints
28 | .get("/", (c) =>
29 | withCors({
30 | endpoints: ["/.mcp/tools.json"],
31 | }),
32 | )
33 | // Tools
34 | .get("/tools.json", (c) => withCors(TOOL_DEFINITIONS));
35 |
```
--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/types.ts:
--------------------------------------------------------------------------------
```typescript
1 | import type { OAuthHelpers } from "@cloudflare/workers-oauth-provider";
2 | import type {
3 | RateLimit,
4 | WorkerVersionMetadata,
5 | } from "@cloudflare/workers-types";
6 | import type { ServerContext } from "@sentry/mcp-server/types";
7 |
8 | export type WorkerProps = ServerContext & {
9 | id: string;
10 | name: string;
11 | scope: string;
12 | grantedScopes?: string[]; // Array of scope strings passed from OAuth
13 | refreshToken?: string; // Refresh token for OAuth token renewal
14 | accessTokenExpiresAt?: number; // Timestamp when the upstream access token expires
15 | };
16 |
17 | export interface Env {
18 | NODE_ENV: string;
19 | ASSETS: Fetcher;
20 | OAUTH_KV: KVNamespace;
21 | COOKIE_SECRET: string;
22 | SENTRY_CLIENT_ID: string;
23 | SENTRY_CLIENT_SECRET: string;
24 | SENTRY_ENVIRONMENT?: string;
25 | SENTRY_DSN?: string;
26 | SENTRY_HOST?: string;
27 | OPENAI_API_KEY: string;
28 | MCP_OBJECT: DurableObjectNamespace;
29 | OAUTH_PROVIDER: OAuthHelpers;
30 | AI: Ai;
31 | CF_VERSION_METADATA: WorkerVersionMetadata;
32 | CHAT_RATE_LIMITER: RateLimit;
33 | SEARCH_RATE_LIMITER: RateLimit;
34 | AUTORAG_INDEX_NAME?: string;
35 | }
36 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/create-project.test.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describe, it, expect } from "vitest";
2 | import createProject from "./create-project.js";
3 |
4 | describe("create_project", () => {
5 | it("serializes", async () => {
6 | const result = await createProject.handler(
7 | {
8 | organizationSlug: "sentry-mcp-evals",
9 | teamSlug: "the-goats",
10 | name: "cloudflare-mcp",
11 | platform: "node",
12 | regionUrl: undefined,
13 | },
14 | {
15 | constraints: {
16 | organizationSlug: null,
17 | },
18 | accessToken: "access-token",
19 | userId: "1",
20 | },
21 | );
22 | expect(result).toMatchInlineSnapshot(`
23 | "# New Project in **sentry-mcp-evals**
24 |
25 | **ID**: 4509109104082945
26 | **Slug**: cloudflare-mcp
27 | **Name**: cloudflare-mcp
28 | **SENTRY_DSN**: https://d20df0a1ab5031c7f3c7edca9c02814d@o4509106732793856.ingest.us.sentry.io/4509109104082945
29 |
30 | # Using this information
31 |
32 | - You can reference the **SENTRY_DSN** value to initialize Sentry's SDKs.
33 | - You should always inform the user of the **SENTRY_DSN** and Project Slug values.
34 | "
35 | `);
36 | });
37 | });
38 |
```