Fixes issue #959 — two bugs causing ChatGPT's custom MCP connector to fail:
1. RFC 9728 path-based PRM: ChatGPT requests
/.well-known/oauth-protected-resource/mcp (path-aware URL per RFC 9728
§5). The old TREK handler only registered the base path; requests for
the path variant fell through to the SPA catch-all and returned HTML.
mcpAuthMetadataRouter registers the path-aware URL automatically.
2. DCR without scope: ChatGPT never sends scope during Dynamic Client
Registration (RFC 7591 makes it optional). The old handler returned
400 for missing scope. clientRegistrationHandler accepts it;
trekClientsStore.registerClient defaults to ALL_SCOPES when absent,
and the user still grants only what they approve at the consent UI
(scopeSelectable=true for DCR clients is unchanged).
Hybrid approach: SDK handles /.well-known, /oauth/authorize (redirect to
consent SPA), and /oauth/register. TREK keeps its own /oauth/token and
/oauth/revoke because SDK clientAuth does plain-text secret comparison
while TREK uses SHA-256 hashing — incompatible without a full clientAuth
rewrite.
SPA consent page renamed /oauth/authorize → /oauth/consent to avoid
routing conflict with the SDK's backend authorize handler now mounted at
that path. Existing URL paths (/oauth/token etc.) are unchanged so
active Claude.ai connections are unaffected.
Other: lazy-init SDK metadata router so getAppUrl() (DB query) is not
called at createApp() time; path-aware mcpAddonGate so only /.well-known
returns 404 when MCP is disabled (previously a blanket middleware blocked
all routes including static files); /api/oauth mounted before the SDK
middleware chain so SPA-facing routes with their own 403 gates are
reached correctly.