#
tokens: 49895/50000 78/408 files (page 2/15)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 2 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
├── .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
│   │   ├── deployment.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-handler.test.ts
│   │   │   │   │   ├── mcp-handler.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
│   │   │   │   ├── context-storage.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-context.test.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

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

```typescript
 1 | #!/usr/bin/env node
 2 | 
 3 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
 4 | import { startStdio } from "@sentry/mcp-server/transports/stdio";
 5 | import { mswServer } from "@sentry/mcp-server-mocks";
 6 | import type { Scope } from "@sentry/mcp-server/permissions";
 7 | import { ALL_SCOPES } from "@sentry/mcp-server/permissions";
 8 | 
 9 | mswServer.listen({
10 |   onUnhandledRequest: (req, print) => {
11 |     if (req.url.startsWith("https://api.openai.com/")) {
12 |       return;
13 |     }
14 | 
15 |     print.warning();
16 |     throw new Error(`Unhandled request: ${req.url}`);
17 |   },
18 |   // onUnhandledRequest: "error"
19 | });
20 | 
21 | const accessToken = "mocked-access-token";
22 | 
23 | // Grant all available scopes for evals to ensure MSW mocks apply broadly
24 | 
25 | const server = new McpServer({
26 |   name: "Sentry MCP",
27 |   version: "0.1.0",
28 | });
29 | 
30 | // Run in-process MCP with all scopes so MSW mocks apply
31 | startStdio(server, {
32 |   accessToken,
33 |   grantedScopes: new Set<Scope>(ALL_SCOPES),
34 |   constraints: {
35 |     organizationSlug: null,
36 |     projectSlug: null,
37 |   },
38 | }).catch((err: unknown) => {
39 |   console.error("Server error:", err);
40 |   process.exit(1);
41 | });
42 | 
```

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

```json
 1 | {
 2 |   "namespace": "azure",
 3 |   "description": "This section defines generic attributes used by Azure Client Libraries.\n",
 4 |   "attributes": {
 5 |     "azure.service.request.id": {
 6 |       "description": "The unique identifier of the service request. It's generated by the Azure service and returned with the response.",
 7 |       "type": "string",
 8 |       "stability": "development",
 9 |       "examples": ["00000000-0000-0000-0000-000000000000"]
10 |     },
11 |     "azure.resource_provider.namespace": {
12 |       "description": "[Azure Resource Provider Namespace](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-services-resource-providers) as recognized by the client.\n",
13 |       "type": "string",
14 |       "stability": "development",
15 |       "examples": [
16 |         "Microsoft.Storage",
17 |         "Microsoft.KeyVault",
18 |         "Microsoft.ServiceBus"
19 |       ]
20 |     },
21 |     "azure.client.id": {
22 |       "description": "The unique identifier of the client instance.",
23 |       "type": "string",
24 |       "stability": "development",
25 |       "examples": ["3ba4827d-4422-483f-b59f-85b74211c11d", "storage-client-1"]
26 |     }
27 |   }
28 | }
29 | 
```

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

```typescript
 1 | import type { Scope } from "../permissions";
 2 | 
 3 | export function buildUsage(
 4 |   packageName: string,
 5 |   defaults: ReadonlyArray<Scope>,
 6 |   all: ReadonlyArray<Scope>,
 7 | ): string {
 8 |   return `Usage: ${packageName} --access-token=<token> [--host=<host>]
 9 | 
10 | Required:
11 |   --access-token <token>  Sentry User Auth Token with API access
12 | 
13 | Common optional flags:
14 |   --host <host>           Change Sentry host (self-hosted)
15 |   --sentry-dsn <dsn>      Override DSN used for telemetry reporting
16 |   --openai-base-url <url> Override OpenAI API base URL for embedded agents
17 | 
18 | Session constraints:
19 |   --organization-slug <slug>  Force all calls to an organization
20 |   --project-slug <slug>       Optional project constraint
21 | 
22 | Scope controls:
23 |   --scopes <list>     Override default scopes
24 |   --add-scopes <list> Add scopes to defaults
25 |   --all-scopes        Grant every available scope
26 | 
27 | Defaults: ${defaults.join(", ")}
28 | All scopes: ${all.join(", ")}
29 | 
30 | Examples:
31 |   ${packageName} --access-token=TOKEN
32 |   ${packageName} --access-token=TOKEN --host=sentry.example.com
33 |   ${packageName} --access-token=TOKEN --openai-base-url=https://proxy.example.com/v1`;
34 | }
35 | 
```

--------------------------------------------------------------------------------
/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 | /**
20 |  * Tool parameter keys that can be auto-injected from constraints.
21 |  * These are filtered from tool schemas when constraints are active.
22 |  */
23 | export const CONSTRAINT_PARAMETER_KEYS = new Set<string>([
24 |   "organizationSlug",
25 |   "projectSlug",
26 |   "projectSlugOrId", // Alias for projectSlug
27 |   "regionUrl",
28 | ]);
29 | 
30 | export type ServerContext = {
31 |   sentryHost?: string;
32 |   mcpUrl?: string;
33 |   accessToken: string;
34 |   openaiBaseUrl?: string;
35 |   userId?: string | null;
36 |   clientId?: string;
37 |   // Granted scopes for tool access control
38 |   grantedScopes?: Set<Scope> | ReadonlySet<Scope>;
39 |   // URL-based session constraints
40 |   constraints: Constraints;
41 | };
42 | 
```

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

```json
 1 | {
 2 |   "namespace": "otel",
 3 |   "description": "Attributes reserved for OpenTelemetry",
 4 |   "attributes": {
 5 |     "otel.status_code": {
 6 |       "description": "Name of the code, either \"OK\" or \"ERROR\". MUST NOT be set if the status code is UNSET.",
 7 |       "type": "string",
 8 |       "stability": "stable",
 9 |       "examples": ["OK", "ERROR"]
10 |     },
11 |     "otel.status_description": {
12 |       "description": "Description of the Status if it has a value, otherwise not set.",
13 |       "type": "string",
14 |       "stability": "stable",
15 |       "examples": ["resource not found"]
16 |     },
17 |     "otel.span.sampling_result": {
18 |       "description": "The result value of the sampler for this span",
19 |       "type": "string",
20 |       "stability": "development",
21 |       "examples": ["DROP", "RECORD_ONLY", "RECORD_AND_SAMPLE"]
22 |     },
23 |     "otel.span.parent.origin": {
24 |       "description": "Determines whether the span has a parent span, and if so, [whether it is a remote parent](https://opentelemetry.io/docs/specs/otel/trace/api/#isremote)",
25 |       "type": "string",
26 |       "stability": "development",
27 |       "examples": ["none", "local", "remote"]
28 |     }
29 |   }
30 | }
31 | 
```

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

```typescript
 1 | /**
 2 |  * Type definitions for Chat API
 3 |  */
 4 | 
 5 | // Error response types
 6 | export type ErrorName =
 7 |   // 400-level errors (client errors)
 8 |   | "MISSING_AUTH_TOKEN"
 9 |   | "INVALID_AUTH_DATA"
10 |   | "INVALID_MESSAGES_FORMAT"
11 |   // 401-level errors (authentication)
12 |   | "AUTH_EXPIRED"
13 |   | "AI_AUTH_FAILED"
14 |   | "SENTRY_AUTH_INVALID"
15 |   // 403-level errors (authorization)
16 |   | "INSUFFICIENT_PERMISSIONS"
17 |   // 429-level errors (rate limiting)
18 |   | "RATE_LIMIT_EXCEEDED"
19 |   | "AI_RATE_LIMIT"
20 |   // 500-level errors (server errors)
21 |   | "AI_SERVICE_UNAVAILABLE"
22 |   | "RATE_LIMITER_ERROR"
23 |   | "MCP_CONNECTION_FAILED"
24 |   | "METADATA_FETCH_FAILED"
25 |   | "INTERNAL_ERROR";
26 | 
27 | export interface ErrorResponse {
28 |   error: string;
29 |   name?: ErrorName;
30 |   eventId?: string;
31 | }
32 | 
33 | // Request types
34 | export interface ChatRequest {
35 |   messages: Array<{
36 |     role: "user" | "assistant" | "system";
37 |     content: string;
38 |     data?: any; // Additional metadata for messages
39 |   }>;
40 | }
41 | 
42 | // MCP types
43 | export interface MCPTools {
44 |   [toolName: string]: {
45 |     description?: string;
46 |     parameters?: unknown;
47 |   };
48 | }
49 | 
50 | // Rate limiter types
51 | export interface RateLimitResult {
52 |   success: boolean;
53 | }
54 | 
```

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

```typescript
 1 | import { ApiNotFoundError } from "../../api-client";
 2 | 
 3 | /**
 4 |  * Enhances a 404 error with parameter context to help users understand what went wrong.
 5 |  * This is optional - tools can use this when they want to provide extra context.
 6 |  *
 7 |  * @example
 8 |  * ```typescript
 9 |  * try {
10 |  *   const issue = await apiService.getIssue({ organizationSlug, issueId });
11 |  * } catch (error) {
12 |  *   if (error instanceof ApiNotFoundError) {
13 |  *     throw enhanceNotFoundError(error, { organizationSlug, issueId });
14 |  *   }
15 |  *   throw error;
16 |  * }
17 |  * ```
18 |  */
19 | export function enhanceNotFoundError(
20 |   error: ApiNotFoundError,
21 |   params: Record<string, unknown>,
22 | ): ApiNotFoundError {
23 |   const paramsList: string[] = [];
24 | 
25 |   for (const [key, value] of Object.entries(params)) {
26 |     if (value !== undefined && value !== null && value !== "") {
27 |       paramsList.push(`${key}: '${value}'`);
28 |     }
29 |   }
30 | 
31 |   if (paramsList.length > 0) {
32 |     const enhancedMessage = `${error.message}\nPlease verify these parameters are correct:\n${paramsList.map((p) => `  - ${p}`).join("\n")}`;
33 |     return new ApiNotFoundError(
34 |       enhancedMessage,
35 |       error.detail,
36 |       error.responseBody,
37 |     );
38 |   }
39 | 
40 |   return error;
41 | }
42 | 
```

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

```typescript
 1 | import { z } from "zod";
 2 | import type { SentryApiService } from "../../../api-client";
 3 | import { agentTool } from "./utils";
 4 | 
 5 | export interface WhoamiResult {
 6 |   id: string | number;
 7 |   name: string | null;
 8 |   email: string;
 9 | }
10 | 
11 | /**
12 |  * Get the current authenticated user's information from Sentry API
13 |  */
14 | export async function getCurrentUser(
15 |   apiService: SentryApiService,
16 | ): Promise<WhoamiResult> {
17 |   // API client throws ApiClientError/ApiServerError which wrapAgentToolExecute handles
18 |   const user = await apiService.getAuthenticatedUser();
19 |   return {
20 |     id: user.id,
21 |     name: user.name,
22 |     email: user.email,
23 |   };
24 | }
25 | 
26 | /**
27 |  * Create a tool for getting current user information
28 |  * The tool is pre-bound with the API service configured for the appropriate region
29 |  */
30 | export function createWhoamiTool(options: { apiService: SentryApiService }) {
31 |   const { apiService } = options;
32 |   return agentTool({
33 |     description: "Get the current authenticated user's information",
34 |     parameters: z.object({}),
35 |     execute: async () => {
36 |       const user = await getCurrentUser(apiService);
37 |       return `Current user: ${user.name || "Unknown"} (${user.email}, ID: ${user.id})`;
38 |     },
39 |   });
40 | }
41 | 
```

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

```yaml
 1 | name: Post-merge tasks
 2 | 
 3 | on:
 4 |   push:
 5 |     branches: ["main", "release/*"]
 6 |   workflow_dispatch:
 7 | 
 8 | jobs:
 9 |   build-publish:
10 |     runs-on: ubuntu-latest
11 | 
12 |     steps:
13 |       - name: Checkout
14 |         uses: actions/checkout@v4
15 | 
16 |       - name: Setup pnpm
17 |         uses: pnpm/action-setup@v4
18 | 
19 |       - name: Set up Node
20 |         uses: actions/setup-node@v4
21 |         with:
22 |           node-version-file: 'package.json'
23 |           cache: 'pnpm'
24 | 
25 |       - name: Install dependencies
26 |         run: pnpm install
27 | 
28 |       - name: Build
29 |         run: pnpm build
30 | 
31 |       - name: Run linter
32 |         run: pnpm lint
33 | 
34 |       - name: Run tests
35 |         run: pnpm test:ci
36 | 
37 |       - name: Package mcp-server
38 |         working-directory: packages/mcp-server
39 |         run: pnpm pack --pack-destination dist
40 | 
41 |       - name: Archive artifacts
42 |         uses: actions/upload-artifact@v4
43 |         with:
44 |           name: ${{ github.sha }}
45 |           path: |
46 |             ${{ github.workspace }}/packages/mcp-server/dist/*.tgz
47 | 
48 |       - name: Publish Test Report
49 |         uses: mikepenz/action-junit-report@cf701569b05ccdd861a76b8607a66d76f6fd4857
50 |         if: ${{ !cancelled() }}
51 |         with:
52 |           report_paths: "**/*.junit.xml"
53 |           comment: false
54 | 
```

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

```typescript
 1 | import type { Scope } from "../permissions";
 2 | 
 3 | export type CliArgs = {
 4 |   accessToken?: string;
 5 |   host?: string;
 6 |   url?: string;
 7 |   mcpUrl?: string;
 8 |   sentryDsn?: string;
 9 |   openaiBaseUrl?: string;
10 |   scopes?: string;
11 |   addScopes?: string;
12 |   allScopes?: boolean;
13 |   organizationSlug?: string;
14 |   projectSlug?: string;
15 |   help?: boolean;
16 |   version?: boolean;
17 |   unknownArgs: string[];
18 | };
19 | 
20 | export type EnvArgs = {
21 |   accessToken?: string;
22 |   host?: string; // parsed from SENTRY_HOST or SENTRY_URL (raw value)
23 |   url?: string; // raw URL if provided (SENTRY_URL)
24 |   mcpUrl?: string;
25 |   sentryDsn?: string;
26 |   scopes?: string;
27 |   addScopes?: string;
28 | };
29 | 
30 | export type MergedArgs = {
31 |   accessToken?: string;
32 |   host?: string;
33 |   url?: string;
34 |   mcpUrl?: string;
35 |   sentryDsn?: string;
36 |   openaiBaseUrl?: string;
37 |   scopes?: string;
38 |   addScopes?: string;
39 |   allScopes?: boolean;
40 |   organizationSlug?: string;
41 |   projectSlug?: string;
42 |   help?: boolean;
43 |   version?: boolean;
44 |   unknownArgs: string[];
45 | };
46 | 
47 | export type ResolvedConfig = {
48 |   accessToken: string;
49 |   sentryHost: string;
50 |   mcpUrl?: string;
51 |   sentryDsn?: string;
52 |   openaiBaseUrl?: string;
53 |   finalScopes?: Set<Scope>;
54 |   organizationSlug?: string;
55 |   projectSlug?: string;
56 | };
57 | 
```

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

```typescript
 1 | import { describeEval } from "vitest-evals";
 2 | import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";
 3 | 
 4 | describeEval("create-project", {
 5 |   data: async () => {
 6 |     return [
 7 |       {
 8 |         input: `Create a new project in Sentry for '${FIXTURES.organizationSlug}' called '${FIXTURES.projectSlug}' with the '${FIXTURES.teamSlug}' team. Output **only** the project slug and the SENTRY_DSN in the format of:\n<PROJECT_SLUG>\n<SENTRY_DSN>`,
 9 |         expectedTools: [
10 |           {
11 |             name: "find_organizations",
12 |             arguments: {},
13 |           },
14 |           {
15 |             name: "find_teams",
16 |             arguments: {
17 |               organizationSlug: FIXTURES.organizationSlug,
18 |               regionUrl: "https://us.sentry.io",
19 |             },
20 |           },
21 |           {
22 |             name: "create_project",
23 |             arguments: {
24 |               organizationSlug: FIXTURES.organizationSlug,
25 |               regionUrl: "https://us.sentry.io",
26 |               teamSlug: FIXTURES.teamSlug,
27 |               name: FIXTURES.projectSlug,
28 |             },
29 |           },
30 |         ],
31 |       },
32 |     ];
33 |   },
34 |   task: NoOpTaskRunner(),
35 |   scorers: [ToolPredictionScorer()],
36 |   threshold: 0.6,
37 |   timeout: 30000,
38 | });
39 | 
```

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

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

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

```json
 1 | {
 2 |   "$schema": "https://turbo.build/schema.json",
 3 |   "daemon": false,
 4 |   "ui": "stream",
 5 |   "tasks": {
 6 |     "setup": {
 7 |       "dependsOn": ["build"],
 8 |       "cache": false
 9 |     },
10 |     "dev": {
11 |       "dependsOn": ["^build"],
12 |       "cache": false,
13 |       "persistent": true
14 |     },
15 |     "deploy": {
16 |       "dependsOn": ["^build"],
17 |       "outputs": [],
18 |       "cache": true
19 |     },
20 |     "lint": {
21 |       "dependsOn": ["^build"],
22 |       "cache": true
23 |     },
24 |     "test": {
25 |       "dependsOn": ["^build"],
26 |       "outputs": [],
27 |       "cache": true
28 |     },
29 |     "tsc": {
30 |       "dependsOn": ["^build"],
31 |       "outputs": [],
32 |       "cache": true
33 |     },
34 |     "eval": {
35 |       "dependsOn": ["^build"],
36 |       "outputs": [],
37 |       "cache": true
38 |     },
39 |     "build": {
40 |       "dependsOn": ["^build"],
41 |       "outputs": [".next/**", "!.next/cache/**", "dist/**", "*.tsbuildinfo"],
42 |       "cache": true
43 |     },
44 |     "after-build": {
45 |       "dependsOn": ["build"],
46 |       "cache": false
47 |     }
48 |   },
49 |   "globalPassThroughEnv": [
50 |     "NODE_ENV",
51 |     "CI",
52 |     "OPENAI_API_KEY",
53 |     "COOKIE_SECRET",
54 |     "SENTRY_CLIENT_ID",
55 |     "SENTRY_CLIENT_SECRET",
56 |     "SENTRY_AUTH_TOKEN",
57 |     "SENTRY_ACCESS_TOKEN",
58 |     "SENTRY_SPOTLIGHT",
59 |     "VITE_SENTRY_DSN",
60 |     "VITE_SENTRY_ENVIRONMENT"
61 |   ]
62 | }
63 | 
```

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

