feat: Integrate Sentry for error reporting#650
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds an opt-out–governed Sentry integration to report MCP server runtime errors (tool handler throws, uncaught exceptions, unhandled rejections), alongside updates to telemetry docs, build-time configuration injection, and the release pipeline to upload source maps.
Changes:
- Add Sentry initialization/capture/flush plumbing and wire it into tool-call error paths and top-level startup error handling.
- Add redaction logic for outbound Sentry events and unit tests covering initialization, flushing, and redaction behavior.
- Update docs/config/changelog and release packaging steps to support baking a DSN at pack time and uploading source maps.
Reviewed changes
Copilot reviewed 17 out of 18 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| telemetry.md | Updates telemetry documentation to include Sentry error reporting and opt-out behavior. |
| src/mcp/server.ts | Adds a captureError hook to report tool handler throws. |
| src/mcp/server.test.ts | Adds test coverage for captureError being invoked with the tool name. |
| src/index.ts | Computes a unified doNotTrack flag, initializes Sentry, captures startup errors, and flushes on shutdown. |
| src/index.test.ts | Adds tests for resolveDoNotTrack() and flushing Sentry during shutdown. |
| src/confluent/sentry.ts | Introduces the Sentry wrapper module (init/capture/close) with redaction hook. |
| src/confluent/sentry.test.ts | Adds unit tests for Sentry init gating, capture, and flush behavior. |
| src/confluent/sentry-redact.ts | Adds deep redaction of sensitive fields/patterns in outbound Sentry events. |
| src/confluent/sentry-redact.test.ts | Adds tests validating secret scrubbing and preservation of non-secret content. |
| src/confluent/node-deps.ts | Wraps @sentry/node behind node-deps for ESM stubbability and build-config access. |
| src/build-config.ts | Adds SENTRY_DSN build-time constant. |
| scripts/inject-build-config.mjs | Injects SENTRY_DSN into packed dist/build-config.js and logs injection status. |
| README.md | Updates the Telemetry section to mention Sentry and YAML opt-out. |
| package.json | Adds @sentry/node dependency and @sentry/cli devDependency. |
| CONFIGURATION.md | Updates opt-out docs to clarify it disables both analytics and Sentry reporting. |
| CHANGELOG.md | Adds an Unreleased entry describing new Sentry error reporting behavior and privacy properties. |
| .semaphore/release-version.yml | Fetches DSN/auth token from Vault and uploads sourcemaps/releases via sentry-cli during release. |
| pnpm-lock.yaml | Locks new Sentry dependencies (reviewed only at the top-level via package.json). |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
|
|
Bernie Chen (@bcscc) Thank you for reviewing the PR, and the valid secure concern about below two different values, handled differently:
Why it can't leak, by construction:
Proof it's not exposed (packed the real tarball with a fake token in the env, then searched the whole package): Proof it's actually used: Then open that Issue in Sentry and check the stack trace. |




Summary of Changes
sentry.ts— Sentry lifecycle: consent-gatedinitSentry(short-circuits onDO_NOT_TRACK/ no DSN),captureException,closeSentry,resolveSentryDsn; PII off,beforeSendredaction,release/transport/connectionstags.sentry-redact.ts— scrubs auth headers, API key/secret, SASL passwords, and YAML secrets from outbound events.index.ts— initializes Sentry after config load (so consent is known), captures startup errors, flushes on shutdown; addsresolveDoNotTrack(one switch for analytics + errors) andconnectionTypescontext.server.ts— reports tool-handler throws viacaptureError(error, toolName).node-deps.ts— adds the stubbablesentrywrapper andSENTRY_DSN.build-config.ts+inject-build-config.mjs— bakeSENTRY_DSNinto the build at pack time.release-version.yml— pullsSENTRY_DSNfrom Vault and uploads source maps at release.Manual testing instructions
Sentry config lives in Vault at
stag/kv/semaphore/mcpconfluent/telemetry(fieldsSENTRY_DSN,SENTRY_AUTH_TOKEN; CI reads them viavault-get-secret). Fetch the DSN:Events land here: https://confluent.sentry.io/issues/?project=4511649921761280&query=is%3Aunresolved&statsPeriod=7d
/mcp-confluent/scripts/sentry-smoke.mjsbuild, then run the smoke tool in its three modes:
Expected:
capture→ new IssueTESTING capture …with tagsconnections=direct,oauth,transport=http,stdio,toolName=list-topics; theBearer …token shows[REDACTED].uncaught→ new IssueTESTING uncaught …; the process prints the stack and exits 1.optout→ no new Issue; logsError reporting disabled.Automated:
pnpm run test:unitExpected: all unit tests pass.Consent + real server — bakes the DSN into
dist(what a published build has) and starts the real server, to confirminitSentryruns in the actual startup path and honors the switch. (inject-build-config.mjsrewritesdist/build-config.jswith the env values — the same steppnpm packruns at release; here it makes a dev build behave like a published one.)Expected:
inject-build-config.mjs→ printsinject-build-config: SENTRY_DSN set.Error reporting enabled.Error reporting disabled.TODO
Pull request checklist
Please check if your PR fulfills the following (if applicable):
Tests
Release notes