Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(core): resolve MCP capture policy per operation - #23437

Merged
JPeer264 merged 4 commits into
developfrom
bt/fix-mcp-capture-policy
Aug 31, 2026
Merged

fix(core): resolve MCP capture policy per operation#23437
JPeer264 merged 4 commits into
developfrom
bt/fix-mcp-capture-policy

Conversation

@betegon

@betegon betegon commented Aug 14, 2026

Copy link
Copy Markdown
Member

MCP server instrumentation now honors the active Sentry client's GenAI input
and output collection settings even when the server was wrapped before that
client became available. Explicit wrapper overrides still win independently,
and the existing default remains unchanged when no policy is configured.

The capture decision belongs to the operation that starts the span.
Request/response pairs therefore retain one policy for their full lifetime
instead of allowing response timing or a different active scope to change what
gets recorded. Notifications resolve against the client active when their
operation begins. Explicit options are also snapshotted on the first wrap,
preserving the wrapper's idempotent behavior.

This is shared transport behavior, so it applies to sessionful MCP SDK v1 and
stable MCP SDK v2 without changing the public API. Packaged SDK coverage uses
the Node and Cloudflare MCP fixtures. A disposable Cloudflare Worker running
the packaged SDK also verified the policy matrix against Sentry for both modern
and legacy-compatible requests.

Root cause

wrapMcpServerWithSentry read dataCollection.genAI once, while the wrapper
was being constructed. Common Node import ordering and Cloudflare Durable
Object initialization can run that code before Sentry binds a client, causing
the true fallback to become the permanent capture policy for every operation
handled by that server.

Fixes #23436

@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 28.56 kB -4.27% -1.27 kB 🔽
@sentry/browser - with treeshaking flags 26.92 kB -3.95% -1.11 kB 🔽
@sentry/browser (incl. Tracing) 48.75 kB +3.19% +1.51 kB 🔺
@sentry/browser (incl. Tracing + Span Streaming) 48.76 kB +3.16% +1.49 kB 🔺
@sentry/browser (incl. Tracing, Profiling) 51.68 kB -0.62% -321 B 🔽
@sentry/browser (incl. Tracing, Replay) 88.23 kB +1.89% +1.64 kB 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 77.63 kB +2.14% +1.62 kB 🔺
@sentry/browser (incl. Tracing, Replay with Canvas) 92.93 kB +1.81% +1.65 kB 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 105.85 kB +1.83% +1.9 kB 🔺
@sentry/browser (incl. Feedback) 46.05 kB -2.31% -1.09 kB 🔽
@sentry/browser (incl. sendFeedback) 33.62 kB -3.02% -1.04 kB 🔽
@sentry/browser (incl. FeedbackAsync) 38.73 kB -2.64% -1.05 kB 🔽
@sentry/browser (incl. Metrics) 29.51 kB -4.53% -1.4 kB 🔽
@sentry/browser (incl. Logs) 29.8 kB -4.32% -1.34 kB 🔽
@sentry/browser (incl. Metrics & Logs) 30.43 kB -4.35% -1.38 kB 🔽
@sentry/react 30.3 kB -4.19% -1.32 kB 🔽
@sentry/react (incl. Tracing) 50.94 kB +2.9% +1.43 kB 🔺
@sentry/vue 35.73 kB +2.31% +806 B 🔺
@sentry/vue (incl. Tracing) 51.02 kB +3.61% +1.77 kB 🔺
@sentry/svelte 28.59 kB -4.25% -1.27 kB 🔽
CDN Bundle 30.35 kB -4.79% -1.52 kB 🔽
CDN Bundle (incl. Tracing) 49.38 kB +3.88% +1.84 kB 🔺
CDN Bundle (incl. Logs, Metrics) 32.58 kB -2.5% -834 B 🔽
CDN Bundle (incl. Tracing, Logs, Metrics) 51.25 kB +4.72% +2.31 kB 🔺
CDN Bundle (incl. Replay, Logs, Metrics) 73.17 kB +0.59% +425 B 🔺
CDN Bundle (incl. Tracing, Replay) 86.86 kB +1.97% +1.68 kB 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 88.73 kB +2.58% +2.23 kB 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 92.8 kB +1.97% +1.79 kB 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 94.64 kB +2.53% +2.33 kB 🔺
CDN Bundle - uncompressed 89.95 kB -4.94% -4.67 kB 🔽
CDN Bundle (incl. Tracing) - uncompressed 147.2 kB +3.58% +5.08 kB 🔺
CDN Bundle (incl. Logs, Metrics) - uncompressed 96.24 kB -3.02% -3 kB 🔽
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 152.89 kB +4.65% +6.79 kB 🔺
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 225.41 kB +0.66% +1.47 kB 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed 266.69 kB +2.04% +5.32 kB 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 272.37 kB +2.65% +7.03 kB 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 280.4 kB +1.94% +5.32 kB 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 286.06 kB +2.52% +7.03 kB 🔺
@sentry/nextjs (client) 53.56 kB +2.84% +1.48 kB 🔺
@sentry/sveltekit (client) 49.19 kB +3.11% +1.48 kB 🔺
@sentry/core/server 65.7 kB +0.28% +179 B 🔺
@sentry/core/browser 51.86 kB -0.04% -20 B 🔽
@sentry/node 123.77 kB +2.94% +3.53 kB 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 85.53 kB added added
@sentry/node - without tracing 88.03 kB +5.19% +4.34 kB 🔺
@sentry/aws-serverless 96.42 kB +4.41% +4.07 kB 🔺
@sentry/cloudflare (withSentry) - minified 201.04 kB -8.06% -17.61 kB 🔽
@sentry/cloudflare (withSentry) 500.26 kB -7.17% -38.59 kB 🔽
@sentry/browser - with treeshaking flags tracing without tracing 26.82 kB added added
@sentry/node - without channel injection 103.18 kB added added