```json
 1 | {
 2 |   "logs": 0,
 3 |   "errors": 2,
 4 |   "performance_issues": 0,
 5 |   "span_count": 85,
 6 |   "transaction_child_count_map": [
 7 |     {
 8 |       "transaction.event_id": "0daf40dc453a429c8c57e4c215c4e82c",
 9 |       "count()": 10.0
10 |     },
11 |     {
12 |       "transaction.event_id": null,
13 |       "count()": 15.0
14 |     },
15 |     {
16 |       "transaction.event_id": "b49a5b53cba046a2bab9323d8f00de96",
17 |       "count()": 7.0
18 |     },
19 |     {
20 |       "transaction.event_id": null,
21 |       "count()": 8.0
22 |     },
23 |     {
24 |       "transaction.event_id": "ee6e7f39107847f980e06119bf116d38",
25 |       "count()": 7.0
26 |     },
27 |     {
28 |       "transaction.event_id": null,
29 |       "count()": 20.0
30 |     },
31 |     {
32 |       "transaction.event_id": "f398bbc635c64e2091d94679dade2957",
33 |       "count()": 3.0
34 |     },
35 |     {
36 |       "transaction.event_id": "f779775e1c6a4f09b62d68818a25d7b5",
37 |       "count()": 15.0
38 |     }
39 |   ],
40 |   "span_count_map": {
41 |     "cache.get": 30.0,
42 |     "middleware.django": 20.0,
43 |     "db": 10.0,
44 |     "function": 5.0,
45 |     "db.redis": 4.0,
46 |     "feature.flagpole.batch_has": 4.0,
47 |     "processor": 2.0,
48 |     "execute": 2.0,
49 |     "fetch_organization_projects": 2.0,
50 |     "other": 1.0,
51 |     "db.clickhouse": 1.0,
52 |     "validator": 1.0,
53 |     "serialize": 1.0,
54 |     "http.client": 1.0,
55 |     "base.paginate.on_results": 1.0
56 |   }
57 | }
58 | 
```

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

```typescript
 1 | import { describe, it, expect, vi, beforeEach } from "vitest";
 2 | import { getCurrentUser } from "./whoami";
 3 | import type { SentryApiService } from "../../../api-client";
 4 | 
 5 | describe("whoami agent tool", () => {
 6 |   let mockApiService: SentryApiService;
 7 | 
 8 |   beforeEach(() => {
 9 |     vi.clearAllMocks();
10 |     mockApiService = {
11 |       getAuthenticatedUser: vi.fn(),
12 |     } as unknown as SentryApiService;
13 |   });
14 | 
15 |   describe("getCurrentUser", () => {
16 |     it("should return current user information", async () => {
17 |       const mockUser = {
18 |         id: "123",
19 |         name: "John Doe",
20 |         email: "[email protected]",
21 |       };
22 | 
23 |       (mockApiService.getAuthenticatedUser as any).mockResolvedValue(mockUser);
24 | 
25 |       const result = await getCurrentUser(mockApiService);
26 | 
27 |       expect(result).toEqual({
28 |         id: "123",
29 |         name: "John Doe",
30 |         email: "[email protected]",
31 |       });
32 | 
33 |       expect(mockApiService.getAuthenticatedUser).toHaveBeenCalledOnce();
34 |     });
35 | 
36 |     it("should handle API errors gracefully", async () => {
37 |       (mockApiService.getAuthenticatedUser as any).mockRejectedValue(
38 |         new Error("Unauthorized"),
39 |       );
40 | 
41 |       await expect(getCurrentUser(mockApiService)).rejects.toThrow(
42 |         "Unauthorized",
43 |       );
44 |     });
45 |   });
46 | });
47 | 
```

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

```typescript
 1 | import { describeEval } from "vitest-evals";
 2 | import { NoOpTaskRunner, ToolPredictionScorer } from "./utils";
 3 | 
 4 | describeEval("search-docs", {
 5 |   data: async () => {
 6 |     return [
 7 |       {
 8 |         input:
 9 |           "I need documentation on how to set up error tracking with Sentry in JavaScript",
10 |         expectedTools: [
11 |           {
12 |             name: "search_docs",
13 |             arguments: {
14 |               query: "set up error tracking JavaScript",
15 |               maxResults: 3,
16 |             },
17 |           },
18 |         ],
19 |       },
20 |       {
21 |         input:
22 |           "I need help configuring Sentry with React components and error boundaries",
23 |         expectedTools: [
24 |           {
25 |             name: "search_docs",
26 |             arguments: {
27 |               query: "React components error boundaries",
28 |               maxResults: 3,
29 |             },
30 |           },
31 |         ],
32 |       },
33 |       {
34 |         input: "What is Sentry's rate limiting and how does it work?",
35 |         expectedTools: [
36 |           {
37 |             name: "search_docs",
38 |             arguments: {
39 |               query: "rate limiting",
40 |               maxResults: 3,
41 |             },
42 |           },
43 |         ],
44 |       },
45 |     ];
46 |   },
47 |   task: NoOpTaskRunner(),
48 |   scorers: [ToolPredictionScorer()],
49 |   threshold: 0.6,
50 |   timeout: 30000,
51 | });
52 | 
```

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

```typescript
 1 | import { describeEval } from "vitest-evals";
 2 | import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";
 3 | 
 4 | describeEval("get-trace-details", {
 5 |   data: async () => {
 6 |     return [
 7 |       {
 8 |         input: `Show me trace ${FIXTURES.traceId} from Sentry in ${FIXTURES.organizationSlug}.`,
 9 |         expectedTools: [
10 |           {
11 |             name: "find_organizations",
12 |             arguments: {},
13 |           },
14 |           {
15 |             name: "get_trace_details",
16 |             arguments: {
17 |               organizationSlug: FIXTURES.organizationSlug,
18 |               traceId: FIXTURES.traceId,
19 |               regionUrl: "https://us.sentry.io",
20 |             },
21 |           },
22 |         ],
23 |       },
24 |       {
25 |         input: `Explain trace ${FIXTURES.traceId} in ${FIXTURES.organizationSlug}.`,
26 |         expectedTools: [
27 |           {
28 |             name: "find_organizations",
29 |             arguments: {},
30 |           },
31 |           {
32 |             name: "get_trace_details",
33 |             arguments: {
34 |               organizationSlug: FIXTURES.organizationSlug,
35 |               traceId: FIXTURES.traceId,
36 |               regionUrl: "https://us.sentry.io",
37 |             },
38 |           },
39 |         ],
40 |       },
41 |     ];
42 |   },
43 |   task: NoOpTaskRunner(),
44 |   scorers: [ToolPredictionScorer()],
45 |   threshold: 0.6,
46 |   timeout: 30000,
47 | });
48 | 
```

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

```json
 1 | {
 2 |   "namespace": "test",
 3 |   "description": "This group describes attributes specific to [software tests](https://wikipedia.org/wiki/Software_testing).\n",
 4 |   "attributes": {
 5 |     "test.suite.name": {
 6 |       "description": "The human readable name of a [test suite](https://wikipedia.org/wiki/Test_suite).\n",
 7 |       "type": "string",
 8 |       "stability": "development",
 9 |       "examples": ["TestSuite1"]
10 |     },
11 |     "test.suite.run.status": {
12 |       "description": "The status of the test suite run.\n",
13 |       "type": "string",
14 |       "stability": "development",
15 |       "examples": [
16 |         "success",
17 |         "failure",
18 |         "skipped",
19 |         "aborted",
20 |         "timed_out",
21 |         "in_progress"
22 |       ]
23 |     },
24 |     "test.case.name": {
25 |       "description": "The fully qualified human readable name of the [test case](https://wikipedia.org/wiki/Test_case).\n",
26 |       "type": "string",
27 |       "stability": "development",
28 |       "examples": [
29 |         "org.example.TestCase1.test1",
30 |         "example/tests/TestCase1.test1",
31 |         "ExampleTestCase1_test1"
32 |       ]
33 |     },
34 |     "test.case.result.status": {
35 |       "description": "The status of the actual test case result from test execution.\n",
36 |       "type": "string",
37 |       "stability": "development",
38 |       "examples": ["pass", "fail"]
39 |     }
40 |   }
41 | }
42 | 
```

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

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

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

```typescript
 1 | import { describeEval } from "vitest-evals";
 2 | import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";
 3 | 
 4 | describeEval("get-issue", {
 5 |   data: async () => {
 6 |     return [
 7 |       {
 8 |         input: `Explain CLOUDFLARE-MCP-41 from Sentry in ${FIXTURES.organizationSlug}.`,
 9 |         expectedTools: [
10 |           {
11 |             name: "find_organizations",
12 |             arguments: {},
13 |           },
14 |           {
15 |             name: "get_issue_details",
16 |             arguments: {
17 |               organizationSlug: FIXTURES.organizationSlug,
18 |               issueId: "CLOUDFLARE-MCP-41",
19 |               regionUrl: "https://us.sentry.io",
20 |             },
21 |           },
22 |         ],
23 |       },
24 |       {
25 |         input: `Explain the event with ID 7ca573c0f4814912aaa9bdc77d1a7d51 from Sentry in ${FIXTURES.organizationSlug}.`,
26 |         expectedTools: [
27 |           {
28 |             name: "find_organizations",
29 |             arguments: {},
30 |           },
31 |           {
32 |             name: "get_issue_details",
33 |             arguments: {
34 |               organizationSlug: FIXTURES.organizationSlug,
35 |               eventId: "7ca573c0f4814912aaa9bdc77d1a7d51",
36 |               regionUrl: "https://us.sentry.io",
37 |             },
38 |           },
39 |         ],
40 |       },
41 |     ];
42 |   },
43 |   task: NoOpTaskRunner(),
44 |   scorers: [ToolPredictionScorer()],
45 |   threshold: 0.6,
46 |   timeout: 30000,
47 | });
48 | 
```

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

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

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

```yaml
 1 | name: Release
 2 | 
 3 | on:
 4 |   workflow_dispatch:
 5 |     inputs:
 6 |       version:
 7 |         description: Version to release
 8 |         required: true
 9 |       force:
10 |         description: Force a release even when there are release-blockers (empty string == false)
11 |         required: false
12 | 
13 | jobs:
14 |   release:
15 |     runs-on: ubuntu-latest
16 |     name: "Release a new version"
17 |     steps:
18 |       - name: Get auth token
19 |         id: token
20 |         uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0
21 |         with:
22 |           app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }}
23 |           private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }}
24 | 
25 |       - name: Checkout
26 |         uses: actions/checkout@v4
27 |         with:
28 |           token: ${{ steps.token.outputs.token }}
29 |           fetch-depth: 0
30 | 
31 |       - name: Setup Node.js
32 |         uses: actions/setup-node@v4
33 |         with:
34 |           node-version: "20"
35 | 
36 |       # pnpm/action-setup@v4
37 |       - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda
38 |         name: Install pnpm
39 |         with:
40 |           run_install: false
41 | 
42 |       - name: Prepare release
43 |         uses: getsentry/action-prepare-release@v1
44 |         env:
45 |           GITHUB_TOKEN: ${{ steps.token.outputs.token }}
46 |         with:
47 |           version: ${{ github.event.inputs.version }}
48 |           force: ${{ github.event.inputs.force }}
49 | 
```

--------------------------------------------------------------------------------
/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 | 
 7 | /**
 8 |  * Props passed through OAuth and available via ExecutionContext.props
 9 |  *
10 |  * These props are set in the OAuth callback and become available
11 |  * to the MCP handler through ExecutionContext.props (set by OAuth provider).
12 |  */
13 | export type WorkerProps = {
14 |   // OAuth standard fields
15 |   id: string;
16 | 
17 |   // Sentry-specific fields
18 |   accessToken: string;
19 |   refreshToken?: string;
20 |   accessTokenExpiresAt?: number; // Timestamp when the upstream access token expires
21 |   clientId: string;
22 |   scope: string;
23 |   grantedScopes?: string[]; // Array of scope strings
24 | 
25 |   // Note: constraints are NOT included - they're extracted per-request from URL
26 |   // Note: sentryHost and mcpUrl come from env, not OAuth props
27 | };
28 | 
29 | export interface Env {
30 |   NODE_ENV: string;
31 |   ASSETS: Fetcher;
32 |   OAUTH_KV: KVNamespace;
33 |   COOKIE_SECRET: string;
34 |   SENTRY_CLIENT_ID: string;
35 |   SENTRY_CLIENT_SECRET: string;
36 |   SENTRY_ENVIRONMENT?: string;
37 |   SENTRY_DSN?: string;
38 |   SENTRY_HOST?: string;
39 |   OPENAI_API_KEY: string;
40 |   MCP_URL?: string;
41 |   OAUTH_PROVIDER: OAuthHelpers;
42 |   AI: Ai;
43 |   CF_VERSION_METADATA: WorkerVersionMetadata;
44 |   CHAT_RATE_LIMITER: RateLimit;
45 |   SEARCH_RATE_LIMITER: RateLimit;
46 |   AUTORAG_INDEX_NAME?: string;
47 | }
48 | 
```

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

```json
 1 | {
 2 |   "namespace": "user",
 3 |   "description": "Describes information about the user.",
 4 |   "attributes": {
 5 |     "user.email": {
 6 |       "description": "User email address.\n",
 7 |       "type": "string",
 8 |       "stability": "development",
 9 |       "examples": ["[email protected]"]
10 |     },
11 |     "user.full_name": {
12 |       "description": "User's full name\n",
13 |       "type": "string",
14 |       "stability": "development",
15 |       "examples": ["Albert Einstein"]
16 |     },
17 |     "user.hash": {
18 |       "description": "Unique user hash to correlate information for a user in anonymized form.\n",
19 |       "type": "string",
20 |       "note": "Useful if `user.id` or `user.name` contain confidential information and cannot be used.\n",
21 |       "stability": "development",
22 |       "examples": ["364fc68eaf4c8acec74a4e52d7d1feaa"]
23 |     },
24 |     "user.id": {
25 |       "description": "Unique identifier of the user.\n",
26 |       "type": "string",
27 |       "stability": "development",
28 |       "examples": ["S-1-5-21-202424912787-2692429404-2351956786-1000"]
29 |     },
30 |     "user.name": {
31 |       "description": "Short name or login/username of the user.\n",
32 |       "type": "string",
33 |       "stability": "development",
34 |       "examples": ["a.einstein"]
35 |     },
36 |     "user.roles": {
37 |       "description": "Array of user roles at the time of the event.\n",
38 |       "type": "string",
39 |       "stability": "development",
40 |       "examples": ["[\"admin\",\"reporting_user\"]"]
41 |     }
42 |   }
43 | }
44 | 
```

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

```typescript
 1 | import { describeEval } from "vitest-evals";
 2 | import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";
 3 | 
 4 | describeEval("list-releases", {
 5 |   data: async () => {
 6 |     return [
 7 |       {
 8 |         input: `Show me the releases in ${FIXTURES.organizationSlug}`,
 9 |         expectedTools: [
10 |           {
11 |             name: "find_organizations",
12 |             arguments: {},
13 |           },
14 |           {
15 |             name: "find_releases",
16 |             arguments: {
17 |               organizationSlug: FIXTURES.organizationSlug,
18 |               regionUrl: "https://us.sentry.io",
19 |             },
20 |           },
21 |         ],
22 |       },
23 |       {
24 |         input: `Show me a list of versions in ${FIXTURES.organizationSlug}/${FIXTURES.projectSlug}`,
25 |         expectedTools: [
26 |           {
27 |             name: "find_organizations",
28 |             arguments: {},
29 |           },
30 |           {
31 |             name: "find_projects",
32 |             arguments: {
33 |               organizationSlug: FIXTURES.organizationSlug,
34 |               regionUrl: "https://us.sentry.io",
35 |             },
36 |           },
37 |           {
38 |             name: "find_releases",
39 |             arguments: {
40 |               organizationSlug: FIXTURES.organizationSlug,
41 |               projectSlug: FIXTURES.projectSlug,
42 |               regionUrl: "https://us.sentry.io",
43 |             },
44 |           },
45 |         ],
46 |       },
47 |     ];
48 |   },
49 |   task: NoOpTaskRunner(),
50 |   scorers: [ToolPredictionScorer()],
51 |   threshold: 0.6,
52 |   timeout: 30000,
53 | });
54 | 
```

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

```json
 1 | {
 2 |   "namespace": "deployment",
 3 |   "description": "This document defines attributes for software deployments.\n",
 4 |   "attributes": {
 5 |     "deployment.name": {
 6 |       "description": "The name of the deployment.\n",
 7 |       "type": "string",
 8 |       "stability": "development",
 9 |       "examples": ["deploy my app", "deploy-frontend"]
10 |     },
11 |     "deployment.id": {
12 |       "description": "The id of the deployment.\n",
13 |       "type": "string",
14 |       "stability": "development",
15 |       "examples": ["1208"]
16 |     },
17 |     "deployment.status": {
18 |       "description": "The status of the deployment.\n",
19 |       "type": "string",
20 |       "stability": "development",
21 |       "examples": ["failed", "succeeded"]
22 |     },
23 |     "deployment.environment.name": {
24 |       "description": "Name of the [deployment environment](https://wikipedia.org/wiki/Deployment_environment) (aka deployment tier).\n",
25 |       "type": "string",
26 |       "note": "`deployment.environment.name` does not affect the uniqueness constraints defined through\nthe `service.namespace`, `service.name` and `service.instance.id` resource attributes.\nThis implies that resources carrying the following attribute combinations MUST be\nconsidered to be identifying the same service:\n\n- `service.name=frontend`, `deployment.environment.name=production`\n- `service.name=frontend`, `deployment.environment.name=staging`.\n",
27 |       "stability": "development",
28 |       "examples": ["staging", "production"]
29 |     }
30 |   }
31 | }
32 | 
```

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

```yaml
 1 | packages:
 2 |   - packages/*
 3 | catalog:
 4 |   "@ai-sdk/openai": ^1.3.22
 5 |   "@ai-sdk/react": ^1.2.12
 6 |   "@biomejs/biome": ^1.9.4
 7 |   "@cloudflare/vite-plugin": ^1.13.15
 8 |   "@cloudflare/vitest-pool-workers": ^0.8.47
 9 |   "@cloudflare/workers-oauth-provider": ^0.0.12
10 |   "@cloudflare/workers-types": ^4.20251014.0
11 |   "@modelcontextprotocol/sdk": ^1.20.2
12 |   "@radix-ui/react-accordion": ^1.2.11
13 |   "@radix-ui/react-slot": ^1.2.3
14 |   "@sentry/cloudflare": 10.22.0
15 |   "@sentry/core": 10.22.0
16 |   "@sentry/node": 10.22.0
17 |   "@sentry/react": 10.22.0
18 |   "@sentry/vite-plugin": ^3.5.0
19 |   "@tailwindcss/typography": ^0.5.16
20 |   "@tailwindcss/vite": ^4.1.11
21 |   "@types/node": ^22.15.33
22 |   "@types/react": ^19.1.8
23 |   "@types/react-dom": ^19.1.6
24 |   "@vitejs/plugin-react": ^4.6.0
25 |   "@vitest/coverage-v8": ^3.2.4
26 |   agents: ^0.2.17
27 |   ai: ^4.3.16
28 |   better-sqlite3: ^11.10.0
29 |   chalk: ^5.4.1
30 |   class-variance-authority: ^0.7.1
31 |   clsx: ^2.1.1
32 |   commander: ^14.0.0
33 |   dotenv: ^16.6.1
34 |   dotenv-cli: ^8.0.0
35 |   hono: ^4.10.3
36 |   lint-staged: ^15.5.2
37 |   lucide-react: ^0.503.0
38 |   msw: ^2.10.2
39 |   open: ^10.1.2
40 |   react: ^19.1.0
41 |   react-dom: ^19.1.0
42 |   react-markdown: ^9.1.0
43 |   remark-gfm: ^4.0.1
44 |   simple-git-hooks: ^2.13.0
45 |   tailwind-merge: ^3.3.1
46 |   tailwindcss: ^4.1.11
47 |   tsdown: ^0.12.9
48 |   tsx: ^4.20.3
49 |   turbo: ^2.5.4
50 |   tw-animate-css: ^1.3.4
51 |   typescript: ^5.8.3
52 |   vite: ^6.3.5
53 |   vitest: ^3.2.4
54 |   vitest-evals: ^0.4.0
55 |   workers-mcp: 0.1.0-3
56 |   wrangler: ^4.45.0
57 |   zod: ^3.25.67
58 |   zod-to-json-schema: ^3.24.6
59 | 
```

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

```typescript
 1 | import { generateText, Output } from "ai";
 2 | import { getOpenAIModel } from "./openai-provider";
 3 | import type { z } from "zod";
 4 | 
 5 | export type ToolCall = {
 6 |   toolName: string;
 7 |   args: any;
 8 | };
 9 | 
10 | interface EmbeddedAgentResult<T> {
11 |   result: T;
12 |   toolCalls: ToolCall[];
13 | }
14 | 
15 | /**
16 |  * Call an embedded agent with tool call capture
17 |  * This is the standard way to call embedded AI agents within MCP tools
18 |  *
19 |  * Error handling:
20 |  * - Errors are re-thrown for the calling agent to handle
21 |  * - Each agent can implement its own error handling strategy
22 |  */
23 | export async function callEmbeddedAgent<T>({
24 |   system,
25 |   prompt,
26 |   tools,
27 |   schema,
28 | }: {
29 |   system: string;
30 |   prompt: string;
31 |   tools: Record<string, any>;
32 |   schema: z.ZodSchema<T>;
33 | }): Promise<EmbeddedAgentResult<T>> {
34 |   const capturedToolCalls: ToolCall[] = [];
35 | 
36 |   const result = await generateText({
37 |     model: getOpenAIModel("gpt-4o"),
38 |     system,
39 |     prompt,
40 |     tools,
41 |     maxSteps: 5,
42 |     experimental_output: Output.object({ schema }),
43 |     onStepFinish: (event) => {
44 |       if (event.toolCalls && event.toolCalls.length > 0) {
45 |         for (const toolCall of event.toolCalls) {
46 |           capturedToolCalls.push({
47 |             toolName: toolCall.toolName,
48 |             args: toolCall.args,
49 |           });
50 |         }
51 |       }
52 |     },
53 |   });
54 | 
55 |   if (!result.experimental_output) {
56 |     throw new Error("Failed to generate output");
57 |   }
58 | 
59 |   return {
60 |     result: result.experimental_output as T,
61 |     toolCalls: capturedToolCalls,
62 |   };
63 | }
64 | 
```

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

```typescript
 1 | import { describeEval } from "vitest-evals";
 2 | import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";
 3 | 
 4 | describeEval("update-project", {
 5 |   data: async () => {
 6 |     return [
 7 |       {
 8 |         input: `Update the project '${FIXTURES.projectSlug}' in organization '${FIXTURES.organizationSlug}' to change its name to 'Updated Project Name' and slug to 'updated-project-slug'. Output only the new project slug as plain text without any formatting:\nupdated-project-slug`,
 9 |         expectedTools: [
10 |           {
11 |             name: "update_project",
12 |             arguments: {
13 |               organizationSlug: FIXTURES.organizationSlug,
14 |               projectSlug: FIXTURES.projectSlug,
15 |               name: "Updated Project Name",
16 |               slug: "updated-project-slug",
17 |             },
18 |           },
19 |         ],
20 |       },
21 |       {
22 |         input: `Assign the project '${FIXTURES.projectSlug}' in organization '${FIXTURES.organizationSlug}' to the team '${FIXTURES.teamSlug}'. Output only the team slug as plain text without any formatting:\nthe-goats`,
23 |         expectedTools: [
24 |           {
25 |             name: "update_project",
26 |             arguments: {
27 |               organizationSlug: FIXTURES.organizationSlug,
28 |               projectSlug: FIXTURES.projectSlug,
29 |               teamSlug: FIXTURES.teamSlug,
30 |             },
31 |           },
32 |         ],
33 |       },
34 |     ];
35 |   },
36 |   task: NoOpTaskRunner(),
37 |   scorers: [ToolPredictionScorer()],
38 |   threshold: 0.6,
39 |   timeout: 30000,
40 | });
41 | 
```

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

```typescript
 1 | import type React from "react";
 2 | import { SentryIcon } from "./icons/sentry";
 3 | import { Github, LogOut } from "lucide-react";
 4 | import { Button } from "./button";
 5 | 
 6 | interface HeaderProps {
 7 |   isAuthenticated?: boolean;
 8 |   onLogout?: () => void;
 9 | }
