gui/pkg/mcp/tools_window.go
Virgil 5ce1d67f70
Some checks failed
Security Scan / security (push) Failing after 28s
Test / test (push) Successful in 1m21s
refactor(ax): add atomic window bounds task
2026-03-31 08:23:59 +00:00

382 lines
13 KiB
Go

// pkg/mcp/tools_window.go
package mcp
import (
"context"
coreerr "forge.lthn.ai/core/go-log"
"forge.lthn.ai/core/gui/pkg/window"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// --- window_list ---
type WindowListInput struct{}
type WindowListOutput struct {
Windows []window.WindowInfo `json:"windows"`
}
func (s *Subsystem) windowList(_ context.Context, _ *mcp.CallToolRequest, _ WindowListInput) (*mcp.CallToolResult, WindowListOutput, error) {
result, _, err := s.core.QUERY(window.QueryWindowList{})
if err != nil {
return nil, WindowListOutput{}, err
}
windows, ok := result.([]window.WindowInfo)
if !ok {
return nil, WindowListOutput{}, coreerr.E("mcp.windowList", "unexpected result type from window list query", nil)
}
return nil, WindowListOutput{Windows: windows}, nil
}
// --- window_get ---
type WindowGetInput struct {
Name string `json:"name"`
}
type WindowGetOutput struct {
Window *window.WindowInfo `json:"window"`
}
func (s *Subsystem) windowGet(_ context.Context, _ *mcp.CallToolRequest, input WindowGetInput) (*mcp.CallToolResult, WindowGetOutput, error) {
result, _, err := s.core.QUERY(window.QueryWindowByName{Name: input.Name})
if err != nil {
return nil, WindowGetOutput{}, err
}
info, ok := result.(*window.WindowInfo)
if !ok {
return nil, WindowGetOutput{}, coreerr.E("mcp.windowGet", "unexpected result type from window get query", nil)
}
return nil, WindowGetOutput{Window: info}, nil
}
// --- window_focused ---
type WindowFocusedInput struct{}
type WindowFocusedOutput struct {
Window string `json:"window"`
}
func (s *Subsystem) windowFocused(_ context.Context, _ *mcp.CallToolRequest, _ WindowFocusedInput) (*mcp.CallToolResult, WindowFocusedOutput, error) {
result, _, err := s.core.QUERY(window.QueryWindowList{})
if err != nil {
return nil, WindowFocusedOutput{}, err
}
windows, ok := result.([]window.WindowInfo)
if !ok {
return nil, WindowFocusedOutput{}, coreerr.E("mcp.windowFocused", "unexpected result type from window list query", nil)
}
for _, w := range windows {
if w.Focused {
return nil, WindowFocusedOutput{Window: w.Name}, nil
}
}
return nil, WindowFocusedOutput{}, nil
}
// --- window_create ---
type WindowCreateOutput struct {
Window window.WindowInfo `json:"window"`
}
func (s *Subsystem) windowCreate(_ context.Context, _ *mcp.CallToolRequest, input window.Window) (*mcp.CallToolResult, WindowCreateOutput, error) {
if input.Name == "" {
return nil, WindowCreateOutput{}, coreerr.E("mcp.windowCreate", "window name is required", nil)
}
result, _, err := s.core.PERFORM(window.TaskOpenWindow{
Window: input,
})
if err != nil {
return nil, WindowCreateOutput{}, err
}
info, ok := result.(window.WindowInfo)
if !ok {
return nil, WindowCreateOutput{}, coreerr.E("mcp.windowCreate", "unexpected result type from window create task", nil)
}
return nil, WindowCreateOutput{Window: info}, nil
}
// --- window_close ---
type WindowCloseInput struct {
Name string `json:"name"`
}
type WindowCloseOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) windowClose(_ context.Context, _ *mcp.CallToolRequest, input WindowCloseInput) (*mcp.CallToolResult, WindowCloseOutput, error) {
_, _, err := s.core.PERFORM(window.TaskCloseWindow{Name: input.Name})
if err != nil {
return nil, WindowCloseOutput{}, err
}
return nil, WindowCloseOutput{Success: true}, nil
}
// --- window_position ---
type WindowPositionInput struct {
Name string `json:"name"`
X int `json:"x"`
Y int `json:"y"`
}
type WindowPositionOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) windowPosition(_ context.Context, _ *mcp.CallToolRequest, input WindowPositionInput) (*mcp.CallToolResult, WindowPositionOutput, error) {
_, _, err := s.core.PERFORM(window.TaskSetPosition{Name: input.Name, X: input.X, Y: input.Y})
if err != nil {
return nil, WindowPositionOutput{}, err
}
return nil, WindowPositionOutput{Success: true}, nil
}
// --- window_size ---
type WindowSizeInput struct {
Name string `json:"name"`
Width int `json:"width"`
Height int `json:"height"`
}
type WindowSizeOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) windowSize(_ context.Context, _ *mcp.CallToolRequest, input WindowSizeInput) (*mcp.CallToolResult, WindowSizeOutput, error) {
_, _, err := s.core.PERFORM(window.TaskSetSize{Name: input.Name, Width: input.Width, Height: input.Height})
if err != nil {
return nil, WindowSizeOutput{}, err
}
return nil, WindowSizeOutput{Success: true}, nil
}
// --- window_bounds ---
type WindowBoundsInput struct {
Name string `json:"name"`
X int `json:"x"`
Y int `json:"y"`
Width int `json:"width"`
Height int `json:"height"`
}
type WindowBoundsOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) windowBounds(_ context.Context, _ *mcp.CallToolRequest, input WindowBoundsInput) (*mcp.CallToolResult, WindowBoundsOutput, error) {
_, _, err := s.core.PERFORM(window.TaskSetBounds{
Name: input.Name, X: input.X, Y: input.Y, Width: input.Width, Height: input.Height,
})
if err != nil {
return nil, WindowBoundsOutput{}, err
}
return nil, WindowBoundsOutput{Success: true}, nil
}
// --- window_maximize ---
type WindowMaximizeInput struct {
Name string `json:"name"`
}
type WindowMaximizeOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) windowMaximize(_ context.Context, _ *mcp.CallToolRequest, input WindowMaximizeInput) (*mcp.CallToolResult, WindowMaximizeOutput, error) {
_, _, err := s.core.PERFORM(window.TaskMaximize{Name: input.Name})
if err != nil {
return nil, WindowMaximizeOutput{}, err
}
return nil, WindowMaximizeOutput{Success: true}, nil
}
// --- window_minimize ---
type WindowMinimizeInput struct {
Name string `json:"name"`
}
type WindowMinimizeOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) windowMinimize(_ context.Context, _ *mcp.CallToolRequest, input WindowMinimizeInput) (*mcp.CallToolResult, WindowMinimizeOutput, error) {
_, _, err := s.core.PERFORM(window.TaskMinimize{Name: input.Name})
if err != nil {
return nil, WindowMinimizeOutput{}, err
}
return nil, WindowMinimizeOutput{Success: true}, nil
}
// --- window_restore ---
type WindowRestoreInput struct {
Name string `json:"name"`
}
type WindowRestoreOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) windowRestore(_ context.Context, _ *mcp.CallToolRequest, input WindowRestoreInput) (*mcp.CallToolResult, WindowRestoreOutput, error) {
_, _, err := s.core.PERFORM(window.TaskRestore{Name: input.Name})
if err != nil {
return nil, WindowRestoreOutput{}, err
}
return nil, WindowRestoreOutput{Success: true}, nil
}
// --- window_focus ---
type WindowFocusInput struct {
Name string `json:"name"`
}
type WindowFocusOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) windowFocus(_ context.Context, _ *mcp.CallToolRequest, input WindowFocusInput) (*mcp.CallToolResult, WindowFocusOutput, error) {
_, _, err := s.core.PERFORM(window.TaskFocus{Name: input.Name})
if err != nil {
return nil, WindowFocusOutput{}, err
}
return nil, WindowFocusOutput{Success: true}, nil
}
// --- window_title ---
type WindowTitleInput struct {
Name string `json:"name"`
Title string `json:"title"`
}
type WindowTitleOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) windowTitle(_ context.Context, _ *mcp.CallToolRequest, input WindowTitleInput) (*mcp.CallToolResult, WindowTitleOutput, error) {
_, _, err := s.core.PERFORM(window.TaskSetTitle{Name: input.Name, Title: input.Title})
if err != nil {
return nil, WindowTitleOutput{}, err
}
return nil, WindowTitleOutput{Success: true}, nil
}
// --- window_title_get ---
type WindowTitleGetInput struct {
Name string `json:"name"`
}
type WindowTitleGetOutput struct {
Title string `json:"title"`
}
func (s *Subsystem) windowTitleGet(_ context.Context, _ *mcp.CallToolRequest, input WindowTitleGetInput) (*mcp.CallToolResult, WindowTitleGetOutput, error) {
result, _, err := s.core.QUERY(window.QueryWindowByName{Name: input.Name})
if err != nil {
return nil, WindowTitleGetOutput{}, err
}
info, _ := result.(*window.WindowInfo)
if info == nil {
return nil, WindowTitleGetOutput{}, nil
}
return nil, WindowTitleGetOutput{Title: info.Title}, nil
}
// --- window_visibility ---
type WindowVisibilityInput struct {
Name string `json:"name"`
Visible bool `json:"visible"`
}
type WindowVisibilityOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) windowVisibility(_ context.Context, _ *mcp.CallToolRequest, input WindowVisibilityInput) (*mcp.CallToolResult, WindowVisibilityOutput, error) {
_, _, err := s.core.PERFORM(window.TaskSetVisibility{Name: input.Name, Visible: input.Visible})
if err != nil {
return nil, WindowVisibilityOutput{}, err
}
return nil, WindowVisibilityOutput{Success: true}, nil
}
// --- window_always_on_top ---
type WindowAlwaysOnTopInput struct {
Name string `json:"name"`
AlwaysOnTop bool `json:"alwaysOnTop"`
}
type WindowAlwaysOnTopOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) windowAlwaysOnTop(_ context.Context, _ *mcp.CallToolRequest, input WindowAlwaysOnTopInput) (*mcp.CallToolResult, WindowAlwaysOnTopOutput, error) {
_, _, err := s.core.PERFORM(window.TaskSetAlwaysOnTop{Name: input.Name, AlwaysOnTop: input.AlwaysOnTop})
if err != nil {
return nil, WindowAlwaysOnTopOutput{}, err
}
return nil, WindowAlwaysOnTopOutput{Success: true}, nil
}
// --- window_background_colour ---
type WindowBackgroundColourInput struct {
Name string `json:"name"`
Red uint8 `json:"red"`
Green uint8 `json:"green"`
Blue uint8 `json:"blue"`
Alpha uint8 `json:"alpha"`
}
type WindowBackgroundColourOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) windowBackgroundColour(_ context.Context, _ *mcp.CallToolRequest, input WindowBackgroundColourInput) (*mcp.CallToolResult, WindowBackgroundColourOutput, error) {
_, _, err := s.core.PERFORM(window.TaskSetBackgroundColour{
Name: input.Name, Red: input.Red, Green: input.Green, Blue: input.Blue, Alpha: input.Alpha,
})
if err != nil {
return nil, WindowBackgroundColourOutput{}, err
}
return nil, WindowBackgroundColourOutput{Success: true}, nil
}
// --- window_fullscreen ---
type WindowFullscreenInput struct {
Name string `json:"name"`
Fullscreen bool `json:"fullscreen"`
}
type WindowFullscreenOutput struct {
Success bool `json:"success"`
}
func (s *Subsystem) windowFullscreen(_ context.Context, _ *mcp.CallToolRequest, input WindowFullscreenInput) (*mcp.CallToolResult, WindowFullscreenOutput, error) {
_, _, err := s.core.PERFORM(window.TaskFullscreen{Name: input.Name, Fullscreen: input.Fullscreen})
if err != nil {
return nil, WindowFullscreenOutput{}, err
}
return nil, WindowFullscreenOutput{Success: true}, nil
}
// --- Registration ---
func (s *Subsystem) registerWindowTools(server *mcp.Server) {
mcp.AddTool(server, &mcp.Tool{Name: "window_list", Description: "List all application windows"}, s.windowList)
mcp.AddTool(server, &mcp.Tool{Name: "window_get", Description: "Get information about a specific window"}, s.windowGet)
mcp.AddTool(server, &mcp.Tool{Name: "window_focused", Description: "Get the currently focused window"}, s.windowFocused)
mcp.AddTool(server, &mcp.Tool{Name: "window_create", Description: "Create a new named application window"}, s.windowCreate)
mcp.AddTool(server, &mcp.Tool{Name: "window_close", Description: "Close an application window"}, s.windowClose)
mcp.AddTool(server, &mcp.Tool{Name: "window_position", Description: "Set the position of a window"}, s.windowPosition)
mcp.AddTool(server, &mcp.Tool{Name: "window_size", Description: "Set the size of a window"}, s.windowSize)
mcp.AddTool(server, &mcp.Tool{Name: "window_bounds", Description: "Set both position and size of a window"}, s.windowBounds)
mcp.AddTool(server, &mcp.Tool{Name: "window_maximize", Description: "Maximize a window"}, s.windowMaximize)
mcp.AddTool(server, &mcp.Tool{Name: "window_minimize", Description: "Minimize a window"}, s.windowMinimize)
mcp.AddTool(server, &mcp.Tool{Name: "window_restore", Description: "Restore a maximized or minimized window"}, s.windowRestore)
mcp.AddTool(server, &mcp.Tool{Name: "window_focus", Description: "Bring a window to the front"}, s.windowFocus)
mcp.AddTool(server, &mcp.Tool{Name: "window_title", Description: "Set the title of a window"}, s.windowTitle)
mcp.AddTool(server, &mcp.Tool{Name: "window_title_get", Description: "Get the title of a window"}, s.windowTitleGet)
mcp.AddTool(server, &mcp.Tool{Name: "window_visibility", Description: "Show or hide a window"}, s.windowVisibility)
mcp.AddTool(server, &mcp.Tool{Name: "window_always_on_top", Description: "Pin a window above others"}, s.windowAlwaysOnTop)
mcp.AddTool(server, &mcp.Tool{Name: "window_background_colour", Description: "Set a window background colour"}, s.windowBackgroundColour)
mcp.AddTool(server, &mcp.Tool{Name: "window_fullscreen", Description: "Set a window to fullscreen mode"}, s.windowFullscreen)
}