This commit is contained in:
Josh at WLTechBlog
2025-09-30 14:11:27 -05:00
parent 86d1db55cd
commit a3c782eb24
11 changed files with 4904 additions and 6 deletions

View File

@@ -1034,6 +1034,300 @@ web_clear_storage_cremotemcp:
timeout: 5
```
### 34. `web_drag_and_drop_cremotemcp` *(New in Phase 6)*
Perform drag and drop operation from source element to target element.
**Parameters:**
- `source` (required): CSS selector for the source element to drag
- `target` (required): CSS selector for the target element to drop on
- `tab` (optional): Tab ID (uses current tab if not specified)
- `timeout` (optional): Timeout in seconds (default: 5)
**Example Usage:**
```
# Drag item to drop zone
web_drag_and_drop_cremotemcp:
source: ".draggable-item"
target: ".drop-zone"
timeout: 10
# Drag file to upload area
web_drag_and_drop_cremotemcp:
source: "#file-item"
target: "#upload-area"
tab: "tab-123"
```
### 35. `web_drag_and_drop_coordinates_cremotemcp` *(New in Phase 6)*
Perform drag and drop operation from source element to specific coordinates.
**Parameters:**
- `source` (required): CSS selector for the source element to drag
- `x` (required): Target X coordinate
- `y` (required): Target Y coordinate
- `tab` (optional): Tab ID (uses current tab if not specified)
- `timeout` (optional): Timeout in seconds (default: 5)
**Example Usage:**
```
# Drag item to specific coordinates
web_drag_and_drop_coordinates_cremotemcp:
source: ".draggable-item"
x: 300
y: 200
timeout: 10
# Drag widget to precise position
web_drag_and_drop_coordinates_cremotemcp:
source: "#dashboard-widget"
x: 150
y: 400
tab: "tab-123"
```
### 36. `web_drag_and_drop_offset_cremotemcp` *(New in Phase 6)*
Perform drag and drop operation from source element by relative offset.
**Parameters:**
- `source` (required): CSS selector for the source element to drag
- `offset_x` (required): Horizontal offset in pixels
- `offset_y` (required): Vertical offset in pixels
- `tab` (optional): Tab ID (uses current tab if not specified)
- `timeout` (optional): Timeout in seconds (default: 5)
**Example Usage:**
```
# Drag item by relative offset
web_drag_and_drop_offset_cremotemcp:
source: ".draggable-item"
offset_x: 100
offset_y: 50
timeout: 10
# Move element slightly to the right and down
web_drag_and_drop_offset_cremotemcp:
source: "#moveable-element"
offset_x: 25
offset_y: 25
tab: "tab-123"
```
### 37. `web_right_click_cremotemcp` *(New in Phase 7)*
Right-click on an element to open context menus.
**Parameters:**
- `selector` (required): CSS selector for the element to right-click
- `tab` (optional): Tab ID (uses current tab if not specified)
- `timeout` (optional): Timeout in seconds (default: 5)
**Example Usage:**
```
# Right-click to open context menu
web_right_click_cremotemcp:
selector: ".file-item"
timeout: 10
# Right-click on specific element
web_right_click_cremotemcp:
selector: "#document-title"
tab: "tab-123"
```
### 38. `web_double_click_cremotemcp` *(New in Phase 7)*
Double-click on an element for file operations or text selection.
**Parameters:**
- `selector` (required): CSS selector for the element to double-click
- `tab` (optional): Tab ID (uses current tab if not specified)
- `timeout` (optional): Timeout in seconds (default: 5)
**Example Usage:**
```
# Double-click to open file
web_double_click_cremotemcp:
selector: ".file-icon"
timeout: 10
# Double-click to select text
web_double_click_cremotemcp:
selector: ".text-content"
tab: "tab-123"
```
### 39. `web_hover_cremotemcp` *(New in Phase 7)*
Hover over an element to trigger tooltips or dropdowns.
**Parameters:**
- `selector` (required): CSS selector for the element to hover over
- `tab` (optional): Tab ID (uses current tab if not specified)
- `timeout` (optional): Timeout in seconds (default: 5)
**Example Usage:**
```
# Hover to show tooltip
web_hover_cremotemcp:
selector: ".tooltip-trigger"
timeout: 10
# Hover to open dropdown menu
web_hover_cremotemcp:
selector: ".nav-item"
tab: "tab-123"
```
### 40. `web_middle_click_cremotemcp` *(New in Phase 7)*
Middle-click on an element (typically opens links in new tabs).
**Parameters:**
- `selector` (required): CSS selector for the element to middle-click
- `tab` (optional): Tab ID (uses current tab if not specified)
- `timeout` (optional): Timeout in seconds (default: 5)
**Example Usage:**
```
# Middle-click to open link in new tab
web_middle_click_cremotemcp:
selector: "a[href='/dashboard']"
timeout: 10
# Middle-click on navigation link
web_middle_click_cremotemcp:
selector: ".nav-link"
tab: "tab-123"
```
### 41. `web_mouse_move_cremotemcp` *(New in Phase 7)*
Move mouse to specific coordinates without clicking.
**Parameters:**
- `x` (required): X coordinate to move mouse to
- `y` (required): Y coordinate to move mouse to
- `tab` (optional): Tab ID (uses current tab if not specified)
- `timeout` (optional): Timeout in seconds (default: 5)
**Example Usage:**
```
# Move mouse to specific position
web_mouse_move_cremotemcp:
x: 400
y: 300
timeout: 5
# Position mouse for subsequent action
web_mouse_move_cremotemcp:
x: 150
y: 200
tab: "tab-123"
```
### 42. `web_scroll_wheel_cremotemcp` *(New in Phase 7)*
Scroll with mouse wheel at specific coordinates.
**Parameters:**
- `x` (required): X coordinate for scroll wheel
- `y` (required): Y coordinate for scroll wheel
- `delta_y` (required): Vertical scroll delta (negative = up, positive = down)
- `delta_x` (optional): Horizontal scroll delta (negative = left, positive = right, default: 0)
- `tab` (optional): Tab ID (uses current tab if not specified)
- `timeout` (optional): Timeout in seconds (default: 5)
**Example Usage:**
```
# Scroll up at specific location
web_scroll_wheel_cremotemcp:
x: 400
y: 300
delta_y: -120
timeout: 5
# Scroll down with horizontal component
web_scroll_wheel_cremotemcp:
x: 500
y: 400
delta_x: 50
delta_y: 120
tab: "tab-123"
```
### 43. `web_key_combination_cremotemcp` *(New in Phase 7)*
Send key combinations like Ctrl+C, Alt+Tab, Shift+Enter.
**Parameters:**
- `keys` (required): Key combination to send (e.g., 'Ctrl+C', 'Alt+Tab', 'Shift+Enter', 'Ctrl+Shift+T')
- `tab` (optional): Tab ID (uses current tab if not specified)
- `timeout` (optional): Timeout in seconds (default: 5)
**Example Usage:**
```
# Copy selected text
web_key_combination_cremotemcp:
keys: "Ctrl+C"
timeout: 5
# Open new tab
web_key_combination_cremotemcp:
keys: "Ctrl+T"
tab: "tab-123"
# Select all text
web_key_combination_cremotemcp:
keys: "Ctrl+A"
```
### 44. `web_special_key_cremotemcp` *(New in Phase 7)*
Send special keys like Enter, Escape, Tab, F1-F12, Arrow keys.
**Parameters:**
- `key` (required): Special key to send (e.g., 'Enter', 'Escape', 'Tab', 'F1', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End', 'PageUp', 'PageDown', 'Delete', 'Backspace')
- `tab` (optional): Tab ID (uses current tab if not specified)
- `timeout` (optional): Timeout in seconds (default: 5)
**Example Usage:**
```
# Press Enter key
web_special_key_cremotemcp:
key: "Enter"
timeout: 5
# Navigate with arrow keys
web_special_key_cremotemcp:
key: "ArrowDown"
tab: "tab-123"
# Press Escape to close dialog
web_special_key_cremotemcp:
key: "Escape"
```
### 45. `web_modifier_click_cremotemcp` *(New in Phase 7)*
Click on an element with modifier keys (Ctrl+click, Shift+click).
**Parameters:**
- `selector` (required): CSS selector for the element to click
- `modifiers` (required): Modifier keys to hold while clicking (e.g., 'Ctrl', 'Shift', 'Alt', 'Ctrl+Shift', 'Ctrl+Alt')
- `tab` (optional): Tab ID (uses current tab if not specified)
- `timeout` (optional): Timeout in seconds (default: 5)
**Example Usage:**
```
# Ctrl+click for multi-selection
web_modifier_click_cremotemcp:
selector: ".selectable-item"
modifiers: "Ctrl"
timeout: 10
# Shift+click for range selection
web_modifier_click_cremotemcp:
selector: ".list-item:nth-child(5)"
modifiers: "Shift"
tab: "tab-123"
# Ctrl+Shift+click for extended selection
web_modifier_click_cremotemcp:
selector: ".table-row"
modifiers: "Ctrl+Shift"
```
## Common Usage Patterns
### 1. Basic Web Navigation
@@ -1737,10 +2031,110 @@ get_partial_accessibility_tree_cremotemcp:
- Test screen reader compatibility by analyzing semantic structure
- Build more robust automation using ARIA roles and accessible names
### Advanced Input Operation Testing *(Phase 7 Patterns)*
```
# Test context menu workflows
web_right_click_cremotemcp:
selector: ".file-item"
timeout: 5
web_interact_cremotemcp:
action: "click"
selector: ".context-menu .delete"
timeout: 5
# Test hover-triggered dropdowns
web_hover_cremotemcp:
selector: ".nav-item"
timeout: 5
web_interact_cremotemcp:
action: "click"
selector: ".dropdown-item"
timeout: 5
# Test keyboard navigation accessibility
web_special_key_cremotemcp:
key: "Tab"
timeout: 5
web_special_key_cremotemcp:
key: "Enter"
timeout: 5
# Test copy/paste workflows
web_key_combination_cremotemcp:
keys: "Ctrl+A"
timeout: 5
web_key_combination_cremotemcp:
keys: "Ctrl+C"
timeout: 5
web_interact_cremotemcp:
action: "click"
selector: "#target-input"
timeout: 5
web_key_combination_cremotemcp:
keys: "Ctrl+V"
timeout: 5
# Test multi-selection with modifier clicks
web_modifier_click_cremotemcp:
selector: ".item:nth-child(1)"
modifiers: "Ctrl"
timeout: 5
web_modifier_click_cremotemcp:
selector: ".item:nth-child(3)"
modifiers: "Ctrl"
timeout: 5
web_modifier_click_cremotemcp:
selector: ".item:nth-child(5)"
modifiers: "Ctrl"
timeout: 5
# Test precise mouse wheel scrolling
web_scroll_wheel_cremotemcp:
x: 400
y: 300
delta_y: -240 # Scroll up 2 notches
timeout: 5
# Test middle-click for new tabs
web_middle_click_cremotemcp:
selector: "a[href='/dashboard']"
timeout: 5
# Test double-click for text selection
web_double_click_cremotemcp:
selector: ".editable-text"
timeout: 5
```
### Advanced Drag & Drop Testing *(Phase 6 Patterns)*
```
# Test sortable list reordering
web_drag_and_drop_cremotemcp:
source: ".list-item:first-child"
target: ".list-item:last-child"
timeout: 10
# Test file upload via drag and drop
web_drag_and_drop_coordinates_cremotemcp:
source: ".file-item"
x: 400
y: 300 # Drop zone coordinates
timeout: 15
# Test dashboard widget repositioning
web_drag_and_drop_offset_cremotemcp:
source: ".widget"
offset_x: 200
offset_y: 100
timeout: 10
```
## 🎉 Production Ready
This comprehensive web automation platform provides **31 tools** across 6 enhancement phases, optimized specifically for LLM agents and production workflows. All tools include proper error handling, timeout management, and structured responses for reliable automation.
This comprehensive web automation platform provides **45 tools** across 7 enhancement phases, optimized specifically for LLM agents and production workflows. All tools include proper error handling, timeout management, and structured responses for reliable automation.
**Latest Enhancement - Phase 7**: Advanced input operations including right-click context menus, hover interactions, keyboard combinations, modifier clicks, precise mouse control, and mouse wheel scrolling for comprehensive testing of modern interactive web applications.
---
**Ready for Production**: Complete web automation platform with 31 tools, designed for maximum efficiency and reliability in LLM-driven workflows.
**Ready for Production**: Complete web automation platform with 45 tools, designed for maximum efficiency and reliability in LLM-driven workflows.

View File

@@ -611,9 +611,187 @@ Clear web storage (localStorage, sessionStorage, IndexedDB, etc.) for a tab.
}
```
#### 34. `web_drag_and_drop_cremotemcp`
Perform drag and drop operation from source element to target element.
```json
{
"name": "web_drag_and_drop_cremotemcp",
"arguments": {
"source": ".draggable-item",
"target": ".drop-zone",
"tab": "tab-123",
"timeout": 5
}
}
```
#### 35. `web_drag_and_drop_coordinates_cremotemcp`
Perform drag and drop operation from source element to specific coordinates.
```json
{
"name": "web_drag_and_drop_coordinates_cremotemcp",
"arguments": {
"source": ".draggable-item",
"x": 300,
"y": 200,
"tab": "tab-123",
"timeout": 5
}
}
```
#### 36. `web_drag_and_drop_offset_cremotemcp`
Perform drag and drop operation from source element by relative offset.
```json
{
"name": "web_drag_and_drop_offset_cremotemcp",
"arguments": {
"source": ".draggable-item",
"offset_x": 100,
"offset_y": 50,
"tab": "tab-123",
"timeout": 5
}
}
```
#### 37. `web_right_click_cremotemcp`
Right-click on an element to open context menus.
```json
{
"name": "web_right_click_cremotemcp",
"arguments": {
"selector": ".file-item",
"tab": "tab-123",
"timeout": 5
}
}
```
#### 38. `web_double_click_cremotemcp`
Double-click on an element for file operations or text selection.
```json
{
"name": "web_double_click_cremotemcp",
"arguments": {
"selector": ".file-icon",
"tab": "tab-123",
"timeout": 5
}
}
```
#### 39. `web_hover_cremotemcp`
Hover over an element to trigger tooltips or dropdowns.
```json
{
"name": "web_hover_cremotemcp",
"arguments": {
"selector": ".tooltip-trigger",
"tab": "tab-123",
"timeout": 5
}
}
```
#### 40. `web_middle_click_cremotemcp`
Middle-click on an element (typically opens links in new tabs).
```json
{
"name": "web_middle_click_cremotemcp",
"arguments": {
"selector": "a[href='/dashboard']",
"tab": "tab-123",
"timeout": 5
}
}
```
#### 41. `web_mouse_move_cremotemcp`
Move mouse to specific coordinates without clicking.
```json
{
"name": "web_mouse_move_cremotemcp",
"arguments": {
"x": 400,
"y": 300,
"tab": "tab-123",
"timeout": 5
}
}
```
#### 42. `web_scroll_wheel_cremotemcp`
Scroll with mouse wheel at specific coordinates.
```json
{
"name": "web_scroll_wheel_cremotemcp",
"arguments": {
"x": 400,
"y": 300,
"delta_x": 0,
"delta_y": -120,
"tab": "tab-123",
"timeout": 5
}
}
```
#### 43. `web_key_combination_cremotemcp`
Send key combinations like Ctrl+C, Alt+Tab, Shift+Enter.
```json
{
"name": "web_key_combination_cremotemcp",
"arguments": {
"keys": "Ctrl+C",
"tab": "tab-123",
"timeout": 5
}
}
```
#### 44. `web_special_key_cremotemcp`
Send special keys like Enter, Escape, Tab, F1-F12, Arrow keys.
```json
{
"name": "web_special_key_cremotemcp",
"arguments": {
"key": "Enter",
"tab": "tab-123",
"timeout": 5
}
}
```
#### 45. `web_modifier_click_cremotemcp`
Click on an element with modifier keys (Ctrl+click, Shift+click).
```json
{
"name": "web_modifier_click_cremotemcp",
"arguments": {
"selector": ".selectable-item",
"modifiers": "Ctrl",
"tab": "tab-123",
"timeout": 5
}
}
```
## 🎉 Complete Enhancement Summary
All 6 phases of the MCP enhancement plan have been successfully implemented, delivering a comprehensive web automation platform with **33 tools** organized across the following capabilities:
All phases of the MCP enhancement plan have been successfully implemented, delivering a comprehensive web automation platform with **45 tools** organized across the following capabilities:
### ✅ Phase 1: Element State and Checking (2 tools)
**Enables conditional logic without timing issues**
@@ -657,16 +835,31 @@ All 6 phases of the MCP enhancement plan have been successfully implemented, del
**Benefits**: Better debugging with targeted screenshots, improved file handling workflows, automatic resource management, enhanced visual debugging capabilities.
### ✅ Phase 6: Browser Cache and Site Data Management (6 tools)
**Enables comprehensive cache and site data control for testing and privacy**
### ✅ Phase 6: Browser Cache, Site Data Management, and Drag & Drop (9 tools)
**Enables comprehensive cache/site data control and advanced drag & drop interactions**
- `web_disable_cache_cremotemcp`: Disable browser cache for a tab
- `web_enable_cache_cremotemcp`: Enable browser cache for a tab
- `web_clear_cache_cremotemcp`: Clear browser cache for a tab
- `web_clear_all_site_data_cremotemcp`: Clear all site data (cookies, storage, cache, etc.)
- `web_clear_cookies_cremotemcp`: Clear cookies for a tab
- `web_clear_storage_cremotemcp`: Clear web storage (localStorage, sessionStorage, IndexedDB, etc.)
- `web_drag_and_drop_cremotemcp`: Drag and drop between elements
- `web_drag_and_drop_coordinates_cremotemcp`: Drag and drop to specific coordinates
- `web_drag_and_drop_offset_cremotemcp`: Drag and drop by relative offset
**Benefits**: Essential for testing scenarios requiring fresh page loads, performance testing without cached resources, debugging cache-related issues, ensuring consistent test environments, privacy testing, authentication testing, and complete site data cleanup.
### ✅ Phase 7: Advanced Input Operations (9 tools)
**Enables sophisticated mouse and keyboard interactions for comprehensive testing**
- `web_right_click_cremotemcp`: Right-click for context menus
- `web_double_click_cremotemcp`: Double-click for file operations and text selection
- `web_hover_cremotemcp`: Hover for tooltips and dropdown triggers
- `web_middle_click_cremotemcp`: Middle-click for opening links in new tabs
- `web_mouse_move_cremotemcp`: Precise mouse positioning without clicking
- `web_scroll_wheel_cremotemcp`: Mouse wheel scrolling with pixel-perfect control
- `web_key_combination_cremotemcp`: Key combinations (Ctrl+C, Alt+Tab, Shift+Enter, etc.)
- `web_special_key_cremotemcp`: Special keys (Enter, Escape, Tab, F1-F12, Arrow keys, etc.)
- `web_modifier_click_cremotemcp`: Modifier clicks (Ctrl+click, Shift+click for multi-selection)
**Benefits**: Essential for testing scenarios requiring fresh page loads, performance testing without cached resources, debugging cache-related issues, ensuring consistent test environments, privacy testing, authentication testing, complete site data cleanup, **plus advanced drag & drop testing for sortable lists, file uploads, kanban boards, dashboard widgets, and interactive UI components**. **Advanced input operations enable context menu testing, keyboard navigation accessibility testing, tooltip/dropdown interactions, multi-selection workflows, copy/paste operations, and sophisticated user interaction patterns**.
## Key Benefits for LLM Agents

