fix: support cloud OAuth clients and graceful DCR fallback

Claude AI (web) sends a Cognito-issued client_id with an HTTPS redirect
URI, but the client registry only supported localhost redirect URIs via
ALLOWED_MCP_CLIENTS. Add ALLOWED_MCP_CLOUD_CLIENTS env var for web-based
clients with format "client_id|redirect_uri".

Also fix the DCR proxy to return a clear error when the upstream IdP
(e.g. Cognito) doesn't support dynamic client registration, instead of
silently falling back to a Nextcloud-specific endpoint that fails.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-04-04 22:17:01 +02:00
co-authored by Claude Opus 4.6
parent 15016ba2f1
commit 2a34015443
2 changed files with 37 additions and 11 deletions
+18 -11
View File
@@ -1228,7 +1228,6 @@ async def oauth_register_proxy(request: Request) -> JSONResponse:
)
oauth_config = oauth_ctx["config"]
nextcloud_host = oauth_config["nextcloud_host"]
# Rate limit DCR requests per client IP
client_ip = request.client.host if request.client else "unknown"
@@ -1249,21 +1248,29 @@ async def oauth_register_proxy(request: Request) -> JSONResponse:
timestamps.append(now)
_dcr_rate_limit[client_ip] = timestamps
# Discover registration endpoint from OIDC discovery (prefer over hardcoded path)
# Discover registration endpoint from OIDC discovery
discovery_url = oauth_config.get("discovery_url")
registration_endpoint = None
if discovery_url:
try:
discovery = await _get_cached_discovery(discovery_url)
registration_endpoint = discovery.get(
"registration_endpoint", f"{nextcloud_host}/apps/oidc/register"
)
registration_endpoint = discovery.get("registration_endpoint")
except Exception:
logger.warning(
"Failed to fetch OIDC discovery for DCR endpoint, using fallback"
)
registration_endpoint = f"{nextcloud_host}/apps/oidc/register"
else:
registration_endpoint = f"{nextcloud_host}/apps/oidc/register"
logger.warning("Failed to fetch OIDC discovery for DCR endpoint")
if not registration_endpoint:
logger.warning(
"DCR proxy: Upstream IdP does not support dynamic client registration"
)
return JSONResponse(
{
"error": "registration_not_supported",
"error_description": "The upstream identity provider does not support "
"dynamic client registration. Configure the client statically using "
"ALLOWED_MCP_CLIENTS or ALLOWED_MCP_CLOUD_CLIENTS.",
},
status_code=400,
)
logger.info(f"DCR proxy: Forwarding registration to {registration_endpoint}")