mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
feat(ui): add Integrations tab to MCP server view with Claude Cowork connect URL
Adds an Integrations tab between MCP Tools and Settings on the MCP server detail page, visible to all users. It surfaces a copyable Claude Cowork connect URL built from getProxyBaseUrl and the server alias or name. When delegate_auth_to_upstream is true, it also shows a Dynamic Client Registration note so the user knows to leave auth fields empty. Bumps the post-OAuth-edit redirect tab index from 2 to 3 since inserting Integrations at index 2 shifts Settings to 3.
This commit is contained in:
parent
4f54f997f8
commit
6f0f895b5b
1 changed files with 47 additions and 2 deletions
|
|
@ -9,6 +9,7 @@ import MCPServerEdit, { EDIT_OAUTH_UI_STATE_KEY } from "./mcp_server_edit";
|
|||
import { getSecureItem } from "@/utils/secureStorage";
|
||||
import MCPServerCostDisplay from "./mcp_server_cost_display";
|
||||
import { getMaskedAndFullUrl } from "./utils";
|
||||
import { getProxyBaseUrl } from "@/components/networking";
|
||||
import { copyToClipboard as utilCopyToClipboard } from "@/utils/dataUtils";
|
||||
import { CheckIcon, CopyIcon } from "lucide-react";
|
||||
import { Button as AntdButton } from "antd";
|
||||
|
|
@ -55,12 +56,12 @@ export const MCPServerView: React.FC<MCPServerViewProps> = ({
|
|||
initialTabIndex = 0,
|
||||
}) => {
|
||||
// Open the editing Settings tab on first render when returning from the edit OAuth
|
||||
// redirect, so the "token fetched" feedback shows where the user left off (Settings=2).
|
||||
// redirect, so the "token fetched" feedback shows where the user left off (Settings=3).
|
||||
const returningFromEditOAuth = isReturningFromEditOAuth(isProxyAdmin, mcpServer.server_id);
|
||||
const [editing, setEditing] = useState(isEditing || returningFromEditOAuth);
|
||||
const [showFullUrl, setShowFullUrl] = useState(false);
|
||||
const [copiedStates, setCopiedStates] = useState<Record<string, boolean>>({});
|
||||
const [selectedTabIndex, setSelectedTabIndex] = useState(returningFromEditOAuth ? 2 : initialTabIndex);
|
||||
const [selectedTabIndex, setSelectedTabIndex] = useState(returningFromEditOAuth ? 3 : initialTabIndex);
|
||||
|
||||
const handleSuccess = (updated: MCPServer) => {
|
||||
setEditing(false);
|
||||
|
|
@ -70,6 +71,10 @@ export const MCPServerView: React.FC<MCPServerViewProps> = ({
|
|||
const urlValue = mcpServer.url ?? "";
|
||||
const { maskedUrl, hasToken } = urlValue ? getMaskedAndFullUrl(urlValue) : { maskedUrl: "—", hasToken: false };
|
||||
|
||||
const coworkServerIdentifier = mcpServer.alias || mcpServer.server_name || mcpServer.server_id;
|
||||
const coworkUrl = `${getProxyBaseUrl()}/${coworkServerIdentifier}/mcp`;
|
||||
const isUpstreamDelegated = mcpServer.delegate_auth_to_upstream === true;
|
||||
|
||||
const renderUrlWithToggle = (url: string | null | undefined, showFull: boolean) => {
|
||||
if (!url) return "—";
|
||||
if (!hasToken) return url;
|
||||
|
|
@ -151,6 +156,7 @@ export const MCPServerView: React.FC<MCPServerViewProps> = ({
|
|||
{[
|
||||
<Tab key="overview">Overview</Tab>,
|
||||
<Tab key="tools">MCP Tools</Tab>,
|
||||
<Tab key="integrations">Integrations</Tab>,
|
||||
...(isProxyAdmin ? [<Tab key="settings">Settings</Tab>] : []),
|
||||
]}
|
||||
</TabList>
|
||||
|
|
@ -219,6 +225,45 @@ export const MCPServerView: React.FC<MCPServerViewProps> = ({
|
|||
/>
|
||||
</TabPanel>
|
||||
|
||||
{/* Integrations Panel */}
|
||||
<TabPanel>
|
||||
<Card className="p-6">
|
||||
<Title>Claude Cowork</Title>
|
||||
<Text className="text-gray-500 mt-1">
|
||||
Add this MCP server to Claude Cowork by pasting the URL below into the connector setup.
|
||||
</Text>
|
||||
|
||||
<div className="mt-5">
|
||||
<Text className="text-xs font-medium text-gray-500 uppercase tracking-wide">Server URL</Text>
|
||||
<div className="mt-2 flex items-center gap-2 rounded border border-gray-200 bg-gray-50 px-3 py-2">
|
||||
<Text className="flex-1 break-all font-mono text-sm text-gray-900">{coworkUrl}</Text>
|
||||
<AntdButton
|
||||
type="text"
|
||||
size="small"
|
||||
icon={copiedStates["mcp-cowork-url"] ? <CheckIcon size={12} /> : <CopyIcon size={12} />}
|
||||
onClick={() => copyToClipboard(coworkUrl, "mcp-cowork-url")}
|
||||
className={`transition-all duration-200 ${
|
||||
copiedStates["mcp-cowork-url"]
|
||||
? "text-green-600 bg-green-50 border-green-200"
|
||||
: "text-gray-400 hover:text-gray-600 hover:bg-gray-100"
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isUpstreamDelegated && (
|
||||
<div className="mt-5 rounded border border-blue-200 bg-blue-50 p-4">
|
||||
<Text className="text-sm font-semibold text-blue-900">OAuth: Dynamic Client Registration</Text>
|
||||
<Text className="mt-1 text-sm text-blue-800">
|
||||
This server delegates authentication upstream, so Claude Cowork completes the OAuth flow directly
|
||||
with the provider through Dynamic Client Registration. Leave the auth fields empty; no LiteLLM key
|
||||
header is needed.
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
</TabPanel>
|
||||
|
||||
{/* Settings Panel */}
|
||||
<TabPanel>
|
||||
<Card>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue