@@ -332,9 +332,6 @@ export class McpHub {
332332 const result = McpSettingsSchema . safeParse ( config )
333333 if ( result . success ) {
334334 await this . updateServerConnections ( result . data . mcpServers || { } )
335-
336- // 2. Initialize project-level MCP servers
337- await this . initializeProjectMcpServers ( )
338335 } else {
339336 // Format validation errors for better user feedback
340337 const errorMessages = result . error . errors
@@ -555,15 +552,40 @@ export class McpHub {
555552
556553 private async fetchToolsList ( serverName : string ) : Promise < McpTool [ ] > {
557554 try {
558- const response = await this . connections
559- . find ( ( conn ) => conn . server . name === serverName )
560- ?. client . request ( { method : "tools/list" } , ListToolsResultSchema )
555+ const connection = this . connections . find ( ( conn ) => conn . server . name === serverName )
556+ if ( ! connection ) {
557+ throw new Error ( `Server ${ serverName } not found` )
558+ }
561559
562- // Get always allow settings
563- const settingsPath = await this . getMcpSettingsFilePath ( )
564- const content = await fs . readFile ( settingsPath , "utf-8" )
565- const config = JSON . parse ( content )
566- const alwaysAllowConfig = config . mcpServers [ serverName ] ?. alwaysAllow || [ ]
560+ const response = await connection . client . request ( { method : "tools/list" } , ListToolsResultSchema )
561+
562+ // Determine which config file to read based on server source
563+ const isProjectServer = connection . server . source === "project"
564+ let configPath : string
565+ let alwaysAllowConfig : string [ ] = [ ]
566+
567+ // Read from the appropriate config file
568+ try {
569+ if ( isProjectServer ) {
570+ // Get project MCP config path
571+ const projectMcpPath = await this . getProjectMcpPath ( )
572+ if ( projectMcpPath ) {
573+ configPath = projectMcpPath
574+ const content = await fs . readFile ( configPath , "utf-8" )
575+ const config = JSON . parse ( content )
576+ alwaysAllowConfig = config . mcpServers ?. [ serverName ] ?. alwaysAllow || [ ]
577+ }
578+ } else {
579+ // Get global MCP settings path
580+ configPath = await this . getMcpSettingsFilePath ( )
581+ const content = await fs . readFile ( configPath , "utf-8" )
582+ const config = JSON . parse ( content )
583+ alwaysAllowConfig = config . mcpServers ?. [ serverName ] ?. alwaysAllow || [ ]
584+ }
585+ } catch ( error ) {
586+ console . error ( `Failed to read alwaysAllow config for ${ serverName } :` , error )
587+ // Continue with empty alwaysAllowConfig
588+ }
567589
568590 // Mark tools as always allowed based on settings
569591 const tools = ( response ?. tools || [ ] ) . map ( ( tool ) => ( {
@@ -574,7 +596,7 @@ export class McpHub {
574596 console . log ( `[MCP] Fetched tools for ${ serverName } :` , tools )
575597 return tools
576598 } catch ( error ) {
577- // console.error(`Failed to fetch tools for ${serverName}:`, error)
599+ console . error ( `Failed to fetch tools for ${ serverName } :` , error )
578600 return [ ]
579601 }
580602 }
@@ -794,115 +816,120 @@ export class McpHub {
794816 }
795817
796818 public async toggleServerDisabled ( serverName : string , disabled : boolean ) : Promise < void > {
797- let settingsPath : string
798819 try {
799- settingsPath = await this . getMcpSettingsFilePath ( )
800-
801- // Ensure the settings file exists and is accessible
802- try {
803- await fs . access ( settingsPath )
804- } catch ( error ) {
805- console . error ( "Settings file not accessible:" , error )
806- throw new Error ( "Settings file not accessible" )
807- }
808- const content = await fs . readFile ( settingsPath , "utf-8" )
809- const config = JSON . parse ( content )
810-
811- // Validate the config structure
812- if ( ! config || typeof config !== "object" ) {
813- throw new Error ( "Invalid config structure" )
814- }
815-
816- if ( ! config . mcpServers || typeof config . mcpServers !== "object" ) {
817- config . mcpServers = { }
820+ // Find the connection to determine if it's a global or project server
821+ const connection = this . connections . find ( ( conn ) => conn . server . name === serverName )
822+ if ( ! connection ) {
823+ throw new Error ( `Server ${ serverName } not found` )
818824 }
819825
820- if ( config . mcpServers [ serverName ] ) {
821- // Create a new server config object to ensure clean structure
822- const serverConfig = {
823- ...config . mcpServers [ serverName ] ,
824- disabled,
825- }
826-
827- // Ensure required fields exist
828- if ( ! serverConfig . alwaysAllow ) {
829- serverConfig . alwaysAllow = [ ]
830- }
831-
832- config . mcpServers [ serverName ] = serverConfig
833-
834- // Write the entire config back
835- const updatedConfig = {
836- mcpServers : config . mcpServers ,
837- }
838-
839- await fs . writeFile ( settingsPath , JSON . stringify ( updatedConfig , null , 2 ) )
826+ // Update the server config in the appropriate file
827+ await this . updateServerConfig ( serverName , { disabled } , connection . server . source || "global" )
840828
841- const connection = this . connections . find ( ( conn ) => conn . server . name === serverName )
842- if ( connection ) {
843- try {
844- connection . server . disabled = disabled
829+ // Update the connection object
830+ if ( connection ) {
831+ try {
832+ connection . server . disabled = disabled
845833
846- // Only refresh capabilities if connected
847- if ( connection . server . status === "connected" ) {
848- connection . server . tools = await this . fetchToolsList ( serverName )
849- connection . server . resources = await this . fetchResourcesList ( serverName )
850- connection . server . resourceTemplates = await this . fetchResourceTemplatesList ( serverName )
851- }
852- } catch ( error ) {
853- console . error ( `Failed to refresh capabilities for ${ serverName } :` , error )
834+ // Only refresh capabilities if connected
835+ if ( connection . server . status === "connected" ) {
836+ connection . server . tools = await this . fetchToolsList ( serverName )
837+ connection . server . resources = await this . fetchResourcesList ( serverName )
838+ connection . server . resourceTemplates = await this . fetchResourceTemplatesList ( serverName )
854839 }
840+ } catch ( error ) {
841+ console . error ( `Failed to refresh capabilities for ${ serverName } :` , error )
855842 }
856-
857- await this . notifyWebviewOfServerChanges ( )
858843 }
844+
845+ await this . notifyWebviewOfServerChanges ( )
859846 } catch ( error ) {
860847 this . showErrorMessage ( `Failed to update server ${ serverName } state` , error )
861848 throw error
862849 }
863850 }
864851
865- public async updateServerTimeout ( serverName : string , timeout : number ) : Promise < void > {
866- let settingsPath : string
852+ /**
853+ * Helper method to update a server's configuration in the appropriate settings file
854+ * @param serverName The name of the server to update
855+ * @param configUpdate The configuration updates to apply
856+ * @param source Whether to update the global or project config
857+ */
858+ private async updateServerConfig (
859+ serverName : string ,
860+ configUpdate : Record < string , any > ,
861+ source : "global" | "project" = "global" ,
862+ ) : Promise < void > {
863+ // Determine which config file to update
864+ let configPath : string
865+ if ( source === "project" ) {
866+ const projectMcpPath = await this . getProjectMcpPath ( )
867+ if ( ! projectMcpPath ) {
868+ throw new Error ( "Project MCP configuration file not found" )
869+ }
870+ configPath = projectMcpPath
871+ } else {
872+ configPath = await this . getMcpSettingsFilePath ( )
873+ }
874+
875+ // Ensure the settings file exists and is accessible
867876 try {
868- settingsPath = await this . getMcpSettingsFilePath ( )
877+ await fs . access ( configPath )
878+ } catch ( error ) {
879+ console . error ( "Settings file not accessible:" , error )
880+ throw new Error ( "Settings file not accessible" )
881+ }
869882
870- // Ensure the settings file exists and is accessible
871- try {
872- await fs . access ( settingsPath )
873- } catch ( error ) {
874- console . error ( "Settings file not accessible:" , error )
875- throw new Error ( "Settings file not accessible" )
876- }
877- const content = await fs . readFile ( settingsPath , "utf-8" )
878- const config = JSON . parse ( content )
883+ // Read and parse the config file
884+ const content = await fs . readFile ( configPath , "utf-8" )
885+ const config = JSON . parse ( content )
879886
880- // Validate the config structure
881- if ( ! config || typeof config !== "object" ) {
882- throw new Error ( "Invalid config structure" )
883- }
887+ // Validate the config structure
888+ if ( ! config || typeof config !== "object" ) {
889+ throw new Error ( "Invalid config structure" )
890+ }
884891
885- if ( ! config . mcpServers || typeof config . mcpServers !== "object" ) {
886- config . mcpServers = { }
887- }
892+ if ( ! config . mcpServers || typeof config . mcpServers !== "object" ) {
893+ config . mcpServers = { }
894+ }
888895
889- if ( config . mcpServers [ serverName ] ) {
890- // Create a new server config object to ensure clean structure
891- const serverConfig = {
892- ...config . mcpServers [ serverName ] ,
893- timeout,
894- }
896+ if ( ! config . mcpServers [ serverName ] ) {
897+ config . mcpServers [ serverName ] = { }
898+ }
895899
896- config . mcpServers [ serverName ] = serverConfig
900+ // Create a new server config object to ensure clean structure
901+ const serverConfig = {
902+ ...config . mcpServers [ serverName ] ,
903+ ...configUpdate ,
904+ }
897905
898- // Write the entire config back
899- const updatedConfig = {
900- mcpServers : config . mcpServers ,
901- }
906+ // Ensure required fields exist
907+ if ( ! serverConfig . alwaysAllow ) {
908+ serverConfig . alwaysAllow = [ ]
909+ }
902910
903- await fs . writeFile ( settingsPath , JSON . stringify ( updatedConfig , null , 2 ) )
904- await this . notifyWebviewOfServerChanges ( )
911+ config . mcpServers [ serverName ] = serverConfig
912+
913+ // Write the entire config back
914+ const updatedConfig = {
915+ mcpServers : config . mcpServers ,
916+ }
917+
918+ await fs . writeFile ( configPath , JSON . stringify ( updatedConfig , null , 2 ) )
919+ }
920+
921+ public async updateServerTimeout ( serverName : string , timeout : number ) : Promise < void > {
922+ try {
923+ // Find the connection to determine if it's a global or project server
924+ const connection = this . connections . find ( ( conn ) => conn . server . name === serverName )
925+ if ( ! connection ) {
926+ throw new Error ( `Server ${ serverName } not found` )
905927 }
928+
929+ // Update the server config in the appropriate file
930+ await this . updateServerConfig ( serverName , { timeout } , connection . server . source || "global" )
931+
932+ await this . notifyWebviewOfServerChanges ( )
906933 } catch ( error ) {
907934 this . showErrorMessage ( `Failed to update server ${ serverName } timeout settings` , error )
908935 throw error
@@ -911,16 +938,36 @@ export class McpHub {
911938
912939 public async deleteServer ( serverName : string ) : Promise < void > {
913940 try {
914- const settingsPath = await this . getMcpSettingsFilePath ( )
941+ // Find the connection to determine if it's a global or project server
942+ const connection = this . connections . find ( ( conn ) => conn . server . name === serverName )
943+ if ( ! connection ) {
944+ throw new Error ( `Server ${ serverName } not found` )
945+ }
946+
947+ // Determine config file based on server source
948+ const isProjectServer = connection . server . source === "project"
949+ let configPath : string
950+
951+ if ( isProjectServer ) {
952+ // Get project MCP config path
953+ const projectMcpPath = await this . getProjectMcpPath ( )
954+ if ( ! projectMcpPath ) {
955+ throw new Error ( "Project MCP configuration file not found" )
956+ }
957+ configPath = projectMcpPath
958+ } else {
959+ // Get global MCP settings path
960+ configPath = await this . getMcpSettingsFilePath ( )
961+ }
915962
916963 // Ensure the settings file exists and is accessible
917964 try {
918- await fs . access ( settingsPath )
965+ await fs . access ( configPath )
919966 } catch ( error ) {
920967 throw new Error ( "Settings file not accessible" )
921968 }
922969
923- const content = await fs . readFile ( settingsPath , "utf-8" )
970+ const content = await fs . readFile ( configPath , "utf-8" )
924971 const config = JSON . parse ( content )
925972
926973 // Validate the config structure
@@ -941,10 +988,10 @@ export class McpHub {
941988 mcpServers : config . mcpServers ,
942989 }
943990
944- await fs . writeFile ( settingsPath , JSON . stringify ( updatedConfig , null , 2 ) )
991+ await fs . writeFile ( configPath , JSON . stringify ( updatedConfig , null , 2 ) )
945992
946- // Update server connections
947- await this . updateServerConnections ( config . mcpServers )
993+ // Update server connections with the correct source
994+ await this . updateServerConnections ( config . mcpServers , connection . server . source || "global" )
948995
949996 vscode . window . showInformationMessage ( t ( "common:info.mcp_server_deleted" , { serverName } ) )
950997 } else {
@@ -1017,10 +1064,41 @@ export class McpHub {
10171064
10181065 async toggleToolAlwaysAllow ( serverName : string , toolName : string , shouldAllow : boolean ) : Promise < void > {
10191066 try {
1020- const settingsPath = await this . getMcpSettingsFilePath ( )
1021- const content = await fs . readFile ( settingsPath , "utf-8" )
1067+ // Find the connection to determine if it's a global or project server
1068+ const connection = this . connections . find ( ( conn ) => conn . server . name === serverName )
1069+ if ( ! connection ) {
1070+ throw new Error ( `Server ${ serverName } not found` )
1071+ }
1072+
1073+ const isProjectServer = connection . server . source === "project"
1074+ let configPath : string
1075+
1076+ if ( isProjectServer ) {
1077+ // Get project MCP config path
1078+ const projectMcpPath = await this . getProjectMcpPath ( )
1079+ if ( ! projectMcpPath ) {
1080+ throw new Error ( "Project MCP configuration file not found" )
1081+ }
1082+ configPath = projectMcpPath
1083+ } else {
1084+ // Get global MCP settings path
1085+ configPath = await this . getMcpSettingsFilePath ( )
1086+ }
1087+
1088+ // Read the appropriate config file
1089+ const content = await fs . readFile ( configPath , "utf-8" )
10221090 const config = JSON . parse ( content )
10231091
1092+ // Initialize mcpServers if it doesn't exist
1093+ if ( ! config . mcpServers ) {
1094+ config . mcpServers = { }
1095+ }
1096+
1097+ // Initialize server config if it doesn't exist
1098+ if ( ! config . mcpServers [ serverName ] ) {
1099+ config . mcpServers [ serverName ] = { }
1100+ }
1101+
10241102 // Initialize alwaysAllow if it doesn't exist
10251103 if ( ! config . mcpServers [ serverName ] . alwaysAllow ) {
10261104 config . mcpServers [ serverName ] . alwaysAllow = [ ]
@@ -1038,10 +1116,9 @@ export class McpHub {
10381116 }
10391117
10401118 // Write updated config back to file
1041- await fs . writeFile ( settingsPath , JSON . stringify ( config , null , 2 ) )
1119+ await fs . writeFile ( configPath , JSON . stringify ( config , null , 2 ) )
10421120
10431121 // Update the tools list to reflect the change
1044- const connection = this . connections . find ( ( conn ) => conn . server . name === serverName )
10451122 if ( connection ) {
10461123 connection . server . tools = await this . fetchToolsList ( serverName )
10471124 await this . notifyWebviewOfServerChanges ( )
0 commit comments