10 | 
11 | export const Header: React.FC<HeaderProps> = ({
12 |   isAuthenticated,
13 |   onLogout,
14 | }) => {
15 |   return (
16 |     <header className="mb-6 w-full">
17 |       <div className="flex items-center justify-between w-full">
18 |         <div className="flex items-center gap-2 flex-shrink-0">
19 |           <SentryIcon className="h-8 w-8 text-violet-400" />
20 |           <div className="flex items-baseline gap-2">
21 |             <h1 className="text-2xl font-bold whitespace-nowrap">Sentry MCP</h1>
22 |           </div>
23 |         </div>
24 |         <div className="flex items-center gap-2">
25 |           <Button variant="secondary" asChild>
26 |             <a
27 |               href="https://github.com/getsentry/sentry-mcp"
28 |               target="_blank"
29 |               rel="noopener noreferrer"
30 |             >
31 |               <Github className="h-5 w-5" />
32 |               <span>GitHub</span>
33 |             </a>
34 |           </Button>
35 |           {isAuthenticated && onLogout && (
36 |             <Button
37 |               variant="secondary"
38 |               onClick={onLogout}
39 |               className="hidden md:flex cursor-pointer"
40 |             >
41 |               <LogOut className="h-4 w-4" />
42 |               <span>Logout</span>
43 |             </Button>
44 |           )}
45 |         </div>
46 |       </div>
47 |     </header>
48 |   );
49 | };
50 | 
```

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

```typescript
 1 | import ReactMarkdown from "react-markdown";
 2 | import remarkGfm from "remark-gfm";
 3 | import { cn } from "@/client/lib/utils";
 4 | 
 5 | interface MarkdownProps {
 6 |   children: string;
 7 |   className?: string;
 8 | }
 9 | 
10 | export function Markdown({ children, className }: MarkdownProps) {
11 |   return (
12 |     <ReactMarkdown
13 |       className={cn(
14 |         "prose prose-invert prose-slate max-w-none",
15 |         "prose-p:my-2 prose-p:leading-relaxed",
16 |         "prose-pre:bg-slate-900 prose-pre:border prose-pre:border-slate-700",
17 |         "prose-code:bg-slate-800 prose-code:px-1 prose-code:py-0.5 prose-code:rounded prose-code:text-sm",
18 |         "prose-code:before:content-none prose-code:after:content-none",
19 |         "prose-strong:text-slate-100",
20 |         "prose-em:text-slate-200",
21 |         "prose-a:text-violet-300",
22 |         "prose-blockquote:border-l-violet-500 prose-blockquote:bg-slate-800/50 prose-blockquote:py-2 prose-blockquote:px-4",
23 |         "prose-h1:text-slate-100 prose-h2:text-slate-100 prose-h3:text-slate-100",
24 |         "prose-h4:text-slate-100 prose-h5:text-slate-100 prose-h6:text-slate-100",
25 |         "prose-ul:my-2 prose-ol:my-2",
26 |         "prose-li:my-1",
27 |         "prose-hr:border-slate-700",
28 |         "prose-table:border-slate-700",
29 |         "prose-th:border-slate-700 prose-td:border-slate-700",
30 |         className,
31 |       )}
32 |       remarkPlugins={[remarkGfm]}
33 |       disallowedElements={["script", "style", "iframe", "object", "embed"]}
34 |       unwrapDisallowed={true}
35 |     >
36 |       {children}
37 |     </ReactMarkdown>
38 |   );
39 | }
40 | 
```

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

```typescript
 1 | import type { Env } from "./types";
 2 | import { LIB_VERSION } from "@sentry/mcp-server/version";
 3 | import * as Sentry from "@sentry/cloudflare";
 4 | import { sentryBeforeSend } from "@sentry/mcp-server/telem/sentry";
 5 | 
 6 | type SentryConfig = ReturnType<Parameters<typeof Sentry.withSentry>[0]>;
 7 | 
 8 | export default function getSentryConfig(env: Env): SentryConfig {
 9 |   const { id: versionId } = env.CF_VERSION_METADATA;
10 | 
11 |   return {
12 |     dsn: env.SENTRY_DSN,
13 |     tracesSampleRate: 1,
14 |     sendDefaultPii: true,
15 |     beforeSend: sentryBeforeSend,
16 |     initialScope: {
17 |       tags: {
18 |         "mcp.server_version": LIB_VERSION,
19 |         "sentry.host": env.SENTRY_HOST,
20 |       },
21 |     },
22 |     release: versionId,
23 |     environment:
24 |       env.SENTRY_ENVIRONMENT ??
25 |       (process.env.NODE_ENV !== "production" ? "development" : "production"),
26 |     _experiments: {
27 |       enableLogs: true,
28 |     },
29 |     integrations: [
30 |       Sentry.consoleLoggingIntegration(),
31 |       Sentry.zodErrorsIntegration(),
32 |       Sentry.vercelAIIntegration(),
33 |     ],
34 |   };
35 | }
36 | 
37 | getSentryConfig.partial = (config: Partial<SentryConfig>) => {
38 |   return (env: Env) => {
39 |     const defaultConfig = getSentryConfig(env);
40 |     return {
41 |       ...defaultConfig,
42 |       ...config,
43 |       initialScope: {
44 |         ...defaultConfig.initialScope,
45 |         ...config.initialScope,
46 |         tags: {
47 |           // idk I can't typescript
48 |           ...((defaultConfig.initialScope ?? {}) as any).tags,
49 |           ...((config.initialScope ?? {}) as any).tags,
50 |         },
51 |       },
52 |     };
53 |   };
54 | };
55 | 
```

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

```json
 1 | [
 2 |   {
 3 |     "key": "transaction",
 4 |     "name": "Transaction",
 5 |     "totalValues": 1080
 6 |   },
 7 |   {
 8 |     "key": "runtime.name",
 9 |     "name": "Runtime.Name",
10 |     "totalValues": 1080
11 |   },
12 |   {
13 |     "key": "level",
14 |     "name": "Level",
15 |     "totalValues": 1144
16 |   },
17 |   {
18 |     "key": "device",
19 |     "name": "Device",
20 |     "totalValues": 25
21 |   },
22 |   {
23 |     "key": "os",
24 |     "name": "OS",
25 |     "totalValues": 1133
26 |   },
27 |   {
28 |     "key": "user",
29 |     "name": "User",
30 |     "totalValues": 1080
31 |   },
32 |   {
33 |     "key": "runtime",
34 |     "name": "Runtime",
35 |     "totalValues": 1080
36 |   },
37 |   {
38 |     "key": "release",
39 |     "name": "Release",
40 |     "totalValues": 1135
41 |   },
42 |   {
43 |     "key": "url",
44 |     "name": "URL",
45 |     "totalValues": 1080
46 |   },
47 |   {
48 |     "key": "uptime_rule",
49 |     "name": "Uptime Rule",
50 |     "totalValues": 9
51 |   },
52 |   {
53 |     "key": "server_name",
54 |     "name": "Server",
55 |     "totalValues": 1080
56 |   },
57 |   {
58 |     "key": "browser",
59 |     "name": "Browser",
60 |     "totalValues": 56
61 |   },
62 |   {
63 |     "key": "os.name",
64 |     "name": "Os.Name",
65 |     "totalValues": 1135
66 |   },
67 |   {
68 |     "key": "device.family",
69 |     "name": "Device.Family",
70 |     "totalValues": 25
71 |   },
72 |   {
73 |     "key": "replayId",
74 |     "name": "Replayid",
75 |     "totalValues": 55
76 |   },
77 |   {
78 |     "key": "client_os.name",
79 |     "name": "Client Os.Name",
80 |     "totalValues": 1
81 |   },
82 |   {
83 |     "key": "environment",
84 |     "name": "Environment",
85 |     "totalValues": 1144
86 |   },
87 |   {
88 |     "key": "service",
89 |     "name": "Service",
90 |     "totalValues": 1135
91 |   },
92 |   {
93 |     "key": "browser.name",
94 |     "name": "Browser.Name",
95 |     "totalValues": 56
96 |   }
97 | ]
98 | 
```

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

```json
  1 | [
  2 |   {
  3 |     "key": "span.op",
  4 |     "name": "Span Operation"
  5 |   },
  6 |   {
  7 |     "key": "span.description",
  8 |     "name": "Span Description"
  9 |   },
 10 |   {
 11 |     "key": "span.status",
 12 |     "name": "Span Status"
 13 |   },
 14 |   {
 15 |     "key": "transaction",
 16 |     "name": "Transaction"
 17 |   },
 18 |   {
 19 |     "key": "transaction.op",
 20 |     "name": "Transaction Operation"
 21 |   },
 22 |   {
 23 |     "key": "transaction.status",
 24 |     "name": "Transaction Status"
 25 |   },
 26 |   {
 27 |     "key": "project",
 28 |     "name": "Project"
 29 |   },
 30 |   {
 31 |     "key": "environment",
 32 |     "name": "Environment"
 33 |   },
 34 |   {
 35 |     "key": "release",
 36 |     "name": "Release"
 37 |   },
 38 |   {
 39 |     "key": "user.id",
 40 |     "name": "User ID"
 41 |   },
 42 |   {
 43 |     "key": "user.email",
 44 |     "name": "User Email"
 45 |   },
 46 |   {
 47 |     "key": "user.username",
 48 |     "name": "Username"
 49 |   },
 50 |   {
 51 |     "key": "platform",
 52 |     "name": "Platform"
 53 |   },
 54 |   {
 55 |     "key": "sdk.name",
 56 |     "name": "SDK Name"
 57 |   },
 58 |   {
 59 |     "key": "sdk.version",
 60 |     "name": "SDK Version"
 61 |   },
 62 |   {
 63 |     "key": "http.method",
 64 |     "name": "HTTP Method"
 65 |   },
 66 |   {
 67 |     "key": "http.url",
 68 |     "name": "HTTP URL"
 69 |   },
 70 |   {
 71 |     "key": "browser.name",
 72 |     "name": "Browser Name"
 73 |   },
 74 |   {
 75 |     "key": "os.name",
 76 |     "name": "OS Name"
 77 |   },
 78 |   {
 79 |     "key": "device",
 80 |     "name": "Device"
 81 |   },
 82 |   {
 83 |     "key": "geo.country_code",
 84 |     "name": "Country Code"
 85 |   },
 86 |   {
 87 |     "key": "geo.region",
 88 |     "name": "Geographic Region"
 89 |   },
 90 |   {
 91 |     "key": "geo.city",
 92 |     "name": "City"
 93 |   },
 94 |   {
 95 |     "key": "custom.tier",
 96 |     "name": "Customer Tier"
 97 |   },
 98 |   {
 99 |     "key": "custom.feature_flag",
100 |     "name": "Feature Flag"
101 |   }
102 | ]
103 | 
```

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

```json
 1 | {
 2 |   "namespace": "server",
 3 |   "description": "These attributes may be used to describe the server in a connection-based network interaction where there is one side that initiates the connection (the client is the side that initiates the connection). This covers all TCP network interactions since TCP is connection-based and one side initiates the connection (an exception is made for peer-to-peer communication over TCP where the \"user-facing\" surface of the protocol / API doesn't expose a clear notion of client and server). This also covers UDP network interactions where one side initiates the interaction, e.g. QUIC (HTTP/3) and DNS.\n",
 4 |   "attributes": {
 5 |     "server.address": {
 6 |       "description": "Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name.",
 7 |       "type": "string",
 8 |       "note": "When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent the server address behind any intermediaries, for example proxies, if it's available.\n",
 9 |       "stability": "stable",
10 |       "examples": ["example.com", "10.1.2.80", "/tmp/my.sock"]
11 |     },
12 |     "server.port": {
13 |       "description": "Server port number.",
14 |       "type": "number",
15 |       "note": "When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available.\n",
16 |       "stability": "stable",
17 |       "examples": ["80", "8080", "443"]
18 |     }
19 |   }
20 | }
21 | 
```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/chat/auth-form.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import { Button } from "../ui/button";
 2 | import { AlertCircle } from "lucide-react";
 3 | 
 4 | import type { AuthFormProps } from "./types";
 5 | 
 6 | export function AuthForm({ authError, onOAuthLogin }: AuthFormProps) {
 7 |   return (
 8 |     <div className="sm:p-8 p-4 flex flex-col items-center">
 9 |       <div className="max-w-md w-full space-y-6">
10 |         {/* Chat illustration - hidden on short screens */}
11 |         <div className="text-slate-400 hidden [@media(min-height:500px)]:block">
12 |           <img
13 |             src="/flow-transparent.png"
14 |             alt="Flow"
15 |             width={1536}
16 |             height={1024}
17 |             className="w-full mb-6 bg-violet-300 rounded"
18 |           />
19 |         </div>
20 | 
21 |         <div className="text-center space-y-2">
22 |           <h1 className="text-2xl font-bold">Live MCP Demo</h1>
23 |           <p className="text-slate-400">
24 |             Connect your Sentry account to test the Model Context Protocol with
25 |             real data from your projects.
26 |           </p>
27 |         </div>
28 | 
29 |         <div className="space-y-4">
30 |           {authError && (
31 |             <div className="p-3 bg-red-900/20 border border-red-500/30 rounded flex items-center gap-2">
32 |               <AlertCircle className="h-4 w-4 text-red-400" />
33 |               <div className="text-red-400 text-sm">{authError}</div>
34 |             </div>
35 |           )}
36 | 
37 |           <Button
38 |             onClick={onOAuthLogin}
39 |             variant="default"
40 |             className="w-full cursor-pointer"
41 |           >
42 |             Connect with Sentry
43 |           </Button>
44 |         </div>
45 |       </div>
46 |     </div>
47 |   );
48 | }
49 | 
```

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