View File

@@ -2440,6 +2440,869 @@ func main() {
}, nil
})
// Drag and drop tools
mcpServer.AddTool(mcp.Tool{
Name: "web_drag_and_drop_cremotemcp",
Description: "Perform drag and drop operation from source element to target element",
InputSchema: mcp.ToolInputSchema{
Type: "object",
Properties: map[string]any{
"source": map[string]any{
"type": "string",
"description": "CSS selector for the source element to drag",
},
"target": map[string]any{
"type": "string",
"description": "CSS selector for the target element to drop on",
},
"tab": map[string]any{
"type": "string",
"description": "Tab ID (optional, uses current tab)",
},
"timeout": map[string]any{
"type": "integer",
"description": "Timeout in seconds (default: 5)",
"default": 5,
},
},
Required: []string{"source", "target"},
},
}, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// Convert arguments to map
params, ok := request.Params.Arguments.(map[string]any)
if !ok {
return nil, fmt.Errorf("invalid arguments format")
}
source := getStringParam(params, "source", "")
target := getStringParam(params, "target", "")
tab := getStringParam(params, "tab", "")
timeout := getIntParam(params, "timeout", 5)
if source == "" {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent("Error: source parameter is required"),
},
IsError: true,
}, nil
}
if target == "" {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent("Error: target parameter is required"),
},
IsError: true,
}, nil
}
err := cremoteServer.client.DragAndDrop(tab, source, target, timeout)
if err != nil {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Error performing drag and drop: %v", err)),
},
IsError: true,
}, nil
}
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Drag and drop completed successfully from %s to %s", source, target)),
},
IsError: false,
}, nil
})
mcpServer.AddTool(mcp.Tool{
Name: "web_drag_and_drop_coordinates_cremotemcp",
Description: "Perform drag and drop operation from source element to specific coordinates",
InputSchema: mcp.ToolInputSchema{
Type: "object",
Properties: map[string]any{
"source": map[string]any{
"type": "string",
"description": "CSS selector for the source element to drag",
},
"x": map[string]any{
"type": "integer",
"description": "Target X coordinate",
},
"y": map[string]any{
"type": "integer",
"description": "Target Y coordinate",
},
"tab": map[string]any{
"type": "string",
"description": "Tab ID (optional, uses current tab)",
},
"timeout": map[string]any{
"type": "integer",
"description": "Timeout in seconds (default: 5)",
"default": 5,
},
},
Required: []string{"source", "x", "y"},
},
}, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// Convert arguments to map
params, ok := request.Params.Arguments.(map[string]any)
if !ok {
return nil, fmt.Errorf("invalid arguments format")
}
source := getStringParam(params, "source", "")
x := getIntParam(params, "x", 0)
y := getIntParam(params, "y", 0)
tab := getStringParam(params, "tab", "")
timeout := getIntParam(params, "timeout", 5)
if source == "" {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent("Error: source parameter is required"),
},
IsError: true,
}, nil
}
err := cremoteServer.client.DragAndDropToCoordinates(tab, source, x, y, timeout)
if err != nil {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Error performing drag and drop to coordinates: %v", err)),
},
IsError: true,
}, nil
}
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Drag and drop to coordinates (%d, %d) completed successfully from %s", x, y, source)),
},
IsError: false,
}, nil
})
mcpServer.AddTool(mcp.Tool{
Name: "web_drag_and_drop_offset_cremotemcp",
Description: "Perform drag and drop operation from source element by relative offset",
InputSchema: mcp.ToolInputSchema{
Type: "object",
Properties: map[string]any{
"source": map[string]any{
"type": "string",
"description": "CSS selector for the source element to drag",
},
"offset_x": map[string]any{
"type": "integer",
"description": "Horizontal offset in pixels",
},
"offset_y": map[string]any{
"type": "integer",
"description": "Vertical offset in pixels",
},
"tab": map[string]any{
"type": "string",
"description": "Tab ID (optional, uses current tab)",
},
"timeout": map[string]any{
"type": "integer",
"description": "Timeout in seconds (default: 5)",
"default": 5,
},
},
Required: []string{"source", "offset_x", "offset_y"},
},
}, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// Convert arguments to map
params, ok := request.Params.Arguments.(map[string]any)
if !ok {
return nil, fmt.Errorf("invalid arguments format")
}
source := getStringParam(params, "source", "")
offsetX := getIntParam(params, "offset_x", 0)
offsetY := getIntParam(params, "offset_y", 0)
tab := getStringParam(params, "tab", "")
timeout := getIntParam(params, "timeout", 5)
if source == "" {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent("Error: source parameter is required"),
},
IsError: true,
}, nil
}
err := cremoteServer.client.DragAndDropByOffset(tab, source, offsetX, offsetY, timeout)
if err != nil {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Error performing drag and drop by offset: %v", err)),
},
IsError: true,
}, nil
}
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Drag and drop by offset (%d, %d) completed successfully from %s", offsetX, offsetY, source)),
},
IsError: false,
}, nil
})
// Register web_right_click tool
mcpServer.AddTool(mcp.Tool{
Name: "web_right_click_cremotemcp",
Description: "Right-click on an element",
InputSchema: mcp.ToolInputSchema{
Type: "object",
Properties: map[string]any{
"selector": map[string]any{
"type": "string",
"description": "CSS selector for the element to right-click",
},
"tab": map[string]any{
"type": "string",
"description": "Tab ID (optional, uses current tab)",
},
"timeout": map[string]any{
"type": "integer",
"description": "Timeout in seconds (default: 5)",
"default": 5,
},
},
Required: []string{"selector"},
},
}, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
params, ok := request.Params.Arguments.(map[string]any)
if !ok {
return nil, fmt.Errorf("invalid arguments format")
}
selector, ok := params["selector"].(string)
if !ok || selector == "" {
return nil, fmt.Errorf("selector is required")
}
tab := ""
if tabParam, exists := params["tab"]; exists {
if tabStr, ok := tabParam.(string); ok {
tab = tabStr
}
}
timeout := 5
if timeoutParam, exists := params["timeout"]; exists {
if timeoutFloat, ok := timeoutParam.(float64); ok {
timeout = int(timeoutFloat)
}
}
err := cremoteServer.client.RightClick(tab, selector, timeout)
if err != nil {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Failed to right-click: %v", err)),
},
IsError: true,
}, nil
}
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent("Right-click completed successfully"),
},
IsError: false,
}, nil
})
// Register web_double_click tool
mcpServer.AddTool(mcp.Tool{
Name: "web_double_click_cremotemcp",
Description: "Double-click on an element",
InputSchema: mcp.ToolInputSchema{
Type: "object",
Properties: map[string]any{
"selector": map[string]any{
"type": "string",
"description": "CSS selector for the element to double-click",
},
"tab": map[string]any{
"type": "string",
"description": "Tab ID (optional, uses current tab)",
},
"timeout": map[string]any{
"type": "integer",
"description": "Timeout in seconds (default: 5)",
"default": 5,
},
},
Required: []string{"selector"},
},
}, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
params, ok := request.Params.Arguments.(map[string]any)
if !ok {
return nil, fmt.Errorf("invalid arguments format")
}
selector, ok := params["selector"].(string)
if !ok || selector == "" {
return nil, fmt.Errorf("selector is required")
}
tab := ""
if tabParam, exists := params["tab"]; exists {
if tabStr, ok := tabParam.(string); ok {
tab = tabStr
}
}
timeout := 5
if timeoutParam, exists := params["timeout"]; exists {
if timeoutFloat, ok := timeoutParam.(float64); ok {
timeout = int(timeoutFloat)
}
}
err := cremoteServer.client.DoubleClick(tab, selector, timeout)
if err != nil {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Failed to double-click: %v", err)),
},
IsError: true,
}, nil
}
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent("Double-click completed successfully"),
},
IsError: false,
}, nil
})
// Register web_hover tool
mcpServer.AddTool(mcp.Tool{
Name: "web_hover_cremotemcp",
Description: "Hover over an element",
InputSchema: mcp.ToolInputSchema{
Type: "object",
Properties: map[string]any{
"selector": map[string]any{
"type": "string",
"description": "CSS selector for the element to hover over",
},
"tab": map[string]any{
"type": "string",
"description": "Tab ID (optional, uses current tab)",
},
"timeout": map[string]any{
"type": "integer",
"description": "Timeout in seconds (default: 5)",
"default": 5,
},
},
Required: []string{"selector"},
},
}, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
params, ok := request.Params.Arguments.(map[string]any)
if !ok {
return nil, fmt.Errorf("invalid arguments format")
}
selector, ok := params["selector"].(string)
if !ok || selector == "" {
return nil, fmt.Errorf("selector is required")
}
tab := ""
if tabParam, exists := params["tab"]; exists {
if tabStr, ok := tabParam.(string); ok {
tab = tabStr
}
}
timeout := 5
if timeoutParam, exists := params["timeout"]; exists {
if timeoutFloat, ok := timeoutParam.(float64); ok {
timeout = int(timeoutFloat)
}
}
err := cremoteServer.client.Hover(tab, selector, timeout)
if err != nil {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Failed to hover: %v", err)),
},
IsError: true,
}, nil
}
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent("Hover completed successfully"),
},
IsError: false,
}, nil
})
// Register web_middle_click tool
mcpServer.AddTool(mcp.Tool{
Name: "web_middle_click_cremotemcp",
Description: "Middle-click on an element (typically opens links in new tabs)",
InputSchema: mcp.ToolInputSchema{
Type: "object",
Properties: map[string]any{
"selector": map[string]any{
"type": "string",
"description": "CSS selector for the element to middle-click",
},
"tab": map[string]any{
"type": "string",
"description": "Tab ID (optional, uses current tab)",
},
"timeout": map[string]any{
"type": "integer",
"description": "Timeout in seconds (default: 5)",
"default": 5,
},
},
Required: []string{"selector"},
},
}, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
params, ok := request.Params.Arguments.(map[string]any)
if !ok {
return nil, fmt.Errorf("invalid arguments format")
}
selector, ok := params["selector"].(string)
if !ok || selector == "" {
return nil, fmt.Errorf("selector is required")
}
tab := ""
if tabParam, exists := params["tab"]; exists {
if tabStr, ok := tabParam.(string); ok {
tab = tabStr
}
}
timeout := 5
if timeoutParam, exists := params["timeout"]; exists {
if timeoutFloat, ok := timeoutParam.(float64); ok {
timeout = int(timeoutFloat)
}
}
err := cremoteServer.client.MiddleClick(tab, selector, timeout)
if err != nil {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Failed to middle-click: %v", err)),
},
IsError: true,
}, nil
}
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent("Middle-click completed successfully"),
},
IsError: false,
}, nil
})
// Register web_mouse_move tool
mcpServer.AddTool(mcp.Tool{
Name: "web_mouse_move_cremotemcp",
Description: "Move mouse to specific coordinates without clicking",
InputSchema: mcp.ToolInputSchema{
Type: "object",
Properties: map[string]any{
"x": map[string]any{
"type": "integer",
"description": "X coordinate to move mouse to",
},
"y": map[string]any{
"type": "integer",
"description": "Y coordinate to move mouse to",
},
"tab": map[string]any{
"type": "string",
"description": "Tab ID (optional, uses current tab)",
},
"timeout": map[string]any{
"type": "integer",
"description": "Timeout in seconds (default: 5)",
"default": 5,
},
},
Required: []string{"x", "y"},
},
}, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
params, ok := request.Params.Arguments.(map[string]any)
if !ok {
return nil, fmt.Errorf("invalid arguments format")
}
xFloat, ok := params["x"].(float64)
if !ok {
return nil, fmt.Errorf("x coordinate is required")
}
x := int(xFloat)
yFloat, ok := params["y"].(float64)
if !ok {
return nil, fmt.Errorf("y coordinate is required")
}
y := int(yFloat)
tab := ""
if tabParam, exists := params["tab"]; exists {
if tabStr, ok := tabParam.(string); ok {
tab = tabStr
}
}
timeout := 5
if timeoutParam, exists := params["timeout"]; exists {
if timeoutFloat, ok := timeoutParam.(float64); ok {
timeout = int(timeoutFloat)
}
}
err := cremoteServer.client.MouseMove(tab, x, y, timeout)
if err != nil {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Failed to move mouse: %v", err)),
},
IsError: true,
}, nil
}
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Mouse moved to coordinates (%d, %d) successfully", x, y)),
},
IsError: false,
}, nil
})
// Register web_scroll_wheel tool
mcpServer.AddTool(mcp.Tool{
Name: "web_scroll_wheel_cremotemcp",
Description: "Scroll with mouse wheel at specific coordinates",
InputSchema: mcp.ToolInputSchema{
Type: "object",
Properties: map[string]any{
"x": map[string]any{
"type": "integer",
"description": "X coordinate for scroll wheel",
},
"y": map[string]any{
"type": "integer",
"description": "Y coordinate for scroll wheel",
},
"delta_x": map[string]any{
"type": "integer",
"description": "Horizontal scroll delta (negative = left, positive = right)",
"default": 0,
},
"delta_y": map[string]any{
"type": "integer",
"description": "Vertical scroll delta (negative = up, positive = down)",
},
"tab": map[string]any{
"type": "string",
"description": "Tab ID (optional, uses current tab)",
},
"timeout": map[string]any{
"type": "integer",
"description": "Timeout in seconds (default: 5)",
"default": 5,
},
},
Required: []string{"x", "y", "delta_y"},
},
}, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
params, ok := request.Params.Arguments.(map[string]any)
if !ok {
return nil, fmt.Errorf("invalid arguments format")
}
xFloat, ok := params["x"].(float64)
if !ok {
return nil, fmt.Errorf("x coordinate is required")
}
x := int(xFloat)
yFloat, ok := params["y"].(float64)
if !ok {
return nil, fmt.Errorf("y coordinate is required")
}
y := int(yFloat)
deltaXFloat := float64(0)
if deltaXParam, exists := params["delta_x"]; exists {
if deltaXVal, ok := deltaXParam.(float64); ok {
deltaXFloat = deltaXVal
}
}
deltaX := int(deltaXFloat)
deltaYFloat, ok := params["delta_y"].(float64)
if !ok {
return nil, fmt.Errorf("delta_y is required")
}
deltaY := int(deltaYFloat)
tab := ""
if tabParam, exists := params["tab"]; exists {
if tabStr, ok := tabParam.(string); ok {
tab = tabStr
}
}
timeout := 5
if timeoutParam, exists := params["timeout"]; exists {
if timeoutFloat, ok := timeoutParam.(float64); ok {
timeout = int(timeoutFloat)
}
}
err := cremoteServer.client.ScrollWheel(tab, x, y, deltaX, deltaY, timeout)
if err != nil {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Failed to scroll with mouse wheel: %v", err)),
},
IsError: true,
}, nil
}
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Mouse wheel scroll at (%d, %d) with delta (%d, %d) completed successfully", x, y, deltaX, deltaY)),
},
IsError: false,
}, nil
})
// Register web_key_combination tool
mcpServer.AddTool(mcp.Tool{
Name: "web_key_combination_cremotemcp",
Description: "Send key combinations like Ctrl+C, Alt+Tab, Shift+Enter, etc.",
InputSchema: mcp.ToolInputSchema{
Type: "object",
Properties: map[string]any{
"keys": map[string]any{
"type": "string",
"description": "Key combination to send (e.g., 'Ctrl+C', 'Alt+Tab', 'Shift+Enter', 'Ctrl+Shift+T')",
},
"tab": map[string]any{
"type": "string",
"description": "Tab ID (optional, uses current tab)",
},
"timeout": map[string]any{
"type": "integer",
"description": "Timeout in seconds (default: 5)",
"default": 5,
},
},
Required: []string{"keys"},
},
}, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
params, ok := request.Params.Arguments.(map[string]any)
if !ok {
return nil, fmt.Errorf("invalid arguments format")
}
keys, ok := params["keys"].(string)
if !ok || keys == "" {
return nil, fmt.Errorf("keys parameter is required")
}
tab := ""
if tabParam, exists := params["tab"]; exists {
if tabStr, ok := tabParam.(string); ok {
tab = tabStr
}
}
timeout := 5
if timeoutParam, exists := params["timeout"]; exists {
if timeoutFloat, ok := timeoutParam.(float64); ok {
timeout = int(timeoutFloat)
}
}
err := cremoteServer.client.KeyCombination(tab, keys, timeout)
if err != nil {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Failed to send key combination: %v", err)),
},
IsError: true,
}, nil
}
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Key combination '%s' sent successfully", keys)),
},
IsError: false,
}, nil
})
// Register web_special_key tool
mcpServer.AddTool(mcp.Tool{
Name: "web_special_key_cremotemcp",
Description: "Send special keys like Enter, Escape, Tab, F1-F12, Arrow keys, etc.",
InputSchema: mcp.ToolInputSchema{
Type: "object",
Properties: map[string]any{
"key": map[string]any{
"type": "string",
"description": "Special key to send (e.g., 'Enter', 'Escape', 'Tab', 'F1', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End', 'PageUp', 'PageDown', 'Delete', 'Backspace')",
},
"tab": map[string]any{
"type": "string",
"description": "Tab ID (optional, uses current tab)",
},
"timeout": map[string]any{
"type": "integer",
"description": "Timeout in seconds (default: 5)",
"default": 5,
},
},
Required: []string{"key"},
},
}, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
params, ok := request.Params.Arguments.(map[string]any)
if !ok {
return nil, fmt.Errorf("invalid arguments format")
}
key, ok := params["key"].(string)
if !ok || key == "" {
return nil, fmt.Errorf("key parameter is required")
}
tab := ""
if tabParam, exists := params["tab"]; exists {
if tabStr, ok := tabParam.(string); ok {
tab = tabStr
}
}
timeout := 5
if timeoutParam, exists := params["timeout"]; exists {
if timeoutFloat, ok := timeoutParam.(float64); ok {
timeout = int(timeoutFloat)
}
}
err := cremoteServer.client.SpecialKey(tab, key, timeout)
if err != nil {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Failed to send special key: %v", err)),
},
IsError: true,
}, nil
}
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Special key '%s' sent successfully", key)),
},
IsError: false,
}, nil
})
// Register web_modifier_click tool
mcpServer.AddTool(mcp.Tool{
Name: "web_modifier_click_cremotemcp",
Description: "Click on an element with modifier keys (Ctrl+click, Shift+click, Alt+click, etc.)",
InputSchema: mcp.ToolInputSchema{
Type: "object",
Properties: map[string]any{
"selector": map[string]any{
"type": "string",
"description": "CSS selector for the element to click",
},
"modifiers": map[string]any{
"type": "string",
"description": "Modifier keys to hold while clicking (e.g., 'Ctrl', 'Shift', 'Alt', 'Ctrl+Shift', 'Ctrl+Alt')",
},
"tab": map[string]any{
"type": "string",
"description": "Tab ID (optional, uses current tab)",
},
"timeout": map[string]any{
"type": "integer",
"description": "Timeout in seconds (default: 5)",
"default": 5,
},
},
Required: []string{"selector", "modifiers"},
},
}, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
params, ok := request.Params.Arguments.(map[string]any)
if !ok {
return nil, fmt.Errorf("invalid arguments format")
}
selector, ok := params["selector"].(string)
if !ok || selector == "" {
return nil, fmt.Errorf("selector is required")
}
modifiers, ok := params["modifiers"].(string)
if !ok || modifiers == "" {
return nil, fmt.Errorf("modifiers parameter is required")
}
tab := ""
if tabParam, exists := params["tab"]; exists {
if tabStr, ok := tabParam.(string); ok {
tab = tabStr
}
}
timeout := 5
if timeoutParam, exists := params["timeout"]; exists {
if timeoutFloat, ok := timeoutParam.(float64); ok {
timeout = int(timeoutFloat)
}
}
err := cremoteServer.client.ModifierClick(tab, selector, modifiers, timeout)
if err != nil {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Failed to perform modifier click: %v", err)),
},
IsError: true,
}, nil
}
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewTextContent(fmt.Sprintf("Modifier click with '%s' on %s completed successfully", modifiers, selector)),
},
IsError: false,
}, nil
})
// Start the server
log.Printf("Cremote MCP server ready")
if err := server.ServeStdio(mcpServer); err != nil {