diff --git a/docker/Dockerfile.non_root b/docker/Dockerfile.non_root index 0235cbe7b58..f15d6cb7cab 100644 --- a/docker/Dockerfile.non_root +++ b/docker/Dockerfile.non_root @@ -53,7 +53,7 @@ RUN mkdir -p /var/lib/litellm/ui && \ mkdir -p /var/lib/litellm/assets && \ cp /app/litellm/proxy/logo.jpg /var/lib/litellm/assets/logo.jpg && \ ( cd /var/lib/litellm/ui && \ - find . -name "*.html" ! -name "index.html" | while read html_file; do \ + find . -name "*.html" ! -name "index.html" | while IFS= read -r html_file; do \ folder_name="${html_file%.html}" && \ mkdir -p "$folder_name" && \ mv "$html_file" "$folder_name/index.html"; \ diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index f2810be27cc..3369af4d1d7 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -1338,17 +1338,6 @@ try: ) # print(f"mounted _next at {server_root_path}/ui/_next") - # Register the MCP OAuth callback route BEFORE mounting the /ui StaticFiles - from litellm.proxy._experimental.mcp_server.discoverable_endpoints import ( - _build_mcp_oauth_callback_html, - ) - - @app.get("/ui/mcp/oauth/callback", include_in_schema=False) - async def _mcp_oauth_ui_callback( - code: Optional[str] = None, state: Optional[str] = None - ) -> HTMLResponse: - return HTMLResponse(content=_build_mcp_oauth_callback_html(code, state)) - app.mount("/ui", StaticFiles(directory=ui_path, html=True), name="ui") def _restructure_ui_html_files(ui_root: str) -> None: @@ -1409,6 +1398,23 @@ try: except Exception: pass + +# Register the MCP OAuth callback route unconditionally (outside UI setup try block) +# This ensures it works even when static files are unavailable (pip install, read-only fs) +try: + from litellm.proxy._experimental.mcp_server.discoverable_endpoints import ( + _build_mcp_oauth_callback_html, + ) + + @app.get("/ui/mcp/oauth/callback", include_in_schema=False) + async def _mcp_oauth_ui_callback( + code: Optional[str] = None, state: Optional[str] = None + ) -> HTMLResponse: + return HTMLResponse(content=_build_mcp_oauth_callback_html(code, state)) +except ImportError: + # MCP endpoints not available in this installation + pass + current_dir = os.path.dirname(os.path.abspath(__file__)) # ui_path = os.path.join(current_dir, "_experimental", "out") # # Mount this test directory instead