```json
 1 | {
 2 |   "namespace": "client",
 3 |   "description": "These attributes may be used to describe the client in a connection-based network interaction where there is one side that initiates the connection (the client is the side that initiates the connection). This covers all TCP network interactions since TCP is connection-based and one side initiates the connection (an exception is made for peer-to-peer communication over TCP where the \"user-facing\" surface of the protocol / API doesn't expose a clear notion of client and server). This also covers UDP network interactions where one side initiates the interaction, e.g. QUIC (HTTP/3) and DNS.\n",
 4 |   "attributes": {
 5 |     "client.address": {
 6 |       "description": "Client address - domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name.",
 7 |       "type": "string",
 8 |       "note": "When observed from the server side, and when communicating through an intermediary, `client.address` SHOULD represent the client address behind any intermediaries,  for example proxies, if it's available.\n",
 9 |       "stability": "stable",
10 |       "examples": ["client.example.com", "10.1.2.80", "/tmp/my.sock"]
11 |     },
12 |     "client.port": {
13 |       "description": "Client port number.",
14 |       "type": "number",
15 |       "note": "When observed from the server side, and when communicating through an intermediary, `client.port` SHOULD represent the client port behind any intermediaries,  for example proxies, if it's available.\n",
16 |       "stability": "stable",
17 |       "examples": ["65123"]
18 |     }
19 |   }
20 | }
21 | 
```

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

```typescript
 1 | /**
 2 |  * Component for rendering clickable slash command buttons
 3 |  */
 4 | import { Button } from "./button";
 5 | import { Terminal } from "lucide-react";
 6 | 
 7 | interface SlashCommandActionsProps {
 8 |   onCommandSelect: (command: string) => void;
 9 | }
10 | 
11 | const SLASH_COMMANDS = [
12 |   { command: "help", description: "Show help message" },
13 |   { command: "tools", description: "List available MCP tools" },
14 |   { command: "resources", description: "List available MCP resources" },
15 |   { command: "prompts", description: "List available MCP prompts" },
16 |   { command: "clear", description: "Clear all chat messages" },
17 |   { command: "logout", description: "Log out of the current session" },
18 | ];
19 | 
20 | export function SlashCommandActions({
21 |   onCommandSelect,
22 | }: SlashCommandActionsProps) {
23 |   return (
24 |     <div className="mt-4 space-y-3">
25 |       <h4 className="text-sm font-medium text-slate-300 mb-2">
26 |         Try these commands:
27 |       </h4>
28 |       <div className="space-y-2">
29 |         {SLASH_COMMANDS.map((cmd) => (
30 |           <div key={cmd.command} className="flex items-center gap-3">
31 |             <Button
32 |               onClick={() => onCommandSelect(cmd.command)}
33 |               size="sm"
34 |               variant="outline"
35 |               className="flex items-center gap-2 text-xs bg-blue-900/50 border-blue-700/50 hover:bg-blue-800/50 hover:border-blue-600/50 text-blue-300 font-mono"
36 |             >
37 |               <Terminal className="h-3 w-3" />/{cmd.command}
38 |             </Button>
39 |             <span className="text-xs text-slate-400">{cmd.description}</span>
40 |           </div>
41 |         ))}
42 |       </div>
43 |     </div>
44 |   );
45 | }
46 | 
```

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

```typescript
 1 | import whoami from "./whoami";
 2 | import findOrganizations from "./find-organizations";
 3 | import findTeams from "./find-teams";
 4 | import findProjects from "./find-projects";
 5 | import findReleases from "./find-releases";
 6 | import getIssueDetails from "./get-issue-details";
 7 | import getTraceDetails from "./get-trace-details";
 8 | import getEventAttachment from "./get-event-attachment";
 9 | import updateIssue from "./update-issue";
10 | import searchEvents from "./search-events";
11 | import createTeam from "./create-team";
12 | import createProject from "./create-project";
13 | import updateProject from "./update-project";
14 | import createDsn from "./create-dsn";
15 | import findDsns from "./find-dsns";
16 | import analyzeIssueWithSeer from "./analyze-issue-with-seer";
17 | import searchDocs from "./search-docs";
18 | import getDoc from "./get-doc";
19 | import searchIssues from "./search-issues";
20 | 
21 | // Default export: object mapping tool names to tools
22 | export default {
23 |   whoami,
24 |   find_organizations: findOrganizations,
25 |   find_teams: findTeams,
26 |   find_projects: findProjects,
27 |   find_releases: findReleases,
28 |   get_issue_details: getIssueDetails,
29 |   get_trace_details: getTraceDetails,
30 |   get_event_attachment: getEventAttachment,
31 |   update_issue: updateIssue,
32 |   search_events: searchEvents,
33 |   create_team: createTeam,
34 |   create_project: createProject,
35 |   update_project: updateProject,
36 |   create_dsn: createDsn,
37 |   find_dsns: findDsns,
38 |   analyze_issue_with_seer: analyzeIssueWithSeer,
39 |   search_docs: searchDocs,
40 |   get_doc: getDoc,
41 |   search_issues: searchIssues,
42 | } as const;
43 | 
44 | // Type export
45 | export type ToolName = keyof typeof import("./index").default;
46 | 
```

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

```json
 1 | {
 2 |   "namespace": "os",
 3 |   "description": "The operating system (OS) on which the process represented by this resource is running.\n",
 4 |   "attributes": {
 5 |     "os.type": {
 6 |       "description": "The operating system type.\n",
 7 |       "type": "string",
 8 |       "stability": "development",
 9 |       "examples": [
10 |         "windows",
11 |         "linux",
12 |         "darwin",
13 |         "freebsd",
14 |         "netbsd",
15 |         "openbsd",
16 |         "dragonflybsd",
17 |         "hpux",
18 |         "aix",
19 |         "solaris",
20 |         "z_os",
21 |         "zos"
22 |       ]
23 |     },
24 |     "os.description": {
25 |       "description": "Human readable (not intended to be parsed) OS version information, like e.g. reported by `ver` or `lsb_release -a` commands.\n",
26 |       "type": "string",
27 |       "stability": "development",
28 |       "examples": [
29 |         "Microsoft Windows [Version 10.0.18363.778]",
30 |         "Ubuntu 18.04.1 LTS"
31 |       ]
32 |     },
33 |     "os.name": {
34 |       "description": "Human readable operating system name.",
35 |       "type": "string",
36 |       "stability": "development",
37 |       "examples": ["iOS", "Android", "Ubuntu"]
38 |     },
39 |     "os.version": {
40 |       "description": "The version string of the operating system as defined in [Version Attributes](/docs/resource/README.md#version-attributes).\n",
41 |       "type": "string",
42 |       "stability": "development",
43 |       "examples": ["14.2.1", "18.04.1"]
44 |     },
45 |     "os.build_id": {
46 |       "description": "Unique identifier for a particular build or compilation of the operating system.",
47 |       "type": "string",
48 |       "stability": "development",
49 |       "examples": ["TQ3C.230805.001.B2", "20E247", "22621"]
50 |     }
51 |   }
52 | }
53 | 
```

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

```json
 1 | {
 2 |   "team": {
 3 |     "id": "4509106733776896",
 4 |     "slug": "the-goats",
 5 |     "name": "the-goats"
 6 |   },
 7 |   "teams": [
 8 |     {
 9 |       "id": "4509106733776896",
10 |       "slug": "the-goats",
11 |       "name": "the-goats"
12 |     }
13 |   ],
14 |   "id": "4509109104082945",
15 |   "name": "cloudflare-mcp",
16 |   "slug": "cloudflare-mcp",
17 |   "isBookmarked": false,
18 |   "isMember": true,
19 |   "access": [
20 |     "event:admin",
21 |     "alerts:read",
22 |     "project:write",
23 |     "org:integrations",
24 |     "alerts:write",
25 |     "member:read",
26 |     "team:write",
27 |     "project:read",
28 |     "event:read",
29 |     "event:write",
30 |     "project:admin",
31 |     "org:read",
32 |     "team:admin",
33 |     "project:releases",
34 |     "team:read"
35 |   ],
36 |   "hasAccess": true,
37 |   "dateCreated": "2025-04-06T14:13:37.825970Z",
38 |   "environments": [],
39 |   "eventProcessing": {
40 |     "symbolicationDegraded": false
41 |   },
42 |   "features": [
43 |     "discard-groups",
44 |     "alert-filters",
45 |     "similarity-embeddings",
46 |     "similarity-indexing",
47 |     "similarity-view"
48 |   ],
49 |   "firstEvent": null,
50 |   "firstTransactionEvent": false,
51 |   "hasSessions": false,
52 |   "hasProfiles": false,
53 |   "hasReplays": false,
54 |   "hasFeedbacks": false,
55 |   "hasNewFeedbacks": false,
56 |   "hasMonitors": false,
57 |   "hasMinifiedStackTrace": false,
58 |   "hasInsightsHttp": false,
59 |   "hasInsightsDb": false,
60 |   "hasInsightsAssets": false,
61 |   "hasInsightsAppStart": false,
62 |   "hasInsightsScreenLoad": false,
63 |   "hasInsightsVitals": false,
64 |   "hasInsightsCaches": false,
65 |   "hasInsightsQueues": false,
66 |   "hasInsightsLlmMonitoring": false,
67 |   "platform": "node",
68 |   "platforms": [],
69 |   "latestRelease": null,
70 |   "hasUserReports": false,
71 |   "hasFlags": false,
72 |   "latestDeploys": null
73 | }
74 | 
```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/utils/chat-error-handler.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Simplified chat error handling utilities
 3 |  * Only handles two concerns: auth errors vs other errors
 4 |  */
 5 | 
 6 | /**
 7 |  * Check if an error is authentication-related (401)
 8 |  */
 9 | export function isAuthError(error: Error): boolean {
10 |   const message = error.message.toLowerCase();
11 | 
12 |   // Check for 401 status code or auth-related keywords
13 |   return (
14 |     message.includes("401") ||
15 |     message.includes("auth_expired") ||
16 |     message.includes("invalid_token") ||
17 |     message.includes("session has expired") ||
18 |     message.includes("unauthorized")
19 |   );
20 | }
21 | 
22 | /**
23 |  * Extract a user-friendly error message from the error
24 |  */
25 | export function getErrorMessage(error: Error): string {
26 |   try {
27 |     // Try to parse JSON error response
28 |     const jsonMatch = error.message.match(/\{.*\}/);
29 |     if (jsonMatch) {
30 |       const data = JSON.parse(jsonMatch[0]);
31 |       if (data.error) {
32 |         return data.error;
33 |       }
34 |     }
35 |   } catch {
36 |     // Ignore JSON parse errors
37 |   }
38 | 
39 |   // Check for specific error types
40 |   if (isAuthError(error)) {
41 |     return "Your session has expired. Please log in again.";
42 |   }
43 | 
44 |   if (
45 |     error.message.includes("429") ||
46 |     error.message.toLowerCase().includes("rate_limit")
47 |   ) {
48 |     return "You've sent too many messages. Please wait a moment before trying again.";
49 |   }
50 | 
51 |   if (
52 |     error.message.includes("403") ||
53 |     error.message.toLowerCase().includes("permission")
54 |   ) {
55 |     return "You don't have permission to access this organization.";
56 |   }
57 | 
58 |   if (error.message.includes("500")) {
59 |     return "Something went wrong on our end. Please try again.";
60 |   }
61 | 
62 |   // Default message
63 |   return "An error occurred. Please try again.";
64 | }
65 | 
```

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

```typescript
 1 | import { describeEval } from "vitest-evals";
 2 | import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";
 3 | 
 4 | describeEval("list-teams", {
 5 |   data: async () => {
 6 |     return [
 7 |       {
 8 |         input: `What teams do I have access to in Sentry for '${FIXTURES.organizationSlug}'`,
 9 |         expectedTools: [
10 |           {
11 |             name: "find_organizations",
12 |             arguments: {},
13 |           },
14 |           {
15 |             name: "find_teams",
16 |             arguments: {
17 |               organizationSlug: FIXTURES.organizationSlug,
18 |               regionUrl: "https://us.sentry.io",
19 |             },
20 |           },
21 |         ],
22 |       },
23 |       {
24 |         input: `Do I have access to the team '${FIXTURES.teamSlug}' for '${FIXTURES.organizationSlug}'`,
25 |         expectedTools: [
26 |           {
27 |             name: "find_organizations",
28 |             arguments: {},
29 |           },
30 |           {
31 |             name: "find_teams",
32 |             arguments: {
33 |               organizationSlug: FIXTURES.organizationSlug,
34 |               regionUrl: "https://us.sentry.io",
35 |             },
36 |           },
37 |         ],
38 |       },
39 |       {
40 |         input: `Do I have access to the team 'an-imaginary-team' for '${FIXTURES.organizationSlug}'`,
41 |         expectedTools: [
42 |           {
43 |             name: "find_organizations",
44 |             arguments: {},
45 |           },
46 |           {
47 |             name: "find_teams",
48 |             arguments: {
49 |               organizationSlug: FIXTURES.organizationSlug,
50 |               regionUrl: "https://us.sentry.io",
51 |             },
52 |           },
53 |         ],
54 |       },
55 |     ];
56 |   },
57 |   task: NoOpTaskRunner(),
58 |   scorers: [ToolPredictionScorer()],
59 |   threshold: 0.6,
60 |   timeout: 30000,
61 | });
62 | 
```

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

```typescript
 1 | import { describe, it, expect } from "vitest";
 2 | import findOrganizations from "./find-organizations.js";
 3 | 
 4 | describe("find_organizations", () => {
 5 |   it("serializes", async () => {
 6 |     const result = await findOrganizations.handler(
 7 |       {},
 8 |       {
 9 |         constraints: {
10 |           organizationSlug: null,
11 |         },
12 |         accessToken: "access-token",
13 |         userId: "1",
14 |       },
15 |     );
16 |     expect(result).toMatchInlineSnapshot(`
17 |       "# Organizations
18 | 
19 |       ## **sentry-mcp-evals**
20 | 
21 |       **Web URL:** https://sentry.io/sentry-mcp-evals
22 |       **Region URL:** https://us.sentry.io
23 | 
24 |       # Using this information
25 | 
26 |       - The organization's name is the identifier for the organization, and is used in many tools for \`organizationSlug\`.
27 |       - If a tool supports passing in the \`regionUrl\`, you MUST pass in the correct value shown above for each organization.
28 |       - For Sentry's Cloud Service (sentry.io), always use the regionUrl to ensure requests go to the correct region.
29 |       "
30 |     `);
31 |   });
32 | 
33 |   it("handles empty regionUrl parameter", async () => {
34 |     const result = await findOrganizations.handler(
35 |       {},
36 |       {
37 |         constraints: {
38 |           organizationSlug: null,
39 |         },
40 |         accessToken: "access-token",
41 |         userId: "1",
42 |       },
43 |     );
44 |     expect(result).toContain("Organizations");
45 |   });
46 | 
47 |   it("handles undefined regionUrl parameter", async () => {
48 |     const result = await findOrganizations.handler(
49 |       {},
50 |       {
51 |         constraints: {
52 |           organizationSlug: null,
53 |         },
54 |         accessToken: "access-token",
55 |         userId: "1",
56 |       },
57 |     );
58 |     expect(result).toContain("Organizations");
59 |   });
60 | });
61 | 
```

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

```json
 1 | {
 2 |   "namespace": "hardware",
 3 |   "description": "Attributes for hardware.\n",
 4 |   "attributes": {
 5 |     "hw.id": {
 6 |       "description": "An identifier for the hardware component, unique within the monitored host\n",
 7 |       "type": "string",
 8 |       "stability": "development",
 9 |       "examples": ["win32battery_battery_testsysa33_1"]
10 |     },
11 |     "hw.name": {
12 |       "description": "An easily-recognizable name for the hardware component\n",
13 |       "type": "string",
14 |       "stability": "development",
15 |       "examples": ["eth0"]
16 |     },
17 |     "hw.parent": {
18 |       "description": "Unique identifier of the parent component (typically the `hw.id` attribute of the enclosure, or disk controller)\n",
19 |       "type": "string",
20 |       "stability": "development",
21 |       "examples": ["dellStorage_perc_0"]
22 |     },
23 |     "hw.type": {
24 |       "description": "Type of the component\n",
25 |       "type": "string",
26 |       "note": "Describes the category of the hardware component for which `hw.state` is being reported. For example, `hw.type=temperature` along with `hw.state=degraded` would indicate that the temperature of the hardware component has been reported as `degraded`.\n",
27 |       "stability": "development",
28 |       "examples": [
29 |         "battery",
30 |         "cpu",
31 |         "disk_controller",
32 |         "enclosure",
33 |         "fan",
34 |         "gpu",
35 |         "logical_disk",
36 |         "memory",
37 |         "network",
38 |         "physical_disk",
39 |         "power_supply",
40 |         "tape_drive",
41 |         "temperature",
42 |         "voltage"
43 |       ]
44 |     },
45 |     "hw.state": {
46 |       "description": "The current state of the component\n",
47 |       "type": "string",
48 |       "stability": "development",
49 |       "examples": ["ok", "degraded", "failed"]
50 |     }
51 |   }
52 | }
53 | 
```

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

```json
 1 | {
 2 |   "namespace": "db",
 3 |   "description": "Database operations attributes",
 4 |   "attributes": {
 5 |     "db.system.name": {
 6 |       "description": "Identifies the database management system product",
 7 |       "type": "string",
 8 |       "examples": [
 9 |         "postgresql",
10 |         "mysql",
11 |         "microsoft.sql_server",
12 |         "mongodb",
13 |         "redis",
14 |         "cassandra"
15 |       ]
16 |     },
17 |     "db.collection.name": {
18 |       "description": "Name of a collection (table, container) within the database",
19 |       "type": "string"
20 |     },
21 |     "db.namespace": {
22 |       "description": "Fully qualified database name within server address and port",
23 |       "type": "string"
24 |     },
25 |     "db.operation.name": {
26 |       "description": "Name of the operation or command being executed",
27 |       "type": "string",
28 |       "examples": [
29 |         "SELECT",
30 |         "INSERT",
31 |         "UPDATE",
32 |         "DELETE",
33 |         "CREATE",
34 |         "DROP",
35 |         "find",
36 |         "insert",
37 |         "update",
38 |         "delete"
39 |       ]
40 |     },
41 |     "db.response.status_code": {
42 |       "description": "Status code returned by the database",
43 |       "type": "string"
44 |     },
45 |     "db.operation.batch.size": {
46 |       "description": "Number of queries in a batch operation",
47 |       "type": "number"
48 |     },
49 |     "db.query.summary": {
50 |       "description": "Low-cardinality summary of a database query",
51 |       "type": "string"
52 |     },
53 |     "db.query.text": {
54 |       "description": "The actual database query being executed",
55 |       "type": "string"
56 |     },
57 |     "db.stored_procedure.name": {
58 |       "description": "Name of a stored procedure within the database",
59 |       "type": "string"
60 |     },
61 |     "db.query.parameter.<key>": {
62 |       "description": "Database query parameter values",
63 |       "type": "string"
64 |     }
65 |   }
66 | }
67 | 
```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/server/utils/auth-errors.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Shared utilities for detecting and handling authentication errors
 3 |  */
 4 | 
 5 | export interface AuthErrorInfo {
 6 |   isAuthError: boolean;
 7 |   isExpired: boolean;
 8 |   isForbidden: boolean;
 9 |   statusCode?: number;
10 | }
11 | 
12 | /**
13 |  * Analyze an error to determine if it's authentication-related
14 |  */
15 | export function analyzeAuthError(error: unknown): AuthErrorInfo {
16 |   const result: AuthErrorInfo = {
17 |     isAuthError: false,
18 |     isExpired: false,
19 |     isForbidden: false,
20 |   };
21 | 
22 |   if (!(error instanceof Error)) {
23 |     return result;
24 |   }
25 | 
26 |   const errorMessage = error.message.toLowerCase();
27 | 
28 |   // Check for 401 Unauthorized errors
29 |   if (
30 |     errorMessage.includes("401") ||
31 |     errorMessage.includes("unauthorized") ||
32 |     errorMessage.includes("authentication") ||
33 |     errorMessage.includes("invalid token") ||
34 |     errorMessage.includes("access token")
35 |   ) {
36 |     result.isAuthError = true;
37 |     result.isExpired = true;
38 |     result.statusCode = 401;
39 |   }
40 | 
41 |   // Check for 403 Forbidden errors
42 |   if (errorMessage.includes("403") || errorMessage.includes("forbidden")) {
43 |     result.isAuthError = true;
44 |     result.isForbidden = true;
45 |     result.statusCode = 403;
46 |   }
47 | 
48 |   return result;
49 | }
50 | 
51 | /**
52 |  * Get appropriate error response based on auth error type
53 |  */
54 | export function getAuthErrorResponse(authInfo: AuthErrorInfo) {
55 |   if (authInfo.isExpired) {
56 |     return {
57 |       error: "Authentication with Sentry has expired. Please log in again.",
58 |       name: "AUTH_EXPIRED" as const,
59 |     };
60 |   }
61 | 
62 |   if (authInfo.isForbidden) {
63 |     return {
64 |       error: "You don't have permission to access this Sentry organization.",
65 |       name: "INSUFFICIENT_PERMISSIONS" as const,
66 |     };
67 |   }
68 | 
69 |   return {
70 |     error: "Authentication error occurred",
71 |     name: "SENTRY_AUTH_INVALID" as const,
72 |   };
73 | }
74 | 
```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/slash-command-text.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Component that renders text with clickable slash commands
 3 |  */
 4 | import { Fragment } from "react";
 5 | 
 6 | interface SlashCommandTextProps {
 7 |   children: string;
 8 |   onSlashCommand: (command: string) => void;
 9 | }
