diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.test.tsx
index b660c4bdb76..8a23c445173 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.test.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.test.tsx
@@ -432,6 +432,86 @@ describe("MCPServerEdit (auth type switch)", () => {
expect(payload.registration_url).toBeNull();
});
+ it("preserves the shared leg-1 endpoint and audience when switching token exchange to ID-JAG", async () => {
+ vi.mocked(networking.updateMCPServer).mockResolvedValue({
+ ...interactiveOAuthServer,
+ auth_type: "oauth2_id_jag",
+ });
+
+ render(
+ ,
+ );
+
+ await selectAntOption("Authentication", "ID-JAG (Okta Cross App Access)");
+
+ const saveButtons = screen.getAllByRole("button", { name: "Save Changes" });
+ await act(async () => {
+ fireEvent.click(saveButtons[0]);
+ });
+
+ await waitFor(() => {
+ expect(networking.updateMCPServer).toHaveBeenCalledTimes(1);
+ });
+
+ const [, payload] = vi.mocked(networking.updateMCPServer).mock.calls[0];
+ expect(payload.auth_type).toBe("oauth2_id_jag");
+ expect(payload.token_exchange_endpoint).toBe("https://idp.example.com/oauth2/token");
+ expect(payload.audience).toBe("api://existing-resource");
+ expect(payload.subject_token_type).toBe("urn:ietf:params:oauth:token-type:saml2");
+ });
+
+ it("clears the shared leg-1 endpoint and audience when switching ID-JAG to an auth type that uses neither", async () => {
+ vi.mocked(networking.updateMCPServer).mockResolvedValue({
+ ...interactiveOAuthServer,
+ auth_type: "none",
+ });
+
+ render(
+ ,
+ );
+
+ await selectAntOption("Authentication", "None");
+
+ const saveButtons = screen.getAllByRole("button", { name: "Save Changes" });
+ await act(async () => {
+ fireEvent.click(saveButtons[0]);
+ });
+
+ await waitFor(() => {
+ expect(networking.updateMCPServer).toHaveBeenCalledTimes(1);
+ });
+
+ const [, payload] = vi.mocked(networking.updateMCPServer).mock.calls[0];
+ expect(payload.auth_type).toBe("none");
+ expect(payload.token_exchange_endpoint).toBeNull();
+ expect(payload.audience).toBeNull();
+ expect(payload.subject_token_type).toBeNull();
+ });
+
it("keeps oauth2 endpoint overrides when the auth type is unchanged", async () => {
vi.mocked(networking.updateMCPServer).mockResolvedValue({ ...interactiveOAuthServer });
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.tsx
index acecec105eb..e9311fce67b 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.tsx
@@ -70,6 +70,7 @@ const AUTH_TYPES_REQUIRING_CREDENTIALS = [
AUTH_TYPE.TRUE_PASSTHROUGH,
AUTH_TYPE.OAUTH_DELEGATE,
];
+const AUTH_TYPES_SHARING_TOKEN_EXCHANGE_COLUMNS = [AUTH_TYPE.OAUTH2_TOKEN_EXCHANGE, AUTH_TYPE.OAUTH2_ID_JAG];
export const EDIT_OAUTH_UI_STATE_KEY = "litellm-mcp-oauth-edit-state";
const MCPServerEdit: React.FC = ({
@@ -858,9 +859,13 @@ const MCPServerEdit: React.FC = ({
...(mcpServer.auth_type === AUTH_TYPE.OAUTH2 && restValues.auth_type !== AUTH_TYPE.OAUTH2
? { issuer: null, authorization_url: null, token_url: null, registration_url: null }
: {}),
+ ...(AUTH_TYPES_SHARING_TOKEN_EXCHANGE_COLUMNS.includes(mcpServer.auth_type ?? "") &&
+ !AUTH_TYPES_SHARING_TOKEN_EXCHANGE_COLUMNS.includes(restValues.auth_type ?? "")
+ ? { token_exchange_endpoint: null, audience: null, subject_token_type: null }
+ : {}),
...(mcpServer.auth_type === AUTH_TYPE.OAUTH2_TOKEN_EXCHANGE &&
restValues.auth_type !== AUTH_TYPE.OAUTH2_TOKEN_EXCHANGE
- ? { token_exchange_endpoint: null, audience: null, subject_token_type: null, token_exchange_profile: null }
+ ? { token_exchange_profile: null }
: {}),
server_id: mcpServer.server_id,
mcp_info: {