fix: add OAuth headers to call_tool_rest_api, fix stale accessToken closure, fix group toggle on filtered subset

This commit is contained in:
Ishaan Jaffer 2026-03-11 19:48:40 -07:00
parent 7259d4f6b4
commit 4e2f18ba49
4 changed files with 37 additions and 14 deletions

View file

@ -557,6 +557,16 @@ if MCP_AVAILABLE:
request, user_api_key_dict, server_id
)
# Look up per-user OAuth headers for this server (mirrors list_tool_rest_api).
user_oauth_extra_headers: Optional[Dict[str, str]] = None
target_server = next(
(s for s in allowed_mcp_servers if s.server_id == server_id), None
)
if target_server is not None:
user_oauth_extra_headers = await _get_user_oauth_extra_headers(
target_server, user_api_key_dict
)
# Call execute_mcp_tool directly (permission checks already done)
result = await execute_mcp_tool(
name=tool_name,
@ -566,7 +576,7 @@ if MCP_AVAILABLE:
user_api_key_auth=data.get("user_api_key_auth"),
mcp_auth_header=data.get("mcp_auth_header"),
mcp_server_auth_headers=data.get("mcp_server_auth_headers"),
oauth2_headers=data.get("oauth2_headers"),
oauth2_headers=user_oauth_extra_headers or data.get("oauth2_headers"),
raw_headers=data.get("raw_headers"),
litellm_logging_obj=data.get("litellm_logging_obj"),
)

View file

@ -43,12 +43,13 @@ const MCPToolPermissions: React.FC<MCPToolPermissionsProps> = ({
}, [allServers, selectedServers]);
// Fetch tools for a specific server; applies delete-blocked-by-default for new servers.
const fetchToolsForServer = async (serverId: string) => {
// `token` is passed explicitly so the closure never captures a stale accessToken.
const fetchToolsForServer = async (serverId: string, token: string) => {
setLoadingTools((prev) => ({ ...prev, [serverId]: true }));
setToolErrors((prev) => ({ ...prev, [serverId]: "" }));
try {
const response = await listMCPTools(accessToken, serverId);
const response = await listMCPTools(token, serverId);
if (response.error) {
setToolErrors((prev) => ({ ...prev, [serverId]: response.message || "Failed to fetch tools" }));
@ -76,14 +77,17 @@ const MCPToolPermissions: React.FC<MCPToolPermissionsProps> = ({
}
};
// Auto-fetch tools when servers change
// Auto-fetch tools when servers or accessToken change
useEffect(() => {
servers.forEach((server) => {
if (!serverTools[server.server_id] && !loadingTools[server.server_id]) {
fetchToolsForServer(server.server_id);
fetchToolsForServer(server.server_id, accessToken);
}
});
}, [servers]);
// fetchToolsForServer is defined in this render scope but receives `accessToken`
// as an explicit argument, so it is safe to omit from deps here.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [servers, accessToken]);
const handleCrudPanelChange = (serverId: string, allowed: string[]) => {
onChange({ ...toolPermissions, [serverId]: allowed });

View file

@ -33,6 +33,12 @@ interface McpCrudPermissionPanelProps {
/** Called whenever the allowed set changes. Always emits a concrete string[]. */
onChange: (allowed: string[]) => void;
readOnly?: boolean;
/**
* Optional search filter string. When set, only tools whose name or description
* contain this string (case-insensitive) are shown. Group-level toggles still
* operate on the complete group not just the visible (filtered) subset.
*/
searchFilter?: string;
}
const CRUD_ORDER: CrudOp[] = ["read", "create", "update", "delete", "unknown"];
@ -67,6 +73,7 @@ const McpCrudPermissionPanel: React.FC<McpCrudPermissionPanelProps> = ({
value,
onChange,
readOnly = false,
searchFilter = "",
}) => {
const [collapsed, setCollapsed] = useState<Record<CrudOp, boolean>>({
read: false,
@ -197,10 +204,16 @@ const McpCrudPermissionPanel: React.FC<McpCrudPermissionPanelProps> = ({
</div>
)}
{/* Tool list */}
{/* Tool list — searchFilter narrows display only; group toggles still cover all tools */}
{!isCollapsed && (
<div className="bg-white divide-y divide-gray-50">
{group.map((tool) => {
{group
.filter((t) =>
!searchFilter ||
t.name.toLowerCase().includes(searchFilter.toLowerCase()) ||
(t.description ?? "").toLowerCase().includes(searchFilter.toLowerCase())
)
.map((tool) => {
const allowed = isToolAllowed(tool.name);
return (
<div

View file

@ -464,12 +464,8 @@ const MCPToolConfiguration: React.FC<MCPToolConfigurationProps> = ({
size="large"
/>
<McpCrudPermissionPanel
tools={tools.filter(
(t) =>
!toolSearchTerm ||
t.name.toLowerCase().includes(toolSearchTerm.toLowerCase()) ||
(t.description ?? "").toLowerCase().includes(toolSearchTerm.toLowerCase())
)}
tools={tools}
searchFilter={toolSearchTerm}
value={allowedTools}
onChange={(allowed) => onAllowedToolsChange(allowed)}
/>