10 | 
11 | const SLASH_COMMAND_REGEX = /\/([a-zA-Z]+)/g;
12 | 
13 | export function SlashCommandText({
14 |   children,
15 |   onSlashCommand,
16 | }: SlashCommandTextProps) {
17 |   const parts = [];
18 |   let lastIndex = 0;
19 |   let match: RegExpExecArray | null;
20 | 
21 |   // Reset regex state before using
22 |   SLASH_COMMAND_REGEX.lastIndex = 0;
23 | 
24 |   // Find all slash commands in the text
25 |   match = SLASH_COMMAND_REGEX.exec(children);
26 |   while (match !== null) {
27 |     const fullMatch = match[0]; // e.g., "/help"
28 |     const command = match[1]; // e.g., "help"
29 |     const startIndex = match.index;
30 | 
31 |     // Add text before the command
32 |     if (startIndex > lastIndex) {
33 |       parts.push(
34 |         <Fragment key={`text-${lastIndex}`}>
35 |           {children.slice(lastIndex, startIndex)}
36 |         </Fragment>,
37 |       );
38 |     }
39 | 
40 |     // Add clickable command
41 |     parts.push(
42 |       <button
43 |         key={`command-${startIndex}`}
44 |         onClick={() => onSlashCommand(command)}
45 |         className="inline-flex items-center gap-1 px-1 py-0.5 text-xs bg-blue-900/50 border border-blue-700/50 rounded text-blue-300 hover:bg-blue-800/50 hover:border-blue-600/50 transition-colors font-mono cursor-pointer"
46 |         type="button"
47 |       >
48 |         {fullMatch}
49 |       </button>,
50 |     );
51 | 
52 |     lastIndex = startIndex + fullMatch.length;
53 | 
54 |     // Continue searching
55 |     match = SLASH_COMMAND_REGEX.exec(children);
56 |   }
57 | 
58 |   // Add remaining text
59 |   if (lastIndex < children.length) {
60 |     parts.push(
61 |       <Fragment key={`text-${lastIndex}`}>
62 |         {children.slice(lastIndex)}
63 |       </Fragment>,
64 |     );
65 |   }
66 | 
67 |   return <>{parts}</>;
68 | }
69 | 
```

--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: Test
 2 | 
 3 | on:
 4 |   push:
 5 |     branches: [main]
 6 |   pull_request:
 7 | 
 8 | jobs:
 9 |   test:
10 |     runs-on: ubuntu-latest
11 |     steps:
12 |       - uses: actions/checkout@v4
13 | 
14 |       - name: Setup Node.js
15 |         uses: actions/setup-node@v4
16 |         with:
17 |           node-version: "20"
18 | 
19 |       # pnpm/action-setup@v4
20 |       - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda
21 |         name: Install pnpm
22 |         with:
23 |           run_install: false
24 | 
25 |       - name: Get pnpm store directory
26 |         shell: bash
27 |         run: |
28 |           echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
29 | 
30 |       - uses: actions/cache@v4
31 |         name: Setup pnpm cache
32 |         with:
33 |           path: ${{ env.STORE_PATH }}
34 |           key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
35 |           restore-keys: |
36 |             ${{ runner.os }}-pnpm-store-
37 | 
38 |       - name: Install dependencies
39 |         run: pnpm install --no-frozen-lockfile
40 |       
41 |       - name: Run build
42 |         run: pnpm build
43 | 
44 |       - name: Run linter
45 |         run: pnpm lint
46 | 
47 |       - name: Run tests
48 |         run: pnpm test:ci
49 | 
50 |       - name: Upload coverage reports to Codecov
51 |         uses: codecov/codecov-action@v4
52 |         env:
53 |           CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
54 |         with:
55 |           flags: unittests
56 |           name: codecov-unittests
57 |           fail_ci_if_error: false
58 | 
59 |       - name: Upload results to Codecov
60 |         if: ${{ !cancelled() }}
61 |         uses: codecov/test-results-action@v1
62 |         with:
63 |           token: ${{ secrets.CODECOV_TOKEN }}
64 | 
65 |       - name: Publish Test Report
66 |         uses: mikepenz/action-junit-report@cf701569b05ccdd861a76b8607a66d76f6fd4857
67 |         if: ${{ !cancelled() }}
68 |         with:
69 |           report_paths: "**/*.junit.xml"
70 |           comment: false
71 | 
```

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

```json
 1 | {
 2 |   "namespace": "cassandra",
 3 |   "description": "This section defines attributes for Cassandra.\n",
 4 |   "attributes": {
 5 |     "cassandra.coordinator.dc": {
 6 |       "description": "The data center of the coordinating node for a query.\n",
 7 |       "type": "string",
 8 |       "stability": "development",
 9 |       "examples": ["us-west-2"]
10 |     },
11 |     "cassandra.coordinator.id": {
12 |       "description": "The ID of the coordinating node for a query.\n",
13 |       "type": "string",
14 |       "stability": "development",
15 |       "examples": ["be13faa2-8574-4d71-926d-27f16cf8a7af"]
16 |     },
17 |     "cassandra.consistency.level": {
18 |       "description": "The consistency level of the query. Based on consistency values from [CQL](https://docs.datastax.com/en/cassandra-oss/3.0/cassandra/dml/dmlConfigConsistency.html).\n",
19 |       "type": "string",
20 |       "stability": "development",
21 |       "examples": [
22 |         "all",
23 |         "each_quorum",
24 |         "quorum",
25 |         "local_quorum",
26 |         "one",
27 |         "two",
28 |         "three",
29 |         "local_one",
30 |         "any",
31 |         "serial",
32 |         "local_serial"
33 |       ]
34 |     },
35 |     "cassandra.query.idempotent": {
36 |       "description": "Whether or not the query is idempotent.\n",
37 |       "type": "boolean",
38 |       "stability": "development"
39 |     },
40 |     "cassandra.page.size": {
41 |       "description": "The fetch size used for paging, i.e. how many rows will be returned at once.\n",
42 |       "type": "number",
43 |       "stability": "development",
44 |       "examples": ["5000"]
45 |     },
46 |     "cassandra.speculative_execution.count": {
47 |       "description": "The number of times a query was speculatively executed. Not set or `0` if the query was not executed speculatively.\n",
48 |       "type": "number",
49 |       "stability": "development",
50 |       "examples": ["0", "2"]
51 |     }
52 |   }
53 | }
54 | 
```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/components/ui/json-schema-params.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | type JsonSchema =
 2 |   | {
 3 |       properties?: Record<string, { description?: string } | undefined>;
 4 |       required?: string[];
 5 |     }
 6 |   | null
 7 |   | undefined;
 8 | 
 9 | interface JsonSchemaParamsProps {
10 |   schema: unknown;
11 |   title?: string;
12 | }
13 | 
14 | /**
15 |  * Renders a standardized Parameters box from a JSON Schema-like object.
16 |  * - Expects an object with a `properties` map; falls back to a flat key->description map.
17 |  * - Returns null when there are no parameters to display.
18 |  */
19 | export default function JsonSchemaParams({
20 |   schema,
21 |   title = "Parameters",
22 | }: JsonSchemaParamsProps) {
23 |   let entries: Array<[string, { description?: string } | undefined]> = [];
24 | 
25 |   const obj = (schema as JsonSchema) ?? undefined;
26 |   if (obj && typeof obj === "object" && "properties" in obj) {
27 |     const props = obj.properties;
28 |     if (props && Object.keys(props).length > 0) {
29 |       entries = Object.entries(props);
30 |     }
31 |   } else if (schema && typeof schema === "object") {
32 |     const flat = schema as Record<string, { description?: string } | undefined>;
33 |     const keys = Object.keys(flat);
34 |     if (keys.length > 0) {
35 |       entries = Object.entries(flat);
36 |     }
37 |   }
38 | 
39 |   if (entries.length === 0) return null;
40 | 
41 |   return (
42 |     <section className="rounded-md border border-slate-700/60 bg-black/30 p-3">
43 |       <div className="text-xs uppercase tracking-wide text-slate-300/80 mb-1">
44 |         {title}
45 |       </div>
46 |       <dl className="space-y-0">
47 |         {entries.map(([key, property]) => (
48 |           <div key={key} className="p-2 bg-black/20">
49 |             <dt className="text-sm font-medium text-violet-300">{key}</dt>
50 |             <dd className="text-sm text-slate-300 mt-0.5">
51 |               {property?.description || ""}
52 |             </dd>
53 |           </div>
54 |         ))}
55 |       </dl>
56 |     </section>
57 |   );
58 | }
59 | 
```

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

```typescript
 1 | import { useState, useEffect, useRef } from "react";
 2 | 
 3 | interface TypewriterProps {
 4 |   text: string;
 5 |   speed?: number;
 6 |   children?: (displayedText: string) => React.ReactNode;
 7 |   className?: string;
 8 |   onComplete?: () => void;
 9 | }
10 | 
11 | export function Typewriter({
12 |   text,
13 |   speed = 30,
14 |   children,
15 |   className = "",
16 |   onComplete,
17 | }: TypewriterProps) {
18 |   const [displayedText, setDisplayedText] = useState("");
19 |   const [isComplete, setIsComplete] = useState(false);
20 |   const indexRef = useRef(0);
21 |   const previousTextRef = useRef("");
22 | 
23 |   useEffect(() => {
24 |     // Reset if text has changed (new content streaming in)
25 |     if (text !== previousTextRef.current) {
26 |       const previousText = previousTextRef.current;
27 | 
28 |       // Check if new text is an extension of the previous text
29 |       if (text.startsWith(previousText) && text.length > previousText.length) {
30 |         // Text got longer, continue from where we left off
31 |         indexRef.current = Math.max(displayedText.length, previousText.length);
32 |       } else {
33 |         // Text completely changed, restart
34 |         indexRef.current = 0;
35 |         setDisplayedText("");
36 |         setIsComplete(false);
37 |       }
38 | 
39 |       previousTextRef.current = text;
40 |     }
41 | 
42 |     if (indexRef.current >= text.length) {
43 |       if (!isComplete) {
44 |         setIsComplete(true);
45 |         onComplete?.();
46 |       }
47 |       return;
48 |     }
49 | 
50 |     const timer = setTimeout(() => {
51 |       setDisplayedText(text.slice(0, indexRef.current + 1));
52 |       indexRef.current++;
53 |     }, speed);
54 | 
55 |     return () => clearTimeout(timer);
56 |   }, [text, speed, displayedText.length, isComplete, onComplete]);
57 | 
58 |   return (
59 |     <span className={className}>
60 |       {children ? children(displayedText) : displayedText}
61 |       {!isComplete && <span className="animate-pulse">|</span>}
62 |     </span>
63 |   );
64 | }
65 | 
```

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

```typescript
 1 | import { config } from "dotenv";
 2 | import path from "node:path";
 3 | import { fileURLToPath } from "node:url";
 4 | import { startMockServer } from "@sentry/mcp-server-mocks";
 5 | import type { ServerContext } from "./types.js";
 6 | 
 7 | const __dirname = path.dirname(fileURLToPath(import.meta.url));
 8 | const rootDir = path.resolve(__dirname, "../../../");
 9 | 
