package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"git.teamworkapps.com/shortcut/cremote/client"
	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

const Version = "2.2.1-contrast-detection-fix"

// CremoteServer wraps the cremote client for MCP
type CremoteServer struct {
	client      *client.Client
	currentTab  string
	tabHistory  []string
	iframeMode  bool
	screenshots []string
}

// NewCremoteServer creates a new cremote MCP server
func NewCremoteServer(host string, port int) *CremoteServer {
	return &CremoteServer{
		client:      client.NewClient(host, port),
		tabHistory:  make([]string, 0),
		screenshots: make([]string, 0),
	}
}

// Helper functions for parameter extraction
func getStringParam(params map[string]any, key, defaultValue string) string {
	if val, ok := params[key].(string); ok {
		return val
	}
	return defaultValue
}

func getBoolParam(params map[string]any, key string, defaultValue bool) bool {
	if val, ok := params[key].(bool); ok {
		return val
	}
	return defaultValue
}

func getIntParam(params map[string]any, key string, defaultValue int) int {
	if val, ok := params[key].(float64); ok {
		return int(val)
	}
	if val, ok := params[key].(int); ok {
		return val
	}
	return defaultValue
}

// handleOptionalNavigation handles optional URL navigation and cache clearing before tool execution
// Returns the tab ID to use (may create a new tab if needed)
func handleOptionalNavigation(cremoteServer *CremoteServer, params map[string]any, timeout int) (string, error) {
	url := getStringParam(params, "url", "")
	clearCache := getBoolParam(params, "clear_cache", false)
	tab := getStringParam(params, "tab", cremoteServer.currentTab)

	// If URL is provided, navigate to it
	if url != "" {
		// If no tab specified and no current tab, create a new one
		if tab == "" {
			newTab, err := cremoteServer.client.OpenTab(timeout)
			if err != nil {
				return "", fmt.Errorf("failed to create new tab: %w", err)
			}
			tab = newTab
			cremoteServer.currentTab = tab
			cremoteServer.tabHistory = append(cremoteServer.tabHistory, tab)
		}

		// Clear cache if requested
		if clearCache {
			err := cremoteServer.client.ClearCache(tab, timeout)
			if err != nil {
				return "", fmt.Errorf("failed to clear cache: %w", err)
			}
		}

		// Load the URL
		err := cremoteServer.client.LoadURL(tab, url, timeout)
		if err != nil {
			return "", fmt.Errorf("failed to load URL: %w", err)
		}

		// Wait 3 seconds after page load to ensure JavaScript has executed
		time.Sleep(3 * time.Second)
	} else if clearCache && tab != "" {
		// Clear cache even if not navigating
		err := cremoteServer.client.ClearCache(tab, timeout)
		if err != nil {
			return "", fmt.Errorf("failed to clear cache: %w", err)
		}
	}

	return tab, nil
}

