diff --git a/TELEMETRY.md b/TELEMETRY.md index 6c88ec684..1b9fe2cd2 100644 --- a/TELEMETRY.md +++ b/TELEMETRY.md @@ -302,7 +302,7 @@ Attributes: `gen_ai.provider.name`, `gen_ai.request.model`, | ------------------------- | -------------------------------------------- | --------------------------------------- | | `VITE_SENTRY_DSN` | Cloudflare Sentry telemetry | disabled when unset | | `VITE_SENTRY_ENVIRONMENT` | Cloudflare Sentry environment | development | -| `SENTRY_DSN` | stdio and Node telemetry | disabled when unset | +| `SENTRY_CLI_NO_TELEMETRY` | stdio telemetry off when `1` | on, to the CLI's project | | `SENTRY_RELEASE` | stdio release tag | unset | | `SENTRY_HOST` | upstream Sentry host and `app.upstream.host` | `sentry.io` | | `NODE_ENV` | stdio environment | production fallback in packaged runtime | diff --git a/docs/operations/monitoring.md b/docs/operations/monitoring.md index 3111673a7..3fb46f370 100644 --- a/docs/operations/monitoring.md +++ b/docs/operations/monitoring.md @@ -8,10 +8,11 @@ Different Sentry SDKs for different environments: - **Core server**: `@sentry/core` (platform-agnostic) - **Cloudflare Workers**: `@sentry/cloudflare` -- **Node.js stdio**: `@sentry/node`. Without `--sentry-dsn`/`SENTRY_DSN`, the - stdio server reports to the Sentry CLI's project and honors the CLI's - opt-outs (`SENTRY_CLI_NO_TELEMETRY=1`, `DO_NOT_TRACK=1`, or - `sentry cli defaults telemetry off`). +- **Node.js stdio**: `@sentry/node`. The stdio server always reports to the + Sentry CLI's project (`SENTRY_CLI_DSN`) and honors the CLI's opt-outs + (`SENTRY_CLI_NO_TELEMETRY=1`, `DO_NOT_TRACK=1`, or + `sentry cli defaults telemetry off`). It never reads `SENTRY_DSN`: a server + started from a project shell or IDE would inherit the app's DSN. - **React client**: `@sentry/react` ## Core Server Instrumentation @@ -132,7 +133,8 @@ export default Sentry.withSentry((env) => getSentryConfig(env), { import * as Sentry from "@sentry/node"; Sentry.init({ - dsn: process.env.SENTRY_DSN, + dsn: SENTRY_CLI_DSN, + enabled: isTelemetryEnabled(), environment: process.env.NODE_ENV || "production", integrations: [Sentry.nodeProfilingIntegration()], tracesSampleRate: 0.1, @@ -355,9 +357,8 @@ Interpretation: VITE_SENTRY_DSN=https://...@sentry.io/... VITE_SENTRY_ENVIRONMENT=production -# Node.js (runtime) -SENTRY_DSN=https://...@sentry.io/... -NODE_ENV=production +# Node.js stdio (runtime): telemetry goes to the CLI's project; opt out with +SENTRY_CLI_NO_TELEMETRY=1 ``` ## Best Practices diff --git a/docs/testing/stdio.md b/docs/testing/stdio.md index 8635e5b88..c71bce4da 100644 --- a/docs/testing/stdio.md +++ b/docs/testing/stdio.md @@ -385,10 +385,6 @@ my-org/my-project # Limit calls to this project --agent-provider=openai # openai, azure-openai, or anthropic --openai-base-url=URL # Custom OpenAI endpoint -# Sentry reporting ---sentry-dsn=DSN # Custom Sentry DSN for telemetry ---sentry-dsn= # Disable telemetry - # Help --help # Show all options --version, -v # Show version (-v alone; elsewhere it is --verbose) @@ -411,8 +407,8 @@ MCP_DISABLE_SKILLS=seer # AI features OPENAI_API_KEY=your-key # For AI-powered search tools like search_errors/search_traces/search_issues -# Sentry reporting -SENTRY_DSN=your-dsn +# Telemetry (always sent to the Sentry CLI's project) +SENTRY_CLI_NO_TELEMETRY=1 # Turn it off (DO_NOT_TRACK=1 works too) ``` **Priority:** Command-line flags override environment variables. diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/mcp.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/mcp.md index 8e8c06927..85619c24c 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/mcp.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/mcp.md @@ -35,7 +35,6 @@ Start a local Sentry MCP server - `--anthropic-base-url - Anthropic API base URL` - `--anthropic-model - Anthropic model (default: claude-sonnet-4-5)` - `--mcp-url - MCP server URL reported in telemetry` -- `--sentry-dsn - DSN for the server's own telemetry` **Examples:** diff --git a/packages/cli/src/commands/mcp.ts b/packages/cli/src/commands/mcp.ts index 63bdb813e..e82078d02 100644 --- a/packages/cli/src/commands/mcp.ts +++ b/packages/cli/src/commands/mcp.ts @@ -83,7 +83,6 @@ export const mcpCommand = buildCommand({ " SENTRY_AUTH_TOKEN Sentry token (same as for other commands)\n" + " SENTRY_HOST, SENTRY_URL Sentry instance (same as for other commands; http:// for plain HTTP)\n" + " MCP_URL MCP server URL reported in telemetry\n" + - " SENTRY_DSN DSN for the server's own telemetry\n" + " OPENAI_API_KEY, ANTHROPIC_API_KEY, OPENROUTER_API_KEY\n" + " LLM API key for AI-powered search tools\n" + " OPENAI_MODEL, ANTHROPIC_MODEL, OPENROUTER_MODEL\n" + @@ -175,7 +174,6 @@ export const mcpCommand = buildCommand({ "Anthropic model (default: claude-sonnet-4-5)", ), "mcp-url": stringFlag("MCP server URL reported in telemetry"), - "sentry-dsn": stringFlag("DSN for the server's own telemetry"), }, }, // oxlint-disable-next-line require-yield -- The server speaks JSON-RPC on stdout; the command yields no output. diff --git a/packages/cli/src/lib/mcp/args.ts b/packages/cli/src/lib/mcp/args.ts index c1c681851..353b5691c 100644 --- a/packages/cli/src/lib/mcp/args.ts +++ b/packages/cli/src/lib/mcp/args.ts @@ -22,7 +22,6 @@ export type McpFlags = { /** Deprecated: an `http://` `SENTRY_URL`. */ readonly "insecure-http": boolean; readonly "mcp-url"?: string; - readonly "sentry-dsn"?: string; readonly "openai-base-url"?: string; readonly "openai-model"?: string; readonly "anthropic-base-url"?: string; @@ -151,9 +150,9 @@ function scopeFlag( /** * Split `--flag=value` into `--flag value` where Stricli does not read the - * joined form: an empty value (`--sentry-dsn=` turns off the server's - * telemetry) or one with a line break (a token pasted with its newline). - * MCP client configurations have always passed both to `@sentry/mcp-server`. + * joined form: an empty value or one with a line break (a token pasted with + * its newline). MCP client configurations have always passed both to + * `@sentry/mcp-server`. */ export function splitInlineFlagValues(args: readonly string[]): string[] { return args.flatMap((arg) => { @@ -170,7 +169,6 @@ export function splitInlineFlagValues(args: readonly string[]): string[] { /** Values read from the environment. */ export type McpEnvArgs = { mcpUrl?: string; - sentryDsn?: string; openaiModel?: string; anthropicModel?: string; agentProvider?: string; @@ -184,7 +182,6 @@ export type McpMergedArgs = { insecureHttp: boolean; url?: string; mcpUrl?: string; - sentryDsn?: string; openaiBaseUrl?: string; openaiModel?: string; anthropicBaseUrl?: string; @@ -211,9 +208,6 @@ export function parseMcpEnv(env: NodeJS.ProcessEnv): McpEnvArgs { if (env.MCP_URL) { fromEnv.mcpUrl = env.MCP_URL; } - if (env.SENTRY_DSN || env.DEFAULT_SENTRY_DSN) { - fromEnv.sentryDsn = env.SENTRY_DSN || env.DEFAULT_SENTRY_DSN; - } if (env.OPENAI_MODEL) { fromEnv.openaiModel = env.OPENAI_MODEL; } @@ -243,7 +237,6 @@ export function mergeMcpArgs( host: flags.host, insecureHttp: flags["insecure-http"], mcpUrl: flags["mcp-url"] ?? env.mcpUrl, - sentryDsn: flags["sentry-dsn"] ?? env.sentryDsn, openaiBaseUrl: flags["openai-base-url"], openaiModel: flags["openai-model"] ?? env.openaiModel, anthropicBaseUrl: flags["anthropic-base-url"], diff --git a/packages/cli/src/lib/mcp/config.ts b/packages/cli/src/lib/mcp/config.ts index cb41df6e1..5baa7b0b2 100644 --- a/packages/cli/src/lib/mcp/config.ts +++ b/packages/cli/src/lib/mcp/config.ts @@ -33,7 +33,6 @@ export type McpServerConfig = { sentryHost: string; sentryProtocol: "http" | "https"; mcpUrl?: string; - sentryDsn?: string; openaiBaseUrl?: string; openaiModel?: string; anthropicBaseUrl?: string; @@ -179,7 +178,6 @@ export function finalizeMcpConfig(input: McpMergedArgs): McpServerConfig { sentryHost, sentryProtocol: input.insecureHttp ? "http" : "https", mcpUrl: input.mcpUrl, - sentryDsn: input.sentryDsn, // Anthropic base URLs follow the same rules as OpenAI ones. openaiBaseUrl: input.openaiBaseUrl ? validated(() => validateOpenAiBaseUrlThrows(input.openaiBaseUrl ?? "")) diff --git a/packages/cli/src/lib/mcp/server.ts b/packages/cli/src/lib/mcp/server.ts index 8f1bb194e..1f1b21aa9 100644 --- a/packages/cli/src/lib/mcp/server.ts +++ b/packages/cli/src/lib/mcp/server.ts @@ -234,12 +234,6 @@ export function initMcpTelemetry(config: McpServerConfig): void { return; } - // An empty `--sentry-dsn=` turns telemetry off. Skip `init` so neither the - // CLI's DSN nor a shell SENTRY_DSN starts the SDK. - if (config.sentryDsn === "") { - return; - } - const { name, packageName } = getAppIdentity(); const scopeContext = { "app.server.version": CLI_VERSION, @@ -250,12 +244,12 @@ export function initMcpTelemetry(config: McpServerConfig): void { "app.url.full": config.mcpUrl, }; - // Without `--sentry-dsn`/`SENTRY_DSN`, report to the CLI's own project, - // honoring the CLI's telemetry opt-outs. - const useCliDsn = config.sentryDsn === undefined; + // Always the CLI's own project, never a DSN from the environment: an MCP + // server started from a project shell or IDE inherits the app's SENTRY_DSN. + // Only the CLI's telemetry opt-outs turn it off. init({ - dsn: config.sentryDsn ?? SENTRY_CLI_DSN, - enabled: !useCliDsn || isTelemetryEnabled(), + dsn: SENTRY_CLI_DSN, + enabled: isTelemetryEnabled(), tracesSampleRate: 1, beforeSend: sentryBeforeSend, initialScope: { diff --git a/packages/cli/test/lib/mcp-command.test.ts b/packages/cli/test/lib/mcp-command.test.ts index 481807cc7..4ed5189fa 100644 --- a/packages/cli/test/lib/mcp-command.test.ts +++ b/packages/cli/test/lib/mcp-command.test.ts @@ -275,7 +275,6 @@ describe("running `mcp`", () => { "--disable-skills", "--agent-provider", "--mcp-url", - "--sentry-dsn", ]) { expect(stdout).toContain(flag); } diff --git a/packages/cli/test/lib/mcp/args.test.ts b/packages/cli/test/lib/mcp/args.test.ts index bc789a08e..68104d16b 100644 --- a/packages/cli/test/lib/mcp/args.test.ts +++ b/packages/cli/test/lib/mcp/args.test.ts @@ -17,7 +17,6 @@ describe("sentry mcp flags", () => { "--insecure-http", "--url=https://example.com", "--mcp-url=https://mcp.example.com", - "--sentry-dsn=dsn", "--openai-base-url=https://api.example.com/v1", "--skills=inspect,triage", "--all-skills", @@ -28,7 +27,6 @@ describe("sentry mcp flags", () => { "insecure-http": true, url: "https://example.com", "mcp-url": "https://mcp.example.com", - "sentry-dsn": "dsn", "openai-base-url": "https://api.example.com/v1", skills: "inspect,triage", "all-skills": true, @@ -57,13 +55,17 @@ describe("sentry mcp flags", () => { ); it("accepts empty and multi-line --flag=value forms", async () => { - const flags = await parseMcpFlags(["--sentry-dsn=", "--access-token=a\nb"]); - expect(flags["sentry-dsn"]).toBe(""); + const flags = await parseMcpFlags(["--mcp-url=", "--access-token=a\nb"]); + expect(flags["mcp-url"]).toBe(""); expect(flags["access-token"]).toBe("a\nb"); }); it("rejects unknown flags and a second positional", async () => { await expect(parseMcpFlags(["--unknown"])).rejects.toThrow(/unknown/); + // Removed: MCP telemetry always goes to the CLI's project. + await expect(parseMcpFlags(["--sentry-dsn="])).rejects.toThrow( + /sentry-dsn/, + ); await expect(parseMcpFlags(["acme/", "extra"])).rejects.toThrow(/extra/); }); }); @@ -72,14 +74,14 @@ describe("splitInlineFlagValues", () => { it("splits only the joined forms Stricli does not read", () => { expect( splitInlineFlagValues([ - "--sentry-dsn=", + "--mcp-url=", "--access-token=tok\n", "--host=sentry.io", "--all-skills", "x=", ]), ).toEqual([ - "--sentry-dsn", + "--mcp-url", "", "--access-token", "tok\n", @@ -95,11 +97,9 @@ describe("parseMcpEnv", () => { const env = parseMcpEnv({ SENTRY_ACCESS_TOKEN: "envtok", MCP_URL: "envmcp", - SENTRY_DSN: "envdsn", MCP_SKILLS: "inspect,triage", }); expect(env.mcpUrl).toBe("envmcp"); - expect(env.sentryDsn).toBe("envdsn"); expect(env.skills).toBe("inspect,triage"); }); @@ -117,21 +117,18 @@ describe("mergeMcpArgs", () => { const env = parseMcpEnv({ SENTRY_ACCESS_TOKEN: "envtok", MCP_URL: "envmcp", - SENTRY_DSN: "envdsn", }); const flags = await parseMcpFlags([ "--access-token=clitok", "--host=clihost", "--insecure-http", "--mcp-url=climcp", - "--sentry-dsn=clidsn", "--openai-base-url=https://api.cli/v1", ]); const merged = mergeMcpArgs(flags, env); expect(merged.host).toBe("clihost"); expect(merged.insecureHttp).toBe(true); expect(merged.mcpUrl).toBe("climcp"); - expect(merged.sentryDsn).toBe("clidsn"); expect(merged.openaiBaseUrl).toBe("https://api.cli/v1"); }); @@ -183,7 +180,6 @@ describe("@sentry/mcp-server flag parity", () => { "--insecure-http", "--url=https://sentry.example.com", "--mcp-url=https://mcp.example.com", - "--sentry-dsn=dsn", "--openai-base-url=https://openai.example.com/v1", "--openai-model=gpt-test", "--anthropic-base-url=https://anthropic.example.com", @@ -201,7 +197,6 @@ describe("@sentry/mcp-server flag parity", () => { insecureHttp: true, url: "https://sentry.example.com", mcpUrl: "https://mcp.example.com", - sentryDsn: "dsn", openaiBaseUrl: "https://openai.example.com/v1", openaiModel: "gpt-test", anthropicBaseUrl: "https://anthropic.example.com", @@ -233,7 +228,6 @@ describe("@sentry/mcp-server flag parity", () => { parseMcpEnv({ SENTRY_ACCESS_TOKEN: "envtok", MCP_URL: "https://mcp.example.com", - SENTRY_DSN: "dsn", OPENAI_MODEL: "gpt-test", ANTHROPIC_MODEL: "claude-test", EMBEDDED_AGENT_PROVIDER: "openrouter", @@ -242,7 +236,6 @@ describe("@sentry/mcp-server flag parity", () => { }), ).toEqual({ mcpUrl: "https://mcp.example.com", - sentryDsn: "dsn", openaiModel: "gpt-test", anthropicModel: "claude-test", agentProvider: "openrouter", @@ -251,10 +244,11 @@ describe("@sentry/mcp-server flag parity", () => { }); }); - it("falls back to DEFAULT_SENTRY_DSN for telemetry", () => { - expect(parseMcpEnv({ DEFAULT_SENTRY_DSN: "default" }).sentryDsn).toBe( - "default", - ); + // A server started from a project shell or IDE inherits the app's DSN. + it("ignores SENTRY_DSN and DEFAULT_SENTRY_DSN", () => { + expect( + parseMcpEnv({ SENTRY_DSN: "app", DEFAULT_SENTRY_DSN: "default" }), + ).toEqual({}); }); it("leaves the deprecated SENTRY_ACCESS_TOKEN to serveMcp", () => { diff --git a/packages/cli/test/lib/mcp/config.test.ts b/packages/cli/test/lib/mcp/config.test.ts index b75be9248..8a7615c54 100644 --- a/packages/cli/test/lib/mcp/config.test.ts +++ b/packages/cli/test/lib/mcp/config.test.ts @@ -312,7 +312,6 @@ describe("finalizeMcpConfig", () => { it("keeps the static token, constraints, and embedded agent settings", () => { const cfg = finalize({ mcpUrl: "https://mcp.example.com", - sentryDsn: "dsn", openaiModel: "gpt-test", anthropicBaseUrl: "https://anthropic.example.com", anthropicModel: "claude-test", @@ -324,7 +323,6 @@ describe("finalizeMcpConfig", () => { }); expect(cfg).toMatchObject({ mcpUrl: "https://mcp.example.com", - sentryDsn: "dsn", openaiModel: "gpt-test", anthropicBaseUrl: "https://anthropic.example.com/", anthropicModel: "claude-test", diff --git a/packages/cli/test/lib/mcp/telemetry.test.ts b/packages/cli/test/lib/mcp/telemetry.test.ts index 6d613a443..368fae2ea 100644 --- a/packages/cli/test/lib/mcp/telemetry.test.ts +++ b/packages/cli/test/lib/mcp/telemetry.test.ts @@ -19,6 +19,7 @@ useEnvSandbox([ "DO_NOT_TRACK", "SENTRY_RELEASE", "SENTRY_DSN", + "DEFAULT_SENTRY_DSN", ]); const config: McpServerConfig = { @@ -52,7 +53,7 @@ afterEach(() => { }); describe("initMcpTelemetry", () => { - test("reports to the CLI's project when no DSN is configured", async () => { + test("reports to the CLI's project", async () => { const options = await initOptions(); expect(options.dsn).toBe(SENTRY_CLI_DSN); expect(options.enabled).toBe(true); @@ -65,33 +66,29 @@ describe("initMcpTelemetry", () => { expect(options.release).toBe(CLI_VERSION); }); - test("honors the CLI's telemetry opt-out", async () => { - process.env.SENTRY_CLI_NO_TELEMETRY = "1"; + test.each(["SENTRY_CLI_NO_TELEMETRY", "DO_NOT_TRACK"])( + "honors the CLI's telemetry opt-out (%s)", + async (name) => { + process.env[name] = "1"; + const options = await initOptions(); + expect(options.dsn).toBe(SENTRY_CLI_DSN); + expect(options.enabled).toBe(false); + }, + ); + + // A server started from a project shell or IDE inherits the app's DSN. + test("ignores SENTRY_DSN and DEFAULT_SENTRY_DSN from the environment", async () => { + const appDsn = "https://key@o1.ingest.sentry.io/1"; + process.env.SENTRY_DSN = appDsn; + process.env.DEFAULT_SENTRY_DSN = appDsn; const options = await initOptions(); expect(options.dsn).toBe(SENTRY_CLI_DSN); - expect(options.enabled).toBe(false); - }); - - test("an explicit DSN wins and ignores the CLI opt-out", async () => { - process.env.SENTRY_CLI_NO_TELEMETRY = "1"; - const dsn = "https://key@o1.ingest.sentry.io/1"; - const options = await initOptions({ sentryDsn: dsn }); - expect(options.dsn).toBe(dsn); expect(options.enabled).toBe(true); }); - test("an empty DSN turns telemetry off, even with SENTRY_DSN set", async () => { - process.env.SENTRY_DSN = "https://key@o1.ingest.sentry.io/1"; - const { initMcpTelemetry } = await import("../../../src/lib/mcp/server.js"); - initMcpTelemetry({ ...config, sentryDsn: "" }); - expect(sentry.init).not.toHaveBeenCalled(); - }); - test("ignores SENTRY_RELEASE so the reported release stays ours", async () => { process.env.SENTRY_RELEASE = "spoofed"; - const options = await initOptions({ - sentryDsn: "https://key@o1.ingest.sentry.io/1", - }); + const options = await initOptions(); expect(options.release).toBe(CLI_VERSION); }); diff --git a/packages/mcp-cloudflare/src/client/components/fragments/stdio-setup.tsx b/packages/mcp-cloudflare/src/client/components/fragments/stdio-setup.tsx index 6a4f0e20d..00f36eb77 100644 --- a/packages/mcp-cloudflare/src/client/components/fragments/stdio-setup.tsx +++ b/packages/mcp-cloudflare/src/client/components/fragments/stdio-setup.tsx @@ -102,11 +102,10 @@ export default function StdioSetup() {
- --sentry-dsn / SENTRY_DSN + SENTRY_CLI_NO_TELEMETRY / DO_NOT_TRACK
- Send telemetry elsewhere or disable it by passing an empty - value. + Set either to 1 to turn off the server's telemetry.
diff --git a/packages/mcp-core/README.md b/packages/mcp-core/README.md index f884777f1..3bbd7fc7e 100644 --- a/packages/mcp-core/README.md +++ b/packages/mcp-core/README.md @@ -133,12 +133,8 @@ The host configuration accepts two distinct formats: **Note**: Only HTTPS connections are supported for security reasons. -By default we also enable Sentry reporting (traces, errors) upstream to our cloud service. You can disable that, or send it to a different Sentry instance by using the `--sentry-dsn` flag: +By default the server reports its own telemetry (traces, errors) to the Sentry CLI's project on sentry.io. Set `SENTRY_CLI_NO_TELEMETRY=1` or `DO_NOT_TRACK=1` to turn it off: ```shell -# disable sentry reporting -npx @sentry/mcp-server@latest --sentry-dsn= - -# use custom sentry instance -npx @sentry/mcp-server@latest --sentry-dsn=https://publicKey@mysentry.example.com/... +SENTRY_CLI_NO_TELEMETRY=1 npx @sentry/mcp-server@latest ``` diff --git a/packages/mcp-core/tsdown.config.ts b/packages/mcp-core/tsdown.config.ts index e212ea53f..20d8d1a2a 100644 --- a/packages/mcp-core/tsdown.config.ts +++ b/packages/mcp-core/tsdown.config.ts @@ -19,8 +19,6 @@ export default defineConfig({ "@sentry/mcp-server-mocks", ], env: { - DEFAULT_SENTRY_DSN: - "https://d0805acebb937435abcb5958da99cdab@o1.ingest.us.sentry.io/4509062593708032", SENTRY_ENVIRONMENT: "stdio", SENTRY_RELEASE: packageVersion, npm_package_version: packageVersion, diff --git a/packages/mcp-server/test/bundle.test.mjs b/packages/mcp-server/test/bundle.test.mjs index e9e00dee8..551487b73 100644 --- a/packages/mcp-server/test/bundle.test.mjs +++ b/packages/mcp-server/test/bundle.test.mjs @@ -220,20 +220,24 @@ async function serveStdio(args, extraEnv, { deletedCwd } = {}) { } test("serves MCP over stdio with SENTRY_AUTH_TOKEN", async () => { - // `--sentry-dsn=` (no telemetry) is a form MCP configs have always used. // Without a stored login, the env token needs no SENTRY_FORCE_ENV_TOKEN. - const { stderr } = await serveStdio(["--sentry-dsn="], { + const { stderr } = await serveStdio([], { SENTRY_AUTH_TOKEN: "sntryu_test", }); assert.doesNotMatch(stderr, /deprecated/); }); +test("rejects the removed --sentry-dsn instead of serving", () => { + // Telemetry always goes to the CLI's project; opt out with + // SENTRY_CLI_NO_TELEMETRY=1 instead. + const result = run(["--sentry-dsn="], { SENTRY_AUTH_TOKEN: "sntryu_test" }); + assert.notEqual(result.status, 0); + assert.match(result.stderr, /No flag registered for --sentry-dsn/); +}); + test("serves the deprecated --access-token with a hint on stderr", async () => { const token = "sntryu_deprecated_flag_secret"; - const { stderr } = await serveStdio( - [`--access-token=${token}`, "--sentry-dsn="], - {}, - ); + const { stderr } = await serveStdio([`--access-token=${token}`], {}); assert.match( stderr, /--access-token is deprecated; set SENTRY_AUTH_TOKEN instead\./, @@ -255,9 +259,11 @@ test( ); test("exits after the client disconnects with telemetry on", async () => { - // An explicit DSN turns on the server's telemetry despite the CLI opt-out. - // Nothing listens on port 9, so no event leaves the machine. - await serveStdio(["--sentry-dsn=http://public@127.0.0.1:9/1"], { + // Telemetry always goes to the CLI's DSN. Nothing listens on the proxy's + // port 9, so no event leaves the machine. + await serveStdio([], { SENTRY_AUTH_TOKEN: "sntryu_test", + SENTRY_CLI_NO_TELEMETRY: "0", + https_proxy: "http://127.0.0.1:9", }); }); diff --git a/packages/mcp-test-client/src/index.ts b/packages/mcp-test-client/src/index.ts index 03ca57223..b55b8de2a 100644 --- a/packages/mcp-test-client/src/index.ts +++ b/packages/mcp-test-client/src/index.ts @@ -54,7 +54,10 @@ program process.env.MCP_URL || "http://localhost:5173", ) .option("--host ", "Sentry host for stdio transport") - .option("--sentry-dsn ", "Sentry DSN for error reporting") + .option( + "--sentry-dsn ", + "Sentry DSN for the test client's own error reporting (not the server's)", + ) .option("--experimental", "Enable experimental tools (/mcp?experimental=1)") .option( "--stdio-bundle", @@ -138,7 +141,6 @@ program connection = await connectToMCPServer({ accessToken, host: sentryHost, - sentryDsn: sentryDsn, useExperimental: options.experimental, useBundle: options.stdioBundle, }); diff --git a/packages/mcp-test-client/src/transport.test.ts b/packages/mcp-test-client/src/transport.test.ts index d151e7b53..60d60fd65 100644 --- a/packages/mcp-test-client/src/transport.test.ts +++ b/packages/mcp-test-client/src/transport.test.ts @@ -57,7 +57,6 @@ describe("buildStdioServerLaunchConfig", () => { { accessToken: "token-123", host: "us.sentry.io", - sentryDsn: "https://dsn.example/1", useExperimental: true, }, { @@ -67,15 +66,11 @@ describe("buildStdioServerLaunchConfig", () => { }, ); - expect(launchConfig.args).toEqual([ - "--sentry-dsn=https://dsn.example/1", - "--experimental", - ]); + expect(launchConfig.args).toEqual(["--experimental"]); expect(launchConfig.env).toEqual({ PATH: "/usr/bin", SENTRY_AUTH_TOKEN: "token-123", SENTRY_HOST: "us.sentry.io", - SENTRY_DSN: "https://dsn.example/1", }); }); }); diff --git a/packages/mcp-test-client/src/transport.ts b/packages/mcp-test-client/src/transport.ts index 119284022..14758819f 100644 --- a/packages/mcp-test-client/src/transport.ts +++ b/packages/mcp-test-client/src/transport.ts @@ -24,9 +24,6 @@ export function buildStdioServerLaunchConfig( // The host goes through SENTRY_HOST below; the server's --host is deprecated. const args: string[] = []; - if (config.sentryDsn) { - args.push(`--sentry-dsn=${config.sentryDsn}`); - } if (config.useExperimental) { args.push("--experimental"); } @@ -49,9 +46,6 @@ export function buildStdioServerLaunchConfig( if (config.host) { env.SENTRY_HOST = config.host; } - if (config.sentryDsn) { - env.SENTRY_DSN = config.sentryDsn; - } return { args, env }; } diff --git a/packages/mcp-test-client/src/types.ts b/packages/mcp-test-client/src/types.ts index d2d13b23d..82a98a802 100644 --- a/packages/mcp-test-client/src/types.ts +++ b/packages/mcp-test-client/src/types.ts @@ -13,7 +13,6 @@ export type RequestedTransportMode = "auto" | "stdio" | "http"; export interface MCPConfig { accessToken?: string; host?: string; - sentryDsn?: string; useExperimental?: boolean; /** Run the built `@sentry/mcp-server` bundle instead of CLI source. */ useBundle?: boolean;