10 | // Load environment variables from multiple possible locations
11 | // IMPORTANT: Do NOT use override:true as it would overwrite shell/CI environment variables
12 | 
13 | // Load local package .env first (for package-specific overrides)
14 | config({ path: path.resolve(__dirname, "../.env") });
15 | 
16 | // Load root .env second (for shared defaults - won't override local or shell vars)
17 | config({ path: path.join(rootDir, ".env") });
18 | 
19 | startMockServer({ ignoreOpenAI: true });
20 | 
21 | /**
22 |  * Creates a ServerContext for testing with default values and optional overrides.
23 |  *
24 |  * @param overrides - Partial ServerContext to override default values
25 |  * @returns Complete ServerContext for testing
26 |  *
27 |  * @example
28 |  * ```typescript
29 |  * // Default context
30 |  * const context = getServerContext();
31 |  *
32 |  * // With constraint overrides
33 |  * const context = getServerContext({
34 |  *   constraints: { organizationSlug: "my-org" }
35 |  * });
36 |  *
37 |  * // With user override
38 |  * const context = getServerContext({
39 |  *   userId: "custom-user-id"
40 |  * });
41 |  * ```
42 |  */
43 | export function getServerContext(
44 |   overrides: Partial<ServerContext> = {},
45 | ): ServerContext {
46 |   const defaultContext: ServerContext = {
47 |     accessToken: "access-token",
48 |     userId: "1",
49 |     constraints: {
50 |       organizationSlug: null,
51 |       projectSlug: null,
52 |     },
53 |   };
54 | 
55 |   return {
56 |     ...defaultContext,
57 |     ...overrides,
58 |     // Ensure constraints are properly merged
59 |     constraints: {
60 |       ...defaultContext.constraints,
61 |       ...overrides.constraints,
62 |     },
63 |   };
64 | }
65 | 
```

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

```typescript
 1 | import { defineTool } from "../internal/tool-helpers/define";
 2 | import { apiServiceFromContext } from "../internal/tool-helpers/api";
 3 | import type { ServerContext } from "../types";
 4 | 
 5 | export default defineTool({
 6 |   name: "whoami",
 7 |   description: [
 8 |     "Identify the authenticated user in Sentry.",
 9 |     "",
10 |     "Use this tool when you need to:",
11 |     "- Get the user's name and email address.",
12 |   ].join("\n"),
13 |   inputSchema: {},
14 |   requiredScopes: [], // No specific scopes required - uses authentication token
15 |   annotations: {
16 |     readOnlyHint: true,
17 |     openWorldHint: true,
18 |   },
19 |   async handler(params, context: ServerContext) {
20 |     // User data endpoints (like /auth/) should never use regionUrl
21 |     // as they must always query the main API server, not region-specific servers
22 |     const apiService = apiServiceFromContext(context);
23 |     // API client will throw ApiClientError/ApiServerError which the MCP server wrapper handles
24 |     const user = await apiService.getAuthenticatedUser();
25 | 
26 |     let output = `You are authenticated as ${user.name} (${user.email}).\n\nYour Sentry User ID is ${user.id}.`;
27 | 
28 |     // Add constraints information
29 |     const constraints = context.constraints;
30 |     if (
31 |       constraints.organizationSlug ||
32 |       constraints.projectSlug ||
33 |       constraints.regionUrl
34 |     ) {
35 |       output += "\n\n## Session Constraints\n\n";
36 | 
37 |       if (constraints.organizationSlug) {
38 |         output += `- **Organization**: ${constraints.organizationSlug}\n`;
39 |       }
40 |       if (constraints.projectSlug) {
41 |         output += `- **Project**: ${constraints.projectSlug}\n`;
42 |       }
43 |       if (constraints.regionUrl) {
44 |         output += `- **Region URL**: ${constraints.regionUrl}\n`;
45 |       }
46 | 
47 |       output += "\nThese constraints limit the scope of this MCP session.";
48 |     }
49 | 
50 |     return output;
51 |   },
52 | });
53 | 
```

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

```json
 1 | {
 2 |   "logs": 0,
 3 |   "errors": 0,
 4 |   "performance_issues": 0,
 5 |   "span_count": 112.0,
 6 |   "transaction_child_count_map": [
 7 |     {
 8 |       "transaction.event_id": "0daf40dc453a429c8c57e4c215c4e82c",
 9 |       "count()": 10.0
10 |     },
11 |     {
12 |       "transaction.event_id": "845c0f1eb7544741a9d08cf28e144f42",
13 |       "count()": 1.0
14 |     },
15 |     {
16 |       "transaction.event_id": "b49a5b53cba046a2bab9323d8f00de96",
17 |       "count()": 7.0
18 |     },
19 |     {
20 |       "transaction.event_id": "c0db3d88529744d393f091b692c024ca",
21 |       "count()": 11.0
22 |     },
23 |     {
24 |       "transaction.event_id": "ee6e7f39107847f980e06119bf116d38",
25 |       "count()": 7.0
26 |     },
27 |     {
28 |       "transaction.event_id": "efa09ae9091e400e8865fe48aaae80d6",
29 |       "count()": 12.0
30 |     },
31 |     {
32 |       "transaction.event_id": "f398bbc635c64e2091d94679dade2957",
33 |       "count()": 3.0
34 |     },
35 |     {
36 |       "transaction.event_id": "f531c48c3eaa43be9587dd880b8ec4bb",
37 |       "count()": 6.0
38 |     },
39 |     {
40 |       "transaction.event_id": "f779775e1c6a4f09b62d68818a25d7b5",
41 |       "count()": 55.0
42 |     }
43 |   ],
44 |   "span_count_map": {
45 |     "cache.get": 41.0,
46 |     "middleware.django": 24.0,
47 |     "db": 11.0,
48 |     "function": 6.0,
49 |     "db.redis": 4.0,
50 |     "feature.flagpole.batch_has": 4.0,
51 |     "processor": 2.0,
52 |     "execute": 2.0,
53 |     "fetch_organization_projects": 2.0,
54 |     "other": 1.0,
55 |     "db.clickhouse": 1.0,
56 |     "validator": 1.0,
57 |     "serialize": 1.0,
58 |     "http.client": 1.0,
59 |     "base.paginate.on_results": 1.0,
60 |     "ratelimit.__call__": 1.0,
61 |     "base.dispatch.request": 1.0,
62 |     "discover.endpoint": 1.0,
63 |     "serialize.iterate": 1.0,
64 |     "base.dispatch.setup": 1.0,
65 |     "serialize.get_attrs": 1.0,
66 |     "build_plan.storage_query_plan_builder": 1.0,
67 |     "serialize.get_attrs.project.options": 1.0,
68 |     "check_object_permissions_on_organization": 1.0,
69 |     "allocation_policy.get_quota_allowance": 1.0
70 |   }
71 | }
72 | 
```

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

```json
 1 | {
 2 |   "namespace": "mcp",
 3 |   "description": "Model Context Protocol attributes for MCP tool calls and sessions",
 4 |   "attributes": {
 5 |     "mcp.tool.name": {
 6 |       "description": "Tool name (e.g., search_issues, search_events)",
 7 |       "type": "string",
 8 |       "examples": [
 9 |         "search_issues",
10 |         "search_events",
11 |         "get_issue_details",
12 |         "update_issue"
13 |       ]
14 |     },
15 |     "mcp.session.id": {
16 |       "description": "MCP session identifier",
17 |       "type": "string"
18 |     },
19 |     "mcp.transport": {
20 |       "description": "MCP transport protocol used",
21 |       "type": "string",
22 |       "examples": ["stdio", "http", "websocket"]
23 |     },
24 |     "mcp.request.id": {
25 |       "description": "MCP request identifier",
26 |       "type": "string"
27 |     },
28 |     "mcp.response.status": {
29 |       "description": "MCP response status",
30 |       "type": "string",
31 |       "examples": ["success", "error"]
32 |     },
33 |     "mcp.client.name": {
34 |       "description": "Name of the MCP client application",
35 |       "type": "string",
36 |       "examples": [
37 |         "Cursor",
38 |         "Claude Code",
39 |         "VSCode MCP Extension",
40 |         "sentry-mcp-stdio"
41 |       ]
42 |     },
43 |     "mcp.client.version": {
44 |       "description": "Version of the MCP client application",
45 |       "type": "string",
46 |       "examples": ["0.16.0", "1.0.0", "2.3.1"]
47 |     },
48 |     "mcp.server.name": {
49 |       "description": "Name of the MCP server application",
50 |       "type": "string",
51 |       "examples": ["Sentry MCP Server", "GitHub MCP Server", "Slack MCP Server"]
52 |     },
53 |     "mcp.server.version": {
54 |       "description": "Version of the MCP server application",
55 |       "type": "string",
56 |       "examples": ["0.1.0", "1.2.3", "2.0.0"]
57 |     },
58 |     "mcp.protocol.version": {
59 |       "description": "MCP protocol version being used",
60 |       "type": "string",
61 |       "examples": ["2024-11-05", "1.0", "2.0"]
62 |     }
63 |   },
64 |   "custom": true
65 | }
66 | 
```

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

```json
 1 | {
 2 |   "namespace": "cloudevents",
 3 |   "description": "This document defines attributes for CloudEvents.\n",
 4 |   "attributes": {
 5 |     "cloudevents.event_id": {
 6 |       "description": "The [event_id](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#id) uniquely identifies the event.\n",
 7 |       "type": "string",
 8 |       "stability": "development",
 9 |       "examples": ["123e4567-e89b-12d3-a456-426614174000", "0001"]
10 |     },
11 |     "cloudevents.event_source": {
12 |       "description": "The [source](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#source-1) identifies the context in which an event happened.\n",
13 |       "type": "string",
14 |       "stability": "development",
15 |       "examples": [
16 |         "https://github.com/cloudevents",
17 |         "/cloudevents/spec/pull/123",
18 |         "my-service"
19 |       ]
20 |     },
21 |     "cloudevents.event_spec_version": {
22 |       "description": "The [version of the CloudEvents specification](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#specversion) which the event uses.\n",
23 |       "type": "string",
24 |       "stability": "development",
25 |       "examples": ["1.0"]
26 |     },
27 |     "cloudevents.event_type": {
28 |       "description": "The [event_type](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#type) contains a value describing the type of event related to the originating occurrence.\n",
29 |       "type": "string",
30 |       "stability": "development",
31 |       "examples": [
32 |         "com.github.pull_request.opened",
33 |         "com.example.object.deleted.v2"
34 |       ]
35 |     },
36 |     "cloudevents.event_subject": {
37 |       "description": "The [subject](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#subject) of the event in the context of the event producer (identified by source).\n",
38 |       "type": "string",
39 |       "stability": "development",
40 |       "examples": ["mynewfile.jpg"]
41 |     }
42 |   }
43 | }
44 | 
```

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

```json
 1 | {
 2 |   "namespace": "aspnetcore",
 3 |   "description": "ASP.NET Core attributes",
 4 |   "attributes": {
 5 |     "aspnetcore.rate_limiting.policy": {
 6 |       "description": "Rate limiting policy name.",
 7 |       "type": "string",
 8 |       "stability": "stable",
 9 |       "examples": ["fixed", "sliding", "token"]
10 |     },
11 |     "aspnetcore.rate_limiting.result": {
12 |       "description": "Rate-limiting result, shows whether the lease was acquired or contains a rejection reason",
13 |       "type": "string",
14 |       "stability": "stable",
15 |       "examples": [
16 |         "acquired",
17 |         "endpoint_limiter",
18 |         "global_limiter",
19 |         "request_canceled"
20 |       ]
21 |     },
22 |     "aspnetcore.routing.is_fallback": {
23 |       "description": "A value that indicates whether the matched route is a fallback route.",
24 |       "type": "boolean",
25 |       "stability": "stable",
26 |       "examples": ["true"]
27 |     },
28 |     "aspnetcore.diagnostics.handler.type": {
29 |       "description": "Full type name of the [`IExceptionHandler`](https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.diagnostics.iexceptionhandler) implementation that handled the exception.",
30 |       "type": "string",
31 |       "stability": "stable",
32 |       "examples": ["Contoso.MyHandler"]
33 |     },
34 |     "aspnetcore.request.is_unhandled": {
35 |       "description": "Flag indicating if request was handled by the application pipeline.",
36 |       "type": "boolean",
37 |       "stability": "stable",
38 |       "examples": ["true"]
39 |     },
40 |     "aspnetcore.routing.match_status": {
41 |       "description": "Match result - success or failure",
42 |       "type": "string",
43 |       "stability": "stable",
44 |       "examples": ["success", "failure"]
45 |     },
46 |     "aspnetcore.diagnostics.exception.result": {
47 |       "description": "ASP.NET Core exception middleware handling result",
48 |       "type": "string",
49 |       "stability": "stable",
50 |       "examples": ["handled", "unhandled", "skipped", "aborted"]
51 |     }
52 |   }
53 | }
54 | 
```

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

```typescript
 1 | import { Copy, Check } from "lucide-react";
 2 | import { useState, useEffect, useRef } from "react";
 3 | import { Button } from "./button";
 4 | 
 5 | export default function CodeSnippet({
 6 |   snippet,
 7 |   noMargin,
 8 | }: {
 9 |   snippet: string;
10 |   noMargin?: boolean;
11 | }) {
12 |   const [copied, setCopied] = useState(false);
13 |   const timeoutRef = useRef<number | null>(null);
14 | 
15 |   // Clean up timeout on unmount
16 |   useEffect(() => {
17 |     return () => {
18 |       if (timeoutRef.current) {
19 |         clearTimeout(timeoutRef.current);
20 |       }
21 |     };
22 |   }, []);
23 | 
24 |   const handleCopy = async () => {
25 |     try {
26 |       await navigator.clipboard.writeText(snippet);
27 |       // Only show success if the operation actually succeeded
28 |       setCopied(true);
29 | 
30 |       // Clear any existing timeout before setting a new one
31 |       if (timeoutRef.current) {
32 |         clearTimeout(timeoutRef.current);
33 |       }
34 | 
35 |       timeoutRef.current = setTimeout(() => {
36 |         setCopied(false);
37 |         timeoutRef.current = null;
38 |       }, 2000);
39 |     } catch (error) {
40 |       // Handle clipboard write failure silently or you could show an error state
41 |       console.error("Failed to copy to clipboard:", error);
42 |     }
43 |   };
44 | 
45 |   return (
46 |     <div className={`relative text-white ${noMargin ? "" : "mb-6"}`}>
47 |       <div className="absolute top-2.5 right-2.5 flex items-center justify-end">
48 |         <Button
49 |           variant="ghost"
50 |           size="icon"
51 |           className="h-8 w-8 text-slate-500 cursor-pointer"
52 |           onClick={handleCopy}
53 |         >
54 |           {copied ? (
55 |             <Check className="h-4 w-4 text-green-500" />
56 |           ) : (
57 |             <Copy className="h-4 w-4 text-slate-500" />
58 |           )}
59 |           <span className="sr-only">Copy Snippet</span>
60 |         </Button>
61 |       </div>
62 |       <pre
63 |         className="p-4 overflow-x-auto text-slate-200 text-sm bg-slate-950"
64 |         style={{ margin: 0 }}
65 |       >
66 |         {snippet}
67 |       </pre>
68 |     </div>
69 |   );
70 | }
71 | 
```

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

```typescript
 1 | import { describeEval } from "vitest-evals";
 2 | import { FIXTURES, NoOpTaskRunner, ToolPredictionScorer } from "./utils";
 3 | 
 4 | describeEval("update-issue", {
 5 |   data: async () => {
 6 |     return [
 7 |       // Core use case: Resolve an issue
 8 |       {
 9 |         input: `Resolve the issue ${FIXTURES.issueId} in organization ${FIXTURES.organizationSlug}. Output only the new status as a single word.`,
10 |         expectedTools: [
11 |           {
12 |             name: "find_organizations",
13 |             arguments: {},
14 |           },
15 |           {
16 |             name: "update_issue",
17 |             arguments: {
18 |               organizationSlug: FIXTURES.organizationSlug,
19 |               issueId: FIXTURES.issueId,
20 |               status: "resolved",
21 |               regionUrl: "https://us.sentry.io",
22 |             },
23 |           },
24 |         ],
25 |       },
26 |       // Core use case: Assign an issue
27 |       {
28 |         input: `Assign the issue ${FIXTURES.issueId} in organization ${FIXTURES.organizationSlug} to 'john.doe'. Output only the assigned username.`,
29 |         expectedTools: [
30 |           {
31 |             name: "find_organizations",
32 |             arguments: {},
33 |           },
34 |           {
35 |             name: "update_issue",
36 |             arguments: {
37 |               organizationSlug: FIXTURES.organizationSlug,
38 |               issueId: FIXTURES.issueId,
39 |               assignedTo: "john.doe",
40 |               regionUrl: "https://us.sentry.io",
41 |             },
42 |           },
43 |         ],
44 |       },
45 |       // Core use case: Using issue URL (alternative input method)
46 |       {
47 |         input: `Resolve the issue at ${FIXTURES.issueUrl}. Output only the new status as a single word.`,
48 |         expectedTools: [
49 |           {
50 |             name: "update_issue",
51 |             arguments: {
52 |               issueUrl: FIXTURES.issueUrl,
53 |               status: "resolved",
54 |             },
55 |           },
56 |         ],
57 |       },
58 |     ];
59 |   },
60 |   task: NoOpTaskRunner(),
61 |   scorers: [ToolPredictionScorer()],
62 |   threshold: 0.6,
63 |   timeout: 30000,
64 | });
65 | 
```

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

```typescript
 1 | import { z } from "zod";
 2 | import { setTag } from "@sentry/core";
 3 | import { defineTool } from "../internal/tool-helpers/define";
 4 | import { apiServiceFromContext } from "../internal/tool-helpers/api";
 5 | import type { ServerContext } from "../types";
 6 | import { ParamOrganizationSlug, ParamRegionUrl } from "../schema";
 7 | 
 8 | export default defineTool({
 9 |   name: "create_team",
10 |   requiredScopes: ["team:write"],
11 |   description: [
12 |     "Create a new team in Sentry.",
13 |     "",
14 |     "🔍 USE THIS TOOL WHEN USERS WANT TO:",
15 |     "- 'Create a new team'",
16 |     "- 'Set up a team called [X]'",
17 |     "- 'I need a team for my project'",
18 |     "",
19 |     "Be careful when using this tool!",
20 |     "",
21 |     "<examples>",
22 |     "### Create a new team",
23 |     "```",
24 |     "create_team(organizationSlug='my-organization', name='the-goats')",
25 |     "```",
26 |     "</examples>",
27 |     "",
28 |     "<hints>",
29 |     "- If any parameter is ambiguous, you should clarify with the user what they meant.",
30 |     "</hints>",
31 |   ].join("\n"),
32 |   inputSchema: {
33 |     organizationSlug: ParamOrganizationSlug,
34 |     regionUrl: ParamRegionUrl.optional(),
35 |     name: z.string().trim().describe("The name of the team to create."),
36 |   },
37 |   annotations: {
38 |     readOnlyHint: false,
39 |     destructiveHint: false,
40 |     openWorldHint: true,
41 |   },
42 |   async handler(params, context: ServerContext) {
43 |     const apiService = apiServiceFromContext(context, {
44 |       regionUrl: params.regionUrl,
45 |     });
46 |     const organizationSlug = params.organizationSlug;
47 | 
48 |     setTag("organization.slug", organizationSlug);
49 | 
50 |     const team = await apiService.createTeam({
51 |       organizationSlug,
52 |       name: params.name,
53 |     });
54 |     let output = `# New Team in **${organizationSlug}**\n\n`;
55 |     output += `**ID**: ${team.id}\n`;
56 |     output += `**Slug**: ${team.slug}\n`;
57 |     output += `**Name**: ${team.name}\n`;
58 |     output += "# Using this information\n\n";
59 |     output += `- You should always inform the user of the Team Slug value.\n`;
60 |     return output;
61 |   },
62 | });
63 | 
```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/index.html:
--------------------------------------------------------------------------------

```html
 1 | <!doctype html>
 2 | <html lang="en">
 3 | 
 4 | <head>
 5 |   <meta charset="UTF-8" />
 6 |   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 7 |   <title>Sentry MCP</title>
 8 |   <link href="./src/client/index.css" rel="stylesheet" />
 9 |   <link rel="icon" href="/favicon.ico" />
10 |   <!-- Primary Meta Tags -->
11 |   <meta name="title" content="Sentry MCP" />
12 |   <meta name="description" content="A Model Context Protocol implementation for interacting with Sentry." />
13 | 
14 |   <!-- Open Graph / Facebook -->
15 |   <meta property="og:type" content="website" />
16 |   <meta property="og:url" content="https://mcp.sentry.dev/" />
17 |   <meta property="og:title" content="A model context protocol implementation for interacting with Sentry." />
18 |   <meta property="og:description"
19 |     content="Simply put, its a way to plug Sentry's API into an LLM, letting you ask questions about your data in context of the LLM itself. This lets you take an agent that you already use, like Cursor, and pull in additional information from Sentry to help with tasks like debugging, code generation, and more." />
20 |   <meta property="og:image" content="https://mcp.sentry.dev/flow.jpg" />
21 | 
22 |   <!-- Twitter -->
23 |   <meta property="twitter:card" content="summary_large_image" />
24 |   <meta property="twitter:url" content="https://mcp.sentry.dev/" />
25 |   <meta property="twitter:title" content="A model context protocol implementation for interacting with Sentry." />
26 |   <meta property="twitter:description"
27 |     content="Simply put, its a way to plug Sentry's API into an LLM, letting you ask questions about your data in context of the LLM itself. This lets you take an agent that you already use, like Cursor, and pull in additional information from Sentry to help with tasks like debugging, code generation, and more." />
28 |   <meta property="twitter:image" content="https://mcp.sentry.dev/flow.jpg" />
29 | </head>
30 | 
31 | <body>
32 |   <div id="root"></div>
33 |   <script type="module" src="./src/client/main.tsx"></script>
34 | </body>
35 | 
36 | </html>
37 | 
```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/tool-helpers/validate-region-url.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { UserInputError } from "../../errors";
 2 | import { SENTRY_ALLOWED_REGION_DOMAINS } from "../../constants";
 3 | 
 4 | /**
 5 |  * Validates that a regionUrl is valid.
 6 |  * Prevents SSRF attacks by only allowing the base host itself or domains from an allowlist.
 7 |  *
 8 |  * Rules:
 9 |  * 1. By default, only the base host itself is allowed as regionUrl
10 |  * 2. For other domains, they must be in SENTRY_ALLOWED_REGION_DOMAINS
11 |  * 3. Protocol MUST be HTTPS for security
12 |  *
13 |  * @param regionUrl - The region URL to validate
14 |  * @param baseHost - The base host to validate against
15 |  * @returns The validated host if valid
16 |  * @throws {UserInputError} If the regionUrl is invalid or not allowed
17 |  */
18 | export function validateRegionUrl(regionUrl: string, baseHost: string): string {
19 |   let parsedUrl: URL;
20 |   try {
21 |     parsedUrl = new URL(regionUrl);
22 |   } catch {
23 |     throw new UserInputError(
24 |       `Invalid regionUrl provided: ${regionUrl}. Must be a valid URL.`,
25 |     );
26 |   }
27 | 
28 |   // Validate protocol - MUST be HTTPS for security
29 |   if (parsedUrl.protocol !== "https:") {
30 |     throw new UserInputError(
31 |       `Invalid regionUrl provided: ${regionUrl}. Must use HTTPS protocol for security.`,
32 |     );
33 |   }
34 | 
35 |   // Validate that the host is not just the protocol name
36 |   if (parsedUrl.host === "https" || parsedUrl.host === "http") {
37 |     throw new UserInputError(
38 |       `Invalid regionUrl provided: ${regionUrl}. The host cannot be just a protocol name.`,
39 |     );
40 |   }
41 | 
42 |   const regionHost = parsedUrl.host.toLowerCase();
43 |   const baseLower = baseHost.toLowerCase();
44 | 
45 |   // First, allow if it's the same as the base host
46 |   if (regionHost === baseLower) {
47 |     return regionHost;
48 |   }
49 | 
50 |   // Otherwise, check against the allowlist
51 |   if (!SENTRY_ALLOWED_REGION_DOMAINS.has(regionHost)) {
52 |     throw new UserInputError(
53 |       `Invalid regionUrl: ${regionUrl}. The domain '${regionHost}' is not allowed. Allowed domains are: ${Array.from(SENTRY_ALLOWED_REGION_DOMAINS).join(", ")}`,
54 |     );
55 |   }
56 | 
57 |   return regionHost;
58 | }
59 | 
```

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

