feat(mcp): add browser, contextmenu, keybinding, dock, lifecycle tools (11)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Snider 2026-03-13 16:08:34 +00:00
parent 69a57a6946
commit a89e66c832
5 changed files with 265 additions and 0 deletions

32
pkg/mcp/tools_browser.go Normal file
View file

@ -0,0 +1,32 @@
// pkg/mcp/tools_browser.go
package mcp
import (
"context"
"forge.lthn.ai/core/gui/pkg/browser"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// --- browser_open_url ---
type BrowserOpenURLInput struct {
URL string `json:"url"`
}
type BrowserOpenURLOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) browserOpenURL(_ context.Context, _ *mcp.CallToolRequest, input BrowserOpenURLInput) (*mcp.CallToolResult, BrowserOpenURLOutput, error) {
_, _, err := s.core.PERFORM(browser.TaskOpenURL{URL: input.URL})
if err != nil {
return nil, BrowserOpenURLOutput{}, err
}
return nil, BrowserOpenURLOutput{Success: true}, nil
}
// --- Registration ---
func (s *Subsystem) registerBrowserTools(server *mcp.Server) {
mcp.AddTool(server, &mcp.Tool{Name: "browser_open_url", Description: "Open a URL in the default system browser"}, s.browserOpenURL)
}

View file

@ -0,0 +1,87 @@
// pkg/mcp/tools_contextmenu.go
package mcp
import (
"context"
"forge.lthn.ai/core/gui/pkg/contextmenu"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// --- contextmenu_add ---
type ContextMenuAddInput struct {
Name string `json:"name"`
Menu contextmenu.ContextMenuDef `json:"menu"`
}
type ContextMenuAddOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) contextMenuAdd(_ context.Context, _ *mcp.CallToolRequest, input ContextMenuAddInput) (*mcp.CallToolResult, ContextMenuAddOutput, error) {
_, _, err := s.core.PERFORM(contextmenu.TaskAdd{Name: input.Name, Menu: input.Menu})
if err != nil {
return nil, ContextMenuAddOutput{}, err
}
return nil, ContextMenuAddOutput{Success: true}, nil
}
// --- contextmenu_remove ---
type ContextMenuRemoveInput struct {
Name string `json:"name"`
}
type ContextMenuRemoveOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) contextMenuRemove(_ context.Context, _ *mcp.CallToolRequest, input ContextMenuRemoveInput) (*mcp.CallToolResult, ContextMenuRemoveOutput, error) {
_, _, err := s.core.PERFORM(contextmenu.TaskRemove{Name: input.Name})
if err != nil {
return nil, ContextMenuRemoveOutput{}, err
}
return nil, ContextMenuRemoveOutput{Success: true}, nil
}
// --- contextmenu_get ---
type ContextMenuGetInput struct {
Name string `json:"name"`
}
type ContextMenuGetOutput struct {
Menu *contextmenu.ContextMenuDef `json:"menu"`
}
func (s *Subsystem) contextMenuGet(_ context.Context, _ *mcp.CallToolRequest, input ContextMenuGetInput) (*mcp.CallToolResult, ContextMenuGetOutput, error) {
result, _, err := s.core.QUERY(contextmenu.QueryGet{Name: input.Name})
if err != nil {
return nil, ContextMenuGetOutput{}, err
}
menu, _ := result.(*contextmenu.ContextMenuDef)
return nil, ContextMenuGetOutput{Menu: menu}, nil
}
// --- contextmenu_list ---
type ContextMenuListInput struct{}
type ContextMenuListOutput struct {
Menus map[string]contextmenu.ContextMenuDef `json:"menus"`
}
func (s *Subsystem) contextMenuList(_ context.Context, _ *mcp.CallToolRequest, _ ContextMenuListInput) (*mcp.CallToolResult, ContextMenuListOutput, error) {
result, _, err := s.core.QUERY(contextmenu.QueryList{})
if err != nil {
return nil, ContextMenuListOutput{}, err
}
menus, _ := result.(map[string]contextmenu.ContextMenuDef)
return nil, ContextMenuListOutput{Menus: menus}, nil
}
// --- Registration ---
func (s *Subsystem) registerContextMenuTools(server *mcp.Server) {
mcp.AddTool(server, &mcp.Tool{Name: "contextmenu_add", Description: "Register a context menu"}, s.contextMenuAdd)
mcp.AddTool(server, &mcp.Tool{Name: "contextmenu_remove", Description: "Unregister a context menu"}, s.contextMenuRemove)
mcp.AddTool(server, &mcp.Tool{Name: "contextmenu_get", Description: "Get a context menu by name"}, s.contextMenuGet)
mcp.AddTool(server, &mcp.Tool{Name: "contextmenu_list", Description: "List all registered context menus"}, s.contextMenuList)
}

64
pkg/mcp/tools_dock.go Normal file
View file

