Skip to content

Commit 7bb8edf

Browse files
author
Roo Code
committed
Added MCP server deletion with confirmation dialog
- Added delete button with trash icon to MCP server rows - Implemented confirmation dialog using existing Dialog component - Added "deleteMcpServer" message type to WebviewMessage interface - Added handler in ClineProvider to process deletion: - Removes server from MCP settings file - Closes server connection - Updates UI to reflect changes - Added user feedback with success/error notifications - Ensured consistent modal design with rest of application
1 parent 9df50b4 commit 7bb8edf

File tree

3 files changed

+111
-0
lines changed

3 files changed

+111
-0
lines changed

src/core/webview/ClineProvider.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,79 @@ export class ClineProvider implements vscode.WebviewViewProvider {
941941
}
942942
break
943943
}
944+
case "deleteMcpServer": {
945+
if (!message.serverName) {
946+
break
947+
}
948+
949+
try {
950+
this.outputChannel.appendLine(`Attempting to delete MCP server: ${message.serverName}`)
951+
952+
const settingsPath = await this.mcpHub?.getMcpSettingsFilePath()
953+
if (!settingsPath) {
954+
throw new Error("Could not get MCP settings file path")
955+
}
956+
957+
// Ensure the settings file exists and is accessible
958+
try {
959+
await fs.access(settingsPath)
960+
} catch (error) {
961+
this.outputChannel.appendLine("Settings file not accessible")
962+
throw new Error("Settings file not accessible")
963+
}
964+
965+
this.outputChannel.appendLine(`Reading MCP settings from: ${settingsPath}`)
966+
const content = await fs.readFile(settingsPath, "utf-8")
967+
const config = JSON.parse(content)
968+
969+
// Validate the config structure
970+
if (!config || typeof config !== "object") {
971+
throw new Error("Invalid config structure")
972+
}
973+
974+
if (!config.mcpServers || typeof config.mcpServers !== "object") {
975+
config.mcpServers = {}
976+
}
977+
978+
// Remove the server from the settings
979+
if (config.mcpServers[message.serverName]) {
980+
this.outputChannel.appendLine(
981+
`Removing server ${message.serverName} from configuration`,
982+
)
983+
delete config.mcpServers[message.serverName]
984+
985+
// Write the entire config back
986+
const updatedConfig = {
987+
mcpServers: config.mcpServers,
988+
}
989+
990+
await fs.writeFile(settingsPath, JSON.stringify(updatedConfig, null, 2))
991+
992+
// Update server connections through McpHub
993+
this.outputChannel.appendLine("Updating server connections")
994+
await this.mcpHub?.updateServerConnections(config.mcpServers)
995+
996+
this.outputChannel.appendLine(`Successfully deleted MCP server: ${message.serverName}`)
997+
vscode.window.showInformationMessage(`Deleted MCP server: ${message.serverName}`)
998+
} else {
999+
this.outputChannel.appendLine(`Server ${message.serverName} not found in configuration`)
1000+
vscode.window.showWarningMessage(
1001+
`Server "${message.serverName}" not found in configuration`,
1002+
)
1003+
}
1004+
} catch (error) {
1005+
console.error("Failed to delete MCP server:", error)
1006+
if (error instanceof Error) {
1007+
console.error("Error details:", error.message, error.stack)
1008+
}
1009+
const errorMessage = error instanceof Error ? error.message : String(error)
1010+
this.outputChannel.appendLine(`Failed to delete MCP server: ${errorMessage}`)
1011+
vscode.window.showErrorMessage(
1012+
`Failed to delete MCP server: ${error instanceof Error ? error.message : String(error)}`,
1013+
)
1014+
}
1015+
break
1016+
}
9441017
case "restartMcpServer": {
9451018
try {
9461019
await this.mcpHub?.restartConnection(message.text!)

src/shared/WebviewMessage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export interface WebviewMessage {
9393
| "openCustomModesSettings"
9494
| "checkpointDiff"
9595
| "checkpointRestore"
96+
| "deleteMcpServer"
9697
| "maxOpenTabsContext"
9798
text?: string
9899
disabled?: boolean

webview-ui/src/components/mcp/McpView.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { McpServer } from "../../../../src/shared/mcp"
1313
import McpToolRow from "./McpToolRow"
1414
import McpResourceRow from "./McpResourceRow"
1515
import McpEnabledToggle from "./McpEnabledToggle"
16+
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "../ui/dialog"
1617

1718
type McpViewProps = {
1819
onDone: () => void
@@ -129,6 +130,7 @@ const McpView = ({ onDone }: McpViewProps) => {
129130
// Server Row Component
130131
const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowMcp?: boolean }) => {
131132
const [isExpanded, setIsExpanded] = useState(false)
133+
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
132134
const [timeoutValue, setTimeoutValue] = useState(() => {
133135
const configTimeout = JSON.parse(server.config)?.timeout
134136
return configTimeout ?? 60 // Default 1 minute (60 seconds)
@@ -179,6 +181,14 @@ const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowM
179181
})
180182
}
181183

184+
const handleDelete = () => {
185+
vscode.postMessage({
186+
type: "deleteMcpServer",
187+
serverName: server.name,
188+
})
189+
setShowDeleteConfirm(false)
190+
}
191+
182192
return (
183193
<div style={{ marginBottom: "10px" }}>
184194
<div
@@ -202,6 +212,12 @@ const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowM
202212
<div
203213
style={{ display: "flex", alignItems: "center", marginRight: "8px" }}
204214
onClick={(e) => e.stopPropagation()}>
215+
<VSCodeButton
216+
appearance="icon"
217+
onClick={() => setShowDeleteConfirm(true)}
218+
style={{ marginRight: "8px" }}>
219+
<span className="codicon codicon-trash" style={{ fontSize: "14px" }}></span>
220+
</VSCodeButton>
205221
<VSCodeButton
206222
appearance="icon"
207223
onClick={handleRestart}
@@ -393,6 +409,27 @@ const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowM
393409
</div>
394410
)
395411
)}
412+
413+
{/* Delete Confirmation Dialog */}
414+
<Dialog open={showDeleteConfirm} onOpenChange={setShowDeleteConfirm}>
415+
<DialogContent>
416+
<DialogHeader>
417+
<DialogTitle>Delete MCP Server</DialogTitle>
418+
<DialogDescription>
419+
Are you sure you want to delete the MCP server "{server.name}"? This action cannot be
420+
undone.
421+
</DialogDescription>
422+
</DialogHeader>
423+
<DialogFooter>
424+
<VSCodeButton appearance="secondary" onClick={() => setShowDeleteConfirm(false)}>
425+
Cancel
426+
</VSCodeButton>
427+
<VSCodeButton appearance="primary" onClick={handleDelete}>
428+
Delete
429+
</VSCodeButton>
430+
</DialogFooter>
431+
</DialogContent>
432+
</Dialog>
396433
</div>
397434
)
398435
}

0 commit comments

Comments
 (0)