@@ -15,6 +15,7 @@ import {
1515 AlertDialogHeader ,
1616 AlertDialogTitle ,
1717} from "@/components/ui/alert-dialog" ;
18+ import { Switch } from '@/components/ui/switch' ;
1819import { listMcpServers , removeMcpServer , updateMcpServer , type McpServer } from '@/utils/api' ;
1920
2021export default function McpManager ( ) {
@@ -63,10 +64,27 @@ export default function McpManager() {
6364 setEditConfig ( getServerConfig ( server ) ) ;
6465 } ;
6566
67+ const parseServerConfig = ( json : string , serverName : string ) => {
68+ const parsed = JSON . parse ( json ) ;
69+ // Handle full mcpServers format: { "mcpServers": { "name": { ... } } }
70+ if ( parsed . mcpServers && typeof parsed . mcpServers === 'object' ) {
71+ const servers = parsed . mcpServers ;
72+ const keys = Object . keys ( servers ) ;
73+ if ( keys . length === 1 ) {
74+ return servers [ keys [ 0 ] ] ;
75+ }
76+ if ( servers [ serverName ] ) {
77+ return servers [ serverName ] ;
78+ }
79+ throw new Error ( `Server "${ serverName } " not found in mcpServers` ) ;
80+ }
81+ return parsed ;
82+ } ;
83+
6684 const handleSaveEdit = async ( ) => {
6785 if ( ! editingServer ) return ;
6886 try {
69- const config = JSON . parse ( editConfig ) ;
87+ const config = parseServerConfig ( editConfig , editingServer . name ) ;
7088 await updateMcpServer ( editingServer . name , config ) ;
7189 setEditingServer ( null ) ;
7290 await loadServers ( ) ;
@@ -78,7 +96,7 @@ export default function McpManager() {
7896 const handleAdd = async ( ) => {
7997 if ( ! newServerName . trim ( ) ) return ;
8098 try {
81- const config = JSON . parse ( newServerConfig ) ;
99+ const config = parseServerConfig ( newServerConfig , newServerName . trim ( ) ) ;
82100 await updateMcpServer ( newServerName . trim ( ) , config ) ;
83101 setNewServerName ( '' ) ;
84102 setNewServerConfig ( '{\n "type": "stdio",\n "command": "npx",\n "args": ["-y", "package-name"]\n}' ) ;
@@ -100,6 +118,17 @@ export default function McpManager() {
100118 setServerToDelete ( null ) ;
101119 } ;
102120
121+ const handleToggleEnabled = async ( server : McpServer ) => {
122+ try {
123+ const config = { ...server , disabled : ! server . disabled } ;
124+ delete ( config as Record < string , unknown > ) . name ;
125+ await updateMcpServer ( server . name , config ) ;
126+ await loadServers ( ) ;
127+ } catch ( err ) {
128+ alert ( err instanceof Error ? err . message : 'Failed to toggle' ) ;
129+ }
130+ } ;
131+
103132 if ( loading ) {
104133 return (
105134 < div className = "flex items-center justify-center h-64" >
@@ -163,6 +192,13 @@ export default function McpManager() {
163192 className = "flex items-center gap-3 px-4 py-3 cursor-pointer hover:bg-muted/50"
164193 onClick = { ( ) => setExpandedServer ( isExpanded ? null : server . name ) }
165194 >
195+ < div onClick = { ( e ) => e . stopPropagation ( ) } >
196+ < Switch
197+ checked = { ! server . disabled }
198+ onCheckedChange = { ( ) => handleToggleEnabled ( server ) }
199+ title = { server . disabled ? 'Enable' : 'Disable' }
200+ />
201+ </ div >
166202 < div className = "text-muted-foreground" >
167203 { isExpanded ? < ChevronDown className = "h-4 w-4" /> : < ChevronRight className = "h-4 w-4" /> }
168204 </ div >
@@ -178,33 +214,33 @@ export default function McpManager() {
178214 </ p >
179215 </ div >
180216 < div className = "flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity" onClick = { ( e ) => e . stopPropagation ( ) } >
181- < Button
182- variant = "ghost"
183- size = "icon"
184- className = "h-8 w-8"
185- onClick = { ( ) => handleCopy ( server ) }
186- title = "Copy config"
187- >
188- { copiedServer === server . name ? < Check className = "h-4 w-4 text-green-500" /> : < Copy className = "h-4 w-4" /> }
189- </ Button >
190- < Button
191- variant = "ghost"
192- size = "icon"
193- className = "h-8 w-8"
194- onClick = { ( ) => handleEdit ( server ) }
195- title = "Edit"
196- >
197- < Pencil className = "h-4 w-4" />
198- </ Button >
199- < Button
200- variant = "ghost"
201- size = "icon"
202- className = "h-8 w-8 text-muted-foreground hover:text-destructive hover:bg-destructive/10"
203- onClick = { ( ) => setServerToDelete ( server . name ) }
204- title = "Delete"
205- >
206- < Trash2 className = "h-4 w-4" />
207- </ Button >
217+ < Button
218+ variant = "ghost"
219+ size = "icon"
220+ className = "h-8 w-8"
221+ onClick = { ( ) => handleCopy ( server ) }
222+ title = "Copy config"
223+ >
224+ { copiedServer === server . name ? < Check className = "h-4 w-4 text-green-500" /> : < Copy className = "h-4 w-4" /> }
225+ </ Button >
226+ < Button
227+ variant = "ghost"
228+ size = "icon"
229+ className = "h-8 w-8"
230+ onClick = { ( ) => handleEdit ( server ) }
231+ title = "Edit"
232+ >
233+ < Pencil className = "h-4 w-4" />
234+ </ Button >
235+ < Button
236+ variant = "ghost"
237+ size = "icon"
238+ className = "h-8 w-8 text-muted-foreground hover:text-destructive hover:bg-destructive/10"
239+ onClick = { ( ) => setServerToDelete ( server . name ) }
240+ title = "Delete"
241+ >
242+ < Trash2 className = "h-4 w-4" />
243+ </ Button >
208244 </ div >
209245 </ div >
210246 { isExpanded && (
0 commit comments