@@ -22,8 +22,10 @@ import {
2222 SelectValue ,
2323} from "@/browser/components/ui/select" ;
2424import { createEditKeyHandler } from "@/browser/utils/ui/keybinds" ;
25+ import { Switch } from "@/browser/components/ui/switch" ;
26+ import { cn } from "@/common/lib/utils" ;
2527import { formatRelativeTime } from "@/browser/utils/ui/dateTime" ;
26- import type { CachedMCPTestResult } from "@/common/types/mcp" ;
28+ import type { CachedMCPTestResult , MCPServerInfo } from "@/common/types/mcp" ;
2729import { getMCPTestResultsKey } from "@/common/constants/storage" ;
2830import { readPersistedState , updatePersistedState } from "@/browser/hooks/usePersistedState" ;
2931
@@ -83,7 +85,7 @@ export const ProjectSettingsSection: React.FC = () => {
8385
8486 // Core state
8587 const [ selectedProject , setSelectedProject ] = useState < string > ( "" ) ;
86- const [ servers , setServers ] = useState < Record < string , string > > ( { } ) ;
88+ const [ servers , setServers ] = useState < Record < string , MCPServerInfo > > ( { } ) ;
8789 const [ loading , setLoading ] = useState ( false ) ;
8890 const [ error , setError ] = useState < string | null > ( null ) ;
8991
@@ -156,6 +158,40 @@ export const ProjectSettingsSection: React.FC = () => {
156158 [ api , selectedProject , refresh , clearTestResult ]
157159 ) ;
158160
161+ const handleToggleEnabled = useCallback (
162+ async ( name : string , enabled : boolean ) => {
163+ if ( ! api || ! selectedProject ) return ;
164+ // Optimistic update
165+ setServers ( ( prev ) => ( {
166+ ...prev ,
167+ [ name ] : { ...prev [ name ] , disabled : ! enabled } ,
168+ } ) ) ;
169+ try {
170+ const result = await api . projects . mcp . setEnabled ( {
171+ projectPath : selectedProject ,
172+ name,
173+ enabled,
174+ } ) ;
175+ if ( ! result . success ) {
176+ // Revert on error
177+ setServers ( ( prev ) => ( {
178+ ...prev ,
179+ [ name ] : { ...prev [ name ] , disabled : enabled } ,
180+ } ) ) ;
181+ setError ( result . error ?? "Failed to update server" ) ;
182+ }
183+ } catch ( err ) {
184+ // Revert on error
185+ setServers ( ( prev ) => ( {
186+ ...prev ,
187+ [ name ] : { ...prev [ name ] , disabled : enabled } ,
188+ } ) ) ;
189+ setError ( err instanceof Error ? err . message : "Failed to update server" ) ;
190+ }
191+ } ,
192+ [ api , selectedProject ]
193+ ) ;
194+
159195 const handleTest = useCallback (
160196 async ( name : string ) => {
161197 if ( ! api || ! selectedProject ) return ;
@@ -320,24 +356,34 @@ export const ProjectSettingsSection: React.FC = () => {
320356 < p className = "text-muted-foreground py-4 text-sm" > No MCP servers configured yet.</ p >
321357 ) : (
322358 < ul className = "space-y-2" >
323- { Object . entries ( servers ) . map ( ( [ name , command ] ) => {
359+ { Object . entries ( servers ) . map ( ( [ name , entry ] ) => {
324360 const isTesting = testingServer === name ;
325361 const cached = testCache [ name ] ;
326362 const isEditing = editing ?. name === name ;
363+ const isEnabled = ! entry . disabled ;
327364 return (
328365 < li key = { name } className = "border-border-medium bg-secondary/20 rounded-lg border p-3" >
329- < div className = "flex items-start justify-between gap-3" >
330- < div className = "min-w-0 flex-1" >
366+ < div className = "flex items-start gap-3" >
367+ < Switch
368+ checked = { isEnabled }
369+ onCheckedChange = { ( checked ) => void handleToggleEnabled ( name , checked ) }
370+ title = { isEnabled ? "Disable server" : "Enable server" }
371+ className = "mt-0.5 shrink-0"
372+ />
373+ < div className = { cn ( "min-w-0 flex-1" , ! isEnabled && "opacity-50" ) } >
331374 < div className = "flex items-center gap-2" >
332375 < span className = "font-medium" > { name } </ span >
333- { cached ?. result . success && ! isEditing && (
376+ { cached ?. result . success && ! isEditing && isEnabled && (
334377 < span
335378 className = "rounded bg-green-500/10 px-1.5 py-0.5 text-xs text-green-500"
336379 title = { `Tested ${ formatRelativeTime ( cached . testedAt ) } ` }
337380 >
338381 { cached . result . tools . length } tools
339382 </ span >
340383 ) }
384+ { ! isEnabled && (
385+ < span className = "text-muted-foreground text-xs" > disabled</ span >
386+ ) }
341387 </ div >
342388 { isEditing ? (
343389 < input
@@ -354,11 +400,11 @@ export const ProjectSettingsSection: React.FC = () => {
354400 />
355401 ) : (
356402 < p className = "text-muted-foreground mt-0.5 font-mono text-xs break-all" >
357- { command }
403+ { entry . command }
358404 </ p >
359405 ) }
360406 </ div >
361- < div className = "flex shrink-0 gap-1" >
407+ < div className = "flex shrink-0 items-center gap-1" >
362408 { isEditing ? (
363409 < >
364410 < Button
@@ -405,7 +451,7 @@ export const ProjectSettingsSection: React.FC = () => {
405451 < Button
406452 variant = "ghost"
407453 size = "icon"
408- onClick = { ( ) => handleStartEdit ( name , command ) }
454+ onClick = { ( ) => handleStartEdit ( name , entry . command ) }
409455 className = "text-muted hover:text-accent h-7 w-7"
410456 title = "Edit command"
411457 >
0 commit comments