View base workflow run

@betegon
betegon marked this pull request as ready for review August 14, 2026 19:37
@betegon
betegon requested a review from JPeer264 August 14, 2026 19:45
@github-actions

Copy link
Copy Markdown
Contributor

👋 @JPeer264 — Please review this PR when you get a chance!

2 similar comments
@github-actions

Copy link
Copy Markdown
Contributor

👋 @JPeer264 — Please review this PR when you get a chance!

@github-actions

Copy link
Copy Markdown
Contributor

👋 @JPeer264 — Please review this PR when you get a chance!

betegon and others added 3 commits August 31, 2026 14:24
MCP servers can be wrapped before a Sentry client exists, causing
inherited data collection settings to be fixed to their fallback values.
Resolve inherited policy when an operation begins and retain request
policy through response correlation.

Co-Authored-By: OpenAI Codex <[email protected]>
Node module evaluation and Cloudflare Durable Object initialization can
wrap MCP servers before Sentry binds a client. Exercise both runtimes
with marker content so capture-policy regressions are observable.

Co-Authored-By: OpenAI Codex <[email protected]>
Keep the public input and output capture defaults protected when an MCP operation has no active client or explicit overrides.

Co-Authored-By: OpenAI Codex <[email protected]>
@JPeer264
JPeer264 force-pushed the bt/fix-mcp-capture-policy branch from 7d7937d to 3af48f3 Compare August 31, 2026 12:27

@JPeer264 JPeer264 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks for that fix

@JPeer264
JPeer264 force-pushed the bt/fix-mcp-capture-policy branch from 9ab7892 to 5e8c79c Compare August 31, 2026 15:30
@JPeer264
JPeer264 merged commit 6f11ca5 into develop Aug 31, 2026
553 of 557 checks passed
@JPeer264
JPeer264 deleted the bt/fix-mcp-capture-policy branch August 31, 2026 17:30
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Backport of: #23437

## Differences to the original PR

- `packages/core/src/integrations/mcp-server/transport.ts`: the
no-client fallback in `resolveMcpOptions` is `false` for
`recordInputs`/`recordOutputs`, not `true`. On v10
`resolveDataCollectionOptions` still routes through the `sendDefaultPii`
bridge when `dataCollection` is absent, so the old
`wrapMcpServerWithSentry` code fell back to `false` when no client
existed. Keeping `true` here would start capturing MCP inputs and
outputs on a maintenance branch.
- `packages/core/src/integrations/mcp-server/transport.ts`:
`startInactiveSpan` is imported from `../../tracing` together with
`withActiveSpan`; v10 has no separate `../../tracing/trace` import in
this file.
-
`packages/core/test/lib/integrations/mcp-server/capturePolicy.test.ts`:
the span-config helpers use `sentry.source` instead of
`sentry.segment.name.source`, and the tool config carries a top-level
`op: 'mcp.server'`, matching v10's `buildMcpServerSpanConfig`. The
no-client case asserts that inputs and outputs are omitted, following
the fallback above.
- `dev-packages/e2e-tests/test-applications/node-express/src/app.ts`:
the `dataCollection.genAI` block is not added. On v10 the presence of
any `dataCollection` key switches the resolution base from the
`sendDefaultPii` bridge to the permissive spec defaults, which would
have flipped `userInfo`, `cookies`, `httpHeaders`, `httpBodies` and
`databaseQueryData` on for every other test in this app. Without the
block, `genAI` already resolves to `{ inputs: false, outputs: false }`,
so the new MCP e2e assertions hold unchanged.
-
`dev-packages/e2e-tests/test-applications/cloudflare-mcp-agent/src/index.ts`:
the `genAI` settings are merged into the existing `dataCollection: {
userInfo: true }` object. v10 already sets `dataCollection` in both
`Sentry.init` calls, so the original patch would have produced a
duplicate key and silently dropped `userInfo: true`.

Co-authored-by: Miguel Betegón <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP server wrapper resolves genAI capture policy before a Sentry client is available

2 participants