Skip to main content
Glama
findmine

FindMine Shopping Stylist

Official
by findmine

get_complete_the_look

Generate personalized outfit recommendations for a specific product based on customer preferences, product details, and availability, enhancing the shopping experience with tailored styling suggestions.

Instructions

Get outfit recommendations for a product

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
api_versionNoAPI version to use (overrides FINDMINE_API_VERSION env var)
customer_genderNoCustomer gender (M = Men, W = Women, U = Unknown)
customer_idNoCustomer ID for personalized recommendations
in_stockNoWhether the product is in stock
on_saleNoWhether the product is on sale
product_color_idNoColor ID of the product (if applicable)
product_idYesID of the product
return_pdp_itemNoWhether to return the original product in the response
session_idNoSession ID for tracking and personalization

Implementation Reference

  • MCP tool handler for get_complete_the_look: validates input parameters, calls findMineService.getCompleteTheLook, processes the response by mapping looks and products to URIs, and returns structured JSON content in MCP format.
    case "get_complete_the_look": { try { const args = request.params.arguments as any; // Extract and validate required parameters const productId = args.product_id; if (!productId) { logger.error('Missing required parameter: product_id'); return { error: { message: "Product ID is required", code: "VALIDATION_ERROR" } }; } // Set defaults for optional parameters with explicit declaration const inStock = args.in_stock ?? true; // Using nullish coalescing const onSale = args.on_sale ?? false; const returnPdpItem = args.return_pdp_item ?? true; const colorId = args.product_color_id; const sessionId = args.session_id; const customerId = args.customer_id; // Don't pass gender by default - this parameter should be explicitly set only when needed const gender = args.customer_gender !== undefined ? args.customer_gender : undefined; const apiVersion = args.api_version; logger.error(`Getting complete the look for product ${productId}${colorId ? ` (color: ${colorId})` : ''}`); // Get complete the look recommendations const result = await findMineService.getCompleteTheLook( productId, inStock, onSale, { colorId, sessionId, customerId, returnPdpItem, gender, apiVersion, } ); // Safety check for result.looks if (!result.looks || !Array.isArray(result.looks)) { return { error: { message: "Received invalid response from FindMine service: looks array missing", code: "INVALID_RESPONSE" } }; } // Process looks data with null safety const lookItems = result.looks.map(look => { if (!look || !look.id) { return null; // Skip invalid looks } const lookUri = createLookUri(look.id); return { look_id: look.id, title: look.title || "", description: look.description || "", image_url: look.imageUrl || "", products: Array.isArray(look.productIds) ? look.productIds.map(pid => { if (!pid) return null; const product = findMineService.getProduct(pid); const productUri = product ? createProductUri(product.id, product.colorId) : null; return { product_id: pid, name: product?.name || "", uri: productUri, }; }).filter(Boolean) : [], // Remove null products and handle missing productIds uri: lookUri, }; }).filter(Boolean); // Remove null looks // Include the product if requested let productInfo = null; if (result.product) { const productUri = createProductUri(result.product.id, result.product.colorId); productInfo = { product_id: result.product.id, name: result.product.name, uri: productUri, }; } // Return success response with structured data return { success: true, content: [{ type: "text", text: JSON.stringify({ product: productInfo, looks: lookItems, total_looks: lookItems.length, }, null, 2) }] }; } catch (error) { logger.error(`Error getting complete the look: ${error instanceof Error ? error.message : String(error)}`, error); return { error: { message: error instanceof Error ? error.message : 'Unknown error occurred while getting complete the look', code: 'COMPLETE_THE_LOOK_ERROR' } }; } }
  • Input schema and description for the get_complete_the_look tool, returned by ListToolsRequestSchema handler.
    { name: "get_complete_the_look", description: "Get outfit recommendations for a product", inputSchema: { type: "object", properties: { product_id: { type: "string", description: "ID of the product" }, product_color_id: { type: "string", description: "Color ID of the product (if applicable)" }, in_stock: { type: "boolean", description: "Whether the product is in stock", default: true }, on_sale: { type: "boolean", description: "Whether the product is on sale", default: false }, customer_id: { type: "string", description: "Customer ID for personalized recommendations" }, customer_gender: { type: "string", enum: ["M", "W", "U"], description: "Customer gender (M = Men, W = Women, U = Unknown)" }, return_pdp_item: { type: "boolean", description: "Whether to return the original product in the response", default: true }, session_id: { type: "string", description: "Session ID for tracking and personalization" }, api_version: { type: "string", description: "API version to use (overrides FINDMINE_API_VERSION env var)" } }, required: ["product_id"] } },
  • FindMineService.getCompleteTheLook: Implements caching, calls the API client, maps API responses to ProductResource and LookResource objects, and stores them in the resource store.
    async getCompleteTheLook( productId: string, inStock: boolean, onSale: boolean, options: { colorId?: string; sessionId?: string; customerId?: string; returnPdpItem?: boolean; gender?: 'M' | 'W' | 'U'; useCache?: boolean; apiVersion?: string; } = {} ): Promise<{ product?: ProductResource; looks: LookResource[]; }> { const sessionId = options.sessionId || config.session.defaultSessionId; const useCache = options.useCache !== false && config.cache.enabled; // Create cache key const cacheKey = Cache.createKey([ 'completeTheLook', productId, options.colorId || 'default', String(inStock), String(onSale), String(options.returnPdpItem) ]); // Try to get from cache let response: CompleteTheLookResponse; if (useCache) { const cached = this.completeTheLookCache.get(cacheKey); if (cached) { response = cached; } else { response = await this.client.getCompleteTheLook( productId, inStock, onSale, sessionId, { colorId: options.colorId, customerId: options.customerId, returnPdpItem: options.returnPdpItem, gender: options.gender, apiVersion: options.apiVersion, } ); // Store in cache this.completeTheLookCache.set(cacheKey, response); } } else { response = await this.client.getCompleteTheLook( productId, inStock, onSale, sessionId, { colorId: options.colorId, customerId: options.customerId, returnPdpItem: options.returnPdpItem, gender: options.gender, apiVersion: options.apiVersion, } ); } // Convert to internal resources let product: ProductResource | undefined; if (response.pdp_item) { product = mapProductToResource(response.pdp_item); this.resources.products[product.id] = product; } const looks: LookResource[] = []; for (const look of response.looks) { try { const lookResource = mapLookToResource(look); this.resources.looks[lookResource.id] = lookResource; looks.push(lookResource); // Store all products from the look - handle different API formats const products = look.products || look.items || []; if (Array.isArray(products)) { for (const product of products) { try { if (product && product.product_id) { const productResource = mapProductToResource(product); this.resources.products[productResource.id] = productResource; } } catch (productError) { if (process.env.FINDMINE_DEBUG === 'true') { console.error(`[FindMineService] Error mapping product in look ${lookResource.id}:`, productError); } // Continue with next product even if one fails } } } } catch (lookError) { if (process.env.FINDMINE_DEBUG === 'true') { console.error(`[FindMineService] Error mapping look:`, lookError); } // Continue with next look even if one fails } } return { product, looks, }; }
  • FindMineClient.getCompleteTheLook: Constructs the API request parameters and makes HTTP GET request to the FindMine complete-the-look endpoint with retry logic.
    async getCompleteTheLook( productId: string, inStock: boolean, onSale: boolean, sessionId: string, options: { colorId?: string; customerId?: string; returnPdpItem?: boolean; gender?: 'M' | 'W' | 'U'; apiVersion?: string; } = {} ): Promise<CompleteTheLookResponse> { const apiVersion = options.apiVersion || this.config.apiVersion; // Create request parameters, only including gender if explicitly provided const params: CompleteTheLookRequest = { ...this.createBaseRequest(sessionId, options.customerId), product_id: productId, product_color_id: options.colorId, product_in_stock: inStock, product_on_sale: onSale, return_pdp_item: options.returnPdpItem, }; // Only add gender param if explicitly provided if (options.gender !== undefined) { params.customer_gender = options.gender; } return this.makeRequest<CompleteTheLookResponse>( `/api/${apiVersion}/complete-the-look`, 'GET', params ); }

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/findmine/findmine-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server