- Thread api_version through HTTP handlers to Azure realtime endpoints
- Make expires_at optional in RealtimeClientSecretResponse
- Fix test token expiry times to be in the future
- Populate user_id and team_id in minimal_auth for spend tracking
Made-with: Cursor
- 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>
- Add break after match in user_api_key_auth.py loop to avoid unnecessary
iterations over remaining mapped routes
- Guard against normalized_route being empty when route == root_path exactly,
which would otherwise match every mapped route via startswith("")
- Apply same empty-string guard in pass_through_endpoints.py for consistency
- Azure Model Router transform_response: let parent extract actual model from raw response
- common_request_processing: skip model override for Azure Model Router requests
- proxy_server: skip streaming chunk model restamp for Azure Model Router
- Add _is_azure_model_router_request helper
- Add tests for non-streaming and streaming
Made-with: Cursor
* fix(mcp): OAuth2 chat connect - tools fetch, auth flow, and status fixes
- schema.prisma: add missing MCP table fields (approval_status, submitted_by, submitted_at, reviewed_at, review_notes) to prevent destructive migrations
- rest_endpoints.py: inject user OAuth token via extra_headers for OAuth2 servers so tools list is populated; add server name->UUID resolution so MCPConnectPicker name lookups work
- mcp_registry.json: fix Atlassian defaults (transport: http, url: .../v1/mcp)
- ChatPage.tsx: read mcpOauthReturn param to init sidebarView="apps" on OAuth return, clean up param after mount
- MCPAppsPanel.tsx: auto-add OAuth2 servers to selectedServers when credential detected; onConnect also enables server for chat; disconnect removes from selectedServers
- mcp_servers.tsx: sort servers by created_at DESC
- useUserMcpOAuthFlow.tsx: append mcpOauthReturn=apps to return URL so Apps panel is mounted on return
* address greptile review feedback (greploop iteration 1)
* fix(mcp): inject stored OAuth2 token when fetching tools via /responses API
When a user has connected an OAuth2 MCP server (e.g. Atlassian) and then
uses the /responses endpoint with that server, tool listing was failing
because the stored per-user OAuth token was never injected.
Two fixes:
1. server.py: add _get_user_oauth_extra_headers_from_db() helper; call it
in _get_tools_from_mcp_servers when oauth2_headers is None for an OAuth2
server, falling back to the user's stored token in LiteLLM_MCPUserCredentials
2. litellm_proxy_mcp_handler.py: also intercept MCP tools whose server_url
matches */mcp/<server_name> (e.g. http://localhost:4000/mcp/atlassian_test)
by rewriting them to litellm_proxy/mcp/<server_name> so they go through
the internal handler (and get the OAuth token injected) instead of being
forwarded to OpenAI raw where localhost is unreachable
* address greptile review feedback (greploop iteration 2)
* test(mcp): add unit test for OAuth2 token injection in _get_tools_from_mcp_servers
Verifies that when _get_tools_from_mcp_servers is called for an OAuth2 MCP
server without oauth2_headers in the request, the implementation:
- calls _prefetch_oauth_creds_for_user once (not per-server) to avoid N+1 queries
- passes the stored token as extra_headers={"Authorization": "Bearer ..."} to
_get_tools_from_server so the upstream OAuth2 MCP server authenticates correctly
* address greptile review feedback (greploop iteration 3)
* address greptile review feedback (greploop iteration 4)
* address greptile review feedback (greploop iteration 5)
* redesign credentials table to use Tremor table layout matching Keys page
* fix: /server/oauth authorize 422 - make client_id optional, fall back to real DB server
* fix: mcp_token client_id optional, resolve from server record
* fix: look up real server by UUID (get_mcp_server_by_id) before falling back to name
* Update litellm/responses/mcp/litellm_proxy_mcp_handler.py
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* fix: address greptile feedback - client_id guards, dict spread, helper refactor, tests
- mcp_management_endpoints: raise 400 when resolved_client_id is empty in
mcp_authorize and mcp_token instead of forwarding "" to upstream
- litellm_proxy_mcp_handler: use {**tool, "server_url": ...} spread instead
of dict(tool) + mutation for shallow copy safety
- rest_endpoints: extract _oauth2_server_ids set comprehension to a named
_get_oauth2_server_ids() helper for clarity; add Set to typing imports
- test_rest_endpoints: add tests for name→UUID resolution path,
access-denied when resolved UUID not in allowed list, and OAuth2 user
token injection for single-server requests; fix fake_get_tools signature
to accept extra_headers kwarg
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Snowflake's Cortex LLM API (like Anthropic) requires tool_choice as an
object with a "type" field, not as a bare string. Passing tool_choice="auto"
(or "required"/"none") results in error 390142 "invalid payload".
This fix transforms OpenAI string tool_choice values to the Snowflake
object format:
- "auto" -> {"type": "auto"}
- "required" -> {"type": "any"} (Snowflake/Anthropic convention)
- "none" -> {"type": "none"}
The dict-to-dict transformation for specific function tool choices
({"type": "function", "function": {"name": "..."}} -> {"type": "tool",
"name": [...]}) remains unchanged.
Fixes#23284
Co-authored-by: gambletan <tan@echooo.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Krish Dholakia <krrishdholakia@gmail.com>
* feat(ui): group MCP tools by CRUD risk category in tool permission panels
Adds a CRUD-classification layer to the MCP tool allowlist UI so admins
can allow/block an entire risk category (Read / Create / Update / Delete)
with a single toggle instead of managing a flat list of individual tools.
- New `mcpToolCrudClassification.ts` utility: regex-based classifier that
buckets tool names/descriptions into read/create/update/delete/unknown
- New `McpCrudPermissionPanel` component: collapsible sections per CRUD
group, group-level Switch toggle, individual tool checkboxes, risk badges
(green Safe / yellow Medium / red High Risk)
- `mcp_tool_configuration.tsx`: adds "Risk Groups / Flat List" radio toggle;
defaults to the CRUD-grouped view, flat list is still accessible
- `MCPToolPermissions.tsx` (key/team assignment): replaces flat checkboxes
with the CRUD panel; adds per-server view toggle; delete tools are blocked
by default for newly-added servers (safer default for key/team scoping)
No backend or schema changes — uses existing `allowed_tools` and
`mcp_tool_permissions` fields.
* fix(mcp): OAuth2 chat connect - tools fetch, auth flow, and status fixes
- schema.prisma: add missing MCP table fields (approval_status, submitted_by, submitted_at, reviewed_at, review_notes) to prevent destructive migrations
- rest_endpoints.py: inject user OAuth token via extra_headers for OAuth2 servers so tools list is populated; add server name->UUID resolution so MCPConnectPicker name lookups work
- mcp_registry.json: fix Atlassian defaults (transport: http, url: .../v1/mcp)
- ChatPage.tsx: read mcpOauthReturn param to init sidebarView="apps" on OAuth return, clean up param after mount
- MCPAppsPanel.tsx: auto-add OAuth2 servers to selectedServers when credential detected; onConnect also enables server for chat; disconnect removes from selectedServers
- mcp_servers.tsx: sort servers by created_at DESC
- useUserMcpOAuthFlow.tsx: append mcpOauthReturn=apps to return URL so Apps panel is mounted on return
* fix(mcp-crud-ui): address greptile review feedback
- use Checkbox (not Switch) for group toggle so indeterminate works
- add toolPermissionsRef to avoid stale closure race on concurrent server fetches
- remove unused blockDeleteByDefault prop from McpCrudPermissionPanel
- classify tools by name first; fall back to description only when name yields no match
- add Risk Groups / Flat List toggle to mcp_tool_configuration.tsx
* fix(mcp-crud-ui): address greptile 3/5 review
- remove non-functional XIcon remove-server button (no onRemoveServer prop wired)
- fix stale closure in MCPAppsPanel auto-enable effect: use serversRef/selectedServersRef
- remove utility re-export from McpCrudPermissionPanel (classifyToolOp, groupToolsByCrud)
- remove redundant selectedTools.length === 0 guard (always true when !toolPermissions[id])
* fix(mcp-crud-ui): address greptile 3/5 review round 2
- check READ_RE before DELETE_RE in classifyToolOp so tools like
get_removed_entries are not silently blocked by delete-by-default
- expand undefined (allow-all) to full tool name list instead of
collapsing to [] (allow-none) in MCPToolPermissions and mcp_tool_configuration
- log OAuth credential fetch failures instead of silently swallowing them
* fix: cursor-pointer on read-only rows, stable sort, simplify handleCrudPanelChange
* fix: sanitize user_id/server_id in log to prevent log injection
* fix: add OAuth headers to call_tool_rest_api, fix stale accessToken closure, fix group toggle on filtered subset
* fix: batch OAuth creds query, hide empty CRUD groups on search, onChange stability
* fix: double-add race, conditional bulk query, narrow DELETE_RE, hoist search input
* fix(mcp): clear oauthConnected on deselect; null guard on allowedTools prop
* fix(mcp): remove user-provided values from debug log to fix log-injection lint
* fix(mcp): fix allowedTools undefined semantics; remove unused import and color field