@ -0,0 +1,64 @@
// pkg/mcp/tools_dock.go
package mcp
import (
"context"
"forge.lthn.ai/core/gui/pkg/dock"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// --- dock_show ---
type DockShowInput struct{}
type DockShowOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) dockShow(_ context.Context, _ *mcp.CallToolRequest, _ DockShowInput) (*mcp.CallToolResult, DockShowOutput, error) {
_, _, err := s.core.PERFORM(dock.TaskShowIcon{})
if err != nil {
return nil, DockShowOutput{}, err
}
return nil, DockShowOutput{Success: true}, nil
}
// --- dock_hide ---
type DockHideInput struct{}
type DockHideOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) dockHide(_ context.Context, _ *mcp.CallToolRequest, _ DockHideInput) (*mcp.CallToolResult, DockHideOutput, error) {
_, _, err := s.core.PERFORM(dock.TaskHideIcon{})
if err != nil {
return nil, DockHideOutput{}, err
}
return nil, DockHideOutput{Success: true}, nil
}
// --- dock_badge ---
type DockBadgeInput struct {
Label string `json:"label"`
}
type DockBadgeOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) dockBadge(_ context.Context, _ *mcp.CallToolRequest, input DockBadgeInput) (*mcp.CallToolResult, DockBadgeOutput, error) {
_, _, err := s.core.PERFORM(dock.TaskSetBadge{Label: input.Label})
if err != nil {
return nil, DockBadgeOutput{}, err
}
return nil, DockBadgeOutput{Success: true}, nil
}
// --- Registration ---
func (s *Subsystem) registerDockTools(server *mcp.Server) {
mcp.AddTool(server, &mcp.Tool{Name: "dock_show", Description: "Show the dock/taskbar icon"}, s.dockShow)
mcp.AddTool(server, &mcp.Tool{Name: "dock_hide", Description: "Hide the dock/taskbar icon"}, s.dockHide)
mcp.AddTool(server, &mcp.Tool{Name: "dock_badge", Description: "Set the dock/taskbar badge label"}, s.dockBadge)
}

View file

@ -0,0 +1,51 @@
// pkg/mcp/tools_keybinding.go
package mcp
import (
"context"
"forge.lthn.ai/core/gui/pkg/keybinding"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// --- keybinding_add ---
type KeybindingAddInput struct {
Accelerator string `json:"accelerator"`
Description string `json:"description,omitempty"`
}
type KeybindingAddOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) keybindingAdd(_ context.Context, _ *mcp.CallToolRequest, input KeybindingAddInput) (*mcp.CallToolResult, KeybindingAddOutput, error) {
_, _, err := s.core.PERFORM(keybinding.TaskAdd{Accelerator: input.Accelerator, Description: input.Description})
if err != nil {
return nil, KeybindingAddOutput{}, err
}
return nil, KeybindingAddOutput{Success: true}, nil
}
// --- keybinding_remove ---
type KeybindingRemoveInput struct {
Accelerator string `json:"accelerator"`
}
type KeybindingRemoveOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) keybindingRemove(_ context.Context, _ *mcp.CallToolRequest, input KeybindingRemoveInput) (*mcp.CallToolResult, KeybindingRemoveOutput, error) {
_, _, err := s.core.PERFORM(keybinding.TaskRemove{Accelerator: input.Accelerator})
if err != nil {
return nil, KeybindingRemoveOutput{}, err
}
return nil, KeybindingRemoveOutput{Success: true}, nil
}
// --- Registration ---
func (s *Subsystem) registerKeybindingTools(server *mcp.Server) {
mcp.AddTool(server, &mcp.Tool{Name: "keybinding_add", Description: "Register a keyboard shortcut"}, s.keybindingAdd)
mcp.AddTool(server, &mcp.Tool{Name: "keybinding_remove", Description: "Unregister a keyboard shortcut"}, s.keybindingRemove)
}

View file

@ -0,0 +1,31 @@
// pkg/mcp/tools_lifecycle.go
package mcp
import (
"context"
"forge.lthn.ai/core/gui/pkg/lifecycle"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// --- app_quit ---
type AppQuitInput struct{}
type AppQuitOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) appQuit(_ context.Context, _ *mcp.CallToolRequest, _ AppQuitInput) (*mcp.CallToolResult, AppQuitOutput, error) {
// Broadcast the will-terminate action which triggers application shutdown
err := s.core.ACTION(lifecycle.ActionWillTerminate{})
if err != nil {
return nil, AppQuitOutput{}, err
}
return nil, AppQuitOutput{Success: true}, nil
}
// --- Registration ---
func (s *Subsystem) registerLifecycleTools(server *mcp.Server) {
mcp.AddTool(server, &mcp.Tool{Name: "app_quit", Description: "Quit the application"}, s.appQuit)
}