The current implementation captured too much data by default (including broad MCP instrumentation and PII-heavy tagging). The fix narrows telemetry to internal runtime failures only, keeps tracing enabled for observability, disables MCP input/output capture, and adds payload scrubbing/redaction.
- Sentry was initialized with
sendDefaultPii: trueandtracesSampleRate: 1.0. - MCP server was wrapped with
wrapMcpServerWithSentry, enabling broad per-call instrumentation. - Logger default sent all
errorlogs to Sentry, including user-domain failures. - Sentry tags included sensitive environment/system values (HOME, USER, PATH, Xcode paths).
- Privacy docs understated actual collection scope.
Hypothesis: Telemetry defaults and wrapper behavior were broader than documented. Findings: Issue #204 correctly identified mismatch between docs and implementation. Evidence:
- GitHub issue: getsentry#204
/Users/cameroncooke/.codex/worktrees/a59a/XcodeBuildMCP/src/utils/sentry.ts/Users/cameroncooke/.codex/worktrees/a59a/XcodeBuildMCP/src/server/server.ts/Users/cameroncooke/.codex/worktrees/a59a/XcodeBuildMCP/src/utils/logger.tsConclusion: Confirmed.
Hypothesis: User-domain tool failures were reaching Sentry through logger defaults.
Findings: log('error', ...) implicitly captured to Sentry unless overridden; many tool/runtime paths emit user-domain errors at error level.
Evidence:
/Users/cameroncooke/.codex/worktrees/a59a/XcodeBuildMCP/src/utils/logger.ts/Users/cameroncooke/.codex/worktrees/a59a/XcodeBuildMCP/src/utils/build-utils.ts/Users/cameroncooke/.codex/worktrees/a59a/XcodeBuildMCP/src/runtime/tool-invoker.tsConclusion: Confirmed.
Hypothesis: Sentry SDK was not at latest patch and docs were not aligned with behavior.
Findings: @sentry/node moved from ^10.37.0 to latest 10.38.0 and docs were updated to match internal-only policy.
Evidence:
- Command:
npm view @sentry/node versionreturned10.38.0 /Users/cameroncooke/.codex/worktrees/a59a/XcodeBuildMCP/package.json/Users/cameroncooke/.codex/worktrees/a59a/XcodeBuildMCP/docs/PRIVACY.md/Users/cameroncooke/.codex/worktrees/a59a/XcodeBuildMCP/docs/CONFIGURATION.md/Users/cameroncooke/.codex/worktrees/a59a/XcodeBuildMCP/README.mdConclusion: Confirmed.
Three defaults combined to over-collect telemetry:
sendDefaultPii: trueand tracing at 100% in Sentry init.wrapMcpServerWithSentryaround the MCP server.- Logger behavior that captured every
errorlog to Sentry by default.
This effectively blurred boundaries between internal platform failures and user-domain build/config/runtime failures, and increased risk of sensitive metadata leakage.
- Sentry initialization hardened (
sendDefaultPii: false,tracesSampleRate: 1.0, breadcrumbs disabled,beforeSendscrubbing/redaction). - Sensitive tags/context removed (no env dumps, no HOME/USER/PATH/Xcode path tagging).
- Restored MCP wrapper with explicit safe options (
recordInputs: false,recordOutputs: false) to keep tool-level observability without payload capture. - Logger changed to explicit opt-in capture only (
context.sentry === true). - Internal boundary capture retained only where appropriate (startup/shutdown/fatal daemon internal errors).
- Added tests for explicit capture policy and path redaction.
- Updated privacy/config/README/architecture docs and changelog.
- "Only MCP-level faults are captured today": Eliminated (not true before this patch due to logger defaults and wrapper).
- "Docs accurately reflected telemetry scope": Eliminated.
- Keep Sentry capture explicit and centralized to internal runtime boundaries.
- Avoid adding environment or filesystem metadata to telemetry tags.
- Preserve redaction tests to prevent regressions.
- Continue documenting telemetry scope in user-facing docs whenever behavior changes.
- CI should keep redaction and logger policy tests running by default.
- Any future telemetry additions should require explicit privacy review with docs update in same PR.
All relevant quality checks were executed after changes:
npm run format:check✅npm run lint✅npm run typecheck✅npm run build✅npm test✅ (117 test files passed; 1274 tests passed, 15 skipped)
Notes:
- Test output includes expected stderr from negative-path parser tests in
src/utils/__tests__/nskeyedarchiver-parser.test.ts; test run still passed.
wrapMcpServerWithSentryresolves options as:recordInputs: options?.recordInputs ?? sendDefaultPiirecordOutputs: options?.recordOutputs ?? sendDefaultPii
- For MCP request spans,
tools/callandprompts/getarguments are added asmcp.request.argument.*attributes whenrecordInputs=true. - Tool/prompt results are added as
mcp.tool.result*/mcp.prompt.result*attributes whenrecordOutputs=true. - Built-in MCP PII filtering in the SDK only strips network-level fields (
client.address,client.port,mcp.resource.uri) whensendDefaultPii=false; it does not by itself scrub arbitrary tool argument/output payloads.
Evidence (source-inspected package build):
@sentry/core@10.38.0build/cjs/integrations/mcp-server/index.js@sentry/core@10.38.0build/cjs/integrations/mcp-server/methodConfig.js@sentry/core@10.38.0build/cjs/integrations/mcp-server/resultExtraction.js@sentry/core@10.38.0build/cjs/integrations/mcp-server/piiFiltering.js
- Runtime config/dependency tags are being attached to issues when events are captured after bootstrap context is set.
- Example: issue
XCODEBUILDMCP-6includesruntime.mode,xcode.version,xcode.xcodebuild_path,axe.source, and config tags. - Startup-phase config parse warnings can occur before full runtime context is attached, so those earlier events may not show the full tag set.
- MCP wrapper instrumentation is active in-process:
- Local debug output shows sampled MCP spans for
initialize,notifications/initialized, andtools/call session_show_defaults. - Local exporter reports spans exported.
- Local debug output shows sampled MCP spans for
- Despite local span export, Sentry project query for spans currently returns
count() = 0in the tested time window.
- Local MCP call validation:
session_show_defaultsinvoked over stdio client; server started successfully.
- Local in-memory instrumentation validation:
- Debug logs show:
Starting sampled root span op: mcp.serverFinishing ... tools/call session_show_defaultsSpanExporter exported 3 spans
- Debug logs show:
- Sentry MCP queries:
- Spans in last hour:
count() = 0 - Transactions in last hour:
count() = 0 - Trace for issue
XCODEBUILDMCP-6:Total Spans: 0, Errors: 1
- Spans in last hour:
Investigated two active symptoms:
- MCP tools are not visible in Sentry MCP view.
- Logs are not visible in Sentry Logs Explorer.
- Error events are ingesting correctly in the target project.
- Sentry query: errors in last 24h =
11.
- Sentry query: errors in last 24h =
- Logs and spans datasets remain empty in the same project/time windows.
- Sentry query: logs in last 24h/7d =
0. - Sentry query: spans in last 24h/14d =
0. - Sentry query: transactions in last 14d/15m =
0.
- Sentry query: logs in last 24h/7d =
- SDK-side emission is working for both logs and transactions.
- Direct probe emitted:
Sentry.logger.info('envelope logger probe ...')Sentry.startSpan({ forceTransaction: true, ... })
- Runtime instrumentation confirmed envelope item types sent:
ENVELOPE_ITEM_TYPES logENVELOPE_ITEM_TYPES transaction- plus expected
event/sessionitems.
- Direct probe emitted:
- Despite emitted envelopes, Sentry queries still return zero logs/spans/transactions.
- Strongly indicates an ingestion/storage/configuration issue outside current app code path.
- MCP wrapper is enabled with safe options:
src/server/server.ts:72useswrapMcpServerWithSentry(..., { recordInputs: false, recordOutputs: false }).
- Sentry logs pipeline is enabled:
src/utils/sentry.ts:282setsenableLogs: true.src/utils/sentry.ts:286setsbeforeSendLog: redactLog.
- Logger forwards only explicit opt-in internal logs:
src/utils/logger.ts:56(context?.sentry === true).src/utils/logger.ts:236fallback usescaptureMessageonly if logger method is unavailable.
- Runtime split is real:
- Daemon handles
tool.invokerequests (src/daemon/daemon-server.ts:117), includingruntime: 'daemon'(src/daemon/daemon-server.ts:128). - CLI paths route many invocations through daemon (
src/runtime/tool-invoker.ts:192). - MCP wrapper only covers stdio MCP server runtime (
src/server/server.ts:72).
- Daemon handles
- Most likely primary blocker: Sentry-side configuration/entitlement/pipeline for traces and logs in this project/org (not client emission).
- Secondary (not primary) code risk:
process.exit(...)without explicitSentry.flush/closein shutdown paths can still drop buffered telemetry in some paths:src/server/start-mcp-server.ts:68src/server/start-mcp-server.ts:83src/daemon.ts:303src/daemon.ts:310src/daemon.ts:402
- "MCP wrapper is removed or disabled." Eliminated.
- "Logs are not being captured by SDK at all." Eliminated (capture hooks + envelope inspection confirm capture/send).
- "Transactions are not being created by SDK at all." Eliminated (manual forced transaction emitted and sent).
- Verify project-level traces/logs ingestion settings in Sentry (
sentry/xcodebuildmcp) and any org-level sampling/filtering rules dropping transactions/logs. - Verify account/product entitlement for Logs and Performance on this project.
- Add explicit shutdown drain in app code (
Sentry.flush/Sentry.close) beforeprocess.exit(...)to reduce telemetry loss on fast shutdown. - Keep MCP-view expectation scoped to MCP stdio runtime; add daemon-specific spans if daemon tool-call observability is required in traces.