Three bugs fixed in the RBAC helper for /v2/user/info:
1. N+1 query: target user was fetched inside the team loop, causing one
redundant DB round-trip per team the caller administers. Now hoisted
before the loop — single fetch regardless of team count.
2. Double fetch: the handler performed a second find_unique on the target
user after the access check already fetched it. The helper now returns
the user row directly (Optional[row] instead of bool), so the handler
reuses it.
3. Silent error swallowing: a bare except Exception caught real DB errors
(connection failures, timeouts) and returned False, surfacing them as
mysterious 404s. Removed the try/except so real errors propagate as 500s.
Co-authored-by: yuneng-jiang <yuneng-jiang@users.noreply.github.com>
Cover utils, types, MCPStandardsSettings, MCPLogoSelector, and
mcp_connection_status with 44 behavior-focused Vitest tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- user_dashboard.tsx: Replace userInfoCall with userGetInfoV2 for spend data,
remove keys/teams logic (keys come from props/useKeys hook, teams from fetchTeams)
- user_info_view.tsx: Replace userInfoCall with userGetInfoV2, flatten data
structure from nested {user_info: {...}} to flat response, fetch team details
separately using teamInfoCall, remove keys display (Virtual Keys section)
- Update user_dashboard.test.tsx and user_info_view.test.tsx mocks
Co-authored-by: yuneng-jiang <yuneng-jiang@users.noreply.github.com>
- Add UserInfoV2Response type and userGetInfoV2() function in networking.tsx
- Migrate useCurrentUser hook from userInfoCall to userGetInfoV2
- Update useCurrentUser.test.ts to test new v2 API integration
- The hook no longer needs userRole since the endpoint handles auth itself
Co-authored-by: yuneng-jiang <yuneng-jiang@users.noreply.github.com>
- Add UserInfoV2Response type in _types.py (returns only user object, no keys/teams)
- Add /v2/user/info endpoint handler with proper access control:
- Proxy admins can query any user
- Team admins can query users in their teams
- Internal users can query themselves only
- Returns 404 for unauthorized/not-found (not 403)
- Add /v2/user/info to info_routes in LiteLLMRoutes
- Add route check passthrough in route_checks.py
- Add get_user_v2() method to Python client
Co-authored-by: yuneng-jiang <yuneng-jiang@users.noreply.github.com>
gemini/gemini-2.5-flash lacks cache_creation_input_token_cost in the
model cost map, causing a TypeError when the test multiplies
cache_creation_input_tokens by None. Use claude-haiku-4-5 instead,
which has the required prompt caching cost fields.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PR #23257 changed proxy startup to exit early with "Database setup
failed after multiple retries" instead of letting uvicorn emit
"Application startup failed. Exiting." Update the CI grep check
to accept either error message for robustness.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(mcp): fix OpenAPI OAuth flow — transport mapping, error messages, and discovery bypass
Three bugs fixed to make the end-to-end OAuth flow work for OpenAPI MCP servers:
1. **Transport mapping in getTemporaryPayload**: `TRANSPORT.OPENAPI` is a UI-only concept;
the backend only accepts `"http"`, `"sse"`, or `"stdio"`. The pre-OAuth temp-session
call was sending `transport: "openapi"` and getting a 422. Fixed by mapping to `"http"`.
2. **deriveErrorMessage handles FastAPI 422 arrays**: FastAPI validation errors return
`detail` as an array of `{loc, msg, type}` objects. The shared error extractor was
returning the array directly, causing `Error: [object Object]`. Fixed to map each
item to its `.msg` field.
3. **Skip OAuth discovery when authorization_url already provided**: `build_mcp_server_from_table`
was unconditionally calling `_descovery_metadata(server_url)` for OAuth servers. For
OpenAPI servers the url is the spec JSON file, not the API base — this caused a timeout
fetching e.g. the GitHub spec (2 MB). Fixed by skipping discovery when `authorization_url`
is already set.
Also: collapsible auth section in MCP server form, "Create OAuth App →" link next to
Client ID when a docs URL is available (e.g. GitHub OAuth App creation page), and
`extractErrorMessage` helper in `useMcpOAuthFlow` for cleaner error display.
* refactor(mcp): extract needs_discovery flag and reduceStaticHeaders helper
* feat(mcp): user OAuth connect flow — OAuthConnectModal, MCPCredentialsTab, useUserMcpOAuthFlow
Adds the user-facing MCP OAuth2 PKCE connect flow:
- OAuthConnectModal: modal that launches the PKCE flow for a user to connect to an MCP server
- MCPCredentialsTab: credentials management tab in the MCP apps panel
- useUserMcpOAuthFlow: hook that handles the full PKCE auth code exchange for user-level connections
- MCPAppsPanel: wires up the new credentials tab and connect modal
- ChatPage: further cleanup after responses-API revert
- db.py / mcp_management_endpoints.py / _types.py: backend support for storing user MCP credentials
* fix(mcp): make client_id optional in /authorize — use server's stored client_id when not provided
* address greptile review feedback
* fix(mcp): narrow bare except to RecordNotFoundError in BYOK credential delete
* refactor(mcp): move inline imports to module level in db.py
* docs(claude): add MCP OAuth, transport mapping, and browser storage patterns
* fix(security): remove accessToken from sessionStorage in OAuth flow state
The LiteLLM API key was being serialised into sessionStorage as part of
StoredFlowState. After the OAuth redirect the component re-mounts with the
same accessToken prop, so it never needed to be stored. Read it from props
in resumeOAuthFlow instead.
* fix(ui): remove duplicate extractErrorMessage, sessionStorage-only in admin OAuth hook, call delete API on disconnect
* fix(ui): guard resumeOAuthFlow against wrong hook instance consuming OAuth result
* fix(ui): separate OAuth result keys per flow, sessionStorage-only, surface revoke errors
* fix(ui): remove dead OAuthConnectModal, revert tsconfig jsx mode to preserve
* fix(mcp): guard BYOK overwrite in oauth credential store, raise clear error when client_id absent
* fix: forward OAuth error params in callback, fix BYOK guard exception handling in db.py
Adds a new job to the existing daily staging branch workflow that creates
a `litellm_internal_dev_MM_DD_YYYY` branch from main twice a day. This
branch serves as a staging area before merging into main to improve
stability.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove unused imports (F401), add missing TYPE_CHECKING imports for
forward references (F821), and extract helpers to reduce statement
counts below the 50-statement limit (PLR0915).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- MCP tests: set mock_mcp_server.oauth2_flow = None to prevent MagicMock
leaking into Pydantic Literal validation for MCPServer
- AgentCore tests: pass api_key="test-jwt-token" to bypass SigV4 credential
lookup that fails in CI without AWS credentials
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously this setting was only honored via the AUTO_REDIRECT_UI_LOGIN_TO_SSO
environment variable. Now it can also be set in config.yaml under general_settings,
matching the pattern used by other proxy settings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a request arrives without an API key, auth fails and the failure
hook triggers spend tracking. _is_master_key was called with api_key=None,
causing secrets.compare_digest to raise TypeError. Add a None guard for
api_key matching the existing guard for _master_key.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace removed deprecated models (claude-3-5-sonnet-20241022,
claude-3-5-haiku-20241022, claude-3-5-haiku-latest) with current
models in web_search and cost calculation tests.