From 15541adeb744002833b3a8b8533bc84c89cec881 Mon Sep 17 00:00:00 2001 From: NianJiuZst <3235467914@qq.com> Date: Tue, 11 Aug 2026 22:23:01 +0800 Subject: [PATCH] Fix MCP OAuth Connect permission gating --- .../admin/capabilities/MarketplaceTab.tsx | 3 ++ .../src/pages/admin/capabilities/index.tsx | 1 + .../mcp-directory/MCPDirectory.tsx | 7 ++- .../mcp-directory/MCPDirectoryCard.tsx | 7 +-- .../mcp-directory/MCPDirectoryDetail.tsx | 6 ++- tests/e2e/mcp-directory.spec.ts | 43 ++++++++++++++++++- 6 files changed, 59 insertions(+), 8 deletions(-) diff --git a/apps/web/src/pages/admin/capabilities/MarketplaceTab.tsx b/apps/web/src/pages/admin/capabilities/MarketplaceTab.tsx index 9fdfc5e..9a2606c 100644 --- a/apps/web/src/pages/admin/capabilities/MarketplaceTab.tsx +++ b/apps/web/src/pages/admin/capabilities/MarketplaceTab.tsx @@ -19,6 +19,7 @@ interface MarketplaceTabProps { query: string typeFilter: "mcp" | "skill" canImport: boolean + canConnect: boolean canManage: boolean onSelectItem: (id: string | null) => void onInstall: (capability: MarketplaceCapability) => void @@ -33,6 +34,7 @@ export function MarketplaceTab(props: MarketplaceTabProps) { itemID={mcpItemID} query={props.query} canImport={props.canImport} + canConnect={props.canConnect} onSelectItem={(id) => props.onSelectItem(id ? `mcp:${id}` : null)} onSelectMarketplaceItem={props.onSelectItem} onInstallMarketplace={props.onInstall} @@ -54,6 +56,7 @@ export function MarketplaceTab(props: MarketplaceTabProps) { itemID={null} query={props.query} canImport={props.canImport} + canConnect={props.canConnect} onSelectItem={(id) => props.onSelectItem(id ? `mcp:${id}` : null)} onSelectMarketplaceItem={props.onSelectItem} onInstallMarketplace={props.onInstall} diff --git a/apps/web/src/pages/admin/capabilities/index.tsx b/apps/web/src/pages/admin/capabilities/index.tsx index 07884cc..fd8b506 100644 --- a/apps/web/src/pages/admin/capabilities/index.tsx +++ b/apps/web/src/pages/admin/capabilities/index.tsx @@ -281,6 +281,7 @@ export function CapabilitiesPage() { query={query} typeFilter={typeFilter} canImport={canImportDirectory} + canConnect={isAdmin} canManage={isAdmin} onSelectItem={(item) => navigate("capabilities", { tab: "marketplace", item })} onInstall={goToAgentsForCapability} diff --git a/apps/web/src/pages/admin/capabilities/mcp-directory/MCPDirectory.tsx b/apps/web/src/pages/admin/capabilities/mcp-directory/MCPDirectory.tsx index 49179a6..dd8fcb9 100644 --- a/apps/web/src/pages/admin/capabilities/mcp-directory/MCPDirectory.tsx +++ b/apps/web/src/pages/admin/capabilities/mcp-directory/MCPDirectory.tsx @@ -25,6 +25,7 @@ interface MCPDirectoryProps { itemID: string | null query: string canImport: boolean + canConnect: boolean onSelectItem: (id: string | null) => void onSelectMarketplaceItem: (id: string | null) => void onInstallMarketplace: (capability: MarketplaceCapability) => void @@ -37,6 +38,7 @@ export function MCPDirectory({ itemID, query, canImport, + canConnect, onSelectItem, onSelectMarketplaceItem, onInstallMarketplace, @@ -106,7 +108,7 @@ export function MCPDirectory({ }, [detailQ, directoryQ]) const connectOAuth = (id: string) => { - if (!workspaceID) return + if (!workspaceID || !canConnect) return setOAuthError(false) const width = 620 const height = 760 @@ -172,6 +174,7 @@ export function MCPDirectory({ loading={detailQ.isLoading} error={detailQ.error} canImport={canImport} + canConnect={canConnect} onBack={() => onSelectItem(null)} onRetry={() => void detailQ.refetch()} onImport={() => requestImport(itemID)} @@ -228,7 +231,7 @@ export function MCPDirectory({ ) : cards.length > 0 ? (
{cards.map((card) => card.kind === "directory" ? ( - onSelectItem(card.item.id)} onImport={() => requestImport(card.item.id)} onConnect={() => connectOAuth(card.item.id)} onViewCapability={onViewCapability} /> + onSelectItem(card.item.id)} onImport={() => requestImport(card.item.id)} onConnect={() => connectOAuth(card.item.id)} onViewCapability={onViewCapability} /> ) : ( onSelectMarketplaceItem(card.item.id)} onInstall={() => onInstallMarketplace(card.item)} onDelete={() => onDeleteMarketplace(card.item)} onViewCapability={() => onViewCapability(card.item.id)} /> ))} diff --git a/apps/web/src/pages/admin/capabilities/mcp-directory/MCPDirectoryCard.tsx b/apps/web/src/pages/admin/capabilities/mcp-directory/MCPDirectoryCard.tsx index 70bdba3..f4151c2 100644 --- a/apps/web/src/pages/admin/capabilities/mcp-directory/MCPDirectoryCard.tsx +++ b/apps/web/src/pages/admin/capabilities/mcp-directory/MCPDirectoryCard.tsx @@ -6,9 +6,10 @@ import { Button } from "../../../../components/ui/button" import { marketplaceSourceName, type MCPDirectoryItem, type MarketplaceCapability } from "../../../../lib/api-marketplace" import { ConnectorIcon, VerifiedBadge } from "./shared" -export function DirectoryCard({ item, canImport, onOpen, onImport, onConnect, onViewCapability }: { +export function DirectoryCard({ item, canImport, canConnect, onOpen, onImport, onConnect, onViewCapability }: { item: MCPDirectoryItem canImport: boolean + canConnect: boolean onOpen: () => void onImport: () => void onConnect: () => void @@ -43,8 +44,8 @@ export function DirectoryCard({ item, canImport, onOpen, onImport, onConnect, on {t("capabilities.mcpDirectory.actions.installed")} ) : item.authentication === "oauth2" && !item.connected ? ( - ) : (
{item.authentication === "oauth2" && !item.connected ? ( - ) : item.installed && item.installed_capability_id ? (