@@ -885,7 +885,44 @@ export class McpHub {
885885 return [ ]
886886 }
887887 const response = await connection . client . request ( { method : "resources/list" } , ListResourcesResultSchema )
888- return response ?. resources || [ ]
888+
889+ // Determine the actual source of the server
890+ const actualSource = connection . server . source || "global"
891+ let configPath : string
892+ let alwaysAllowResourcesConfig : string [ ] = [ ]
893+
894+ // Read from the appropriate config file based on the actual source
895+ try {
896+ let serverConfigData : Record < string , any > = { }
897+ if ( actualSource === "project" ) {
898+ // Get project MCP config path
899+ const projectMcpPath = await this . getProjectMcpPath ( )
900+ if ( projectMcpPath ) {
901+ configPath = projectMcpPath
902+ const content = await fs . readFile ( configPath , "utf-8" )
903+ serverConfigData = JSON . parse ( content )
904+ }
905+ } else {
906+ // Get global MCP settings path
907+ configPath = await this . getMcpSettingsFilePath ( )
908+ const content = await fs . readFile ( configPath , "utf-8" )
909+ serverConfigData = JSON . parse ( content )
910+ }
911+ if ( serverConfigData ) {
912+ alwaysAllowResourcesConfig = serverConfigData . mcpServers ?. [ serverName ] ?. alwaysAllowResources || [ ]
913+ }
914+ } catch ( error ) {
915+ console . error ( `Failed to read resource configuration for ${ serverName } :` , error )
916+ // Continue with empty configs
917+ }
918+
919+ // Mark resources as always allowed based on settings
920+ const resources = ( response ?. resources || [ ] ) . map ( ( resource ) => ( {
921+ ...resource ,
922+ alwaysAllow : alwaysAllowResourcesConfig . includes ( resource . uri ) ,
923+ } ) )
924+
925+ return resources
889926 } catch ( error ) {
890927 // console.error(`Failed to fetch resources for ${serverName}:`, error)
891928 return [ ]
@@ -905,7 +942,44 @@ export class McpHub {
905942 { method : "resources/templates/list" } ,
906943 ListResourceTemplatesResultSchema ,
907944 )
908- return response ?. resourceTemplates || [ ]
945+
946+ // Determine the actual source of the server
947+ const actualSource = connection . server . source || "global"
948+ let configPath : string
949+ let alwaysAllowResourcesConfig : string [ ] = [ ]
950+
951+ // Read from the appropriate config file based on the actual source
952+ try {
953+ let serverConfigData : Record < string , any > = { }
954+ if ( actualSource === "project" ) {
955+ // Get project MCP config path
956+ const projectMcpPath = await this . getProjectMcpPath ( )
957+ if ( projectMcpPath ) {
958+ configPath = projectMcpPath
959+ const content = await fs . readFile ( configPath , "utf-8" )
960+ serverConfigData = JSON . parse ( content )
961+ }
962+ } else {
963+ // Get global MCP settings path
964+ configPath = await this . getMcpSettingsFilePath ( )
965+ const content = await fs . readFile ( configPath , "utf-8" )
966+ serverConfigData = JSON . parse ( content )
967+ }
968+ if ( serverConfigData ) {
969+ alwaysAllowResourcesConfig = serverConfigData . mcpServers ?. [ serverName ] ?. alwaysAllowResources || [ ]
970+ }
971+ } catch ( error ) {
972+ console . error ( `Failed to read resource template configuration for ${ serverName } :` , error )
973+ // Continue with empty configs
974+ }
975+
976+ // Mark resource templates as always allowed based on settings
977+ const resourceTemplates = ( response ?. resourceTemplates || [ ] ) . map ( ( template ) => ( {
978+ ...template ,
979+ alwaysAllow : alwaysAllowResourcesConfig . includes ( template . uriTemplate ) ,
980+ } ) )
981+
982+ return resourceTemplates
909983 } catch ( error ) {
910984 // console.error(`Failed to fetch resource templates for ${serverName}:`, error)
911985 return [ ]
@@ -1609,6 +1683,104 @@ export class McpHub {
16091683 }
16101684 }
16111685
1686+ async toggleResourceAlwaysAllow (
1687+ serverName : string ,
1688+ source : "global" | "project" ,
1689+ resourceUri : string ,
1690+ shouldAllow : boolean ,
1691+ ) : Promise < void > {
1692+ try {
1693+ await this . updateServerResourceList ( serverName , source , resourceUri , "alwaysAllowResources" , shouldAllow )
1694+ } catch ( error ) {
1695+ this . showErrorMessage (
1696+ `Failed to toggle always allow for resource "${ resourceUri } " on server "${ serverName } " with source "${ source } "` ,
1697+ error ,
1698+ )
1699+ throw error
1700+ }
1701+ }
1702+
1703+ /**
1704+ * Helper method to update the resource always allow list
1705+ * in the appropriate settings file.
1706+ * @param serverName The name of the server to update
1707+ * @param source Whether to update the global or project config
1708+ * @param resourceUri The URI of the resource to add or remove
1709+ * @param listName The name of the list to modify ("alwaysAllowResources")
1710+ * @param addResource Whether to add (true) or remove (false) the resource from the list
1711+ */
1712+ private async updateServerResourceList (
1713+ serverName : string ,
1714+ source : "global" | "project" ,
1715+ resourceUri : string ,
1716+ listName : "alwaysAllowResources" ,
1717+ addResource : boolean ,
1718+ ) : Promise < void > {
1719+ // Find the connection with matching name and source
1720+ const connection = this . findConnection ( serverName , source )
1721+
1722+ if ( ! connection ) {
1723+ throw new Error ( `Server ${ serverName } with source ${ source } not found` )
1724+ }
1725+
1726+ // Determine the correct config path based on the source
1727+ let configPath : string
1728+ if ( source === "project" ) {
1729+ // Get project MCP config path
1730+ const projectMcpPath = await this . getProjectMcpPath ( )
1731+ if ( ! projectMcpPath ) {
1732+ throw new Error ( "Project MCP configuration file not found" )
1733+ }
1734+ configPath = projectMcpPath
1735+ } else {
1736+ // Get global MCP settings path
1737+ configPath = await this . getMcpSettingsFilePath ( )
1738+ }
1739+
1740+ // Normalize path for cross-platform compatibility
1741+ // Use a consistent path format for both reading and writing
1742+ const normalizedPath = process . platform === "win32" ? configPath . replace ( / \\ / g, "/" ) : configPath
1743+
1744+ // Read the appropriate config file
1745+ const content = await fs . readFile ( normalizedPath , "utf-8" )
1746+ const config = JSON . parse ( content )
1747+
1748+ if ( ! config . mcpServers ) {
1749+ config . mcpServers = { }
1750+ }
1751+
1752+ if ( ! config . mcpServers [ serverName ] ) {
1753+ config . mcpServers [ serverName ] = {
1754+ type : "stdio" ,
1755+ command : "node" ,
1756+ args : [ ] , // Default to an empty array; can be set later if needed
1757+ }
1758+ }
1759+
1760+ if ( ! config . mcpServers [ serverName ] [ listName ] ) {
1761+ config . mcpServers [ serverName ] [ listName ] = [ ]
1762+ }
1763+
1764+ const targetList = config . mcpServers [ serverName ] [ listName ]
1765+ const resourceIndex = targetList . indexOf ( resourceUri )
1766+
1767+ if ( addResource && resourceIndex === - 1 ) {
1768+ targetList . push ( resourceUri )
1769+ } else if ( ! addResource && resourceIndex !== - 1 ) {
1770+ targetList . splice ( resourceIndex , 1 )
1771+ }
1772+
1773+ // Write config file first, then update UI only if successful
1774+ await fs . writeFile ( normalizedPath , JSON . stringify ( config , null , 2 ) )
1775+
1776+ // Only update UI after successful config file write
1777+ if ( connection ) {
1778+ connection . server . resources = await this . fetchResourcesList ( serverName , source )
1779+ connection . server . resourceTemplates = await this . fetchResourceTemplatesList ( serverName , source )
1780+ await this . notifyWebviewOfServerChanges ( )
1781+ }
1782+ }
1783+
16121784 async dispose ( ) : Promise < void > {
16131785 // Prevent multiple disposals
16141786 if ( this . isDisposed ) {
0 commit comments