@@ -93,10 +93,13 @@ type ServerInterface interface {
9393// App represents the system tray application
9494type App struct {
9595 server ServerInterface
96- apiClient interface { OpenWebUI () error } // API client for web UI access (optional)
97- logger * zap.SugaredLogger
98- version string
99- shutdown func ()
96+ apiClient interface {
97+ OpenWebUI () error
98+ OpenWebUIPath (path string ) error
99+ } // API client for web UI access (optional)
100+ logger * zap.SugaredLogger
101+ version string
102+ shutdown func ()
100103
101104 connectionState ConnectionState
102105 connectionStateMu sync.RWMutex
@@ -128,11 +131,11 @@ type App struct {
128131 autostartItem * systray.MenuItem
129132
130133 // Update notification menu item (hidden until update is available)
131- updateMenuItem * systray.MenuItem
132- updateAvailable bool
133- latestVersion string
134- latestReleaseURL string
135- updateCheckMu sync.RWMutex
134+ updateMenuItem * systray.MenuItem
135+ updateAvailable bool
136+ latestVersion string
137+ latestReleaseURL string
138+ updateCheckMu sync.RWMutex
136139
137140 // Config path for opening from menu
138141 configPath string
@@ -161,7 +164,10 @@ func New(server ServerInterface, logger *zap.SugaredLogger, version string, shut
161164}
162165
163166// NewWithAPIClient creates a new tray application with an API client for web UI access
164- func NewWithAPIClient (server ServerInterface , apiClient interface { OpenWebUI () error }, logger * zap.SugaredLogger , version string , shutdown func ()) * App {
167+ func NewWithAPIClient (server ServerInterface , apiClient interface {
168+ OpenWebUI () error
169+ OpenWebUIPath (path string ) error
170+ }, logger * zap.SugaredLogger , version string , shutdown func ()) * App {
165171 app := & App {
166172 server : server ,
167173 apiClient : apiClient ,
@@ -574,8 +580,12 @@ func (a *App) onReady() {
574580
575581 // Add Web Control Panel menu item if API client is available
576582 var openWebUIItem * systray.MenuItem
583+ var installServerItem * systray.MenuItem
577584 if a .apiClient != nil {
578585 openWebUIItem = systray .AddMenuItem ("Open Web Control Panel" , "Open the web control panel in your browser" )
586+ // Deep-link into the Web UI marketplace (Repositories.vue) to browse
587+ // and install MCP servers (MCP-37a).
588+ installServerItem = systray .AddMenuItem ("Install server…" , "Browse and install MCP servers in the web UI marketplace" )
579589 }
580590 systray .AddSeparator ()
581591
@@ -744,6 +754,20 @@ func (a *App) onReady() {
744754 }()
745755 }
746756
757+ // --- Install Server Click Handler (deep-link to the marketplace) ---
758+ if installServerItem != nil {
759+ go func () {
760+ for {
761+ select {
762+ case <- installServerItem .ClickedCh :
763+ a .handleInstallServer ()
764+ case <- a .ctx .Done ():
765+ return
766+ }
767+ }
768+ }()
769+ }
770+
747771 // --- Autostart Click Handler (separate goroutine for macOS) ---
748772 if runtime .GOOS == osDarwin && a .autostartItem != nil {
749773 go func () {
@@ -1768,6 +1792,23 @@ func (a *App) handleOpenWebUI() {
17681792 }
17691793}
17701794
1795+ // handleInstallServer deep-links to the Web UI marketplace (Repositories.vue)
1796+ // so users can browse and install MCP servers (MCP-37a).
1797+ func (a * App ) handleInstallServer () {
1798+ if a .apiClient == nil {
1799+ a .logger .Warn ("API client not available, cannot open marketplace" )
1800+ return
1801+ }
1802+
1803+ a .logger .Info ("Opening server marketplace from tray menu" )
1804+
1805+ if err := a .apiClient .OpenWebUIPath ("repositories" ); err != nil {
1806+ a .logger .Error ("Failed to open server marketplace" , zap .Error (err ))
1807+ } else {
1808+ a .logger .Info ("Successfully opened server marketplace" )
1809+ }
1810+ }
1811+
17711812// startUpdateChecker starts a background goroutine that periodically checks for updates
17721813// by querying the core's /api/v1/info endpoint
17731814func (a * App ) startUpdateChecker () {
0 commit comments