func main() {
	// Get cremote daemon connection settings
	cremoteHost := os.Getenv("CREMOTE_HOST")
	if cremoteHost == "" {
		cremoteHost = "localhost"
	}

	cremotePortStr := os.Getenv("CREMOTE_PORT")
	cremotePort := 8989
	if cremotePortStr != "" {
		if p, err := strconv.Atoi(cremotePortStr); err == nil {
			cremotePort = p
		}
	}

	log.Printf("Starting cremote MCP server, connecting to cremote daemon at %s:%d", cremoteHost, cremotePort)

	// Create the cremote server
	cremoteServer := NewCremoteServer(cremoteHost, cremotePort)

	// Create MCP server
	mcpServer := server.NewMCPServer("cremote-mcp", Version)

	// Register version tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "version_cremotemcp",
		Description: "Get version information for MCP server and daemon",
		InputSchema: mcp.ToolInputSchema{
			Type:       "object",
			Properties: map[string]any{},
			Required:   []string{},
		},
	}, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		// Get daemon version
		daemonVersion, err := cremoteServer.client.GetVersion()
		if err != nil {
			daemonVersion = fmt.Sprintf("Unable to connect: %v", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("MCP Server version: %s\nDaemon version: %s", Version, daemonVersion)),
			},
			IsError: false,
		}, nil
	})

	// Register web_navigate tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_navigate_cremotemcp",
		Description: "Navigate to a URL with optional cache clearing, screenshot, and data extraction in a single call",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"url": map[string]any{
					"type":        "string",
					"description": "URL to navigate 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": 30,
				},
				"clear_cache": map[string]any{
					"type":        "boolean",
					"description": "Clear browser cache before navigation (default: false)",
					"default":     false,
				},
				"screenshot": map[string]any{
					"type":        "boolean",
					"description": "Take screenshot after navigation",
				},
				"extract": map[string]any{
					"type":        "string",
					"description": "Extract data after navigation: 'source' (page HTML), 'element' (requires extract_selector), 'javascript' (requires extract_code)",
					"enum":        []any{"source", "element", "javascript"},
				},
				"extract_selector": map[string]any{
					"type":        "string",
					"description": "CSS selector for element extraction (required when extract='element')",
				},
				"extract_code": map[string]any{
					"type":        "string",
					"description": "JavaScript code to execute (required when extract='javascript')",
				},
			},
			Required: []string{"url"},
		},
	}, 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")
		}

		url := getStringParam(params, "url", "")
		if url == "" {
			return nil, fmt.Errorf("url parameter is required")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)
		clearCache := getBoolParam(params, "clear_cache", false)
		takeScreenshot := getBoolParam(params, "screenshot", false)
		extractType := getStringParam(params, "extract", "")
		extractSelector := getStringParam(params, "extract_selector", "")
		extractCode := getStringParam(params, "extract_code", "")

		// If no tab specified and no current tab, create a new one
		if tab == "" {
			newTab, err := cremoteServer.client.OpenTab(timeout)
			if err != nil {
				return nil, fmt.Errorf("failed to create new tab: %w", err)
			}
			tab = newTab
			cremoteServer.currentTab = tab
			cremoteServer.tabHistory = append(cremoteServer.tabHistory, tab)
		}

		// Clear cache if requested
		if clearCache {
			err := cremoteServer.client.ClearCache(tab, timeout)
			if err != nil {
				return nil, fmt.Errorf("failed to clear cache: %w", err)
			}
		}

		// Load the URL
		err := cremoteServer.client.LoadURL(tab, url, timeout)
		if err != nil {
			return nil, fmt.Errorf("failed to load URL: %w", err)
		}

		// Wait 3 seconds after page load to ensure JavaScript has executed
		time.Sleep(3 * time.Second)

		message := fmt.Sprintf("Successfully navigated to %s in tab %s", url, tab)
		var extractedData string

		// Extract data if requested
		if extractType != "" {
			switch extractType {
			case "source":
				data, err := cremoteServer.client.GetPageSource(tab, timeout)
				if err != nil {
					return nil, fmt.Errorf("failed to extract page source: %w", err)
				}
				extractedData = data
				message += "\n\nExtracted page source"

			case "element":
				if extractSelector == "" {
					return nil, fmt.Errorf("extract_selector is required when extract='element'")
				}
				data, err := cremoteServer.client.GetElementHTML(tab, extractSelector, timeout)
				if err != nil {
					return nil, fmt.Errorf("failed to extract element: %w", err)
				}
				extractedData = data
				message += fmt.Sprintf("\n\nExtracted element: %s", extractSelector)

			case "javascript":
				if extractCode == "" {
					return nil, fmt.Errorf("extract_code is required when extract='javascript'")
				}
				data, err := cremoteServer.client.EvalJS(tab, extractCode, timeout)
				if err != nil {
					return nil, fmt.Errorf("failed to execute JavaScript: %w", err)
				}
				extractedData = data
				message += "\n\nExecuted JavaScript"

			default:
				return nil, fmt.Errorf("unknown extraction type: %s", extractType)
			}
		}

		// Take screenshot if requested
		if takeScreenshot {
			screenshotPath := fmt.Sprintf("/tmp/navigate-%d.png", time.Now().Unix())
			err = cremoteServer.client.TakeScreenshot(tab, screenshotPath, false, timeout)
			if err == nil {
				cremoteServer.screenshots = append(cremoteServer.screenshots, screenshotPath)
				message += fmt.Sprintf("\n\nScreenshot saved to %s", screenshotPath)
			}
		}

		// Build response content
		content := []mcp.Content{mcp.NewTextContent(message)}
		if extractedData != "" {
			content = append(content, mcp.NewTextContent(fmt.Sprintf("\n\nExtracted data:\n%s", extractedData)))
		}

		return &mcp.CallToolResult{
			Content: content,
			IsError: false,
		}, nil
	})

	// Register web_interact tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_interact_cremotemcp",
		Description: "Interact with web elements (click, fill, submit, upload). For upload action, automatically handles file transfer from host to container if needed.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"action": map[string]any{
					"type":        "string",
					"description": "Action to perform",
					"enum":        []any{"click", "fill", "submit", "upload", "select"},
				},
				"selector": map[string]any{
					"type":        "string",
					"description": "CSS selector for the element",
				},
				"value": map[string]any{
					"type":        "string",
					"description": "Value to fill (for fill/upload actions). For upload, can be either a local host path or container path - will auto-detect and transfer if needed.",
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{"action", "selector"},
		},
	}, 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")
		}

		action := getStringParam(params, "action", "")
		selector := getStringParam(params, "selector", "")
		value := getStringParam(params, "value", "")
		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)

		if action == "" {
			return nil, fmt.Errorf("action parameter is required")
		}
		if selector == "" {
			return nil, fmt.Errorf("selector parameter is required")
		}
		if tab == "" {
			return nil, fmt.Errorf("no tab available - navigate to a page first")
		}

		var err error
		var message string

		switch action {
		case "click":
			err = cremoteServer.client.ClickElement(tab, selector, timeout)
			message = fmt.Sprintf("Clicked element %s", selector)

		case "fill":
			if value == "" {
				return nil, fmt.Errorf("value parameter is required for fill action")
			}
			err = cremoteServer.client.FillFormField(tab, selector, value, timeout)
			message = fmt.Sprintf("Filled element %s with value", selector)

		case "submit":
			err = cremoteServer.client.SubmitForm(tab, selector, timeout)
			message = fmt.Sprintf("Submitted form %s", selector)

		case "upload":
			if value == "" {
				return nil, fmt.Errorf("value parameter (file path) is required for upload action")
			}

			// Auto-detect if file needs to be transferred to container
			// If the path doesn't start with /tmp/ or other container paths, assume it's a host path
			containerPath := value
			var transferredFile bool

			// Check if file exists in container - if not, try to upload from host
			if !strings.HasPrefix(value, "/tmp/") && !strings.HasPrefix(value, "/var/") {
				// This looks like a host path, try to upload to container
				uploadedPath, uploadErr := cremoteServer.client.UploadFileToContainer(value, "")
				if uploadErr == nil {
					containerPath = uploadedPath
					transferredFile = true
				} else {
					// If upload fails, maybe it's already a valid container path, try to use it as-is
					// The actual upload to the form will fail if the file doesn't exist
				}
			}

			err = cremoteServer.client.UploadFile(tab, selector, containerPath, timeout)
			if transferredFile {
				message = fmt.Sprintf("Transferred file from host (%s) to container (%s) and uploaded to element %s", value, containerPath, selector)
			} else {
				message = fmt.Sprintf("Uploaded file %s to element %s", containerPath, selector)
			}

		case "select":
			if value == "" {
				return nil, fmt.Errorf("value parameter is required for select action")
			}
			err = cremoteServer.client.SelectElement(tab, selector, value, timeout)
			message = fmt.Sprintf("Selected option %s in element %s", value, selector)

		default:
			return nil, fmt.Errorf("unknown action: %s", action)
		}

		if err != nil {
			return nil, fmt.Errorf("failed to %s element: %w", action, err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(message),
			},
			IsError: false,
		}, nil
	})

	// Register web_extract tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_extract_cremotemcp",
		Description: "Extract data from the page (source, element HTML, or execute JavaScript). Optionally navigate to URL first with cache clearing.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"type": map[string]any{
					"type":        "string",
					"description": "Type of extraction",
					"enum":        []any{"source", "element", "javascript"},
				},
				"selector": map[string]any{
					"type":        "string",
					"description": "CSS selector (for element type)",
				},
				"code": map[string]any{
					"type":        "string",
					"description": "JavaScript code (for javascript type)",
				},
				"url": map[string]any{
					"type":        "string",
					"description": "Optional URL to navigate to before extraction",
				},
				"clear_cache": map[string]any{
					"type":        "boolean",
					"description": "Clear browser cache before operation (default: false)",
					"default":     false,
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{"type"},
		},
	}, 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")
		}

		extractType := getStringParam(params, "type", "")
		selector := getStringParam(params, "selector", "")
		code := getStringParam(params, "code", "")
		timeout := getIntParam(params, "timeout", 30)

		if extractType == "" {
			return nil, fmt.Errorf("type parameter is required")
		}

		// Handle optional navigation and cache clearing
		tab, err := handleOptionalNavigation(cremoteServer, params, timeout)
		if err != nil {
			return nil, err
		}

		if tab == "" {
			return nil, fmt.Errorf("no tab available - navigate to a page first or provide url parameter")
		}

		var data string

		switch extractType {
		case "source":
			data, err = cremoteServer.client.GetPageSource(tab, timeout)

		case "element":
			if selector == "" {
				return nil, fmt.Errorf("selector parameter is required for element extraction")
			}
			data, err = cremoteServer.client.GetElementHTML(tab, selector, timeout)

		case "javascript":
			if code == "" {
				return nil, fmt.Errorf("code parameter is required for javascript extraction")
			}
			data, err = cremoteServer.client.EvalJS(tab, code, timeout)

		default:
			return nil, fmt.Errorf("unknown extraction type: %s", extractType)
		}

		if err != nil {
			return nil, fmt.Errorf("failed to extract %s: %w", extractType, err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Extracted %s data: %s", extractType, data)),
			},
			IsError: false,
		}, nil
	})

	// Register web_screenshot tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_screenshot_cremotemcp",
		Description: "Take a screenshot of the current page with optional zoom level and viewport size for accessibility testing. Automatically downloads the screenshot from container to host.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"output": map[string]any{
					"type":        "string",
					"description": "Output file path on the host machine (e.g., /home/user/screenshots/page.png). The screenshot will be automatically downloaded from the container.",
				},
				"full_page": map[string]any{
					"type":        "boolean",
					"description": "Capture full page",
					"default":     false,
				},
				"zoom_level": map[string]any{
					"type":        "number",
					"description": "Zoom level (e.g., 1.0, 2.0, 4.0) for accessibility testing",
				},
				"width": map[string]any{
					"type":        "integer",
					"description": "Viewport width in pixels for responsive testing",
				},
				"height": map[string]any{
					"type":        "integer",
					"description": "Viewport height in pixels for responsive testing",
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{"output"},
		},
	}, 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")
		}

		output := getStringParam(params, "output", "")
		fullPage := getBoolParam(params, "full_page", false)
		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)

		// Get optional zoom and viewport parameters
		var zoomLevel float64
		if zoomParam, ok := params["zoom_level"].(float64); ok {
			zoomLevel = zoomParam
		}
		var width, height int
		if widthParam, ok := params["width"].(float64); ok {
			width = int(widthParam)
		}
		if heightParam, ok := params["height"].(float64); ok {
			height = int(heightParam)
		}

		if output == "" {
			return nil, fmt.Errorf("output parameter is required")
		}
		if tab == "" {
			return nil, fmt.Errorf("no tab available - navigate to a page first")
		}

		// Determine container path and host path
		var containerPath, hostPath string

		// If output path starts with /tmp/ or /var/, treat it as container path
		if strings.HasPrefix(output, "/tmp/") || strings.HasPrefix(output, "/var/") {
			containerPath = output
			// Generate a default host path
			hostPath = "/tmp/" + filepath.Base(output)
		} else {
			// Treat as host path, generate container path
			hostPath = output
			containerPath = "/tmp/screenshot-" + strconv.FormatInt(time.Now().Unix(), 10) + filepath.Ext(output)
		}

		// Build command parameters for taking screenshot in container
		cmdParams := map[string]string{
			"output":    containerPath,
			"full-page": strconv.FormatBool(fullPage),
			"tab":       tab,
			"timeout":   strconv.Itoa(timeout),
		}
		if zoomLevel > 0 {
			cmdParams["zoom_level"] = strconv.FormatFloat(zoomLevel, 'f', 1, 64)
		}
		if width > 0 {
			cmdParams["width"] = strconv.Itoa(width)
		}
		if height > 0 {
			cmdParams["height"] = strconv.Itoa(height)
		}

		// Send command to daemon to take screenshot
		resp, err := cremoteServer.client.SendCommand("screenshot", cmdParams)
		if err != nil {
			return nil, fmt.Errorf("failed to take screenshot: %w", err)
		}

		if !resp.Success {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Screenshot failed: %s", resp.Error)),
				},
				IsError: true,
			}, nil
		}

		// Automatically download the screenshot from container to host
		err = cremoteServer.client.DownloadFileFromContainer(containerPath, hostPath)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Screenshot taken in container (%s) but failed to download to host: %v", containerPath, err)),
				},
				IsError: true,
			}, nil
		}

		cremoteServer.screenshots = append(cremoteServer.screenshots, hostPath)

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Screenshot saved to %s (automatically downloaded from container)", hostPath)),
			},
			IsError: false,
		}, nil
	})

	// Register web_manage_tabs tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_manage_tabs_cremotemcp",
		Description: "Manage browser tabs (open, close, list, switch)",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"action": map[string]any{
					"type":        "string",
					"description": "Action to perform",
					"enum":        []any{"open", "close", "list", "switch"},
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (for close/switch actions)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{"action"},
		},
	}, 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")
		}

		action := getStringParam(params, "action", "")
		tab := getStringParam(params, "tab", "")
		timeout := getIntParam(params, "timeout", 30)

		if action == "" {
			return nil, fmt.Errorf("action parameter is required")
		}

		var err error
		var message string

		switch action {
		case "open":
			newTab, err := cremoteServer.client.OpenTab(timeout)
			if err != nil {
				return nil, fmt.Errorf("failed to open new tab: %w", err)
			}
			cremoteServer.currentTab = newTab
			cremoteServer.tabHistory = append(cremoteServer.tabHistory, newTab)
			message = fmt.Sprintf("Opened new tab: %s", newTab)

		case "close":
			if tab == "" {
				return nil, fmt.Errorf("tab parameter is required for close action")
			}
			err = cremoteServer.client.CloseTab(tab, timeout)
			if err != nil {
				return nil, fmt.Errorf("failed to close tab: %w", err)
			}
			// Remove from history and update current tab
			for i, id := range cremoteServer.tabHistory {
				if id == tab {
					cremoteServer.tabHistory = append(cremoteServer.tabHistory[:i], cremoteServer.tabHistory[i+1:]...)
					break
				}
			}
			if cremoteServer.currentTab == tab {
				if len(cremoteServer.tabHistory) > 0 {
					cremoteServer.currentTab = cremoteServer.tabHistory[len(cremoteServer.tabHistory)-1]
				} else {
					cremoteServer.currentTab = ""
				}
			}
			message = fmt.Sprintf("Closed tab: %s", tab)

		case "list":
			tabs, err := cremoteServer.client.ListTabs()
			if err != nil {
				return nil, fmt.Errorf("failed to list tabs: %w", err)
			}
			message = fmt.Sprintf("Found %d tabs: %v", len(tabs), tabs)

		case "switch":
			if tab == "" {
				return nil, fmt.Errorf("tab parameter is required for switch action")
			}
			cremoteServer.currentTab = tab
			// Add to history if not already there
			found := false
			for _, t := range cremoteServer.tabHistory {
				if t == tab {
					found = true
					break
				}
			}
			if !found {
				cremoteServer.tabHistory = append(cremoteServer.tabHistory, tab)
			}
			message = fmt.Sprintf("Switched to tab: %s", tab)

		default:
			return nil, fmt.Errorf("unknown tab action: %s", action)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(message),
			},
			IsError: false,
		}, nil
	})

	// Register web_iframe tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_iframe_cremotemcp",
		Description: "Switch iframe context for subsequent operations",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"action": map[string]any{
					"type":        "string",
					"description": "Action to perform",
					"enum":        []any{"enter", "exit"},
				},
				"selector": map[string]any{
					"type":        "string",
					"description": "Iframe CSS selector (for enter action)",
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{"action"},
		},
	}, 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")
		}

		action := getStringParam(params, "action", "")
		selector := getStringParam(params, "selector", "")
		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)

		if action == "" {
			return nil, fmt.Errorf("action parameter is required")
		}
		if tab == "" {
			return nil, fmt.Errorf("no tab available - navigate to a page first")
		}

		var err error
		var message string

		switch action {
		case "enter":
			if selector == "" {
				return nil, fmt.Errorf("selector parameter is required for enter action")
			}
			err = cremoteServer.client.SwitchToIframe(tab, selector, timeout)
			cremoteServer.iframeMode = true
			message = fmt.Sprintf("Entered iframe: %s", selector)

		case "exit":
			err = cremoteServer.client.SwitchToMain(tab, timeout)
			cremoteServer.iframeMode = false
			message = "Exited iframe context"

		default:
			return nil, fmt.Errorf("unknown iframe action: %s", action)
		}

		if err != nil {
			return nil, fmt.Errorf("failed to %s iframe: %w", action, err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(message),
			},
			IsError: false,
		}, nil
	})

	// Register file_upload tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "file_upload_cremotemcp",
		Description: "Upload a file from the client to the container for use in form uploads",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"local_path": map[string]any{
					"type":        "string",
					"description": "Path to the file on the client machine",
				},
				"container_path": map[string]any{
					"type":        "string",
					"description": "Optional path where to store the file in the container (defaults to /tmp/filename)",
				},
			},
			Required: []string{"local_path"},
		},
	}, 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")
		}

		localPath := getStringParam(params, "local_path", "")
		containerPath := getStringParam(params, "container_path", "")

		if localPath == "" {
			return nil, fmt.Errorf("local_path parameter is required")
		}

		// Upload the file to the container
		targetPath, err := cremoteServer.client.UploadFileToContainer(localPath, containerPath)
		if err != nil {
			return nil, fmt.Errorf("failed to upload file: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("File uploaded successfully to container at: %s", targetPath)),
			},
			IsError: false,
		}, nil
	})

	// Register file_download tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "file_download_cremotemcp",
		Description: "Download a file from the container to the client (e.g., downloaded files from browser)",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"container_path": map[string]any{
					"type":        "string",
					"description": "Path to the file in the container",
				},
				"local_path": map[string]any{
					"type":        "string",
					"description": "Path where to save the file on the client machine",
				},
			},
			Required: []string{"container_path", "local_path"},
		},
	}, 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")
		}

		containerPath := getStringParam(params, "container_path", "")
		localPath := getStringParam(params, "local_path", "")

		if containerPath == "" {
			return nil, fmt.Errorf("container_path parameter is required")
		}
		if localPath == "" {
			return nil, fmt.Errorf("local_path parameter is required")
		}

		// Download the file from the container
		err := cremoteServer.client.DownloadFileFromContainer(containerPath, localPath)
		if err != nil {
			return nil, fmt.Errorf("failed to download file: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("File downloaded successfully from container to: %s", localPath)),
			},
			IsError: false,
		}, nil
	})

	// Register console_logs tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "console_logs_cremotemcp",
		Description: "Get console logs from the browser tab",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"clear": map[string]any{
					"type":        "boolean",
					"description": "Clear logs after retrieval (default: false)",
					"default":     false,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		clear := getBoolParam(params, "clear", false)

		// Get console logs
		logs, err := cremoteServer.client.GetConsoleLogs(tab, clear)
		if err != nil {
			return nil, fmt.Errorf("failed to get console logs: %w", err)
		}

		// Format logs for display
		var logText string
		if len(logs) == 0 {
			logText = "No console logs found."
		} else {
			logText = fmt.Sprintf("Found %d console log entries:\n\n", len(logs))
			for i, log := range logs {
				level := log["level"].(string)
				message := log["message"].(string)
				timestamp := log["timestamp"].(string)
				logText += fmt.Sprintf("[%d] %s [%s]: %s\n", i+1, timestamp, level, message)
			}
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(logText),
			},
			IsError: false,
		}, nil
	})

	// Register console_command tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "console_command_cremotemcp",
		Description: "Execute a command in the browser console with optional library injection (axe-core, jQuery, Lodash, etc.)",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"command": map[string]any{
					"type":        "string",
					"description": "JavaScript command to execute in console",
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"inject_library": map[string]any{
					"type":        "string",
					"description": "Library to inject before executing command (optional). Can be a known library name (axe, jquery, lodash, moment, underscore) or a full URL",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default": 30,
				},
			},
			Required: []string{"command"},
		},
	}, 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")
		}

		command := getStringParam(params, "command", "")
		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		injectLibrary := getStringParam(params, "inject_library", "")
		timeout := getIntParam(params, "timeout", 30)

		if command == "" {
			return nil, fmt.Errorf("command parameter is required")
		}

		// Build command parameters
		cmdParams := map[string]string{
			"command": command,
			"timeout": strconv.Itoa(timeout),
		}
		if tab != "" {
			cmdParams["tab"] = tab
		}
		if injectLibrary != "" {
			cmdParams["inject_library"] = injectLibrary
		}

		// Send command to daemon
		resp, err := cremoteServer.client.SendCommand("console-command", cmdParams)
		if err != nil {
			return nil, fmt.Errorf("failed to execute console command: %w", err)
		}

		if !resp.Success {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Console command failed: %s", resp.Error)),
				},
				IsError: true,
			}, nil
		}

		// Format result
		resultStr := fmt.Sprintf("Console command executed successfully.\nCommand: %s", command)
		if injectLibrary != "" {
			resultStr += fmt.Sprintf("\nInjected library: %s", injectLibrary)
		}
		if resp.Data != nil {
			resultStr += fmt.Sprintf("\nResult: %v", resp.Data)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(resultStr),
			},
			IsError: false,
		}, nil
	})

	// Register web_element_check tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_element_check_cremotemcp",
		Description: "Check existence, visibility, enabled state, count elements. Optionally navigate to URL first with cache clearing.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"selector": map[string]any{
					"type":        "string",
					"description": "CSS selector for the element(s)",
				},
				"check_type": map[string]any{
					"type":        "string",
					"description": "Type of check to perform",
					"enum":        []any{"exists", "visible", "enabled", "focused", "selected", "all"},
					"default":     "exists",
				},
				"url": map[string]any{
					"type":        "string",
					"description": "Optional URL to navigate to before checking element",
				},
				"clear_cache": map[string]any{
					"type":        "boolean",
					"description": "Clear browser cache before operation (default: false)",
					"default":     false,
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{"selector"},
		},
	}, 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")
		}

		selector := getStringParam(params, "selector", "")
		checkType := getStringParam(params, "check_type", "exists")
		timeout := getIntParam(params, "timeout", 30)

		if selector == "" {
			return nil, fmt.Errorf("selector parameter is required")
		}

		// Handle optional navigation and cache clearing
		tab, err := handleOptionalNavigation(cremoteServer, params, timeout)
		if err != nil {
			return nil, err
		}

		if tab == "" {
			return nil, fmt.Errorf("no tab available - navigate to a page first or provide url parameter")
		}

		result, err := cremoteServer.client.CheckElement(tab, selector, checkType, timeout)
		if err != nil {
			return nil, fmt.Errorf("failed to check element: %w", err)
		}

		// Format result as JSON string for display
		resultJSON, _ := json.Marshal(result)

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Element check result: %s", string(resultJSON))),
			},
			IsError: false,
		}, nil
	})

	// Register web_element_attributes tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_element_attributes_cremotemcp",
		Description: "Get attributes, properties, computed styles of an element. Optionally navigate to URL first with cache clearing.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"selector": map[string]any{
					"type":        "string",
					"description": "CSS selector for the element",
				},
				"attributes": map[string]any{
					"type":        "string",
					"description": "Comma-separated list of attributes or 'all' for common attributes. Use 'style_' prefix for computed styles, 'prop_' for JavaScript properties",
					"default":     "all",
				},
				"url": map[string]any{
					"type":        "string",
					"description": "Optional URL to navigate to before getting attributes",
				},
				"clear_cache": map[string]any{
					"type":        "boolean",
					"description": "Clear browser cache before operation (default: false)",
					"default":     false,
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{"selector"},
		},
	}, 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")
		}

		selector := getStringParam(params, "selector", "")
		attributes := getStringParam(params, "attributes", "all")
		timeout := getIntParam(params, "timeout", 30)

		if selector == "" {
			return nil, fmt.Errorf("selector parameter is required")
		}

		// Handle optional navigation and cache clearing
		tab, err := handleOptionalNavigation(cremoteServer, params, timeout)
		if err != nil {
			return nil, err
		}

		if tab == "" {
			return nil, fmt.Errorf("no tab available - navigate to a page first or provide url parameter")
		}

		result, err := cremoteServer.client.GetElementAttributes(tab, selector, attributes, timeout)
		if err != nil {
			return nil, fmt.Errorf("failed to get element attributes: %w", err)
		}

		// Format result as JSON string for display
		resultJSON, _ := json.Marshal(result)

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Element attributes: %s", string(resultJSON))),
			},
			IsError: false,
		}, nil
	})

	// Register web_extract_multiple tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_extract_multiple_cremotemcp",
		Description: "Extract from multiple selectors in one call",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"selectors": map[string]any{
					"type":        "object",
					"description": "Object with keys as labels and values as CSS selectors",
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{"selectors"},
		},
	}, 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")
		}

		selectorsParam := params["selectors"]
		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)

		if selectorsParam == nil {
			return nil, fmt.Errorf("selectors parameter is required")
		}
		if tab == "" {
			return nil, fmt.Errorf("no tab available - navigate to a page first")
		}

		// Convert selectors to map[string]string
		selectorsMap := make(map[string]string)
		if selectorsObj, ok := selectorsParam.(map[string]any); ok {
			for key, value := range selectorsObj {
				if selector, ok := value.(string); ok {
					selectorsMap[key] = selector
				}
			}
		} else {
			return nil, fmt.Errorf("selectors must be an object with string values")
		}

		result, err := cremoteServer.client.ExtractMultiple(tab, selectorsMap, timeout)
		if err != nil {
			return nil, fmt.Errorf("failed to extract multiple: %w", err)
		}

		// Format result as JSON string for display
		resultJSON, _ := json.Marshal(result)

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Multiple extraction result: %s", string(resultJSON))),
			},
			IsError: false,
		}, nil
	})

	// Register web_extract_links tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_extract_links_cremotemcp",
		Description: "Extract all links with filtering options",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"container_selector": map[string]any{
					"type":        "string",
					"description": "Optional CSS selector to limit search to a container",
				},
				"href_pattern": map[string]any{
					"type":        "string",
					"description": "Optional regex pattern to filter links by href",
				},
				"text_pattern": map[string]any{
					"type":        "string",
					"description": "Optional regex pattern to filter links by text content",
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		containerSelector := getStringParam(params, "container_selector", "")
		hrefPattern := getStringParam(params, "href_pattern", "")
		textPattern := getStringParam(params, "text_pattern", "")
		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)

		if tab == "" {
			return nil, fmt.Errorf("no tab available - navigate to a page first")
		}

		result, err := cremoteServer.client.ExtractLinks(tab, containerSelector, hrefPattern, textPattern, timeout)
		if err != nil {
			return nil, fmt.Errorf("failed to extract links: %w", err)
		}

		// Format result as JSON string for display
		resultJSON, _ := json.Marshal(result)

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Links extraction result: %s", string(resultJSON))),
			},
			IsError: false,
		}, nil
	})

	// Register web_extract_table tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_extract_table_cremotemcp",
		Description: "Extract table data as structured JSON",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"selector": map[string]any{
					"type":        "string",
					"description": "CSS selector for the table element",
				},
				"include_headers": map[string]any{
					"type":        "boolean",
					"description": "Whether to extract and use headers for structured data",
					"default":     true,
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{"selector"},
		},
	}, 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")
		}

		selector := getStringParam(params, "selector", "")
		includeHeaders := getBoolParam(params, "include_headers", true)
		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)

		if selector == "" {
			return nil, fmt.Errorf("selector parameter is required")
		}
		if tab == "" {
			return nil, fmt.Errorf("no tab available - navigate to a page first")
		}

		result, err := cremoteServer.client.ExtractTable(tab, selector, includeHeaders, timeout)
		if err != nil {
			return nil, fmt.Errorf("failed to extract table: %w", err)
		}

		// Format result as JSON string for display
		resultJSON, _ := json.Marshal(result)

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Table extraction result: %s", string(resultJSON))),
			},
			IsError: false,
		}, nil
	})

	// Register web_extract_text tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_extract_text_cremotemcp",
		Description: "Extract text with pattern matching",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"selector": map[string]any{
					"type":        "string",
					"description": "CSS selector for elements to extract text from",
				},
				"pattern": map[string]any{
					"type":        "string",
					"description": "Optional regex pattern to match within text",
				},
				"extract_type": map[string]any{
					"type":        "string",
					"description": "Type of text extraction",
					"enum":        []any{"text", "innerText", "textContent"},
					"default":     "textContent",
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{"selector"},
		},
	}, 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")
		}

		selector := getStringParam(params, "selector", "")
		pattern := getStringParam(params, "pattern", "")
		extractType := getStringParam(params, "extract_type", "textContent")
		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)

		if selector == "" {
			return nil, fmt.Errorf("selector parameter is required")
		}
		if tab == "" {
			return nil, fmt.Errorf("no tab available - navigate to a page first")
		}

		result, err := cremoteServer.client.ExtractText(tab, selector, pattern, extractType, timeout)
		if err != nil {
			return nil, fmt.Errorf("failed to extract text: %w", err)
		}

		// Format result as JSON string for display
		resultJSON, _ := json.Marshal(result)

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Text extraction result: %s", string(resultJSON))),
			},
			IsError: false,
		}, nil
	})

	// Register web_form_analyze tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_form_analyze_cremotemcp",
		Description: "Analyze forms completely",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"selector": map[string]any{
					"type":        "string",
					"description": "CSS selector for the form element",
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{"selector"},
		},
	}, 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")
		}

		selector := getStringParam(params, "selector", "")
		if selector == "" {
			return nil, fmt.Errorf("selector parameter is required")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)

		result, err := cremoteServer.client.AnalyzeForm(tab, selector, timeout)
		if err != nil {
			return nil, fmt.Errorf("failed to analyze form: %w", err)
		}

		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal result: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Form analysis result: %s", string(resultJSON))),
			},
			IsError: false,
		}, nil
	})

	// Register web_interact_multiple tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_interact_multiple_cremotemcp",
		Description: "Batch interactions",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"interactions": map[string]any{
					"type":        "array",
					"description": "Array of interactions to perform",
					"items": map[string]any{
						"type": "object",
						"properties": map[string]any{
							"selector": map[string]any{
								"type":        "string",
								"description": "CSS selector for the element",
							},
							"action": map[string]any{
								"type":        "string",
								"description": "Action to perform",
								"enum":        []any{"click", "fill", "select", "check", "uncheck"},
							},
							"value": map[string]any{
								"type":        "string",
								"description": "Value for the action (required for fill, select)",
							},
						},
						"required": []string{"selector", "action"},
					},
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{"interactions"},
		},
	}, 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")
		}

		interactionsData, ok := params["interactions"].([]any)
		if !ok {
			return nil, fmt.Errorf("interactions parameter is required and must be an array")
		}

		// Parse interactions
		var interactions []client.InteractionItem
		for _, interactionData := range interactionsData {
			interactionMap, ok := interactionData.(map[string]any)
			if !ok {
				return nil, fmt.Errorf("each interaction must be an object")
			}

			interaction := client.InteractionItem{}

			if selector, ok := interactionMap["selector"].(string); ok {
				interaction.Selector = selector
			} else {
				return nil, fmt.Errorf("each interaction must have a selector")
			}

			if action, ok := interactionMap["action"].(string); ok {
				interaction.Action = action
			} else {
				return nil, fmt.Errorf("each interaction must have an action")
			}

			if value, ok := interactionMap["value"].(string); ok {
				interaction.Value = value
			}

			interactions = append(interactions, interaction)
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)

		result, err := cremoteServer.client.InteractMultiple(tab, interactions, timeout)
		if err != nil {
			return nil, fmt.Errorf("failed to perform multiple interactions: %w", err)
		}

		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal result: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Multiple interactions result: %s", string(resultJSON))),
			},
			IsError: false,
		}, nil
	})

	// Register web_form_fill_bulk tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_form_fill_bulk_cremotemcp",
		Description: "Fill entire forms with key-value pairs",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"fields": map[string]any{
					"type":        "object",
					"description": "Map of field names/selectors to values",
				},
				"form_selector": map[string]any{
					"type":        "string",
					"description": "CSS selector for the form element (optional)",
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{"fields"},
		},
	}, 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")
		}

		fieldsData, ok := params["fields"].(map[string]any)
		if !ok {
			return nil, fmt.Errorf("fields parameter is required and must be an object")
		}

		// Convert fields to map[string]string
		fields := make(map[string]string)
		for key, value := range fieldsData {
			if strValue, ok := value.(string); ok {
				fields[key] = strValue
			} else {
				return nil, fmt.Errorf("all field values must be strings")
			}
		}

		formSelector := getStringParam(params, "form_selector", "")
		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)

		result, err := cremoteServer.client.FillFormBulk(tab, formSelector, fields, timeout)
		if err != nil {
			return nil, fmt.Errorf("failed to fill form bulk: %w", err)
		}

		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal result: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Form bulk fill result: %s", string(resultJSON))),
			},
			IsError: false,
		}, nil
	})

	// Register web_page_info tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_page_info_cremotemcp",
		Description: "Get comprehensive page metadata and state information. Optionally navigate to URL first with cache clearing.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"url": map[string]any{
					"type":        "string",
					"description": "Optional URL to navigate to before getting page info",
				},
				"clear_cache": map[string]any{
					"type":        "boolean",
					"description": "Clear browser cache before operation (default: false)",
					"default":     false,
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab if not specified)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default": 30,
				},
			},
		},
	}, 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")
		}

		timeout := getIntParam(params, "timeout", 30)

		// Handle optional navigation and cache clearing
		tabID, err := handleOptionalNavigation(cremoteServer, params, timeout)
		if err != nil {
			return nil, err
		}

		result, err := cremoteServer.client.GetPageInfo(tabID, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Error getting page info: %v", err)),
				},
				IsError: true,
			}, nil
		}

		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal result: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Page info: %s", string(resultJSON))),
			},
			IsError: false,
		}, nil
	})

	// Register web_viewport_info tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_viewport_info_cremotemcp",
		Description: "Get viewport and scroll information",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab if not specified)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default": 30,
				},
			},
		},
	}, 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")
		}

		tabID := getStringParam(params, "tab", "")
		timeout := getIntParam(params, "timeout", 30)

		result, err := cremoteServer.client.GetViewportInfo(tabID, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Error getting viewport info: %v", err)),
				},
				IsError: true,
			}, nil
		}

		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal result: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Viewport info: %s", string(resultJSON))),
			},
			IsError: false,
		}, nil
	})

	// Register web_performance_metrics tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_performance_metrics_cremotemcp",
		Description: "Get page performance metrics",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab if not specified)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default": 30,
				},
			},
		},
	}, 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")
		}

		tabID := getStringParam(params, "tab", "")
		timeout := getIntParam(params, "timeout", 30)

		result, err := cremoteServer.client.GetPerformance(tabID, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Error getting performance metrics: %v", err)),
				},
				IsError: true,
			}, nil
		}

		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal result: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Performance metrics: %s", string(resultJSON))),
			},
			IsError: false,
		}, nil
	})

	// Register web_content_check tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_content_check_cremotemcp",
		Description: "Check for specific content types and loading states",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"type": map[string]any{
					"type":        "string",
					"description": "Content type to check",
					"enum":        []any{"images", "scripts", "styles", "forms", "links", "iframes", "errors"},
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab if not specified)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default": 30,
				},
			},
			Required: []string{"type"},
		},
	}, 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")
		}

		contentType := getStringParam(params, "type", "")
		if contentType == "" {
			return nil, fmt.Errorf("type parameter is required")
		}

		tabID := getStringParam(params, "tab", "")
		timeout := getIntParam(params, "timeout", 30)

		result, err := cremoteServer.client.CheckContent(tabID, contentType, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Error checking content: %v", err)),
				},
				IsError: true,
			}, nil
		}

		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal result: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Content check result: %s", string(resultJSON))),
			},
			IsError: false,
		}, nil
	})

	// Phase 5: Enhanced Screenshot and File Management Tools

	// web_screenshot_element_cremotemcp - Screenshot specific elements
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_screenshot_element_cremotemcp",
		Description: "Take a screenshot of a specific element on the page. Automatically downloads the screenshot from container to host.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"selector": map[string]any{
					"type":        "string",
					"description": "CSS selector for the element to screenshot",
				},
				"output": map[string]any{
					"type":        "string",
					"description": "Path where to save the screenshot on the host machine. The screenshot will be automatically downloaded from the container.",
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab if not specified)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
				},
			},
			Required: []string{"selector", "output"},
		},
	}, 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")
		}

		selector := getStringParam(params, "selector", "")
		output := getStringParam(params, "output", "")
		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)

		if selector == "" {
			return nil, fmt.Errorf("selector parameter is required")
		}
		if output == "" {
			return nil, fmt.Errorf("output parameter is required")
		}
		if tab == "" {
			return nil, fmt.Errorf("no tab available - navigate to a page first")
		}

		// Determine container path and host path
		var containerPath, hostPath string

		// If output path starts with /tmp/ or /var/, treat it as container path
		if strings.HasPrefix(output, "/tmp/") || strings.HasPrefix(output, "/var/") {
			containerPath = output
			// Generate a default host path
			hostPath = "/tmp/" + filepath.Base(output)
		} else {
			// Treat as host path, generate container path
			hostPath = output
			containerPath = "/tmp/screenshot-element-" + strconv.FormatInt(time.Now().Unix(), 10) + filepath.Ext(output)
		}

		// Take screenshot in container
		err := cremoteServer.client.ScreenshotElement(tab, selector, containerPath, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Error taking element screenshot: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Automatically download the screenshot from container to host
		err = cremoteServer.client.DownloadFileFromContainer(containerPath, hostPath)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Screenshot taken in container (%s) but failed to download to host: %v", containerPath, err)),
				},
				IsError: true,
			}, nil
		}

		cremoteServer.screenshots = append(cremoteServer.screenshots, hostPath)

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Element screenshot saved to %s (automatically downloaded from container)", hostPath)),
			},
			IsError: false,
		}, nil
	})

	// web_screenshot_enhanced_cremotemcp - Enhanced screenshots with metadata
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_screenshot_enhanced_cremotemcp",
		Description: "Take an enhanced screenshot with metadata (timestamp, viewport size, URL). Automatically downloads the screenshot from container to host.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"output": map[string]any{
					"type":        "string",
					"description": "Path where to save the screenshot on the host machine. The screenshot will be automatically downloaded from the container.",
				},
				"full_page": map[string]any{
					"type":        "boolean",
					"description": "Capture full page (default: false)",
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab if not specified)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
				},
			},
			Required: []string{"output"},
		},
	}, 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")
		}

		output := getStringParam(params, "output", "")
		fullPage := getBoolParam(params, "full_page", false)
		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)

		if output == "" {
			return nil, fmt.Errorf("output parameter is required")
		}
		if tab == "" {
			return nil, fmt.Errorf("no tab available - navigate to a page first")
		}

		// Determine container path and host path
		var containerPath, hostPath string

		// If output path starts with /tmp/ or /var/, treat it as container path
		if strings.HasPrefix(output, "/tmp/") || strings.HasPrefix(output, "/var/") {
			containerPath = output
			// Generate a default host path
			hostPath = "/tmp/" + filepath.Base(output)
		} else {
			// Treat as host path, generate container path
			hostPath = output
			containerPath = "/tmp/screenshot-enhanced-" + strconv.FormatInt(time.Now().Unix(), 10) + filepath.Ext(output)
		}

		// Take enhanced screenshot in container
		metadata, err := cremoteServer.client.ScreenshotEnhanced(tab, containerPath, fullPage, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Error taking enhanced screenshot: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Automatically download the screenshot from container to host
		err = cremoteServer.client.DownloadFileFromContainer(containerPath, hostPath)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Screenshot taken in container (%s) but failed to download to host: %v", containerPath, err)),
				},
				IsError: true,
			}, nil
		}

		cremoteServer.screenshots = append(cremoteServer.screenshots, hostPath)

		metadataJSON, err := json.MarshalIndent(metadata, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal metadata: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Enhanced screenshot saved to %s (automatically downloaded from container) with metadata:\n%s", hostPath, string(metadataJSON))),
			},
			IsError: false,
		}, nil
	})

	// file_operations_bulk_cremotemcp - Bulk file operations
	mcpServer.AddTool(mcp.Tool{
		Name:        "file_operations_bulk_cremotemcp",
		Description: "Perform bulk file operations (upload/download multiple files)",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"operation": map[string]any{
					"type":        "string",
					"description": "Operation type",
					"enum":        []any{"upload", "download"},
				},
				"files": map[string]any{
					"type":        "array",
					"description": "Array of file operations",
					"items": map[string]any{
						"type": "object",
						"properties": map[string]any{
							"local_path": map[string]any{
								"type":        "string",
								"description": "Path on client machine",
							},
							"container_path": map[string]any{
								"type":        "string",
								"description": "Path in container",
							},
							"operation": map[string]any{
								"type":        "string",
								"description": "Override operation type for this file",
								"enum":        []any{"upload", "download"},
							},
						},
						"required": []any{"local_path", "container_path"},
					},
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
				},
			},
			Required: []string{"operation", "files"},
		},
	}, 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")
		}

		operation := getStringParam(params, "operation", "")
		filesParam := params["files"]
		timeout := getIntParam(params, "timeout", 30)

		if operation == "" {
			return nil, fmt.Errorf("operation parameter is required")
		}
		if filesParam == nil {
			return nil, fmt.Errorf("files parameter is required")
		}

		// Convert files parameter to FileOperation slice
		filesArray, ok := filesParam.([]any)
		if !ok {
			return nil, fmt.Errorf("files must be an array")
		}

		var operations []client.FileOperation
		for _, fileItem := range filesArray {
			fileMap, ok := fileItem.(map[string]any)
			if !ok {
				return nil, fmt.Errorf("each file must be an object")
			}

			localPath := getStringParam(fileMap, "local_path", "")
			containerPath := getStringParam(fileMap, "container_path", "")
			fileOperation := getStringParam(fileMap, "operation", operation)

			if localPath == "" || containerPath == "" {
				return nil, fmt.Errorf("local_path and container_path are required for each file")
			}

			operations = append(operations, client.FileOperation{
				LocalPath:     localPath,
				ContainerPath: containerPath,
				Operation:     fileOperation,
			})
		}

		result, err := cremoteServer.client.BulkFiles(operation, operations, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Error performing bulk file operations: %v", err)),
				},
				IsError: true,
			}, nil
		}

		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal result: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Bulk file operations completed:\n%s", string(resultJSON))),
			},
			IsError: false,
		}, nil
	})

	// file_management_cremotemcp - File management operations
	mcpServer.AddTool(mcp.Tool{
		Name:        "file_management_cremotemcp",
		Description: "Manage files (cleanup, list, get info)",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"operation": map[string]any{
					"type":        "string",
					"description": "Management operation",
					"enum":        []any{"cleanup", "list", "info"},
				},
				"pattern": map[string]any{
					"type":        "string",
					"description": "File pattern for cleanup/list, or file path for info",
				},
				"max_age": map[string]any{
					"type":        "string",
					"description": "Max age in hours for cleanup (default: 24)",
				},
			},
			Required: []string{"operation"},
		},
	}, 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")
		}

		operation := getStringParam(params, "operation", "")
		pattern := getStringParam(params, "pattern", "")
		maxAge := getStringParam(params, "max_age", "")

		if operation == "" {
			return nil, fmt.Errorf("operation parameter is required")
		}

		result, err := cremoteServer.client.ManageFiles(operation, pattern, maxAge)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Error managing files: %v", err)),
				},
				IsError: true,
			}, nil
		}

		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal result: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("File management result:\n%s", string(resultJSON))),
			},
			IsError: false,
		}, nil
	})

	// Accessibility tree tools
	mcpServer.AddTool(mcp.Tool{
		Name:        "get_accessibility_tree_cremotemcp",
		Description: "Get the full accessibility tree for a page with optional contrast data annotation",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"depth": map[string]any{
					"type":        "integer",
					"description": "Maximum depth to retrieve (optional, omit for full tree)",
					"minimum":     0,
				},
				"include_contrast": map[string]any{
					"type":        "boolean",
					"description": "Include contrast check availability annotation for text nodes (default: false)",
					"default":     false,
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		includeContrast := getBoolParam(params, "include_contrast", false)
		timeout := getIntParam(params, "timeout", 30)

		// Parse depth parameter
		var depth *int
		if depthParam := getIntParam(params, "depth", -1); depthParam >= 0 {
			depth = &depthParam
		}

		// Build command parameters
		cmdParams := map[string]string{
			"timeout": strconv.Itoa(timeout),
		}
		if tab != "" {
			cmdParams["tab"] = tab
		}
		if depth != nil {
			cmdParams["depth"] = strconv.Itoa(*depth)
		}
		if includeContrast {
			cmdParams["include_contrast"] = "true"
		}

		// Send command to daemon
		resp, err := cremoteServer.client.SendCommand("get-accessibility-tree", cmdParams)
		if err != nil {
			return nil, fmt.Errorf("failed to get accessibility tree: %w", err)
		}

		if !resp.Success {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to get accessibility tree: %s", resp.Error)),
				},
				IsError: true,
			}, nil
		}

		resultJSON, err := json.MarshalIndent(resp.Data, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal result: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(string(resultJSON)),
			},
			IsError: false,
		}, nil
	})

	mcpServer.AddTool(mcp.Tool{
		Name:        "get_partial_accessibility_tree_cremotemcp",
		Description: "Get accessibility tree for a specific element and its relatives",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"selector": map[string]any{
					"type":        "string",
					"description": "CSS selector for the target element",
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"fetch_relatives": map[string]any{
					"type":        "boolean",
					"description": "Whether to fetch ancestors, siblings, and children",
					"default":     true,
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			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 := getStringParam(params, "selector", "")
		if selector == "" {
			return nil, fmt.Errorf("selector parameter is required")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)
		fetchRelatives := getBoolParam(params, "fetch_relatives", true)

		result, err := cremoteServer.client.GetPartialAccessibilityTree(tab, selector, fetchRelatives, timeout)
		if err != nil {
			return nil, fmt.Errorf("failed to get partial accessibility tree: %w", err)
		}

		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal result: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(string(resultJSON)),
			},
			IsError: false,
		}, nil
	})

	mcpServer.AddTool(mcp.Tool{
		Name:        "query_accessibility_tree_cremotemcp",
		Description: "Query accessibility tree for nodes matching specific criteria",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"selector": map[string]any{
					"type":        "string",
					"description": "CSS selector to limit search scope (optional)",
				},
				"accessible_name": map[string]any{
					"type":        "string",
					"description": "Accessible name to match (optional)",
				},
				"role": map[string]any{
					"type":        "string",
					"description": "ARIA role to match (optional)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds",
					"default": 30,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)
		selector := getStringParam(params, "selector", "")
		accessibleName := getStringParam(params, "accessible_name", "")
		role := getStringParam(params, "role", "")

		// At least one search criteria must be provided
		if selector == "" && accessibleName == "" && role == "" {
			return nil, fmt.Errorf("at least one search criteria (selector, accessible_name, or role) must be provided")
		}

		result, err := cremoteServer.client.QueryAccessibilityTree(tab, selector, accessibleName, role, timeout)
		if err != nil {
			return nil, fmt.Errorf("failed to query accessibility tree: %w", err)
		}

		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal result: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(string(resultJSON)),
			},
			IsError: false,
		}, nil
	})

	// Cache management tools
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_disable_cache_cremotemcp",
		Description: "Disable browser cache for a tab",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default": 30,
				},
			},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", "")
		timeout := getIntParam(params, "timeout", 30)

		err := cremoteServer.client.DisableCache(tab, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Error disabling cache: %v", err)),
				},
				IsError: true,
			}, nil
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent("Cache disabled successfully"),
			},
			IsError: false,
		}, nil
	})

	mcpServer.AddTool(mcp.Tool{
		Name:        "web_enable_cache_cremotemcp",
		Description: "Enable browser cache for a tab",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default": 30,
				},
			},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", "")
		timeout := getIntParam(params, "timeout", 30)

		err := cremoteServer.client.EnableCache(tab, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Error enabling cache: %v", err)),
				},
				IsError: true,
			}, nil
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent("Cache enabled successfully"),
			},
			IsError: false,
		}, nil
	})

	mcpServer.AddTool(mcp.Tool{
		Name:        "web_clear_cache_cremotemcp",
		Description: "Clear browser cache for a tab",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default": 30,
				},
			},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", "")
		timeout := getIntParam(params, "timeout", 30)

		err := cremoteServer.client.ClearCache(tab, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Error clearing cache: %v", err)),
				},
				IsError: true,
			}, nil
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent("Cache cleared successfully"),
			},
			IsError: false,
		}, nil
	})

	// Site data management tools
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_clear_all_site_data_cremotemcp",
		Description: "Clear all site data including cookies, storage, cache, etc. for a tab",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default": 30,
				},
			},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", "")
		timeout := getIntParam(params, "timeout", 30)

		err := cremoteServer.client.ClearAllSiteData(tab, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Error clearing all site data: %v", err)),
				},
				IsError: true,
			}, nil
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent("All site data cleared successfully"),
			},
			IsError: false,
		}, nil
	})

	mcpServer.AddTool(mcp.Tool{
		Name:        "web_clear_cookies_cremotemcp",
		Description: "Clear cookies for a tab",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default": 30,
				},
			},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", "")
		timeout := getIntParam(params, "timeout", 30)

		err := cremoteServer.client.ClearCookies(tab, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Error clearing cookies: %v", err)),
				},
				IsError: true,
			}, nil
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent("Cookies cleared successfully"),
			},
			IsError: false,
		}, nil
	})

	mcpServer.AddTool(mcp.Tool{
		Name:        "web_clear_storage_cremotemcp",
		Description: "Clear web storage (localStorage, sessionStorage, IndexedDB, etc.) for a tab",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default": 30,
				},
			},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", "")
		timeout := getIntParam(params, "timeout", 30)

		err := cremoteServer.client.ClearStorage(tab, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Error clearing storage: %v", err)),
				},
				IsError: true,
			}, nil
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent("Storage cleared successfully"),
			},
			IsError: false,
		}, 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: 30)",
					"default": 30,
				},
			},
			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", 30)

		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: 30)",
					"default": 30,
				},
			},
			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", 30)

		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: 30)",
					"default": 30,
				},
			},
			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", 30)

		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: 30)",
					"default": 30,
				},
			},
			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: 30)",
					"default": 30,
				},
			},
			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: 30)",
					"default": 30,
				},
			},
			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: 30)",
					"default": 30,
				},
			},
			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: 30)",
					"default": 30,
				},
			},
			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: 30)",
					"default": 30,
				},
			},
			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: 30)",
					"default": 30,
				},
			},
			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: 30)",
					"default": 30,
				},
			},
			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: 30)",
					"default": 30,
				},
			},
			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
	})

	// Register web_inject_axe tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_inject_axe_cremotemcp",
		Description: "Inject axe-core accessibility testing library into the page. NOTE: Auto-injection happens automatically when using web_run_axe_cremotemcp or web_page_accessibility_report_cremotemcp, so manual injection is optional.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"version": map[string]any{
					"type":        "string",
					"description": "Axe-core version (optional, defaults to 4.8.0)",
					"default":     "4.8.0",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 10)",
					"default":     10,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		version := getStringParam(params, "version", "4.8.0")
		timeout := getIntParam(params, "timeout", 10)

		err := cremoteServer.client.InjectAxeCore(tab, version, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to inject axe-core: %v", err)),
				},
				IsError: true,
			}, nil
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(fmt.Sprintf("Successfully injected axe-core v%s", version)),
			},
			IsError: false,
		}, nil
	})

	// Register web_run_axe tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_run_axe_cremotemcp",
		Description: "Run axe-core accessibility tests and return violations, passes, incomplete checks, and inapplicable rules. Automatically injects axe-core if not already loaded.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"run_only": map[string]any{
					"type":        "array",
					"description": "Array of tags to run (e.g., ['wcag2a', 'wcag2aa', 'wcag21aa'])",
					"items": map[string]any{
						"type": "string",
					},
				},
				"rules": map[string]any{
					"type":        "object",
					"description": "Specific rules configuration (optional)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default":     30,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)

		// Build options
		options := make(map[string]interface{})
		if runOnly, ok := params["run_only"].([]interface{}); ok && len(runOnly) > 0 {
			tags := make([]string, 0, len(runOnly))
			for _, tag := range runOnly {
				if tagStr, ok := tag.(string); ok {
					tags = append(tags, tagStr)
				}
			}
			if len(tags) > 0 {
				options["runOnly"] = map[string]interface{}{
					"type":   "tag",
					"values": tags,
				}
			}
		}

		if rules, ok := params["rules"].(map[string]interface{}); ok && len(rules) > 0 {
			options["rules"] = rules
		}

		result, err := cremoteServer.client.RunAxeCore(tab, options, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to run axe-core: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		// Create summary
		summary := fmt.Sprintf("Axe-core Accessibility Test Results:\n\n"+
			"URL: %s\n"+
			"Timestamp: %s\n"+
			"Test Engine: %s v%s\n\n"+
			"Summary:\n"+
			"  Violations: %d\n"+
			"  Passes: %d\n"+
			"  Incomplete: %d (require manual review)\n"+
			"  Inapplicable: %d\n\n"+
			"Full Results:\n%s",
			result.URL,
			result.Timestamp,
			result.TestEngine.Name,
			result.TestEngine.Version,
			len(result.Violations),
			len(result.Passes),
			len(result.Incomplete),
			len(result.Inapplicable),
			string(resultJSON))

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(summary),
			},
			IsError: false,
		}, nil
	})

	// Register web_contrast_check tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_contrast_check_cremotemcp",
		Description: "Check color contrast ratios for text elements and verify WCAG AA/AAA compliance",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"selector": map[string]any{
					"type":        "string",
					"description": "CSS selector for specific elements (optional, defaults to all text elements)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 10)",
					"default":     10,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		selector := getStringParam(params, "selector", "")
		timeout := getIntParam(params, "timeout", 10)

		result, err := cremoteServer.client.CheckContrast(tab, selector, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to check contrast: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		// Create summary with violations
		summary := fmt.Sprintf("Color Contrast Check Results:\n\n"+
			"Summary:\n"+
			"  Total Elements Checked: %d\n"+
			"  WCAG AA Compliance:\n"+
			"    Passed: %d\n"+
			"    Failed: %d\n"+
			"  WCAG AAA Compliance:\n"+
			"    Passed: %d\n"+
			"    Failed: %d\n"+
			"  Unable to Check: %d\n\n",
			result.TotalElements,
			result.PassedAA,
			result.FailedAA,
			result.PassedAAA,
			result.FailedAAA,
			result.UnableToCheck)

		// Add violations if any
		if result.FailedAA > 0 {
			summary += "WCAG AA Violations:\n"
			for _, elem := range result.Elements {
				if !elem.PassesAA {
					summary += fmt.Sprintf("  - %s: %.2f:1 (required: %.1f:1)\n"+
						"    Text: %s\n"+
						"    Colors: %s on %s\n",
						elem.Selector,
						elem.ContrastRatio,
						elem.RequiredAA,
						elem.Text,
						elem.ForegroundColor,
						elem.BackgroundColor)
				}
			}
			summary += "\n"
		}

		summary += fmt.Sprintf("Full Results:\n%s", string(resultJSON))

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(summary),
			},
			IsError: false,
		}, nil
	})

	// Register web_gradient_contrast_check tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_gradient_contrast_check_cremotemcp",
		Description: "Check color contrast for text on gradient backgrounds using ImageMagick analysis. Samples 100 points across the background and reports worst-case contrast ratio.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"selector": map[string]any{
					"type":        "string",
					"description": "CSS selector for element with gradient background (required)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 10)",
					"default":     10,
				},
			},
			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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		selector := getStringParam(params, "selector", "")
		timeout := getIntParam(params, "timeout", 10)

		if selector == "" {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent("Error: selector parameter is required for gradient contrast check"),
				},
				IsError: true,
			}, nil
		}

		result, err := cremoteServer.client.CheckGradientContrast(tab, selector, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to check gradient contrast: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Check if there was an error in the result
		if result.Error != "" {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Gradient Contrast Check Error:\n%s", result.Error)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		// Create summary
		complianceStatus := "✅ PASS"
		if !result.PassesAA {
			complianceStatus = "❌ FAIL"
		}

		summary := fmt.Sprintf("Gradient Contrast Check Results:\n\n"+
			"Element: %s\n"+
			"Text Color: %s\n"+
			"Background Gradient Range:\n"+
			"  Darkest: %s\n"+
			"  Lightest: %s\n\n"+
			"Contrast Ratios:\n"+
			"  Worst Case: %.2f:1\n"+
			"  Best Case: %.2f:1\n\n"+
			"WCAG Compliance:\n"+
			"  Text Size: %s\n"+
			"  Required AA: %.1f:1\n"+
			"  Required AAA: %.1f:1\n"+
			"  AA Compliance: %s\n"+
			"  AAA Compliance: %s\n\n"+
			"Analysis:\n"+
			"  Sample Points: %d\n"+
			"  Status: %s\n\n",
			result.Selector,
			result.TextColor,
			result.DarkestBgColor,
			result.LightestBgColor,
			result.WorstContrast,
			result.BestContrast,
			map[bool]string{true: "Large (18pt+ or 14pt+ bold)", false: "Normal"}[result.IsLargeText],
			result.RequiredAA,
			result.RequiredAAA,
			map[bool]string{true: "✅ PASS", false: "❌ FAIL"}[result.PassesAA],
			map[bool]string{true: "✅ PASS", false: "❌ FAIL"}[result.PassesAAA],
			result.SamplePoints,
			complianceStatus)

		if !result.PassesAA {
			summary += fmt.Sprintf("\n⚠️  WARNING: Worst-case contrast ratio (%.2f:1) fails WCAG AA requirements (%.1f:1)\n"+
				"This gradient background creates accessibility issues for users with low vision.\n"+
				"Recommendation: Adjust gradient colors or use solid background.\n",
				result.WorstContrast, result.RequiredAA)
		}

		summary += fmt.Sprintf("\nFull Results:\n%s", string(resultJSON))

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(summary),
			},
			IsError: false,
		}, nil
	})

	// Register web_media_validation tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_media_validation_cremotemcp",
		Description: "Validate time-based media (video/audio) for WCAG compliance: checks for captions, audio descriptions, transcripts, controls, and autoplay issues",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 10)",
					"default":     10,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 10)

		result, err := cremoteServer.client.ValidateMedia(tab, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to validate media: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		// Create summary
		complianceStatus := "✅ PASS"
		if result.CriticalViolations > 0 {
			complianceStatus = "❌ CRITICAL VIOLATIONS"
		} else if result.TotalViolations > 0 {
			complianceStatus = "⚠️  VIOLATIONS"
		} else if result.Warnings > 0 {
			complianceStatus = "⚠️  WARNINGS"
		}

		summary := fmt.Sprintf("Time-Based Media Validation Results:\n\n"+
			"Summary:\n"+
			"  Videos Found: %d\n"+
			"  Audio Elements Found: %d\n"+
			"  Embedded Players: %d (YouTube/Vimeo)\n"+
			"  Transcript Links: %d\n\n"+
			"Compliance Status: %s\n"+
			"  Critical Violations: %d\n"+
			"  Total Violations: %d\n"+
			"  Warnings: %d\n\n",
			len(result.Videos),
			len(result.Audios),
			len(result.EmbeddedPlayers),
			len(result.TranscriptLinks),
			complianceStatus,
			result.CriticalViolations,
			result.TotalViolations,
			result.Warnings)

		// Add video details if any violations
		if result.CriticalViolations > 0 || result.TotalViolations > 0 {
			summary += "Video Issues:\n"
			for i, video := range result.Videos {
				if len(video.Violations) > 0 || len(video.Warnings) > 0 {
					summary += fmt.Sprintf("\n  Video %d: %s\n", i+1, video.Src)
					summary += fmt.Sprintf("    Has Captions: %v\n", video.HasCaptions)
					summary += fmt.Sprintf("    Has Descriptions: %v\n", video.HasDescriptions)
					summary += fmt.Sprintf("    Has Controls: %v\n", video.HasControls)
					summary += fmt.Sprintf("    Autoplay: %v\n", video.Autoplay)

					if len(video.Violations) > 0 {
						summary += "    Violations:\n"
						for _, violation := range video.Violations {
							summary += fmt.Sprintf("      - %s\n", violation)
						}
					}

					if len(video.Warnings) > 0 {
						summary += "    Warnings:\n"
						for _, warning := range video.Warnings {
							summary += fmt.Sprintf("      - %s\n", warning)
						}
					}
				}
			}
			summary += "\n"
		}

		// Add recommendations if critical violations
		if result.CriticalViolations > 0 {
			summary += "⚠️  CRITICAL RECOMMENDATIONS:\n"
			summary += "  1. Add <track kind=\"captions\"> elements to all videos\n"
			summary += "  2. Ensure caption files (.vtt, .srt) are accessible\n"
			summary += "  3. Test captions display correctly in video player\n"
			summary += "  4. Consider adding audio descriptions for visual content\n\n"
		}

		// Add embedded player notes
		if len(result.EmbeddedPlayers) > 0 {
			summary += "Embedded Players:\n"
			for i, player := range result.EmbeddedPlayers {
				summary += fmt.Sprintf("  %d. %s: %s\n", i+1, player.Type, player.Src)
			}
			summary += "\nNote: YouTube and Vimeo players should have captions enabled in their settings.\n"
			summary += "Check video settings on the platform to ensure captions are available.\n\n"
		}

		// Add transcript links
		if len(result.TranscriptLinks) > 0 {
			summary += "Transcript Links Found:\n"
			for i, link := range result.TranscriptLinks {
				summary += fmt.Sprintf("  %d. %s\n", i+1, link)
			}
			summary += "\n"
		}

		summary += fmt.Sprintf("Full Results:\n%s", string(resultJSON))

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(summary),
			},
			IsError: false,
		}, nil
	})

	// Register web_hover_focus_test tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_hover_focus_test_cremotemcp",
		Description: "Test WCAG 1.4.13 compliance for content on hover or focus: checks dismissibility, hoverability, and persistence",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 10)",
					"default":     10,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 10)

		result, err := cremoteServer.client.TestHoverFocusContent(tab, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to test hover/focus content: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		// Create summary
		complianceStatus := "✅ PASS"
		if result.ElementsWithIssues > 0 {
			complianceStatus = "⚠️  ISSUES FOUND"
		}

		summary := fmt.Sprintf("Hover/Focus Content Test Results (WCAG 1.4.13):\n\n"+
			"Summary:\n"+
			"  Total Elements Tested: %d\n"+
			"  Elements with Issues: %d\n"+
			"  Elements Passed: %d\n"+
			"  Compliance Status: %s\n\n",
			result.TotalElements,
			result.ElementsWithIssues,
			result.PassedElements,
			complianceStatus)

		// Add issues if any
		if len(result.Issues) > 0 {
			summary += "Issues Found:\n"
			for i, issue := range result.Issues {
				summary += fmt.Sprintf("\n  %d. %s\n", i+1, issue.Selector)
				summary += fmt.Sprintf("     Type: %s\n", issue.Type)
				summary += fmt.Sprintf("     Severity: %s\n", issue.Severity)
				summary += fmt.Sprintf("     Description: %s\n", issue.Description)
				summary += fmt.Sprintf("     WCAG: %s\n", issue.WCAG)
			}
			summary += "\n"
		}

		// Add element details
		if result.TotalElements > 0 {
			summary += "Tested Elements:\n"
			for i, elem := range result.TestedElements {
				if len(elem.Violations) > 0 {
					summary += fmt.Sprintf("\n  %d. %s (%s)\n", i+1, elem.Selector, elem.Type)
					summary += fmt.Sprintf("     Dismissible: %v\n", elem.Dismissible)
					summary += fmt.Sprintf("     Hoverable: %v\n", elem.Hoverable)
					summary += fmt.Sprintf("     Persistent: %v\n", elem.Persistent)
					summary += fmt.Sprintf("     Passes WCAG: %v\n", elem.PassesWCAG)

					if len(elem.Violations) > 0 {
						summary += "     Violations:\n"
						for _, violation := range elem.Violations {
							summary += fmt.Sprintf("       - %s\n", violation)
						}
					}
				}
			}
			summary += "\n"
		}

		// Add recommendations if issues found
		if result.ElementsWithIssues > 0 {
			summary += "⚠️  RECOMMENDATIONS:\n"
			summary += "  1. Replace native title attributes with custom tooltips that can be dismissed with Escape\n"
			summary += "  2. Ensure hover/focus content can be dismissed without moving pointer/focus\n"
			summary += "  3. Allow pointer to move over new content without it disappearing\n"
			summary += "  4. Keep content visible until dismissed or no longer relevant\n"
			summary += "  5. Test with keyboard-only navigation (Tab, Escape keys)\n\n"
		}

		summary += fmt.Sprintf("Full Results:\n%s", string(resultJSON))

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(summary),
			},
			IsError: false,
		}, nil
	})

	// Register web_text_in_images tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_text_in_images_cremotemcp",
		Description: "Detect text in images using Tesseract OCR and flag accessibility violations (WCAG 1.4.5, 1.4.9)",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30 for OCR processing)",
					"default":     30,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 30)

		result, err := cremoteServer.client.DetectTextInImages(tab, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to detect text in images: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		// Create summary
		complianceStatus := "✅ PASS"
		if result.Violations > 0 {
			complianceStatus = "❌ CRITICAL VIOLATIONS"
		} else if result.Warnings > 0 {
			complianceStatus = "⚠️  WARNINGS"
		}

		summary := fmt.Sprintf("Text-in-Images Detection Results:\n\n"+
			"Summary:\n"+
			"  Total Images Analyzed: %d\n"+
			"  Images with Text: %d\n"+
			"  Images without Text: %d\n"+
			"  Compliance Status: %s\n"+
			"  Critical Violations: %d\n"+
			"  Warnings: %d\n\n",
			result.TotalImages,
			result.ImagesWithText,
			result.ImagesWithoutText,
			complianceStatus,
			result.Violations,
			result.Warnings)

		// Add violations if any
		if result.Violations > 0 || result.Warnings > 0 {
			summary += "Images with Issues:\n"
			for i, img := range result.Images {
				if img.IsViolation {
					summary += fmt.Sprintf("\n  %d. %s\n", i+1, img.Src)
					summary += fmt.Sprintf("     Has Alt: %v\n", img.HasAlt)
					if img.Alt != "" {
						summary += fmt.Sprintf("     Alt Text: \"%s\"\n", img.Alt)
					}
					summary += fmt.Sprintf("     Detected Text: \"%s\"\n", img.DetectedText)
					summary += fmt.Sprintf("     Text Length: %d characters\n", img.TextLength)
					summary += fmt.Sprintf("     Confidence: %.1f%%\n", img.Confidence*100)
					summary += fmt.Sprintf("     Violation Type: %s\n", img.ViolationType)
					summary += fmt.Sprintf("     Recommendation: %s\n", img.Recommendation)
				}
			}
			summary += "\n"
		}

		// Add recommendations if violations
		if result.Violations > 0 {
			summary += "⚠️  CRITICAL RECOMMENDATIONS:\n"
			summary += "  1. Add alt text to all images containing text\n"
			summary += "  2. Ensure alt text includes all text visible in the image\n"
			summary += "  3. Consider using real text instead of text-in-images where possible\n"
			summary += "  4. If text-in-images is necessary, provide equivalent text alternatives\n\n"
		}

		// Add WCAG references
		summary += "WCAG Criteria:\n"
		summary += "  - WCAG 1.4.5 (Images of Text - Level AA): Use real text instead of images of text\n"
		summary += "  - WCAG 1.4.9 (Images of Text - No Exception - Level AAA): No images of text except logos\n"
		summary += "  - WCAG 1.1.1 (Non-text Content - Level A): All images must have text alternatives\n\n"

		summary += fmt.Sprintf("Full Results:\n%s", string(resultJSON))

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(summary),
			},
			IsError: false,
		}, nil
	})

	// Register web_cross_page_consistency tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_cross_page_consistency_cremotemcp",
		Description: "Check consistency of navigation, headers, footers, and landmarks across multiple pages (WCAG 3.2.3, 3.2.4)",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"urls": map[string]any{
					"type":        "array",
					"description": "Array of URLs to check for consistency",
					"items": map[string]any{
						"type": "string",
					},
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds per page (default: 10)",
					"default":     10,
				},
			},
			Required: []string{"urls"},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 10)

		// Parse URLs array
		urlsParam, ok := params["urls"].([]any)
		if !ok || len(urlsParam) == 0 {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent("Error: urls parameter is required and must be a non-empty array"),
				},
				IsError: true,
			}, nil
		}

		urls := make([]string, 0, len(urlsParam))
		for _, u := range urlsParam {
			if urlStr, ok := u.(string); ok {
				urls = append(urls, urlStr)
			}
		}

		if len(urls) == 0 {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent("Error: no valid URLs provided"),
				},
				IsError: true,
			}, nil
		}

		result, err := cremoteServer.client.CheckCrossPageConsistency(tab, urls, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to check cross-page consistency: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		// Create summary
		complianceStatus := "✅ PASS"
		if result.ConsistencyIssues > 0 {
			complianceStatus = "❌ INCONSISTENCIES FOUND"
		}

		summary := fmt.Sprintf("Cross-Page Consistency Check Results:\n\n"+
			"Summary:\n"+
			"  Pages Analyzed: %d\n"+
			"  Compliance Status: %s\n"+
			"  Total Issues: %d\n"+
			"  Navigation Issues: %d\n"+
			"  Structure Issues: %d\n"+
			"  Common Navigation Links: %d\n\n",
			result.PagesAnalyzed,
			complianceStatus,
			result.ConsistencyIssues,
			result.NavigationIssues,
			result.StructureIssues,
			len(result.CommonNavigation))

		// Add common navigation
		if len(result.CommonNavigation) > 0 {
			summary += "Common Navigation Links (present on all pages):\n"
			for i, link := range result.CommonNavigation {
				summary += fmt.Sprintf("  %d. %s\n", i+1, link)
			}
			summary += "\n"
		}

		// Add inconsistent pages
		if len(result.InconsistentPages) > 0 {
			summary += "Pages with Inconsistencies:\n"
			for i, url := range result.InconsistentPages {
				summary += fmt.Sprintf("  %d. %s\n", i+1, url)
			}
			summary += "\n"
		}

		// Add page details
		if result.ConsistencyIssues > 0 {
			summary += "Page Details:\n"
			for i, page := range result.Pages {
				if len(page.Issues) > 0 {
					summary += fmt.Sprintf("\n  %d. %s\n", i+1, page.URL)
					summary += fmt.Sprintf("     Title: %s\n", page.Title)
					summary += fmt.Sprintf("     Has Header: %v\n", page.HasHeader)
					summary += fmt.Sprintf("     Has Footer: %v\n", page.HasFooter)
					summary += fmt.Sprintf("     Has Navigation: %v\n", page.HasNavigation)
					summary += fmt.Sprintf("     Main Landmarks: %d\n", page.MainLandmarks)
					summary += "     Issues:\n"
					for _, issue := range page.Issues {
						summary += fmt.Sprintf("       - %s\n", issue)
					}
				}
			}
			summary += "\n"
		}

		// Add recommendations
		if result.ConsistencyIssues > 0 {
			summary += "⚠️  RECOMMENDATIONS:\n"
			if result.NavigationIssues > 0 {
				summary += "  1. Ensure consistent navigation across all pages\n"
				summary += "  2. Use the same navigation structure and labels on every page\n"
			}
			if result.StructureIssues > 0 {
				summary += "  3. Add proper landmark elements (header, footer, main, nav)\n"
				summary += "  4. Ensure exactly one main landmark per page\n"
			}
			summary += "\n"
		}

		// Add WCAG references
		summary += "WCAG Criteria:\n"
		summary += "  - WCAG 3.2.3 (Consistent Navigation - Level AA): Navigation repeated on multiple pages must be in the same relative order\n"
		summary += "  - WCAG 3.2.4 (Consistent Identification - Level AA): Components with the same functionality must be identified consistently\n"
		summary += "  - WCAG 1.3.1 (Info and Relationships - Level A): Proper use of landmarks for page structure\n\n"

		summary += fmt.Sprintf("Full Results:\n%s", string(resultJSON))

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(summary),
			},
			IsError: false,
		}, nil
	})

	// Register web_animation_flash tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_animation_flash_cremotemcp",
		Description: "Detect animations and flashing content that may trigger seizures or cause accessibility issues (WCAG 2.3.1, 2.2.2)",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 10)",
					"default":     10,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 10)

		result, err := cremoteServer.client.DetectAnimationFlash(tab, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to detect animation/flash: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		// Create summary
		complianceStatus := "✅ PASS"
		if result.Violations > 0 {
			complianceStatus = "❌ VIOLATIONS FOUND"
		} else if result.Warnings > 0 {
			complianceStatus = "⚠️  WARNINGS"
		}

		summary := fmt.Sprintf("Animation/Flash Detection Results:\n\n"+
			"Summary:\n"+
			"  Total Animations: %d\n"+
			"  Flashing Content: %d\n"+
			"  Rapid Animations: %d\n"+
			"  Autoplay Animations: %d\n"+
			"  Compliance Status: %s\n"+
			"  Violations: %d\n"+
			"  Warnings: %d\n\n",
			result.TotalAnimations,
			result.FlashingContent,
			result.RapidAnimations,
			result.AutoplayAnimations,
			complianceStatus,
			result.Violations,
			result.Warnings)

		// Add violations/warnings
		if result.Violations > 0 || result.Warnings > 0 {
			summary += "Elements with Issues:\n"
			for i, elem := range result.Elements {
				if elem.IsViolation || elem.ViolationType != "" {
					if i >= 10 { // Limit to first 10 for readability
						summary += fmt.Sprintf("\n  ... and %d more elements\n", len(result.Elements)-10)
						break
					}
					summary += fmt.Sprintf("\n  %d. <%s> %s\n", i+1, elem.TagName, elem.Selector)
					summary += fmt.Sprintf("     Animation Type: %s\n", elem.AnimationType)
					summary += fmt.Sprintf("     Duration: %.2fs\n", elem.Duration)
					if elem.FlashRate > 0 {
						summary += fmt.Sprintf("     Flash Rate: %.1f flashes/second\n", elem.FlashRate)
					}
					summary += fmt.Sprintf("     Autoplay: %v\n", elem.IsAutoplay)
					summary += fmt.Sprintf("     Has Controls: %v\n", elem.HasControls)
					summary += fmt.Sprintf("     Can Pause: %v\n", elem.CanPause)
					if elem.IsViolation {
						summary += fmt.Sprintf("     ❌ Violation: %s\n", elem.ViolationType)
					} else {
						summary += fmt.Sprintf("     ⚠️  Warning: %s\n", elem.ViolationType)
					}
					summary += fmt.Sprintf("     Recommendation: %s\n", elem.Recommendation)
				}
			}
			summary += "\n"
		}

		// Add recommendations
		if result.Violations > 0 {
			summary += "⚠️  CRITICAL RECOMMENDATIONS:\n"
			if result.FlashingContent > 0 {
				summary += "  1. Reduce flash rate to 3 or fewer flashes per second\n"
				summary += "  2. Provide mechanism to disable flashing content\n"
			}
			if result.AutoplayAnimations > 0 {
				summary += "  3. Provide pause/stop controls for autoplay animations longer than 5 seconds\n"
				summary += "  4. Allow users to disable animations\n"
			}
			summary += "\n"
		}

		// Add WCAG references
		summary += "WCAG Criteria:\n"
		summary += "  - WCAG 2.3.1 (Three Flashes or Below Threshold - Level A): Content must not flash more than 3 times per second\n"
		summary += "  - WCAG 2.2.2 (Pause, Stop, Hide - Level A): Moving, blinking, or auto-updating content must have pause/stop controls\n"
		summary += "  - WCAG 2.3.2 (Three Flashes - Level AAA): No content flashes more than 3 times per second\n\n"

		summary += fmt.Sprintf("Full Results:\n%s", string(resultJSON))

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(summary),
			},
			IsError: false,
		}, nil
	})

	// Register web_enhanced_accessibility tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_enhanced_accessibility_cremotemcp",
		Description: "Perform enhanced accessibility tree analysis with ARIA validation, role verification, and relationship checking (WCAG 1.3.1, 4.1.2)",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 10)",
					"default":     10,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 10)

		result, err := cremoteServer.client.AnalyzeEnhancedAccessibility(tab, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to analyze enhanced accessibility: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		// Create summary
		complianceStatus := "✅ PASS"
		if result.ARIAViolations > 0 || result.LandmarkIssues > 0 {
			complianceStatus = "❌ VIOLATIONS FOUND"
		}

		summary := fmt.Sprintf("Enhanced Accessibility Analysis Results:\n\n"+
			"Summary:\n"+
			"  Total Elements Analyzed: %d\n"+
			"  Elements with Issues: %d\n"+
			"  Compliance Status: %s\n"+
			"  ARIA Violations: %d\n"+
			"  Role Violations: %d\n"+
			"  Relationship Issues: %d\n"+
			"  Landmark Issues: %d\n\n",
			result.TotalElements,
			result.ElementsWithIssues,
			complianceStatus,
			result.ARIAViolations,
			result.RoleViolations,
			result.RelationshipIssues,
			result.LandmarkIssues)

		// Add elements with issues
		if result.ElementsWithIssues > 0 {
			summary += "Elements with Issues:\n"
			for i, elem := range result.Elements {
				if i >= 15 { // Limit to first 15 for readability
					summary += fmt.Sprintf("\n  ... and %d more elements\n", len(result.Elements)-15)
					break
				}
				summary += fmt.Sprintf("\n  %d. <%s> %s\n", i+1, elem.TagName, elem.Selector)
				summary += fmt.Sprintf("     Role: %s\n", elem.Role)
				if elem.AriaLabel != "" {
					summary += fmt.Sprintf("     ARIA Label: %s\n", elem.AriaLabel)
				}
				if elem.AriaLabelledBy != "" {
					summary += fmt.Sprintf("     ARIA Labelled By: %s\n", elem.AriaLabelledBy)
				}
				if elem.AriaDescribedBy != "" {
					summary += fmt.Sprintf("     ARIA Described By: %s\n", elem.AriaDescribedBy)
				}
				summary += fmt.Sprintf("     Interactive: %v\n", elem.IsInteractive)
				summary += fmt.Sprintf("     Has Accessible Name: %v\n", elem.HasAccessibleName)
				if elem.TabIndex != 0 {
					summary += fmt.Sprintf("     Tab Index: %d\n", elem.TabIndex)
				}
				if len(elem.Issues) > 0 {
					summary += "     Issues:\n"
					for _, issue := range elem.Issues {
						summary += fmt.Sprintf("       - %s\n", issue)
					}
				}
				if len(elem.Recommendations) > 0 {
					summary += "     Recommendations:\n"
					for _, rec := range elem.Recommendations {
						summary += fmt.Sprintf("       - %s\n", rec)
					}
				}
			}
			summary += "\n"
		}

		// Add recommendations
		if result.ARIAViolations > 0 || result.LandmarkIssues > 0 {
			summary += "⚠️  CRITICAL RECOMMENDATIONS:\n"
			if result.ARIAViolations > 0 {
				summary += "  1. Add accessible names to all interactive elements\n"
				summary += "  2. Remove aria-hidden from interactive elements\n"
				summary += "  3. Use valid tabindex values (0 or -1)\n"
			}
			if result.LandmarkIssues > 0 {
				summary += "  4. Add distinguishing labels to multiple landmarks of the same type\n"
				summary += "  5. Use aria-label or aria-labelledby for landmark identification\n"
			}
			summary += "\n"
		}

		// Add WCAG references
		summary += "WCAG Criteria:\n"
		summary += "  - WCAG 1.3.1 (Info and Relationships - Level A): Information, structure, and relationships must be programmatically determined\n"
		summary += "  - WCAG 4.1.2 (Name, Role, Value - Level A): All UI components must have accessible names and roles\n"
		summary += "  - WCAG 2.4.6 (Headings and Labels - Level AA): Headings and labels must describe topic or purpose\n\n"

		summary += fmt.Sprintf("Full Results:\n%s", string(resultJSON))

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(summary),
			},
			IsError: false,
		}, nil
	})

	// Register web_keyboard_test tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_keyboard_test_cremotemcp",
		Description: "Test keyboard navigation and accessibility including tab order, focus indicators, and keyboard traps. Uses real Tab key simulation for accurate :focus-within and :focus-visible testing. Automatically detects accessibility plugins (Accessifix, UserWay, AccessiBe, AudioEye, EqualWeb) and provides confidence scoring for focus indicator findings.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 15)",
					"default":     15,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 15)

		result, err := cremoteServer.client.TestKeyboardNavigation(tab, true, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to test keyboard navigation: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		// Create summary with issues
		summary := fmt.Sprintf("Keyboard Navigation Test Results:\n\n"+
			"Summary:\n"+
			"  Total Interactive Elements: %d\n"+
			"  Keyboard Focusable: %d\n"+
			"  Not Focusable: %d\n"+
			"  Missing Focus Indicator: %d\n"+
			"  Keyboard Traps Detected: %d\n"+
			"  Total Issues: %d\n\n",
			result.TotalInteractive,
			result.Focusable,
			result.NotFocusable,
			result.NoFocusIndicator,
			result.KeyboardTraps,
			len(result.Issues))

		// Add high severity issues
		highSeverityIssues := 0
		for _, issue := range result.Issues {
			if issue.Severity == "high" {
				highSeverityIssues++
			}
		}

		if highSeverityIssues > 0 {
			summary += fmt.Sprintf("High Severity Issues (%d):\n", highSeverityIssues)
			count := 0
			for _, issue := range result.Issues {
				if issue.Severity == "high" && count < 10 {
					summary += fmt.Sprintf("  - %s: %s\n    Element: %s\n",
						issue.Type,
						issue.Description,
						issue.Element)
					count++
				}
			}
			if highSeverityIssues > 10 {
				summary += fmt.Sprintf("  ... and %d more issues\n", highSeverityIssues-10)
			}
			summary += "\n"
		}

		// Add tab order summary
		if len(result.TabOrder) > 0 {
			summary += fmt.Sprintf("Tab Order (first 5 elements):\n")
			for i, elem := range result.TabOrder {
				if i >= 5 {
					summary += fmt.Sprintf("  ... and %d more elements\n", len(result.TabOrder)-5)
					break
				}
				focusIndicator := "✓"
				if !elem.HasFocusStyle {
					focusIndicator = "✗"
				}
				summary += fmt.Sprintf("  %d. %s [%s] %s - Focus: %s\n",
					elem.Index+1,
					elem.Selector,
					elem.TagName,
					elem.Text,
					focusIndicator)
			}
			summary += "\n"
		}

		summary += fmt.Sprintf("Full Results:\n%s", string(resultJSON))

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(summary),
			},
			IsError: false,
		}, nil
	})

	// Register web_zoom_test tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_zoom_test_cremotemcp",
		Description: "Test page at different zoom levels (100%, 200%, 400%) and verify WCAG 1.4.4 and 1.4.10 compliance",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"zoom_levels": map[string]any{
					"type":        "array",
					"description": "Array of zoom levels to test (optional, defaults to [1.0, 2.0, 4.0])",
					"items": map[string]any{
						"type": "number",
					},
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds per zoom level (default: 10)",
					"default":     10,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 10)

		// Parse zoom levels if provided
		var zoomLevels []float64
		if zoomLevelsParam, ok := params["zoom_levels"].([]interface{}); ok {
			for _, level := range zoomLevelsParam {
				if levelFloat, ok := level.(float64); ok {
					zoomLevels = append(zoomLevels, levelFloat)
				}
			}
		}

		result, err := cremoteServer.client.TestZoom(tab, zoomLevels, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to test zoom: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		// Create summary
		summary := fmt.Sprintf("Zoom Level Test Results:\n\n"+
			"Tested %d zoom levels\n"+
			"Total Issues: %d\n\n",
			len(result.ZoomLevels),
			len(result.Issues))

		// Add zoom level details
		for _, zoomTest := range result.ZoomLevels {
			status := "✓ PASS"
			if zoomTest.HasHorizontalScroll || zoomTest.OverflowingElements > 0 || !zoomTest.TextReadable {
				status = "✗ FAIL"
			}

			summary += fmt.Sprintf("Zoom %.0f%% %s:\n"+
				"  Viewport: %dx%d\n"+
				"  Content: %dx%d\n"+
				"  Horizontal Scroll: %v\n"+
				"  Overflowing Elements: %d\n"+
				"  Text Readable: %v\n\n",
				zoomTest.ZoomLevel*100,
				status,
				zoomTest.ViewportWidth,
				zoomTest.ViewportHeight,
				zoomTest.ContentWidth,
				zoomTest.ContentHeight,
				zoomTest.HasHorizontalScroll,
				zoomTest.OverflowingElements,
				zoomTest.TextReadable)
		}

		// Add issues
		if len(result.Issues) > 0 {
			summary += "Issues Found:\n"
			for _, issue := range result.Issues {
				summary += fmt.Sprintf("  [%.0f%%] %s (%s): %s\n",
					issue.ZoomLevel*100,
					issue.Type,
					issue.Severity,
					issue.Description)
			}
			summary += "\n"
		}

		summary += fmt.Sprintf("Full Results:\n%s", string(resultJSON))

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(summary),
			},
			IsError: false,
		}, nil
	})

	// Register web_reflow_test tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_reflow_test_cremotemcp",
		Description: "Test responsive design at WCAG breakpoints (320px, 1280px) and verify WCAG 1.4.10 reflow compliance",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"widths": map[string]any{
					"type":        "array",
					"description": "Array of viewport widths to test in pixels (optional, defaults to [320, 1280])",
					"items": map[string]any{
						"type": "integer",
					},
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds per width (default: 10)",
					"default":     10,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		timeout := getIntParam(params, "timeout", 10)

		// Parse widths if provided
		var widths []int
		if widthsParam, ok := params["widths"].([]interface{}); ok {
			for _, width := range widthsParam {
				if widthFloat, ok := width.(float64); ok {
					widths = append(widths, int(widthFloat))
				}
			}
		}

		result, err := cremoteServer.client.TestReflow(tab, widths, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to test reflow: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		// Create summary
		summary := fmt.Sprintf("Reflow/Responsive Design Test Results:\n\n"+
			"Tested %d breakpoints\n"+
			"Total Issues: %d\n\n",
			len(result.Breakpoints),
			len(result.Issues))

		// Add breakpoint details
		for _, breakpoint := range result.Breakpoints {
			status := "✓ PASS"
			if breakpoint.HasHorizontalScroll || !breakpoint.ResponsiveLayout || breakpoint.OverflowingElements > 0 {
				status = "✗ FAIL"
			}

			summary += fmt.Sprintf("%dpx Width %s:\n"+
				"  Viewport: %dx%d\n"+
				"  Content: %dx%d\n"+
				"  Horizontal Scroll: %v\n"+
				"  Responsive Layout: %v\n"+
				"  Overflowing Elements: %d\n\n",
				breakpoint.Width,
				status,
				breakpoint.Width,
				breakpoint.Height,
				breakpoint.ContentWidth,
				breakpoint.ContentHeight,
				breakpoint.HasHorizontalScroll,
				breakpoint.ResponsiveLayout,
				breakpoint.OverflowingElements)
		}

		// Add issues
		if len(result.Issues) > 0 {
			summary += "Issues Found:\n"
			for _, issue := range result.Issues {
				summary += fmt.Sprintf("  [%dpx] %s (%s): %s\n",
					issue.Width,
					issue.Type,
					issue.Severity,
					issue.Description)
			}
			summary += "\n"
		}

		summary += fmt.Sprintf("Full Results:\n%s", string(resultJSON))

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(summary),
			},
			IsError: false,
		}, nil
	})

	// Register web_page_accessibility_report tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_page_accessibility_report_cremotemcp",
		Description: "Perform comprehensive accessibility assessment of a page and return a summarized report with actionable findings. This tool combines multiple accessibility tests (axe-core, contrast, keyboard, forms) and returns only the critical findings in a token-efficient format. Keyboard testing uses real Tab key simulation for accurate :focus-visible detection and includes accessibility plugin detection with confidence scoring. Automatically injects axe-core if not already loaded.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"tests": map[string]any{
					"type":        "array",
					"description": "Array of test types to run (e.g., ['wcag', 'contrast', 'keyboard', 'forms']). Defaults to 'all'",
					"items": map[string]any{
						"type": "string",
					},
				},
				"standard": map[string]any{
					"type":        "string",
					"description": "WCAG standard to test against (default: WCAG21AA)",
					"default":     "WCAG21AA",
				},
				"include_screenshots": map[string]any{
					"type":        "boolean",
					"description": "Whether to capture screenshots of violations (default: false)",
					"default":     false,
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default":     30,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		standard := getStringParam(params, "standard", "WCAG21AA")
		includeScreenshots := getBoolParam(params, "include_screenshots", false)
		timeout := getIntParam(params, "timeout", 30)

		// Parse tests array
		var tests []string
		if testsParam, ok := params["tests"].([]interface{}); ok {
			for _, t := range testsParam {
				if testStr, ok := t.(string); ok {
					tests = append(tests, testStr)
				}
			}
		}

		result, err := cremoteServer.client.GetPageAccessibilityReport(tab, tests, standard, includeScreenshots, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to get page accessibility report: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(string(resultJSON)),
			},
			IsError: false,
		}, nil
	})

	// Register web_accessibility_full_audit tool - Master accessibility tool with navigation
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_accessibility_full_audit_cremotemcp",
		Description: "Master accessibility tool: Navigate to URL, clear cache, and run comprehensive accessibility assessment in a single call. Combines navigation, cache clearing, and all accessibility tests (axe-core, contrast, keyboard, forms) with token-efficient reporting. Automatically injects axe-core if not already loaded.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"url": map[string]any{
					"type":        "string",
					"description": "URL to navigate to and test (required)",
				},
				"clear_cache": map[string]any{
					"type":        "boolean",
					"description": "Clear browser cache before navigation (default: true)",
					"default":     true,
				},
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, creates new tab if not specified)",
				},
				"tests": map[string]any{
					"type":        "array",
					"description": "Array of test types to run (e.g., ['wcag', 'contrast', 'keyboard', 'forms']). Defaults to 'all'",
					"items": map[string]any{
						"type": "string",
					},
				},
				"standard": map[string]any{
					"type":        "string",
					"description": "WCAG standard to test against (default: WCAG21AA)",
					"default":     "WCAG21AA",
				},
				"include_screenshots": map[string]any{
					"type":        "boolean",
					"description": "Whether to capture screenshots of violations (default: false)",
					"default":     false,
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds for each operation (default: 30)",
					"default":     30,
				},
			},
			Required: []string{"url"},
		},
	}, 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")
		}

		url := getStringParam(params, "url", "")
		if url == "" {
			return nil, fmt.Errorf("url parameter is required")
		}

		clearCache := getBoolParam(params, "clear_cache", true)
		standard := getStringParam(params, "standard", "WCAG21AA")
		includeScreenshots := getBoolParam(params, "include_screenshots", false)
		timeout := getIntParam(params, "timeout", 30)

		// Parse tests array
		var tests []string
		if testsParam, ok := params["tests"].([]interface{}); ok {
			for _, t := range testsParam {
				if testStr, ok := t.(string); ok {
					tests = append(tests, testStr)
				}
			}
		}

		// Handle navigation with cache clearing
		tab, err := handleOptionalNavigation(cremoteServer, params, timeout)
		if err != nil {
			return nil, fmt.Errorf("failed to navigate: %w", err)
		}

		if tab == "" {
			return nil, fmt.Errorf("failed to create or identify tab")
		}

		// Run comprehensive accessibility assessment
		result, err := cremoteServer.client.GetPageAccessibilityReport(tab, tests, standard, includeScreenshots, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to get page accessibility report: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		// Build response message
		message := fmt.Sprintf("Accessibility audit completed for %s", url)
		if clearCache {
			message += " (cache cleared)"
		}
		message += "\n\n" + string(resultJSON)

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(message),
			},
			IsError: false,
		}, nil
	})

	// Register web_contrast_audit tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_contrast_audit_cremotemcp",
		Description: "Perform smart contrast checking with prioritized failures and pattern detection. Returns only failures and common patterns, significantly reducing token usage compared to full contrast check.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"priority_selectors": map[string]any{
					"type":        "array",
					"description": "Array of CSS selectors to prioritize (e.g., ['button', 'a', 'nav', 'footer'])",
					"items": map[string]any{
						"type": "string",
					},
				},
				"threshold": map[string]any{
					"type":        "string",
					"description": "WCAG level to test against: 'AA' or 'AAA' (default: AA)",
					"default":     "AA",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 10)",
					"default":     10,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		threshold := getStringParam(params, "threshold", "AA")
		timeout := getIntParam(params, "timeout", 10)

		// Parse priority selectors array
		var prioritySelectors []string
		if selectorsParam, ok := params["priority_selectors"].([]interface{}); ok {
			for _, s := range selectorsParam {
				if selectorStr, ok := s.(string); ok {
					prioritySelectors = append(prioritySelectors, selectorStr)
				}
			}
		}

		result, err := cremoteServer.client.GetContrastAudit(tab, prioritySelectors, threshold, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to get contrast audit: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(string(resultJSON)),
			},
			IsError: false,
		}, nil
	})

	// Register web_keyboard_audit tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_keyboard_audit_cremotemcp",
		Description: "Perform keyboard navigation assessment with actionable results. Uses real Tab key simulation for accurate :focus-within and :focus-visible testing. Automatically detects accessibility plugins (Accessifix, UserWay, AccessiBe, AudioEye, EqualWeb) and provides confidence scoring for focus indicator findings. Returns summary of issues rather than full element lists, reducing token usage by ~80%.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"check_focus_indicators": map[string]any{
					"type":        "boolean",
					"description": "Check for visible focus indicators (default: true)",
					"default":     true,
				},
				"check_tab_order": map[string]any{
					"type":        "boolean",
					"description": "Check tab order (default: true)",
					"default":     true,
				},
				"check_keyboard_traps": map[string]any{
					"type":        "boolean",
					"description": "Check for keyboard traps (default: true)",
					"default":     true,
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 15)",
					"default":     15,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		checkFocusIndicators := getBoolParam(params, "check_focus_indicators", true)
		checkTabOrder := getBoolParam(params, "check_tab_order", true)
		checkKeyboardTraps := getBoolParam(params, "check_keyboard_traps", true)
		timeout := getIntParam(params, "timeout", 15)

		result, err := cremoteServer.client.GetKeyboardAudit(tab, checkFocusIndicators, checkTabOrder, checkKeyboardTraps, true, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to get keyboard audit: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(string(resultJSON)),
			},
			IsError: false,
		}, nil
	})

	// Register web_form_accessibility_audit tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_form_accessibility_audit_cremotemcp",
		Description: "Perform comprehensive form accessibility check with summarized results. Analyzes labels, ARIA attributes, keyboard accessibility, and contrast issues.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"form_selector": map[string]any{
					"type":        "string",
					"description": "CSS selector for specific form (optional, defaults to all forms)",
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 10)",
					"default":     10,
				},
			},
			Required: []string{},
		},
	}, 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")
		}

		tab := getStringParam(params, "tab", cremoteServer.currentTab)
		formSelector := getStringParam(params, "form_selector", "")
		timeout := getIntParam(params, "timeout", 10)

		result, err := cremoteServer.client.GetFormAccessibilityAudit(tab, formSelector, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to get form accessibility audit: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(string(resultJSON)),
			},
			IsError: false,
		}, nil
	})

	// Register web_extract_divi_structure tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_extract_divi_structure_cremotemcp",
		Description: "Extract Divi page structure from rendered HTML using CSS classes and DOM analysis. Returns approximated structure (60-70% accuracy) including sections, rows, columns, and modules. Cannot access original Divi shortcode/JSON or builder settings.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"url": map[string]any{
					"type":        "string",
					"description": "Optional URL to navigate to before extraction",
				},
				"clear_cache": map[string]any{
					"type":        "boolean",
					"description": "Clear browser cache before operation (default: false)",
					"default":     false,
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default":     30,
				},
			},
		},
	}, 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")
		}

		timeout := getIntParam(params, "timeout", 30)

		// Handle optional navigation and cache clearing
		tab, err := handleOptionalNavigation(cremoteServer, params, timeout)
		if err != nil {
			return nil, err
		}

		result, err := cremoteServer.client.ExtractDiviStructure(tab, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to extract Divi structure: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(string(resultJSON)),
			},
			IsError: false,
		}, nil
	})

	// Register web_extract_divi_images tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_extract_divi_images_cremotemcp",
		Description: "Extract all images from a Divi page with metadata including URLs, dimensions, alt text, and context. Returns 100% of visible images.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"url": map[string]any{
					"type":        "string",
					"description": "Optional URL to navigate to before extraction",
				},
				"clear_cache": map[string]any{
					"type":        "boolean",
					"description": "Clear browser cache before operation (default: false)",
					"default":     false,
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default":     30,
				},
			},
		},
	}, 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")
		}

		timeout := getIntParam(params, "timeout", 30)

		// Handle optional navigation and cache clearing
		tab, err := handleOptionalNavigation(cremoteServer, params, timeout)
		if err != nil {
			return nil, err
		}

		result, err := cremoteServer.client.ExtractDiviImages(tab, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to extract Divi images: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(string(resultJSON)),
			},
			IsError: false,
		}, nil
	})

	// Register web_extract_divi_content tool
	mcpServer.AddTool(mcp.Tool{
		Name:        "web_extract_divi_content_cremotemcp",
		Description: "Extract text content and module data from Divi pages including module types, content, and styling. Returns 90-100% of visible content.",
		InputSchema: mcp.ToolInputSchema{
			Type: "object",
			Properties: map[string]any{
				"tab": map[string]any{
					"type":        "string",
					"description": "Tab ID (optional, uses current tab)",
				},
				"url": map[string]any{
					"type":        "string",
					"description": "Optional URL to navigate to before extraction",
				},
				"clear_cache": map[string]any{
					"type":        "boolean",
					"description": "Clear browser cache before operation (default: false)",
					"default":     false,
				},
				"timeout": map[string]any{
					"type":        "integer",
					"description": "Timeout in seconds (default: 30)",
					"default":     30,
				},
			},
		},
	}, 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")
		}

		timeout := getIntParam(params, "timeout", 30)

		// Handle optional navigation and cache clearing
		tab, err := handleOptionalNavigation(cremoteServer, params, timeout)
		if err != nil {
			return nil, err
		}

		result, err := cremoteServer.client.ExtractDiviContent(tab, timeout)
		if err != nil {
			return &mcp.CallToolResult{
				Content: []mcp.Content{
					mcp.NewTextContent(fmt.Sprintf("Failed to extract Divi content: %v", err)),
				},
				IsError: true,
			}, nil
		}

		// Format results as JSON
		resultJSON, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("failed to marshal results: %w", err)
		}

		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.NewTextContent(string(resultJSON)),
			},
			IsError: false,
		}, nil
	})

	// Start the server
	log.Printf("Cremote MCP server ready")
	if err := server.ServeStdio(mcpServer); err != nil {
		log.Fatalf("Server error: %v", err)
	}
}
