# Patch: hide RFC 9728 / RFC 8414 OAuth discovery on the MetaMCP host. # # Why: MetaMCP unconditionally publishes /.well-known/oauth-protected-resource # and /.well-known/oauth-authorization-server for the WHOLE host, even when # every configured endpoint is public. Spec-compliant MCP clients (claude.ai, # Claude Desktop, per MCP Authorization spec 2026-03-26 + RFC 9728) probe # those paths on connect, see "resource requires OAuth", and pop the # MetaMCP/Authentik login before calling any tool — even a public one. # # The route mounts live in a compiled bundle with no env-var gate # (app.use(oauth_default) at line 10560 of dist/index.js pulls the metadata # router in unconditionally). Fix here is a surgical string swap on the # path literals so Express falls through to its default 404 for those # requests. All 4 references get swapped (2 route registrations + 2 # WWW-Authenticate/resource_metadata string interpolations) so the set of # references is self-consistent. The WWW-Authenticate change is harmless # because it only fires on 401 responses from ENFORCED endpoints, and our # only enforced endpoint (OB1) is consumed with static bearers set in # client config, never via OAuth discovery. # # The RUN block is guarded — it verifies the target strings exist and that # the exact expected number of substitutions happens. A future upstream # rewrite that renames or restructures these paths will FAIL THE BUILD # LOUDLY rather than silently ship a container that still leaks OAuth # discovery. When that happens, re-inspect the bundle and update this file. # # Delete this whole file the day upstream ships an env-var toggle to # disable OAuth discovery (or per-endpoint metadata scoping per RFC 9728). FROM ghcr.io/metatool-ai/metamcp:latest USER root RUN set -eux; \ F=/app/apps/backend/dist/index.js; \ test -f "$F"; \ # Sanity: both discovery route registrations must exist before we patch. grep -Fq "\"/.well-known/oauth-protected-resource\"" "$F"; \ grep -Fq "\"/.well-known/oauth-authorization-server\"" "$F"; \ # Refuse to double-patch (idempotency guard). if grep -Fq "/__jpaul_disabled_oauth" "$F"; then \ echo "already patched — aborting"; exit 1; \ fi; \ # Count occurrences to catch upstream drift (expect 2 of each today). B1=$(grep -Fc "\"/.well-known/oauth-protected-resource\"" "$F"); \ B2=$(grep -Fc "\"/.well-known/oauth-authorization-server\"" "$F"); \ [ "$B1" = "1" ] || { echo "unexpected count $B1 for oauth-protected-resource; upstream changed"; exit 2; }; \ [ "$B2" = "1" ] || { echo "unexpected count $B2 for oauth-authorization-server; upstream changed"; exit 2; }; \ sed -i \ -e "s#\"/\\.well-known/oauth-protected-resource\"#\"/__jpaul_disabled_oauth_pr\"#g" \ -e "s#\"/\\.well-known/oauth-authorization-server\"#\"/__jpaul_disabled_oauth_as\"#g" \ "$F"; \ # Post-condition: no more references to the original discovery paths. if grep -Fq "\"/.well-known/oauth-protected-resource\"" "$F"; then \ echo "patch failed: oauth-protected-resource still present"; exit 3; \ fi; \ if grep -Fq "\"/.well-known/oauth-authorization-server\"" "$F"; then \ echo "patch failed: oauth-authorization-server still present"; exit 3; \ fi; \ # Patched markers present. grep -Fq "/__jpaul_disabled_oauth_pr" "$F"; \ grep -Fq "/__jpaul_disabled_oauth_as" "$F"; \ echo "OAuth discovery routes disabled — patch verified"