Skip to content

fix(telemetry): Report createMcpHandler errors from the Worker - #72

Merged
sergical merged 1 commit into
mainfrom
fix/worker-mcp-onerror
Oct 28, 2026
Merged

sergical merged 1 commit into
mainfrom
fix/worker-mcp-onerror

Conversation

@sergical

Copy link
Copy Markdown
Member

Follow-up to a review finding on #67.

src/worker.ts builds its handler with createMcpHandler(...) but gave it no onerror. The STDIO entry point has one; the Worker did not. The handler catches some faults itself and only reports them through that callback, so Sentry never saw them:

  • Faults inside the handler (for example a modern-protocol request that throws). The handler returns a 500 itself, so the Worker's own try/catch around workerMcpHandler.fetch never sees them.
  • subscriptions/listen refused at the subscription limit (1,024 open streams). The SDK answers HTTP 200 with a JSON-RPC -32603, so app.server.response counts it as a success.

Change

  • onerror now calls Sentry.captureException, except for client rejections.
  • isMcpClientRejection (in src/telemetry.ts) matches the rejections the handler sends to the same callback: UnsupportedProtocolVersionError, Rejected … header and envelope checks, and Unsupported Media Type. The handler already answers each one with a 4xx that the response metric counts, so capturing them would only add scanner and misconfigured-client noise.
  • TELEMETRY.md documents the new error path.

Notes for review

  • Privacy: these events go through the same beforeSend anonymization as every other error event. The SDK error messages contain no request bodies or headers.
  • Duplicates: if the Sentry MCP wrapper has already captured an error object, the SDK skips capturing it again.
  • The legacy (2025) path does not pass its transport errors to this callback, so the transport rejections already handled by errorDropReason are not affected.
  • Tests cover the filter with real SDK error types and messages. The one-line wiring is checked by typecheck only; reaching the subscription limit in a test needs 1,024 open streams.

Checks

  • pnpm typecheck (Worker + Node), pnpm build
  • pnpm test: 299 passed

Created with Claude Code

The Worker built its MCP handler without an onerror callback, so faults
the handler catches itself never reached Sentry. Two cases had no signal
at all: failures it answers with a 500 from inside the handler, and
subscriptions/listen calls refused at the 1,024-stream limit, which
answer HTTP 200 with a JSON-RPC error and so look like success in the
app.server.response metric.

The callback captures everything except the client rejections the
handler also routes there (unsupported protocol revision, failed header
or envelope checks, wrong content type), which already answer 4xx.

Co-authored-by: Claude <claude@anthropic.com>
@sergical
sergical merged commit 72625ba into main Oct 28, 2026
13 checks passed
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.

1 participant