package mcpclient import ( "fmt" "path/filepath" "runtime" "github.com/ituoke/ituoke/internal/runtimeassets" ) const mobileServerID = "builtin-mobile-next" // The builtin uses the local ADB driver. Do not advertise cloud authentication // or operations that this driver cannot implement (including unrestricted batches). func supportedTool(c ServerConfig, name string) bool { if c.Transport != "mobile" { return true } switch name { case "mobile_list_available_devices", "mobile_list_apps", "mobile_launch_app", "mobile_terminate_app", "mobile_install_app", "mobile_uninstall_app", "mobile_get_screen_size", "mobile_click_on_screen_at_coordinates", "mobile_double_tap_on_screen", "mobile_long_press_on_screen_at_coordinates", "mobile_list_elements_on_screen", "mobile_press_button", "mobile_open_url", "mobile_swipe_on_screen", "mobile_type_keys", "mobile_save_screenshot", "mobile_take_screenshot", "mobile_set_orientation", "mobile_get_orientation": return true default: return false } } func toolDescription(c ServerConfig, name, description string) string { if c.Transport == "mobile" && name == "mobile_list_available_devices" { return "List local devices connected to this computer. Use the connected Android phone for mobile tasks. No cloud account or login is needed. If no device is available, ask the user to connect their phone in iTuoke settings." } return description } // Keep a stable config id and honor the user's saved enabled/disabled choice. func (s *Service) ensureMobile() error { s.mu.Lock() defer s.mu.Unlock() if s.loadErr != nil { return s.loadErr } for _, c := range s.servers { if c.ID == mobileServerID || c.Transport == "mobile" { return nil } } c := ServerConfig{ID: mobileServerID, Name: "Mobile Next", Enabled: true, Transport: "mobile", Args: []string{}, TimeoutSeconds: 30} next := append(append([]ServerConfig{}, s.servers...), c) if err := s.persist(next); err != nil { return err } s.servers = next return nil } func mobileCommand(c ServerConfig) (ServerConfig, error) { nodeName := "node" if runtime.GOOS == "windows" { nodeName += ".exe" } node := runtimeassets.Find(filepath.Join("mcp-filesystem", nodeName)) entry := runtimeassets.Find(filepath.Join("mcp-mobile", "node_modules", "@mobilenext", "mobile-mcp", "lib", "index.js")) bootstrap := runtimeassets.Find(filepath.Join("mcp-mobile", "server.cjs")) if node == "" || entry == "" || bootstrap == "" { return c, fmt.Errorf("缺少内置 Mobile Next MCP 运行资源,请在构建机执行 npm --prefix runtime/mobile run stage") } c.Command = node c.Args = []string{bootstrap, entry} c.Transport = "stdio" c.WorkingDirectory = filepath.Dir(node) return c, nil }