Skip to content

fix(sentry): stop tracing GET requests to the MCP streamable routes - #2100

Merged
egelhaus merged 1 commit into
mainfrom
fix/sentry-skip-mcp-get-traces
Sep 21, 2026
Merged

egelhaus merged 1 commit into
mainfrom
fix/sentry-skip-mcp-get-traces

Conversation

@giladresisi

Copy link
Copy Markdown
Collaborator

What kind of change does this PR introduce?

Observability fix (backend and orchestrator, Sentry init). tracesSampler in libraries/nestjs-libraries/src/sentry/initialize.sentry.ts now returns 0 for GET requests to the MCP streamable-HTTP routes (/mcp, /mcp/:id and the /mcp-oauth* mounts), so they no longer produce Sentry transactions. POST traffic on the same routes, the legacy /sse/:id transport, the /.well-known OAuth discovery routes and every other route keep the existing sample rates (20%, and 1% for public analytics). No request handling changes.

Why was this change needed?

The MCP server is stateless, so the GET that streamable-HTTP clients send to open a server-to-client stream is not a supported route: nothing is ever pushed on it. It is still about a quarter of MCP traffic, roughly 180k to 214k of about 750k requests per day, and each GET became a Sentry transaction that stayed open for the life of the held connection (about 5 minutes on average, 15 minutes at p95).

Sentry usage is already close to its limits, which is why #2082 recently cut trace sampling from 100% to 20%. Traces of an unsupported route tell us nothing, so there is no reason to keep spending quota on them. While sampling was at 100%, these long-lived transactions (plus a profiler each) were also a large part of what made the MCP service's heap climb to the V8 limit about once a day; the climb stopped when #2082 deployed.

Other information:

This pairs with #1850, which answers these GETs with 405. Please merge and deploy this PR after #1850 has been verified in production, because that verification reads the GET transactions in Sentry (grouped by user agent and status code) and this PR removes them.

The route match is anchored at the start of the path, so /.well-known/oauth-protected-resource/mcp-oauth and unrelated paths such as /mcpfoo are not affected.

QA

  1. Run the backend with a Sentry DSN pointing at a non-production environment
  2. Send about 50 GET requests to /mcp, /mcp/<api key> and /mcp-oauth-claude (with and without an Authorization header)
  3. Send about 50 POST tools/list requests to /mcp (bearer token) and /mcp/<api key>
  4. Wait about 5 minutes for ingestion, then in Sentry Explore > Traces query is_transaction:true transaction:*mcp* for that environment, grouped by transaction and http.request.method
  5. Expect POST /mcp and POST /mcp/:id transactions to be present (at the 20% sample rate) and no transaction with http.request.method:GET for any MCP route
  6. Request /.well-known/oauth-protected-resource/mcp-oauth and any regular API route a few dozen times and confirm their GET transactions still appear

Results of the testing already done:

  • Called the real tracesSampler with request contexts shaped like Sentry's http instrumentation passes them (method and URL via normalizedRequest, and via span attributes only). GET on /mcp, /mcp/:id, /mcp-oauth-claude and /mcp?x=1 returns 0. POST on the same routes returns 0.2. Unrelated GETs return 0.2, public analytics 0.01, legacy /sse/:id 0.2, /.well-known/.../mcp-oauth 0.2, /mcpfoo 0.2.
  • Ran the backend against a Sentry development environment and sent 140+ GETs and 60+ POSTs to /mcp, /mcp/:id and /mcp-oauth-claude: zero GET transactions were recorded, while POST /mcp and POST /mcp/:id were recorded as before. Same result on SDK 10.45.0 (the locked version) and 10.56.0.
  • Backend type-check passes.

Checklist:

Put a "X" in the boxes below to indicate you have followed the checklist;

  • I have read the CONTRIBUTING guide.
  • I have signed the Contributor License Agreement (CLA) (ICLA for individuals, CCLA for entities).
  • I confirm I have not used AI to submit this PR or generate code for it.
  • I checked that there were no similar issues or PRs already open for this.
  • This PR fixes just ONE issue
  • I have filled in the QA section above with real steps to verify this change.

🤖 Generated with Claude Code

The MCP server is stateless, so the GET that streamable-HTTP clients send
to open a server-to-client stream is not a supported route: nothing is
ever pushed on it. It is still about a quarter of MCP traffic (roughly
180k-214k of ~750k requests per day), and each one became a Sentry
transaction that stayed open for the life of the held connection
(avg ~5 min, p95 15 min).

Sentry usage is already near its limits, which is why #2082 recently cut
trace sampling from 100% to 20%. There is nothing to learn from traces of
an unsupported route, so tracesSampler now returns 0 for GET on /mcp,
/mcp/:id and the /mcp-oauth* mounts. POST traffic on the same routes, the
legacy /sse/:id transport and the /.well-known discovery routes keep the
existing sample rates.

Pairs with the change that answers these GETs with 405. Deploy this one
after that change has been verified in Sentry, because the verification
reads the GET transactions this commit removes.

Testing:
- Called the real tracesSampler with request contexts shaped like the
  http instrumentation passes them (method and URL via normalizedRequest
  and via span attributes only): GET on the MCP routes returns 0; POST on
  the same routes 0.2; unrelated GETs 0.2; analytics 0.01; legacy /sse
  0.2; /.well-known/.../mcp-oauth discovery 0.2; /mcpfoo 0.2.
- Ran the backend against a Sentry development environment and sent
  140+ GETs and 60+ POSTs to /mcp, /mcp/:id and /mcp-oauth-claude: zero
  GET transactions recorded, POST /mcp and POST /mcp/:id recorded as
  before. Same result on SDK 10.45.0 and 10.56.0.
- Backend type-check passes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@strix-security

strix-security Bot commented Sep 18, 2026

Copy link
Copy Markdown

Strix Security Review

No security issues found.

Updated for 78f8a04.


Reviewed by Strix
Re-run review · Configure security review settings

@postiz-contribution postiz-contribution Bot added the contribution:approved Approved contributor label Sep 18, 2026
@postiz-agent

postiz-agent Bot commented Sep 18, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@egelhaus
egelhaus added this pull request to the merge queue Sep 21, 2026
Merged via the queue into main with commit 30be46e Sep 21, 2026
13 checks passed
@egelhaus
egelhaus deleted the fix/sentry-skip-mcp-get-traces branch September 21, 2026 04:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants