Skip to content

Commit b64c81a

Browse files
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 <[email protected]>
1 parent a8e78ae commit b64c81a

3 files changed

Lines changed: 17 additions & 2 deletions

File tree

ui/litellm-dashboard/src/components/mcp_tools/mcp_server_view.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ export const MCPServerView: React.FC<MCPServerViewProps> = ({
174174
serverId={mcpServer.server_id}
175175
accessToken={accessToken}
176176
auth_type={mcpServer.auth_type}
177+
tokenUrl={mcpServer.token_url}
177178
userRole={userRole}
178179
userID={userID}
179180
serverAlias={mcpServer.alias}

ui/litellm-dashboard/src/components/mcp_tools/mcp_tools.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const MCPToolsViewer = ({
1515
serverId,
1616
accessToken,
1717
auth_type,
18+
tokenUrl,
1819
userRole,
1920
userID,
2021
serverAlias,
@@ -29,8 +30,14 @@ const MCPToolsViewer = ({
2930
const [passthroughHeaders, setPassthroughHeaders] = useState<Record<string, string>>({});
3031
const [showHeaderInput, setShowHeaderInput] = useState(false);
3132

32-
// OAuth session token (sessionStorage-backed, cleared on tab/browser close)
33-
const isOAuth = auth_type === "oauth2";
33+
// OAuth session token (sessionStorage-backed, cleared on tab/browser close).
34+
// Only the interactive (authorization_code/PKCE) flow needs a user-facing
35+
// auth gate. M2M (client_credentials) servers are also `auth_type === "oauth2"`,
36+
// but the backend fetches their token internally — gating tool listing on
37+
// them would force users through a non-existent authorization endpoint.
38+
// We detect M2M via the presence of `tokenUrl`, matching the heuristic in
39+
// `mcp_server_edit.tsx`.
40+
const isOAuth = auth_type === "oauth2" && !tokenUrl;
3441
const [oauthToken, setOauthToken] = useState<string | null>(() =>
3542
isOAuth && isTokenValid(serverId, userID)
3643
? (getToken(serverId, userID)?.access_token ?? null)

ui/litellm-dashboard/src/components/mcp_tools/types.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,13 @@ export interface MCPToolsViewerProps {
163163
serverId: string;
164164
accessToken: string | null;
165165
auth_type?: string | null;
166+
/**
167+
* When set, indicates the server uses the OAuth2 M2M (client_credentials)
168+
* flow — the backend handles token acquisition internally, so the UI must
169+
* not gate tool listing behind an interactive PKCE authorization. Mirrors
170+
* the heuristic used in `mcp_server_edit.tsx` (`token_url` set => M2M).
171+
*/
172+
tokenUrl?: string | null;
166173
userRole: string | null;
167174
userID: string | null;
168175
serverAlias?: string | null;

0 commit comments

Comments
 (0)