```typescript
 1 | import { z } from "zod";
 2 | import type { SentryApiService } from "../../api-client";
 3 | import { ConfigurationError } from "../../errors";
 4 | import { callEmbeddedAgent } from "../../internal/agents/callEmbeddedAgent";
 5 | import { createDatasetFieldsTool } from "../../internal/agents/tools/dataset-fields";
 6 | import { createWhoamiTool } from "../../internal/agents/tools/whoami";
 7 | import { systemPrompt } from "./config";
 8 | 
 9 | const outputSchema = z.object({
10 |   query: z
11 |     .string()
12 |     .default("")
13 |     .nullish()
14 |     .describe("The Sentry issue search query"),
15 |   sort: z
16 |     .enum(["date", "freq", "new", "user"])
17 |     .default("date")
18 |     .nullish()
19 |     .describe("How to sort the results"),
20 |   explanation: z
21 |     .string()
22 |     .describe("Brief explanation of how you translated this query."),
23 | });
24 | 
25 | export interface SearchIssuesAgentOptions {
26 |   query: string;
27 |   organizationSlug: string;
28 |   apiService: SentryApiService;
29 |   projectId?: string;
30 | }
31 | 
32 | /**
33 |  * Search issues agent - single entry point for translating natural language queries to Sentry issue search syntax
34 |  * This returns both the translated query result AND the tool calls made by the agent
35 |  */
36 | export async function searchIssuesAgent(
37 |   options: SearchIssuesAgentOptions,
38 | ): Promise<{
39 |   result: z.infer<typeof outputSchema>;
40 |   toolCalls: any[];
41 | }> {
42 |   if (!process.env.OPENAI_API_KEY) {
43 |     throw new ConfigurationError(
44 |       "OPENAI_API_KEY environment variable is required for semantic search",
45 |     );
46 |   }
47 | 
48 |   // Create tools pre-bound with the provided API service and organization
49 |   return await callEmbeddedAgent({
50 |     system: systemPrompt,
51 |     prompt: options.query,
52 |     tools: {
53 |       issueFields: createDatasetFieldsTool({
54 |         apiService: options.apiService,
55 |         organizationSlug: options.organizationSlug,
56 |         dataset: "search_issues",
57 |         projectId: options.projectId,
58 |       }),
59 |       whoami: createWhoamiTool({ apiService: options.apiService }),
60 |     },
61 |     schema: outputSchema,
62 |   });
63 | }
64 | 
```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/hooks/use-mcp-metadata.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Custom hook to fetch and manage MCP metadata
 3 |  *
 4 |  * Provides immediate access to prompts and tools without waiting for chat stream
 5 |  */
 6 | import { useState, useEffect, useCallback } from "react";
 7 | 
 8 | export interface McpMetadata {
 9 |   type: "mcp-metadata";
10 |   prompts: Array<{
11 |     name: string;
12 |     description: string;
13 |     parameters: Record<
14 |       string,
15 |       {
16 |         type: string;
17 |         required: boolean;
18 |         description?: string;
19 |       }
20 |     >;
21 |   }>;
22 |   tools: string[];
23 |   resources?: Array<{
24 |     name: string;
25 |     description: string;
26 |   }>;
27 |   timestamp: string;
28 | }
29 | 
30 | interface UseMcpMetadataResult {
31 |   metadata: McpMetadata | null;
32 |   isLoading: boolean;
33 |   error: string | null;
34 |   refetch: () => Promise<void>;
35 | }
36 | 
37 | export function useMcpMetadata(enabled = true): UseMcpMetadataResult {
38 |   const [metadata, setMetadata] = useState<McpMetadata | null>(null);
39 |   const [isLoading, setIsLoading] = useState(false);
40 |   const [error, setError] = useState<string | null>(null);
41 | 
42 |   const fetchMetadata = useCallback(async () => {
43 |     if (!enabled) {
44 |       return;
45 |     }
46 | 
47 |     setIsLoading(true);
48 |     setError(null);
49 | 
50 |     try {
51 |       const response = await fetch("/api/metadata", {
52 |         credentials: "include", // Include cookies
53 |       });
54 | 
55 |       if (!response.ok) {
56 |         const errorData = await response.json().catch(() => ({}));
57 |         throw new Error(errorData.error || `HTTP ${response.status}`);
58 |       }
59 | 
60 |       const data = await response.json();
61 |       setMetadata(data);
62 |     } catch (err) {
63 |       const errorMessage =
64 |         err instanceof Error ? err.message : "Failed to fetch metadata";
65 |       setError(errorMessage);
66 |       console.error("Failed to fetch MCP metadata:", err);
67 |     } finally {
68 |       setIsLoading(false);
69 |     }
70 |   }, [enabled]);
71 | 
72 |   // Fetch metadata when auth token changes or component mounts
73 |   useEffect(() => {
74 |     fetchMetadata();
75 |   }, [fetchMetadata]);
76 | 
77 |   return {
78 |     metadata,
79 |     isLoading,
80 |     error,
81 |     refetch: fetchMetadata,
82 |   };
83 | }
84 | 
```

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

```typescript
 1 | import { describe, it, expect } from "vitest";
 2 | import whoami from "./whoami.js";
 3 | import {
 4 |   createTestContext,
 5 |   createTestContextWithConstraints,
 6 | } from "../test-utils/context.js";
 7 | 
 8 | describe("whoami", () => {
 9 |   it("serializes without constraints", async () => {
10 |     const result = await whoami.handler(
11 |       {},
12 |       createTestContext({
13 |         constraints: {},
14 |         accessToken: "access-token",
15 |         userId: "123456",
16 |       }),
17 |     );
18 |     expect(result).toMatchInlineSnapshot(
19 |       `
20 |       "You are authenticated as Test User ([email protected]).
21 | 
22 |       Your Sentry User ID is 123456."
23 |     `,
24 |     );
25 |   });
26 | 
27 |   it("serializes with constraints", async () => {
28 |     const result = await whoami.handler(
29 |       {},
30 |       createTestContextWithConstraints(
31 |         {
32 |           organizationSlug: "sentry",
33 |           projectSlug: "mcp-server",
34 |           regionUrl: "https://us.sentry.io",
35 |         },
36 |         {
37 |           accessToken: "access-token",
38 |           userId: "123456",
39 |         },
40 |       ),
41 |     );
42 |     expect(result).toMatchInlineSnapshot(
43 |       `
44 |       "You are authenticated as Test User ([email protected]).
45 | 
46 |       Your Sentry User ID is 123456.
47 | 
48 |       ## Session Constraints
49 | 
50 |       - **Organization**: sentry
51 |       - **Project**: mcp-server
52 |       - **Region URL**: https://us.sentry.io
53 | 
54 |       These constraints limit the scope of this MCP session."
55 |     `,
56 |     );
57 |   });
58 | 
59 |   it("serializes with partial constraints", async () => {
60 |     const result = await whoami.handler(
61 |       {},
62 |       createTestContextWithConstraints(
63 |         {
64 |           organizationSlug: "sentry",
65 |         },
66 |         {
67 |           accessToken: "access-token",
68 |           userId: "123456",
69 |         },
70 |       ),
71 |     );
72 |     expect(result).toMatchInlineSnapshot(
73 |       `
74 |       "You are authenticated as Test User ([email protected]).
75 | 
76 |       Your Sentry User ID is 123456.
77 | 
78 |       ## Session Constraints
79 | 
80 |       - **Organization**: sentry
81 | 
82 |       These constraints limit the scope of this MCP session."
83 |     `,
84 |     );
85 |   });
86 | });
87 | 
```

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

```typescript
 1 | /**
 2 |  * Reusable sliding panel component
 3 |  * Handles responsive slide-out behavior
 4 |  */
 5 | 
 6 | import type { ReactNode } from "react";
 7 | import { useScrollLock } from "../../hooks/use-scroll-lock";
 8 | 
 9 | interface SlidingPanelProps {
10 |   isOpen: boolean;
11 |   onClose?: () => void;
12 |   children: ReactNode;
13 |   className?: string;
14 | }
15 | 
16 | export function SlidingPanel({
17 |   isOpen,
18 |   onClose,
19 |   children,
20 |   className = "",
21 | }: SlidingPanelProps) {
22 |   // Lock body scroll when panel is open on mobile
23 |   useScrollLock(isOpen);
24 | 
25 |   return (
26 |     <>
27 |       {/* Mobile: Slide from right */}
28 |       <div
29 |         className={`md:hidden fixed inset-0 bg-transparent max-w-none max-h-none w-full h-full m-0 p-0 z-40 ${
30 |           isOpen ? "" : "pointer-events-none"
31 |         }`}
32 |       >
33 |         {/* Backdrop */}
34 |         <div
35 |           className={`fixed inset-0 bg-black/50 backdrop-blur-sm transition-opacity ${
36 |             isOpen
37 |               ? "opacity-100 pointer-events-auto duration-200"
38 |               : "opacity-0 pointer-events-none duration-300"
39 |           }`}
40 |           onClick={isOpen ? onClose : undefined}
41 |           onKeyDown={
42 |             isOpen ? (e) => e.key === "Escape" && onClose?.() : undefined
43 |           }
44 |           role={isOpen ? "button" : undefined}
45 |           tabIndex={isOpen ? 0 : -1}
46 |           aria-label={isOpen ? "Close panel" : undefined}
47 |         />
48 | 
49 |         {/* Panel */}
50 |         <div
51 |           className={`fixed inset-y-0 right-0 w-full max-w-2xl bg-slate-950 border-l border-slate-800 z-50 shadow-2xl flex flex-col transition-transform duration-500 ease-in-out ${
52 |             isOpen ? "translate-x-0" : "translate-x-full"
53 |           } ${className}`}
54 |         >
55 |           {children}
56 |         </div>
57 |       </div>
58 | 
59 |       {/* Desktop: Fixed right half */}
60 |       <div
61 |         className={`${
62 |           isOpen ? "hidden md:flex" : "hidden"
63 |         } fixed top-0 right-0 h-screen w-1/2 bg-slate-950 flex-col border-l border-slate-800 transition-opacity duration-300 ${className}`}
64 |       >
65 |         {children}
66 |       </div>
67 |     </>
68 |   );
69 | }
70 | 
```

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

```json
 1 | {
 2 |   "namespace": "error",
 3 |   "description": "This document defines the shared attributes used to report an error.\n",
 4 |   "attributes": {
 5 |     "error.type": {
 6 |       "description": "Describes a class of error the operation ended with.\n",
 7 |       "type": "string",
 8 |       "note": "The `error.type` SHOULD be predictable, and SHOULD have low cardinality.\n\nWhen `error.type` is set to a type (e.g., an exception type), its\ncanonical class name identifying the type within the artifact SHOULD be used.\n\nInstrumentations SHOULD document the list of errors they report.\n\nThe cardinality of `error.type` within one instrumentation library SHOULD be low.\nTelemetry consumers that aggregate data from multiple instrumentation libraries and applications\nshould be prepared for `error.type` to have high cardinality at query time when no\nadditional filters are applied.\n\nIf the operation has completed successfully, instrumentations SHOULD NOT set `error.type`.\n\nIf a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes),\nit's RECOMMENDED to:\n\n- Use a domain-specific attribute\n- Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not.\n",
 9 |       "stability": "stable",
10 |       "examples": ["_OTHER"]
11 |     },
12 |     "error.message": {
13 |       "description": "A message providing more detail about an error in human-readable form.",
14 |       "type": "string",
15 |       "note": "`error.message` should provide additional context and detail about an error.\nIt is NOT RECOMMENDED to duplicate the value of `error.type` in `error.message`.\nIt is also NOT RECOMMENDED to duplicate the value of `exception.message` in `error.message`.\n\n`error.message` is NOT RECOMMENDED for metrics or spans due to its unbounded cardinality and overlap with span status.\n",
16 |       "stability": "development",
17 |       "examples": [
18 |         "Unexpected input type: string",
19 |         "The user has exceeded their storage quota"
20 |       ]
21 |     }
22 |   }
23 | }
24 | 
```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/hooks/use-streaming-simulation.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Hook for simulating streaming animation for local messages (like slash commands)
 3 |  * This provides the same UX as AI-generated responses for locally generated content
 4 |  */
 5 | import { useState, useCallback, useRef, useEffect } from "react";
 6 | 
 7 | interface StreamingSimulationState {
 8 |   isStreaming: boolean;
 9 |   streamingMessageId: string | null;
10 | }
11 | 
12 | export function useStreamingSimulation() {
13 |   const [state, setState] = useState<StreamingSimulationState>({
14 |     isStreaming: false,
15 |     streamingMessageId: null,
16 |   });
17 | 
18 |   const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
19 | 
20 |   // Start streaming simulation for a specific message
21 |   const startStreaming = useCallback((messageId: string, duration = 1000) => {
22 |     setState({
23 |       isStreaming: true,
24 |       streamingMessageId: messageId,
25 |     });
26 | 
27 |     // Clear any existing timeout
28 |     if (timeoutRef.current) {
29 |       clearTimeout(timeoutRef.current);
30 |     }
31 | 
32 |     // Stop streaming after the specified duration
33 |     timeoutRef.current = setTimeout(() => {
34 |       setState({
35 |         isStreaming: false,
36 |         streamingMessageId: null,
37 |       });
38 |     }, duration);
39 |   }, []);
40 | 
41 |   // Stop streaming simulation immediately
42 |   const stopStreaming = useCallback(() => {
43 |     if (timeoutRef.current) {
44 |       clearTimeout(timeoutRef.current);
45 |       timeoutRef.current = null;
46 |     }
47 |     setState({
48 |       isStreaming: false,
49 |       streamingMessageId: null,
50 |     });
51 |   }, []);
52 | 
53 |   // Check if a specific message is currently streaming
54 |   const isMessageStreaming = useCallback(
55 |     (messageId: string) => {
56 |       return state.isStreaming && state.streamingMessageId === messageId;
57 |     },
58 |     [state.isStreaming, state.streamingMessageId],
59 |   );
60 | 
61 |   // Cleanup on unmount
62 |   useEffect(() => {
63 |     return () => {
64 |       if (timeoutRef.current) {
65 |         clearTimeout(timeoutRef.current);
66 |       }
67 |     };
68 |   }, []);
69 | 
70 |   return {
71 |     isStreaming: state.isStreaming,
72 |     streamingMessageId: state.streamingMessageId,
73 |     startStreaming,
74 |     stopStreaming,
75 |     isMessageStreaming,
76 |   };
77 | }
78 | 
```

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

```json
  1 | [
  2 |   {
  3 |     "key": "span.op",
  4 |     "name": "Span Operation"
  5 |   },
  6 |   {
  7 |     "key": "span.description",
  8 |     "name": "Span Description"
  9 |   },
 10 |   {
 11 |     "key": "span.status",
 12 |     "name": "Span Status"
 13 |   },
 14 |   {
 15 |     "key": "span.duration",
 16 |     "name": "Span Duration"
 17 |   },
 18 |   {
 19 |     "key": "transaction",
 20 |     "name": "Transaction"
 21 |   },
 22 |   {
 23 |     "key": "transaction.op",
 24 |     "name": "Transaction Operation"
 25 |   },
 26 |   {
 27 |     "key": "transaction.duration",
 28 |     "name": "Transaction Duration"
 29 |   },
 30 |   {
 31 |     "key": "transaction.status",
 32 |     "name": "Transaction Status"
 33 |   },
 34 |   {
 35 |     "key": "project",
 36 |     "name": "Project"
 37 |   },
 38 |   {
 39 |     "key": "environment",
 40 |     "name": "Environment"
 41 |   },
 42 |   {
 43 |     "key": "release",
 44 |     "name": "Release"
 45 |   },
 46 |   {
 47 |     "key": "user.id",
 48 |     "name": "User ID"
 49 |   },
 50 |   {
 51 |     "key": "user.email",
 52 |     "name": "User Email"
 53 |   },
 54 |   {
 55 |     "key": "user.username",
 56 |     "name": "Username"
 57 |   },
 58 |   {
 59 |     "key": "error.type",
 60 |     "name": "Error Type"
 61 |   },
 62 |   {
 63 |     "key": "error.value",
 64 |     "name": "Error Value"
 65 |   },
 66 |   {
 67 |     "key": "error.handled",
 68 |     "name": "Error Handled"
 69 |   },
 70 |   {
 71 |     "key": "message",
 72 |     "name": "Message"
 73 |   },
 74 |   {
 75 |     "key": "level",
 76 |     "name": "Level"
 77 |   },
 78 |   {
 79 |     "key": "platform",
 80 |     "name": "Platform"
 81 |   },
 82 |   {
 83 |     "key": "sdk.name",
 84 |     "name": "SDK Name"
 85 |   },
 86 |   {
 87 |     "key": "sdk.version",
 88 |     "name": "SDK Version"
 89 |   },
 90 |   {
 91 |     "key": "http.method",
 92 |     "name": "HTTP Method"
 93 |   },
 94 |   {
 95 |     "key": "http.status_code",
 96 |     "name": "HTTP Status Code"
 97 |   },
 98 |   {
 99 |     "key": "http.url",
100 |     "name": "HTTP URL"
101 |   },
102 |   {
103 |     "key": "browser.name",
104 |     "name": "Browser Name"
105 |   },
106 |   {
107 |     "key": "os.name",
108 |     "name": "OS Name"
109 |   },
110 |   {
111 |     "key": "device",
112 |     "name": "Device"
113 |   },
114 |   {
115 |     "key": "geo.country_code",
116 |     "name": "Country Code"
117 |   },
118 |   {
119 |     "key": "geo.region",
120 |     "name": "Geographic Region"
121 |   },
122 |   {
123 |     "key": "geo.city",
124 |     "name": "City"
125 |   },
126 |   {
127 |     "key": "custom.tier",
128 |     "name": "Customer Tier"
129 |   },
130 |   {
131 |     "key": "custom.feature_flag",
132 |     "name": "Feature Flag"
133 |   }
134 | ]
135 | 
```

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

