litellm/ui/litellm-dashboard
Sameer Kankute ef36e89638
feat(mcp): Add tool call and tool list support via UI for Oauth mcps (#28454)
* feat(mcp): cache OAuth token client-side so Tools tab loads without re-auth

After a user creates an OAuth MCP server and completes the authorization
flow, the resulting access token is now stored in sessionStorage keyed by
server_id.  The MCP Tools tab reads this cached token and includes it as
an MCP auth header when listing and invoking tools, so the user never sees
an empty tool list.  When the session ends (tab close / new browser) an
Authorize button re-triggers the flow without leaving the Tools screen.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

* fix(ui/mcp): surface listMCPTools 401 errors so auth gate reappears

listMCPTools previously swallowed all errors (including HTTP 401) by
returning a synthetic { tools: [], error: 'network_error', ... } payload.
That made the useQuery retry-on-401 guard and mcpToolsError dead code,
so expired OAuth tokens never re-triggered the auth gate.

- Throw an enhanced Error with .status attached on non-2xx responses
  (still preserves the legacy shape for true network failures so the
  caller can render a generic message without crashing).
- Clear the cached OAuth session token when the tools query fails with
  401, mirroring callMCPTool's onError handler so the Authorize button
  is shown again.
- Surface mcpToolsError in the existing error banner.

Co-authored-by: Yassin Kortam <yassin@berri.ai>

* fix(mcp-tools): stable onSuccess + reuse parsed flow state

- Pass stable setOauthToken setter directly as onSuccess to avoid
  recreating useToolsOAuthFlow's resumeOAuthFlow on every render.
- Reuse the already-parsed FLOW_STATE_KEY value (peeked) instead of
  re-reading and re-parsing sessionStorage in resumeOAuthFlow.

Co-authored-by: Yassin Kortam <yassin@berri.ai>

* fix(ui/mcp): restore listMCPTools never-throws contract

The previous fix made listMCPTools throw on HTTP errors while still
returning a synthetic object on network errors. This inconsistent
contract broke existing callers (MCPToolPermissions, MCPAppsPanel,
MCPConnectPicker) which inspect result.error / result.message and
expect the function to never throw.

- Return a normalized { tools: [], error, message, status, ... }
  object on HTTP errors (instead of throwing) so all callers see a
  consistent shape and the user-visible error text from
  result.message is preserved.
- Convert the returned error object into a thrown Error inside the
  one caller that needs it — the useQuery in mcp_tools.tsx — so the
  401 retry/onError handlers still trigger and clear the cached
  OAuth token.

Co-authored-by: Yassin Kortam <yassin@berri.ai>

* fix greptile

* fix(mcp): align OAuth header alias lookup with dashboard sanitization

Backend auth header resolution now matches x-mcp-{alias} keys produced by
the dashboard sanitizer, and the Tools tab re-syncs OAuth tokens when
serverId changes.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(mcp): widen auth header lookup types for list_tools

Accept legacy str | dict server auth maps and annotate list_tools
server_auth_header as Union[str, dict] for mypy.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor(ui): extract shared buildCallbackUrl/clearStorage for MCP OAuth hooks

Hoist the duplicate buildCallbackUrl and clearStorage helpers out of
useToolsOAuthFlow and useUserMcpOAuthFlow into a new shared module
src/hooks/mcpOAuthUtils.ts so the two hooks cannot drift if the URL
construction or storage cleanup logic needs to change.

Co-authored-by: Yassin Kortam <yassin@berri.ai>

* fix(ui): don't gate M2M OAuth MCP servers behind interactive authorize

M2M (client_credentials) OAuth servers share auth_type="oauth2" with
interactive PKCE servers, but the backend fetches their token internally
and they typically lack a user authorization endpoint. Gating tool
listing on them rendered an Authorize button that would fail or redirect
incorrectly. Detect M2M via the presence of token_url (matching the
existing heuristic in mcp_server_edit.tsx) and skip the auth gate.

Co-authored-by: Yassin Kortam <yassin@berri.ai>

* fix(ui/mcp): return error shape when listMCPTools JSON parse fails

Restore the never-throws contract when response.json() fails on a 2xx
body so callers do not receive null and crash on result.tools.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 09:04:04 -07:00
..
e2e_tests test(e2e): forward LITELLM_LICENSE to UI e2e proxy (#28398) 2026-05-21 18:17:03 -07:00
public [Infra] Promote internal staging to main (#27245) 2026-05-05 16:15:03 -07:00
scripts style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
src feat(mcp): Add tool call and tool list support via UI for Oauth mcps (#28454) 2026-05-22 09:04:04 -07:00
tests [Refactor] UI - Spend Logs: consolidate filter state and extract components (#25847) 2026-05-19 10:58:48 -07:00
.env.development hidden dashboard routing, dev and build env files 2025-10-06 19:21:34 -07:00
.env.production remove next env 2026-04-18 16:45:32 -07:00
.eslintrc.json removed unused imports 2025-10-10 10:25:00 -07:00
.npmrc [Fix] CI/Tooling: Correct min-release-age value in .npmrc files 2026-04-29 19:49:27 -07:00
.nvmrc [Infra] Promote internal staging to main (#27245) 2026-05-05 16:15:03 -07:00
.prettierignore added and ran prettier autoformatter 2025-10-04 18:19:48 -07:00
.prettierrc added and ran prettier autoformatter 2025-10-04 18:19:48 -07:00
build_release_ui.sh build release ui script 2026-01-17 18:16:14 -08:00
build_ui.sh chore: harden npm supply chain — pin overrides, enforce npm ci, add ignore-scripts (#24838) 2026-03-31 13:41:37 -07:00
build_ui_custom_path.sh chore: harden npm supply chain — pin overrides, enforce npm ci, add ignore-scripts (#24838) 2026-03-31 13:41:37 -07:00
knip.json add knip as a dev dependency, remove some unused files 2026-02-07 15:51:21 -08:00
next.config.mjs feat(proxy): move search tool access to object permissions 2026-04-29 12:29:20 +05:30
package-lock.json build(deps): bump next from 16.2.4 to 16.2.6 in /ui/litellm-dashboard (#27665) (#28524) 2026-05-22 00:13:56 +00:00
package.json build(deps): bump next from 16.2.4 to 16.2.6 in /ui/litellm-dashboard (#27665) (#28524) 2026-05-22 00:13:56 +00:00
postcss.config.js build(ui/litellm-dashboard): initial commit of litellm dashboard 2024-01-27 12:12:48 -08:00
README.md build(ui/litellm-dashboard): initial commit of litellm dashboard 2024-01-27 12:12:48 -08:00
tailwind.config.js added and ran prettier autoformatter 2025-10-04 18:19:48 -07:00
tailwind.config.ts added and ran prettier autoformatter 2025-10-04 18:19:48 -07:00
tsconfig.json [Infra] Promote internal staging to main (#27245) 2026-05-05 16:15:03 -07:00
tsconfig.tsbuildinfo [Infra] Promote internal staging to main (#27245) 2026-05-05 16:15:03 -07:00
ui_colors.json added and ran prettier autoformatter 2025-10-04 18:19:48 -07:00
vitest.config.ts [Test] UI - Unit tests: raise global vitest timeout and remove per-test overrides 2026-04-09 23:58:35 -07:00

This is a Next.js project bootstrapped with create-next-app.

Getting Started

First, run the development server:

npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev

Open http://localhost:3000 with your browser to see the result.

You can start editing the page by modifying app/page.tsx. The page auto-updates as you edit the file.

This project uses next/font to automatically optimize and load Inter, a custom Google Font.

Learn More

To learn more about Next.js, take a look at the following resources:

You can check out the Next.js GitHub repository - your feedback and contributions are welcome!

Deploy on Vercel

The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.

Check out our Next.js deployment documentation for more details.