## Problem
Sentry **PHP-LARAVEL-4Q** fires on POST `/mcp/oauth`: a client presents
a bearer token with a bad/expired/wrong JWT signature ("Token signature
mismatch"), Passport's `TokenGuard` → league/oauth2-server throws
`OAuthServerException::accessDenied` (HTTP **401**). Laravel returns the
correct 401 to the client (`handled: yes`) **but also reports it to
Sentry as an error** — noise, not a server fault. It's recurring (fresh
events after the initial ones).
These OAuth exceptions are, by design, client-facing 4xx protocol
responses (expired/invalid tokens, denied consent, bad grants). Any
public OAuth endpoint — and the MCP endpoint accepts
dynamically-registered Claude/ChatGPT clients — sees a steady stream of
them. They should not page as errors.
`OAuthServerException` does not implement `HttpExceptionInterface`, so
Laravel's built-in `internalDontReport` does not already cover it.
## Fix
Add a `dontReportWhen` rule in `bootstrap/app.php` for
`OAuthServerException` whose HTTP status is **< 500**, mirroring the
existing `MaxAttemptsExceededException` guard right above it.
`serverError` (500) — the only 5xx variant, the genuine "unexpected
condition" case — still reports, so real OAuth-flow faults stay visible.
**Reporting-only change — no user-facing behavior changes.** Clients
still receive the same 4xx OAuth error responses (status/body/headers
unchanged).
## Tests
`tests/Feature/Mcp/McpOAuthTest.php`: assert
`ExceptionHandler::shouldReport()` is `false` for `accessDenied()` (401)
and `invalidCredentials()` (400), and `true` for `serverError()` (500).
## Notes
- Two independent reviews (architecture + product/bug): no must-fix,
both "ship as-is".
- Follow-up (not code): a mass signing-key mismatch would fail as
`access_denied` (401) and thus be suppressed here — the right way to
catch that is an MCP success-rate / 401-rate alert, not error-count.
Worth adding as an alert later.