```typescript
 1 | /**
 2 |  * Simple terminal output logger for the MCP client.
 3 |  *
 4 |  * In an ideal world, this would use a state manager to track the last active logger,
 5 |  * and it'd accept streams to the log functions. It'd then handle automatically
 6 |  * terminating a previous block, inserting a new block, and restarting the previous
 7 |  * block when streams receive new data. This is just a simplified version as this is
 8 |  * not a big concern in this project.
 9 |  */
10 | 
11 | import chalk from "chalk";
12 | 
13 | let responseStarted = false;
14 | 
15 | export const logError = (msg: string, detail?: any) =>
16 |   process.stdout.write(
17 |     `\n${chalk.red("●")} ${msg}${detail ? `\n  ⎿  ${chalk.gray(detail instanceof Error ? detail.message : detail)}` : ""}\n`,
18 |   );
19 | 
20 | export const logSuccess = (msg: string, detail?: string) =>
21 |   process.stdout.write(
22 |     `\n${chalk.green("●")} ${msg}${detail ? `\n  ⎿  ${chalk.gray(detail)}` : ""}\n`,
23 |   );
24 | 
25 | export const logInfo = (msg: string, detail?: string) =>
26 |   process.stdout.write(
27 |     `\n${chalk.blue("●")} ${msg}${detail ? `\n  ⎿  ${chalk.gray(detail)}` : ""}\n`,
28 |   );
29 | 
30 | export const logUser = (msg: string) =>
31 |   process.stdout.write(`\n${chalk.gray(">")} ${chalk.gray(msg)}\n`);
32 | 
33 | export const logTool = (name: string, args?: any) => {
34 |   const params =
35 |     args && Object.keys(args).length > 0
36 |       ? `(${Object.entries(args)
37 |           .map(
38 |             ([k, v]) =>
39 |               `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`,
40 |           )
41 |           .join(", ")})`
42 |       : "()";
43 |   process.stdout.write(`\n${chalk.green("●")} ${name}${params}\n`);
44 | };
45 | 
46 | export const logToolResult = (msg: string) =>
47 |   process.stdout.write(`  ⎿  ${chalk.white(msg)}\n`);
48 | 
49 | export const logStreamStart = () => {
50 |   if (!responseStarted) {
51 |     process.stdout.write(`\n${chalk.white("●")} `);
52 |     responseStarted = true;
53 |   }
54 | };
55 | 
56 | export const logStreamWrite = (chunk: string) =>
57 |   process.stdout.write(chunk.replace(/\n/g, "\n  "));
58 | 
59 | export const logStreamEnd = () => {
60 |   if (responseStarted) {
61 |     process.stdout.write("\n");
62 |     responseStarted = false;
63 |   }
64 | };
65 | 
```

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

```typescript
 1 | import { describe, it, expect } from "vitest";
 2 | import updateProject from "./update-project.js";
 3 | 
 4 | describe("update_project", () => {
 5 |   it("updates name and platform", async () => {
 6 |     const result = await updateProject.handler(
 7 |       {
 8 |         organizationSlug: "sentry-mcp-evals",
 9 |         projectSlug: "cloudflare-mcp",
10 |         name: "New Project Name",
11 |         slug: undefined,
12 |         platform: "python",
13 |         teamSlug: undefined,
14 |         regionUrl: undefined,
15 |       },
16 |       {
17 |         constraints: {
18 |           organizationSlug: null,
19 |         },
20 |         accessToken: "access-token",
21 |         userId: "1",
22 |       },
23 |     );
24 |     expect(result).toMatchInlineSnapshot(`
25 |       "# Updated Project in **sentry-mcp-evals**
26 | 
27 |       **ID**: 4509109104082945
28 |       **Slug**: cloudflare-mcp
29 |       **Name**: New Project Name
30 |       **Platform**: python
31 | 
32 |       ## Updates Applied
33 |       - Updated name to "New Project Name"
34 |       - Updated platform to "python"
35 | 
36 |       # Using this information
37 | 
38 |       - The project is now accessible at slug: \`cloudflare-mcp\`
39 |       "
40 |     `);
41 |   });
42 | 
43 |   it("assigns project to new team", async () => {
44 |     const result = await updateProject.handler(
45 |       {
46 |         organizationSlug: "sentry-mcp-evals",
47 |         projectSlug: "cloudflare-mcp",
48 |         name: undefined,
49 |         slug: undefined,
50 |         platform: undefined,
51 |         teamSlug: "backend-team",
52 |         regionUrl: undefined,
53 |       },
54 |       {
55 |         constraints: {
56 |           organizationSlug: null,
57 |         },
58 |         accessToken: "access-token",
59 |         userId: "1",
60 |       },
61 |     );
62 |     expect(result).toMatchInlineSnapshot(`
63 |       "# Updated Project in **sentry-mcp-evals**
64 | 
65 |       **ID**: 4509106749636608
66 |       **Slug**: cloudflare-mcp
67 |       **Name**: cloudflare-mcp
68 |       **Platform**: node
69 | 
70 |       ## Updates Applied
71 |       - Updated team assignment to "backend-team"
72 | 
73 |       # Using this information
74 | 
75 |       - The project is now accessible at slug: \`cloudflare-mcp\`
76 |       - The project is now assigned to the \`backend-team\` team
77 |       "
78 |     `);
79 |   });
80 | });
81 | 
```

--------------------------------------------------------------------------------
/packages/mcp-cloudflare/src/client/hooks/use-scroll-lock.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Hook to lock body scroll when a component is active
 3 |  * Handles edge cases like iOS Safari and nested locks
 4 |  */
 5 | 
 6 | import { useEffect, useRef } from "react";
 7 | 
 8 | // Track active locks to handle nested components
 9 | let activeLocks = 0;
10 | let originalStyles: {
11 |   overflow?: string;
12 |   position?: string;
13 |   top?: string;
14 |   width?: string;
15 | } = {};
16 | 
17 | export function useScrollLock(enabled = true) {
18 |   const scrollPositionRef = useRef(0);
19 | 
20 |   useEffect(() => {
21 |     if (!enabled) return;
22 | 
23 |     // Save scroll position and lock scroll
24 |     const lockScroll = () => {
25 |       // First lock - save original styles
26 |       if (activeLocks === 0) {
27 |         scrollPositionRef.current = window.scrollY;
28 | 
29 |         originalStyles = {
30 |           overflow: document.body.style.overflow,
31 |           position: document.body.style.position,
32 |           top: document.body.style.top,
33 |           width: document.body.style.width,
34 |         };
35 | 
36 |         // Apply scroll lock styles
37 |         document.body.style.overflow = "hidden";
38 | 
39 |         // iOS Safari fix - prevent rubber band scrolling
40 |         if (/iPad|iPhone|iPod/.test(navigator.userAgent)) {
41 |           document.body.style.position = "fixed";
42 |           document.body.style.top = `-${scrollPositionRef.current}px`;
43 |           document.body.style.width = "100%";
44 |         }
45 |       }
46 | 
47 |       activeLocks++;
48 |     };
49 | 
50 |     // Restore scroll position and unlock
51 |     const unlockScroll = () => {
52 |       activeLocks--;
53 | 
54 |       // Last lock removed - restore original styles
55 |       if (activeLocks === 0) {
56 |         document.body.style.overflow = originalStyles.overflow || "";
57 |         document.body.style.position = originalStyles.position || "";
58 |         document.body.style.top = originalStyles.top || "";
59 |         document.body.style.width = originalStyles.width || "";
60 | 
61 |         // Restore scroll position for iOS
62 |         if (/iPad|iPhone|iPod/.test(navigator.userAgent)) {
63 |           window.scrollTo(0, scrollPositionRef.current);
64 |         }
65 | 
66 |         originalStyles = {};
67 |       }
68 |     };
69 | 
70 |     lockScroll();
71 | 
72 |     // Cleanup
73 |     return () => {
74 |       unlockScroll();
75 |     };
76 |   }, [enabled]);
77 | }
78 | 
```

--------------------------------------------------------------------------------
/packages/mcp-server/src/internal/context-storage.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Request-scoped context storage using AsyncLocalStorage.
 3 |  *
 4 |  * This module provides per-request storage for the complete ServerContext,
 5 |  * including authentication and constraints extracted from URL patterns.
 6 |  * Used by the Cloudflare Worker MCP handler to make context available
 7 |  * to tool handlers without passing them through every function call.
 8 |  *
 9 |  * The context is stored in AsyncLocalStorage which is supported in:
10 |  * - Node.js (native)
11 |  * - Cloudflare Workers (via compatibility layer)
12 |  * - Other modern JavaScript runtimes
13 |  */
14 | 
15 | import { AsyncLocalStorage } from "node:async_hooks";
16 | import type { ServerContext } from "../types";
17 | 
18 | /**
19 |  * AsyncLocalStorage instance for storing ServerContext per-request.
20 |  *
21 |  * Each MCP request runs within its own async context, ensuring
22 |  * context is isolated between concurrent requests.
23 |  */
24 | export const serverContextStorage = new AsyncLocalStorage<ServerContext>();
25 | 
26 | /**
27 |  * Get the current request's ServerContext from async storage.
28 |  *
29 |  * @returns ServerContext for the current request, or undefined if not in a request context
30 |  *
31 |  * @example
32 |  * ```typescript
33 |  * // In a Cloudflare Worker handler:
34 |  * serverContextStorage.run(context, () => {
35 |  *   // Inside this callback, getServerContext() returns the context
36 |  *   const context = getServerContext();
37 |  * });
38 |  * ```
39 |  */
40 | export function getServerContext(): ServerContext | undefined {
41 |   return serverContextStorage.getStore();
42 | }
43 | 
44 | /**
45 |  * Get the current request's ServerContext from async storage, throwing if not available.
46 |  *
47 |  * Use this when you need the context and it's an error condition if it's missing.
48 |  *
49 |  * @returns ServerContext for the current request
50 |  * @throws Error if no context is available in async storage
51 |  *
52 |  * @example
53 |  * ```typescript
54 |  * // In a tool handler:
55 |  * const context = requireServerContext();
56 |  * // Use context knowing it's always defined
57 |  * ```
58 |  */
59 | export function requireServerContext(): ServerContext {
60 |   const context = serverContextStorage.getStore();
61 |   if (!context) {
62 |     throw new Error("No ServerContext available in async storage");
63 |   }
64 |   return context;
65 | }
66 | 
```

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

```json
 1 | {
 2 |   "namespace": "telemetry",
 3 |   "description": "This document defines attributes for telemetry SDK.\n",
 4 |   "attributes": {
 5 |     "telemetry.sdk.name": {
 6 |       "description": "The name of the telemetry SDK as defined above.\n",
 7 |       "type": "string",
 8 |       "note": "The OpenTelemetry SDK MUST set the `telemetry.sdk.name` attribute to `opentelemetry`.\nIf another SDK, like a fork or a vendor-provided implementation, is used, this SDK MUST set the\n`telemetry.sdk.name` attribute to the fully-qualified class or module name of this SDK's main entry point\nor another suitable identifier depending on the language.\nThe identifier `opentelemetry` is reserved and MUST NOT be used in this case.\nAll custom identifiers SHOULD be stable across different versions of an implementation.\n",
 9 |       "stability": "stable",
10 |       "examples": ["opentelemetry"]
11 |     },
12 |     "telemetry.sdk.language": {
13 |       "description": "The language of the telemetry SDK.\n",
14 |       "type": "string",
15 |       "stability": "stable",
16 |       "examples": [
17 |         "cpp",
18 |         "dotnet",
19 |         "erlang",
20 |         "go",
21 |         "java",
22 |         "nodejs",
23 |         "php",
24 |         "python",
25 |         "ruby",
26 |         "rust",
27 |         "swift",
28 |         "webjs"
29 |       ]
30 |     },
31 |     "telemetry.sdk.version": {
32 |       "description": "The version string of the telemetry SDK.\n",
33 |       "type": "string",
34 |       "stability": "stable",
35 |       "examples": ["1.2.3"]
36 |     },
37 |     "telemetry.distro.name": {
38 |       "description": "The name of the auto instrumentation agent or distribution, if used.\n",
39 |       "type": "string",
40 |       "note": "Official auto instrumentation agents and distributions SHOULD set the `telemetry.distro.name` attribute to\na string starting with `opentelemetry-`, e.g. `opentelemetry-java-instrumentation`.\n",
41 |       "stability": "development",
42 |       "examples": ["parts-unlimited-java"]
43 |     },
44 |     "telemetry.distro.version": {
45 |       "description": "The version string of the auto instrumentation agent or distribution, if used.\n",
46 |       "type": "string",
47 |       "stability": "development",
48 |       "examples": ["1.2.3"]
49 |     }
50 |   }
51 | }
52 | 
```

--------------------------------------------------------------------------------
/packages/mcp-server/src/permissions.parseScopes.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { describe, it, expect } from "vitest";
 2 | import { parseScopes, expandScopes, type Scope } from "./permissions";
 3 | 
 4 | describe("parseScopes", () => {
 5 |   it("parses comma-separated string with trimming and de-dup", () => {
 6 |     const { valid, invalid } = parseScopes(
 7 |       "event:write, foo, org:admin, , event:write",
 8 |     );
 9 |     const v = new Set<Scope>(valid);
10 |     expect(v.has("event:write")).toBe(true);
11 |     expect(v.has("org:admin")).toBe(true);
12 |     expect(invalid).toEqual(["foo"]);
13 |   });
14 | 
15 |   it("parses arrays and filters non-strings", () => {
16 |     const { valid, invalid } = parseScopes([
17 |       "member:read",
18 |       "x",
19 |       123 as unknown,
20 |       " team:write ",
21 |       "",
22 |     ]);
23 |     const v = new Set<Scope>(valid);
24 |     expect(v.has("member:read")).toBe(true);
25 |     expect(v.has("team:write")).toBe(true);
26 |     expect(invalid).toEqual(["x"]);
27 |   });
28 | 
29 |   it("handles empty or undefined inputs", () => {
30 |     expect(parseScopes("")).toEqual({ valid: new Set<Scope>(), invalid: [] });
31 |     expect(parseScopes(undefined)).toEqual({
32 |       valid: new Set<Scope>(),
33 |       invalid: [],
34 |     });
35 |     expect(parseScopes([])).toEqual({ valid: new Set<Scope>(), invalid: [] });
36 |   });
37 | });
38 | 
39 | // Consolidated strict-like parseScopes cases
40 | describe("parseScopes (strict-like cases)", () => {
41 |   it("returns invalid tokens for unknown scopes", () => {
42 |     const { valid, invalid } = parseScopes("foo,bar,org:admin");
43 |     expect(invalid).toEqual(["foo", "bar"]);
44 |     expect([...valid]).toContain("org:admin");
45 |   });
46 | 
47 |   it("returns only valid set when all are valid", () => {
48 |     const { valid, invalid } = parseScopes("event:admin,org:read");
49 |     expect(invalid).toEqual([]);
50 |     const out = new Set<Scope>(valid);
51 |     expect(out.has("event:admin")).toBe(true);
52 |     expect(out.has("org:read")).toBe(true);
53 |   });
54 | });
55 | 
56 | // Related behavior validation for expandScopes
57 | describe("expandScopes", () => {
58 |   it("includes implied lower scopes", () => {
59 |     const expanded = expandScopes(new Set<Scope>(["event:write"]));
60 |     expect(expanded.has("event:read")).toBe(true);
61 |     expect(expanded.has("event:write")).toBe(true);
62 |   });
63 | });
64 | 
```

--------------------------------------------------------------------------------
/.github/workflows/eval.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: Eval
 2 | 
 3 | on:
 4 |   workflow_dispatch:
 5 |   push:
 6 |     branches: [main]
 7 |     paths:
 8 |       - "packages/mcp-server/src/tools*"
 9 |       - "packages/mcp-server-evals/**"
10 |       - "packages/mcp-server-mocks/**"
11 |       - ".github/workflows/eval.yml"
12 |   pull_request:
13 |     paths:
14 |       - "packages/mcp-server/src/tools*"
15 |       - "packages/mcp-server-evals/**"
16 |       - "packages/mcp-server-mocks/**"
17 |       - ".github/workflows/eval.yml"
18 | 
19 | jobs:
20 |   eval:
21 |     environment: Actions
22 |     runs-on: ubuntu-latest
23 |     steps:
24 |       - uses: actions/checkout@v4
25 | 
26 |       - name: Setup Node.js
27 |         uses: actions/setup-node@v4
28 |         with:
29 |           node-version: "20"
30 | 
31 |       # pnpm/action-setup@v4
32 |       - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda
33 |         name: Install pnpm
34 |         with:
35 |           run_install: false
36 | 
37 |       - name: Get pnpm store directory
38 |         shell: bash
39 |         run: |
40 |           echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
41 | 
42 |       - uses: actions/cache@v4
43 |         name: Setup pnpm cache
44 |         with:
45 |           path: ${{ env.STORE_PATH }}
46 |           key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
47 |           restore-keys: |
48 |             ${{ runner.os }}-pnpm-store-
49 | 
50 |       - name: Install dependencies
51 |         run: pnpm install --no-frozen-lockfile
52 | 
53 |       - name: Run build
54 |         run: pnpm build
55 | 
56 |       - name: Run evals
57 |         run: pnpm eval:ci evals
58 |         env:
59 |           OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
60 | 
61 |       - name: Upload coverage reports to Codecov
62 |         uses: codecov/codecov-action@v4
63 |         env:
64 |           CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
65 |         with:
66 |           flags: evals
67 |           name: codecov-evals
68 |           fail_ci_if_error: false
69 | 
70 |       - name: Upload results to Codecov
71 |         if: ${{ !cancelled() }}
72 |         uses: codecov/test-results-action@v1
73 |         with:
74 |           token: ${{ secrets.CODECOV_TOKEN }}
75 | 
76 |       - name: Publish Test Report
77 |         uses: mikepenz/action-junit-report@cf701569b05ccdd861a76b8607a66d76f6fd4857
78 |         if: ${{ !cancelled() }}
79 |         with:
80 |           report_paths: "**/*.junit.xml"
81 |           comment: false
82 | 
```

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

```typescript
 1 | import type * as React from "react";
 2 | import { Slot } from "@radix-ui/react-slot";
 3 | import { cva, type VariantProps } from "class-variance-authority";
 4 | import { cn } from "../../lib/utils";
 5 | 
 6 | const buttonVariants = cva(
 7 |   "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive cursor-pointer",
 8 |   {
 9 |     variants: {
10 |       variant: {
11 |         default: "bg-violet-300 text-black shadow-xs hover:bg-violet-300/90",
12 |         destructive:
13 |           "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20",
14 |         outline:
15 |           "bg-slate-800/50 border border-slate-600/50 shadow-xs hover:bg-slate-700/50 hover:text-white ",
16 |         secondary:
17 |           "bg-background shadow-xs hover:bg-violet-300 hover:text-black",
18 |         ghost: "hover:text-white hover:bg-slate-700/50 ",
19 |         link: "text-primary hover:underline hover:text-violet-300 cursor-pointer",
20 |       },
21 |       size: {
22 |         default: "h-9 px-4 py-2 has-[>svg]:px-3",
23 |         sm: "h-8 gap-1.5 px-3 has-[>svg]:px-2.5",
24 |         xs: "h-7 gap-1.5 px-2 has-[>svg]:px-1.5",
25 |         lg: "h-10 px-6 has-[>svg]:px-4",
26 |         icon: "size-9",
27 |       },
28 |       active: {
29 |         true: "text-violet-300 underline",
30 |       },
31 |     },
32 |     defaultVariants: {
33 |       variant: "default",
34 |       size: "default",
35 |     },
36 |   },
37 | );
38 | 
39 | function Button({
40 |   className,
41 |   variant,
42 |   size,
43 |   active = false,
44 |   asChild = false,
45 |   ...props
46 | }: React.ComponentProps<"button"> &
47 |   VariantProps<typeof buttonVariants> & {
48 |     asChild?: boolean;
49 |     active?: boolean;
50 |   }) {
51 |   const Comp = asChild ? Slot : "button";
52 | 
53 |   return (
54 |     <Comp
55 |       data-slot="button"
56 |       className={cn(buttonVariants({ variant, size, className, active }))}
57 |       {...props}
58 |     />
59 |   );
60 | }
61 | 
62 | export { Button, buttonVariants };
63 | 
```
Page 2/15FirstPrevNextLast