Context
Once #57529 ships RFC 6750 `insufficient_scope` challenges and #57528 confirms client behavior, MCP no longer needs to publish its own `scopes_supported`. The AS becomes the single source of truth. Linear/Notion/Cloudflare/Stripe already ship without it.
This is the architecture from Matt's #56835 review comment:
Better fix is probably dropping scopes_supported from the resource metadata entirely. RFC 9728 makes it optional, the MCP spec says clients must omit scope when it's absent, and Linear/Notion/Cloudflare/Stripe already ship without it. One list (the AS), no drift.
Change
Drop `scopes_supported: OAUTH_SCOPES_SUPPORTED` from `services/mcp/src/index.ts:243`. Reframe the `OAUTH_SCOPES_SUPPORTED completeness` test in `tool-filtering.test.ts` to assert against the AS list (which the existing generated file already mirrors). Delete `bin/build-mcp-oauth-scopes.py` and `services/mcp/src/lib/oauth-scopes.generated.ts` once nothing else depends on them.
Feature-flagged rollout
The field's presence is gated by a server-side flag:
```ts
scopes_supported: SCOPES_SUPPORTED_PUBLISHED_FLAG
? OAUTH_SCOPES_SUPPORTED
: undefined,
```
(Filtered out of the JSON if undefined.) Default off in dev/preview, off in canary, then full. Allows fast rollback without a deploy if a real-world client breaks.
Pre-conditions
Why
Reaches the spec-clean architecture: AS is the only place `scopes_supported` is published. Any future PostHog resource server (partner SDKs, etc.) inherits "don't publish" by default. The drift class is killed across all surfaces.
Acceptance
- `scopes_supported` field absent from MCP metadata response when flag is off
- Codegen (`bin/build-mcp-oauth-scopes.py`) and generated file deleted, completeness test reframed
- Feature flag wired in, defaulted off, documented rollout plan
- Post-rollout: 0 `invalid_scope` errors in MCP auth logs over 7-day window vs. baseline
Tracking
Parent: #57524
Blocked by: #57525, #57526, #57527, #57528, #57529
Project: https://github.com/orgs/PostHog/projects/194
Context
Once #57529 ships RFC 6750 `insufficient_scope` challenges and #57528 confirms client behavior, MCP no longer needs to publish its own `scopes_supported`. The AS becomes the single source of truth. Linear/Notion/Cloudflare/Stripe already ship without it.
This is the architecture from Matt's #56835 review comment:
Change
Drop `scopes_supported: OAUTH_SCOPES_SUPPORTED` from `services/mcp/src/index.ts:243`. Reframe the `OAUTH_SCOPES_SUPPORTED completeness` test in `tool-filtering.test.ts` to assert against the AS list (which the existing generated file already mirrors). Delete `bin/build-mcp-oauth-scopes.py` and `services/mcp/src/lib/oauth-scopes.generated.ts` once nothing else depends on them.
Feature-flagged rollout
The field's presence is gated by a server-side flag:
```ts
scopes_supported: SCOPES_SUPPORTED_PUBLISHED_FLAG
? OAUTH_SCOPES_SUPPORTED
: undefined,
```
(Filtered out of the JSON if undefined.) Default off in dev/preview, off in canary, then full. Allows fast rollback without a deploy if a real-world client breaks.
Pre-conditions
Why
Reaches the spec-clean architecture: AS is the only place `scopes_supported` is published. Any future PostHog resource server (partner SDKs, etc.) inherits "don't publish" by default. The drift class is killed across all surfaces.
Acceptance
Tracking
Parent: #57524
Blocked by: #57525, #57526, #57527, #57528, #57529
Project: https://github.com/orgs/PostHog/projects/194