suna/frontend/src/components/agents/mcp/mcp-configuration-new.tsx

138 lines
5.2 KiB
TypeScript
Raw Normal View History

2025-05-30 19:03:53 +08:00
import React, { useState } from 'react';
import { Button } from '@/components/ui/button';
2025-07-10 08:51:55 +08:00
import { Zap, Server, Store } from 'lucide-react';
2025-07-10 01:47:52 +08:00
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
2025-05-30 19:03:53 +08:00
import { MCPConfigurationProps, MCPConfiguration as MCPConfigurationType } from './types';
import { ConfiguredMcpList } from './configured-mcp-list';
2025-06-02 13:44:22 +08:00
import { CustomMCPDialog } from './custom-mcp-dialog';
2025-07-08 21:18:49 +08:00
import { PipedreamRegistry } from '@/components/agents/pipedream/pipedream-registry';
2025-05-30 19:03:53 +08:00
export const MCPConfigurationNew: React.FC<MCPConfigurationProps> = ({
configuredMCPs,
onConfigurationChange,
}) => {
2025-06-02 13:44:22 +08:00
const [showCustomDialog, setShowCustomDialog] = useState(false);
2025-07-08 21:18:49 +08:00
const [showRegistryDialog, setShowRegistryDialog] = useState(false);
2025-05-30 19:03:53 +08:00
const [editingIndex, setEditingIndex] = useState<number | null>(null);
const handleEditMCP = (index: number) => {
const mcp = configuredMCPs[index];
2025-07-08 21:18:49 +08:00
if (mcp.customType === 'pipedream') {
2025-06-02 13:44:22 +08:00
return;
}
2025-05-30 19:03:53 +08:00
setEditingIndex(index);
};
const handleRemoveMCP = (index: number) => {
const newMCPs = [...configuredMCPs];
newMCPs.splice(index, 1);
onConfigurationChange(newMCPs);
};
2025-06-02 13:44:22 +08:00
const handleSaveCustomMCP = (customConfig: any) => {
const mcpConfig: MCPConfigurationType = {
name: customConfig.name,
2025-06-02 19:04:14 +08:00
qualifiedName: `custom_${customConfig.type}_${Date.now()}`,
2025-06-02 13:44:22 +08:00
config: customConfig.config,
enabledTools: customConfig.enabledTools,
selectedProfileId: customConfig.selectedProfileId,
2025-06-02 13:44:22 +08:00
isCustom: true,
2025-06-02 19:04:14 +08:00
customType: customConfig.type as 'http' | 'sse'
2025-06-02 13:44:22 +08:00
};
2025-07-09 21:51:47 +08:00
onConfigurationChange([...configuredMCPs, mcpConfig]);
2025-07-08 21:18:49 +08:00
};
2025-07-09 02:40:58 +08:00
const handleToolsSelected = (profileId: string, selectedTools: string[], appName: string, appSlug: string) => {
2025-07-08 21:18:49 +08:00
const pipedreamMCP: MCPConfigurationType = {
2025-07-09 02:40:58 +08:00
name: appName,
qualifiedName: `pipedream_${appSlug}_${profileId}`,
2025-07-08 21:18:49 +08:00
config: {
url: 'https://remote.mcp.pipedream.net',
headers: {
'x-pd-app-slug': appSlug,
2025-07-09 02:40:58 +08:00
},
profile_id: profileId
2025-07-08 21:18:49 +08:00
},
enabledTools: selectedTools,
isCustom: true,
2025-07-09 02:40:58 +08:00
customType: 'pipedream',
selectedProfileId: profileId
2025-07-08 21:18:49 +08:00
};
const nonPipedreamMCPs = configuredMCPs.filter(mcp =>
mcp.customType !== 'pipedream' ||
2025-07-09 02:40:58 +08:00
mcp.selectedProfileId !== profileId
2025-07-08 21:18:49 +08:00
);
onConfigurationChange([...nonPipedreamMCPs, pipedreamMCP]);
setShowRegistryDialog(false);
2025-06-02 13:44:22 +08:00
};
2025-05-30 19:03:53 +08:00
return (
<div className="space-y-6">
{configuredMCPs.length === 0 && (
<div className="text-center py-12 px-6 bg-muted/30 rounded-xl border-2 border-dashed border-border">
<div className="mx-auto w-12 h-12 bg-muted rounded-full flex items-center justify-center mb-4">
<Zap className="h-6 w-6 text-muted-foreground" />
</div>
<h4 className="text-sm font-medium text-foreground mb-2">
2025-07-08 21:18:49 +08:00
No integrations configured
</h4>
<p className="text-sm text-muted-foreground mb-6 max-w-sm mx-auto">
2025-07-08 21:18:49 +08:00
Browse the app registry to connect your apps through Pipedream or add custom MCP servers
</p>
2025-07-08 21:18:49 +08:00
<div className="flex gap-2 justify-center">
<Button onClick={() => setShowRegistryDialog(true)} variant="default">
<Store className="h-4 w-4 mr-2" />
Browse Apps
</Button>
<Button onClick={() => setShowCustomDialog(true)} variant="outline">
<Server className="h-4 w-4 mr-2" />
Custom MCP
</Button>
</div>
</div>
)}
2025-07-08 21:18:49 +08:00
{configuredMCPs.length > 0 && (
2025-07-10 13:21:23 +08:00
<div className="space-y-4">
<div className="bg-card rounded-xl border border-border overflow-hidden">
<div className="px-6 py-4 border-b border-border bg-muted/30">
<h4 className="text-sm font-medium text-foreground">
Configured Integrations
</h4>
</div>
<div className="p-2 divide-y divide-border">
<ConfiguredMcpList
configuredMCPs={configuredMCPs}
onEdit={handleEditMCP}
onRemove={handleRemoveMCP}
/>
</div>
</div>
2025-07-10 13:21:23 +08:00
<div className="flex gap-2 justify-center">
<Button onClick={() => setShowRegistryDialog(true)} variant="default">
<Store className="h-4 w-4 mr-2" />
Browse Apps
</Button>
<Button onClick={() => setShowCustomDialog(true)} variant="outline">
<Server className="h-4 w-4 mr-2" />
Custom MCP
</Button>
</div>
</div>
)}
2025-07-08 21:18:49 +08:00
<Dialog open={showRegistryDialog} onOpenChange={setShowRegistryDialog}>
<DialogContent className="p-0 max-w-6xl max-h-[90vh] overflow-y-auto">
2025-07-10 01:47:52 +08:00
<DialogHeader className="sr-only">
<DialogTitle>Select Integration</DialogTitle>
</DialogHeader>
2025-07-08 21:18:49 +08:00
<PipedreamRegistry onToolsSelected={handleToolsSelected} />
</DialogContent>
</Dialog>
2025-06-02 13:44:22 +08:00
<CustomMCPDialog
open={showCustomDialog}
onOpenChange={setShowCustomDialog}
onSave={handleSaveCustomMCP}
/>
2025-05-30 19:03:53 +08:00
</div>
);
};