diff --git a/webview-ui/src/components/mcp/McpView.tsx b/webview-ui/src/components/mcp/McpView.tsx index 7188f86..9143121 100644 --- a/webview-ui/src/components/mcp/McpView.tsx +++ b/webview-ui/src/components/mcp/McpView.tsx @@ -1,10 +1,120 @@ -import { VSCodeButton } from "@vscode/webview-ui-toolkit/react" +import { + VSCodeButton, + VSCodeDivider, + VSCodeTextArea, + VSCodeTextField, + VSCodeTag, + VSCodePanelTab, + VSCodePanelView, + VSCodeDataGrid, + VSCodeDataGridRow, + VSCodeDataGridCell, + VSCodePanels, +} from "@vscode/webview-ui-toolkit/react" +import { useState } from "react" + +type McpServer = { + name: string + config: string // JSON config + status: "connected" | "connecting" | "disconnected" + error?: string + tools?: any[] // We'll type this properly later + resources?: any[] // We'll type this properly later +} type McpViewProps = { onDone: () => void } const McpView = ({ onDone }: McpViewProps) => { + const [isAdding, setIsAdding] = useState(false) + const [servers, setServers] = useState([ + // Add some mock servers for testing + { + name: "local-tools", + config: JSON.stringify({ + mcpServers: { + "local-tools": { + command: "npx", + args: ["-y", "@modelcontextprotocol/server-tools"], + }, + }, + }), + status: "connected", + tools: [ + { + name: "execute_command", + description: "Run a shell command on the local system", + }, + { + name: "read_file", + description: "Read contents of a file from the filesystem", + }, + ], + }, + { + name: "postgres-db", + config: JSON.stringify({ + mcpServers: { + "postgres-db": { + command: "npx", + args: ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/mydb"], + }, + }, + }), + status: "disconnected", + error: "Failed to connect to database: Connection refused", + }, + { + name: "github-tools", + config: JSON.stringify({ + mcpServers: { + "github-tools": { + command: "npx", + args: ["-y", "@modelcontextprotocol/server-github"], + }, + }, + }), + status: "connecting", + resources: [ + { + uri: "github://repo/issues", + name: "Repository Issues", + }, + { + uri: "github://repo/pulls", + name: "Pull Requests", + }, + ], + }, + ]) + const [configInput, setConfigInput] = useState("") + + const handleAddServer = () => { + try { + const config = JSON.parse(configInput) + const serverName = Object.keys(config.mcpServers)[0] + + setServers((prev) => [ + ...prev, + { + name: serverName, + config: configInput, + status: "connecting", + }, + ]) + + setIsAdding(false) + setConfigInput("") + + // Here you would trigger the actual server connection + // and update its status/tools/resources accordingly + } catch (e) { + // Handle invalid JSON + console.error("Invalid server configuration:", e) + } + } + return (
{ alignItems: "center", padding: "10px 17px 10px 20px", }}> -

MCP

+

MCP Servers

Done
-
- Add Server +

+ MCP (Model Context Protocol) enables AI models to access external tools and data through standardized + interfaces. Add MCP servers to extend Claude's capabilities with custom functionality and real-time data + access. +

+ + {/* Server List */} +
+ {servers.map((server) => ( + + ))} +
+ + {/* Add Server UI */} +
+ {isAdding ? ( +
+ setConfigInput((e.target as HTMLTextAreaElement).value)} + /> +
+ + Add Server + + setIsAdding(false)}> + Cancel + +
+
+ ) : ( + setIsAdding(true)}> + + Add MCP Server + + )}
) } +// Server Row Component +const ServerRow = ({ server }: { server: McpServer }) => { + const [isExpanded, setIsExpanded] = useState(false) + const [isEditing, setIsEditing] = useState(false) + const [editConfig, setEditConfig] = useState(server.config) + + const getStatusColor = () => { + switch (server.status) { + case "connected": + return "var(--vscode-testing-iconPassed)" + case "connecting": + return "var(--vscode-charts-yellow)" + case "disconnected": + return "var(--vscode-testing-iconFailed)" + } + } + + const handleSaveConfig = () => { + try { + JSON.parse(editConfig) // Validate JSON + // Here you would update the server config + setIsEditing(false) + } catch (e) { + console.error("Invalid JSON config:", e) + } + } + + // Don't allow expansion if server has error + const handleRowClick = () => { + if (!server.error) { + setIsExpanded(!isExpanded) + } + } + + return ( +
+
+ {!server.error && ( + + )} + {server.name} +
+
+ + {server.error ? ( +
+ {server.error} +
+ ) : ( + isExpanded && ( +
+ + Tools ({server.tools?.length || 0}) + Resources ({server.resources?.length || 0}) + + + {server.tools && server.tools.length > 0 ? ( +
+ {server.tools.map((tool) => ( +
+
+ + {tool.name} +
+
+ {tool.description} +
+
+ ))} +
+ ) : ( +
+ No tools found +
+ )} +
+ + {/* Resources Panel View */} + + {server.resources && server.resources.length > 0 ? ( +
+ {server.resources.map((resource) => ( +
+
+ + {resource.name} +
+
+ + {resource.uri} + +
+
+ ))} +
+ ) : ( +
+ No resources found +
+ )} +
+
+ + {/* Edit/Remove Buttons */} +
+ {isEditing ? ( + <> + setEditConfig((e.target as HTMLTextAreaElement).value)} + style={{ width: "100%" }} + /> +
+ + Save + + setIsEditing(false)} + style={{ flex: 1 }}> + Cancel + +
+ + ) : ( +
+ setIsEditing(true)} + style={{ flex: 1 }}> + Edit + + + Remove + +
+ )} +
+
+ ) + )} +
+ ) +} + export default McpView