Skip to content

Commit b3d8a6b

Browse files
wagnerjtwagnerjt
andauthored
Proxy UI MCP Auth passthrough (#11968)
* initial mcp auth with special header * MCP Servers moved and added auth part * Pass in x-mcp-auth with banner on tool call * Revert "initial mcp auth with special header" This reverts commit b22fb6d. --------- Co-authored-by: wagnerjt <[email protected]>
1 parent cde20cf commit b3d8a6b

File tree

6 files changed

+364
-181
lines changed

6 files changed

+364
-181
lines changed

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

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,34 @@
11
import React from "react";
22
import { ColumnDef } from "@tanstack/react-table";
33
import { MCPTool, InputSchema } from "./types";
4-
import { Button } from "@tremor/react"
4+
import { Button, Callout, Icon } from "@tremor/react"
5+
6+
const AuthBanner = ({needsAuth, authValue}) => {
7+
if(!needsAuth || (needsAuth && authValue)) {
8+
return (
9+
<Callout
10+
title="Authentication"
11+
color="green"
12+
className="mb-4"
13+
>
14+
This tool does not require authentication or has authentication added.
15+
</Callout>
16+
)
17+
}
18+
19+
if (needsAuth && !authValue) {
20+
return (
21+
<Callout
22+
title="Authentication required"
23+
color="yellow"
24+
className="mb-4"
25+
>
26+
Please provide authentication details if this tool call requires auth.
27+
</Callout>
28+
);
29+
}
30+
return null;
31+
}
532

633
export const columns: ColumnDef<MCPTool>[] = [
734
{
@@ -78,13 +105,17 @@ export const columns: ColumnDef<MCPTool>[] = [
78105
// Tool Panel component to display when a tool is selected
79106
export function ToolTestPanel({
80107
tool,
108+
needsAuth,
109+
authValue,
81110
onSubmit,
82111
isLoading,
83112
result,
84113
error,
85114
onClose
86115
}: {
87116
tool: MCPTool;
117+
needsAuth: boolean;
118+
authValue?: string | null;
88119
onSubmit: (args: Record<string, any>) => void;
89120
isLoading: boolean;
90121
result: any | null;
@@ -131,6 +162,12 @@ export function ToolTestPanel({
131162
<p className="text-gray-600">{tool.description}</p>
132163
<p className="text-sm text-gray-500 mt-1">Provider: {tool.mcp_info.server_name}</p>
133164
</div>
165+
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
166+
<AuthBanner
167+
needsAuth={needsAuth}
168+
authValue={authValue}
169+
/>
170+
</div>
134171
<button
135172
onClick={onClose}
136173
className="p-1 rounded-full hover:bg-gray-200"
Lines changed: 1 addition & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -1,178 +1,4 @@
1-
import React, { useState } from 'react';
2-
import { useQuery, useMutation } from '@tanstack/react-query';
3-
import { DataTable } from '../view_logs/table';
4-
import { columns, ToolTestPanel } from './columns';
5-
import { MCPTool, MCPToolsViewerProps, CallMCPToolResponse } from './types';
6-
import { listMCPTools, callMCPTool } from '../networking';
71
import MCPServers from './mcp_servers';
8-
9-
// Wrapper to handle the type mismatch between MCPTool and DataTable's expected type
10-
function DataTableWrapper({
11-
columns,
12-
data,
13-
isLoading,
14-
}: {
15-
columns: any;
16-
data: MCPTool[];
17-
isLoading: boolean;
18-
}) {
19-
// Create a dummy renderSubComponent and getRowCanExpand function
20-
const renderSubComponent = () => <div />;
21-
const getRowCanExpand = () => false;
22-
23-
return (
24-
<DataTable
25-
columns={columns as any}
26-
data={data as any}
27-
isLoading={isLoading}
28-
renderSubComponent={renderSubComponent}
29-
getRowCanExpand={getRowCanExpand}
30-
loadingMessage="🚅 Loading tools..."
31-
noDataMessage="No tools found"
32-
/>
33-
);
34-
}
35-
36-
const MCPToolsViewer = ({
37-
serverId,
38-
accessToken,
39-
userRole,
40-
userID,
41-
}: MCPToolsViewerProps) => {
42-
const [searchTerm, setSearchTerm] = useState('');
43-
const [selectedTool, setSelectedTool] = useState<MCPTool | null>(null);
44-
const [toolResult, setToolResult] = useState<CallMCPToolResponse | null>(null);
45-
const [toolError, setToolError] = useState<Error | null>(null);
46-
47-
// Query to fetch MCP tools
48-
const { data: mcpTools, isLoading: isLoadingTools } = useQuery({
49-
queryKey: ['mcpTools'],
50-
queryFn: () => {
51-
if (!accessToken) throw new Error('Access Token required');
52-
return listMCPTools(accessToken, serverId);
53-
},
54-
enabled: !!accessToken,
55-
});
56-
57-
// Mutation for calling a tool
58-
const { mutate: executeTool, isPending: isCallingTool } = useMutation({
59-
mutationFn: (args: { tool: MCPTool; arguments: Record<string, any> }) => {
60-
if (!accessToken) throw new Error('Access Token required');
61-
return callMCPTool(
62-
accessToken,
63-
args.tool.name,
64-
args.arguments
65-
);
66-
},
67-
onSuccess: (data) => {
68-
setToolResult(data);
69-
setToolError(null);
70-
},
71-
onError: (error: Error) => {
72-
setToolError(error);
73-
setToolResult(null);
74-
},
75-
});
76-
77-
// Add onToolSelect handler to each tool
78-
const toolsData = React.useMemo(() => {
79-
if (!mcpTools) return [];
80-
81-
return mcpTools.map((tool: MCPTool) => ({
82-
...tool,
83-
onToolSelect: (tool: MCPTool) => {
84-
setSelectedTool(tool);
85-
setToolResult(null);
86-
setToolError(null);
87-
}
88-
}));
89-
}, [mcpTools]);
90-
91-
// Filter tools based on search term
92-
const filteredTools = React.useMemo(() => {
93-
return toolsData.filter((tool: MCPTool) => {
94-
const searchLower = searchTerm.toLowerCase();
95-
return (
96-
tool.name.toLowerCase().includes(searchLower) ||
97-
(tool.description != null && tool.description.toLowerCase().includes(searchLower)) ||
98-
tool.mcp_info.server_name.toLowerCase().includes(searchLower)
99-
);
100-
});
101-
}, [toolsData, searchTerm]);
102-
103-
// Handle tool call submission
104-
const handleToolSubmit = (args: Record<string, any>) => {
105-
if (!selectedTool) return;
106-
107-
executeTool({
108-
tool: selectedTool,
109-
arguments: args,
110-
});
111-
};
112-
113-
if (!accessToken || !userRole || !userID) {
114-
return <div className="p-6 text-center text-gray-500">Missing required authentication parameters.</div>;
115-
}
116-
117-
return (
118-
<div className="w-full p-6">
119-
<div className="flex items-center justify-between mb-4">
120-
<h1 className="text-xl font-semibold">MCP Tools</h1>
121-
</div>
122-
123-
<div className="bg-white rounded-lg shadow">
124-
<div className="border-b px-6 py-4">
125-
<div className="flex items-center justify-between">
126-
<div className="relative w-64">
127-
<input
128-
type="text"
129-
placeholder="Search tools..."
130-
className="w-full px-3 py-2 pl-8 border rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
131-
value={searchTerm}
132-
onChange={(e) => setSearchTerm(e.target.value)}
133-
/>
134-
<svg
135-
className="absolute left-2.5 top-2.5 h-4 w-4 text-gray-500"
136-
fill="none"
137-
stroke="currentColor"
138-
viewBox="0 0 24 24"
139-
>
140-
<path
141-
strokeLinecap="round"
142-
strokeLinejoin="round"
143-
strokeWidth={2}
144-
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
145-
/>
146-
</svg>
147-
</div>
148-
<div className="text-sm text-gray-500">
149-
{filteredTools.length} tool{filteredTools.length !== 1 ? "s" : ""} available
150-
</div>
151-
</div>
152-
</div>
153-
154-
<DataTableWrapper
155-
columns={columns}
156-
data={filteredTools}
157-
isLoading={isLoadingTools}
158-
/>
159-
</div>
160-
161-
{/* Tool Test Panel - Show when a tool is selected */}
162-
{selectedTool && (
163-
<div className="fixed inset-0 bg-gray-800 bg-opacity-75 flex items-center justify-center z-50 p-4">
164-
<ToolTestPanel
165-
tool={selectedTool}
166-
onSubmit={handleToolSubmit}
167-
isLoading={isCallingTool}
168-
result={toolResult}
169-
error={toolError}
170-
onClose={() => setSelectedTool(null)}
171-
/>
172-
</div>
173-
)}
174-
</div>
175-
);
176-
}
2+
import MCPToolsViewer from './mcp_tools';
1773

1784
export { MCPToolsViewer, MCPServers };

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
@@ -96,6 +96,7 @@ export const MCPServerView: React.FC<MCPServerViewProps> = ({
9696
<MCPToolsViewer
9797
serverId={mcpServer.server_id}
9898
accessToken={accessToken}
99+
auth_type={mcpServer.auth_type}
99100
userRole={userRole}
100101
userID={userID}
101102
/>

0 commit comments

Comments
 (0)