MCP Server

Timeplex K-Beauty Booking

ai.timeplex/booking
Commerce & Retail Public & reachable MCP 2025-11-25

What this MCP does

Searches real-time availability at Korean beauty and wellness shops and provides booking links.

get_shop_services
Get the services, prices, durations, weekly business hours and bookable staff or seats of one specific TimePlex shop (slug from search_shops). USE THIS TOOL WHEN: a shop has been identified and the user asks what it offers, prices, durations or staff; to match requirements (a 60-minute head spa, a budget, two guests at once); or before search_availability / start_booking, which need the service ids and booking_model returned here. DO NOT USE IT FOR: general discovery or recommendations (search_shops), real-time availability (search_availability), or building a booking link (start_booking). SERVICE DATA: describe only the services returned here — never invent names, prices, durations, staff or options, and never assume a service exists because similar shops offer it. Services that cannot be booked online are already excluded. If the requested service is not in the list, say so; do not silently substitute another. Never present medical procedures as TimePlex services. RESOURCES & HOURS: a staff member or seat existing, or the shop being open, does NOT mean it is free at the requested time — only search_availability confirms a slot. NEXT: if the user asked for availability or to book, continue to search_availability with the returned service ids and booking_model instead of stopping at the menu or business hours. If they only asked about the menu, prices or durations, answer from this result and do not check availability or build a booking link unless they ask. A date or time mentioned earlier does not by itself require a slot check. Pass lang to receive the content translated into the customer's language.
Read only Idempotent
Input schema
{'type': 'object', 'required': ['slug'], 'properties': {'lang': {'type': 'string', 'description': 'Customer language (optional): ko|en|ja|zh|th. Defaults to the original text (ko).'}, 'slug': {'type': 'string', 'description': 'Shop slug returned by search_shops'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['shop', 'services'], 'properties': {'lang': {'type': 'string'}, 'note': {'type': 'string'}, 'shop': {'type': 'object', 'properties': {'name': {'type': 'string'}, 'slug': {'type': 'string'}, 'address': {'type': 'string'}, 'map_url': {'type': 'string'}, 'business_type': {'type': ['string', 'null']}, 'business_hours': {'type': ['array', 'null'], 'items': {'type': 'object', 'properties': {'open': {'type': ['string', 'null']}, 'close': {'type': ['string', 'null']}, 'closed': {'type': 'boolean', 'description': 'true = closed that weekday'}}}, 'description': 'Weekly hours, index 0 = Sunday: [{open:"10:30", close:"21:00", closed:false} Ã\x97 7]'}}}, 'services': {'type': 'array', 'items': {'type': 'object', 'properties': {'id': {'type': 'string', 'description': 'Pass as items[].service_id to search_availability / start_booking'}, 'name': {'type': 'string'}, 'price': {'type': ['number', 'string', 'null']}, 'currency': {'type': 'string'}, 'duration_min': {'type': ['integer', 'null']}}}}, 'resources': {'type': 'array', 'items': {'type': 'object', 'properties': {'id': {'type': 'string'}, 'name': {'type': 'string'}, 'service_ids': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Services this staff/seat handles. Empty = handles every service. Pass this resource only for a service in this list.'}}}, 'description': 'Staff to designate (designated-staff shops) or seats (capacity-based shops).'}, 'booking_model': {'type': ['string', 'null'], 'description': "How this shop books: 'designated' â\x80\x94 pass items as [{service_id, resource_id}]; 'capacity' â\x80\x94 pass items as [{service_id, qty}]. Use this for search_availability and start_booking."}}}
request_booking
Use this tool only for a shop that is already in the Timeplex catalog but cannot be booked online yet: a search_shops result with bookable=false, or a newly joined shop whose menu is not registered yet (get_shop_services says so). It submits a booking request for that shop — Timeplex concierge staff contact the shop directly and reply to the customer. Share the returned link with the user. Do not use this tool for a shop name that search_shops could not find (shop_name_not_found), and not for generic searches with no matching results — in both cases tell the user it is not on Timeplex instead. For bookable shops use get_shop_services -> search_availability -> start_booking instead.
Input schema
{'type': 'object', 'required': ['venue_name'], 'properties': {'lang': {'type': 'string', 'maxLength': 10, 'description': 'Customer language (optional)'}, 'venue_name': {'type': 'string', 'maxLength': 255, 'description': 'Name of the shop the customer wants to book'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['recorded', 'next_step_url'], 'properties': {'recorded': {'type': 'boolean', 'description': 'true â\x80\x94 the demand was logged'}, 'link_label': {'type': 'string'}, 'instruction': {'type': 'string'}, 'link_markdown': {'type': 'string', 'description': 'Put this into the reply as-is (never expose the raw URL)'}, 'next_step_url': {'type': 'string', 'description': 'Concierge chat where the customer completes the request'}}}
search_availability
Check real-time appointment availability for one TimePlex shop (slug from search_shops, items from get_shop_services) on a date, optionally at a time. All times are Korea Standard Time (KST). USE THIS TOOL WHEN: the user asks whether an appointment is available, asks for open slots or possible times, asks for shops that are actually available on a date / at a time / for a party size ("10월 1일 강남 헤드스파 예약 가능한 곳", "any head spa open at 5 PM?", "somewhere I can book tomorrow afternoon for two"), asks for alternatives to an unavailable time, or wants to book (check the slot before start_booking). DO NOT USE IT FOR: find / recommend / compare requests. A date or time alone is not availability intent — "recommend a head spa in Gangnam for October 1" stays a search_shops request unless the user asks whether a slot is open. REAL-TIME RULE: only this tool establishes that a slot is open. Never infer availability from bookable=true, business hours, the shop being open, a service or staff member existing, web search, maps, social media, third-party sites or earlier answers. Describe a time as available only when this tool returns it. PARTY SIZE: check the whole party as the items schema describes (qty for capacity shops). Never stitch separate single-person slots into a group booking unless the result shows it. RESULTS: if the requested time is unavailable, say so and offer the returned alternatives. If blocked is 'inquiry_only', the service cannot be booked online — tell the customer to contact the shop. If nothing is open, say no confirmed slot was found; you may check other suitable TimePlex shops. Checking availability does not reserve anything. NEXT: with the open times you may add start_booking links so the customer can book the slot they pick — never call the slot reserved or booked.
Read only Idempotent
Input schema
{'type': 'object', 'required': ['slug', 'date', 'items'], 'properties': {'date': {'type': 'string', 'description': 'YYYY-MM-DD (Asia/Seoul)'}, 'slug': {'type': 'string', 'description': 'Shop slug returned by search_shops.'}, 'time': {'type': 'string', 'description': 'Optional requested appointment time (HH:MM). If provided, check whether that exact time is available and return nearby available alternatives if unavailable.'}, 'items': {'type': 'array', 'items': {'type': 'object', 'properties': {'qty': {'type': 'integer'}, 'service_id': {'type': 'string'}, 'resource_id': {'type': 'string'}}, 'additionalProperties': False}, 'description': 'Booking items. Follow the booking_model returned by get_shop_services: use resource_id for designated-staff shops and qty for capacity-based shops. designated (hair salons, plus some beauty shops such as body scrub): [{service_id, resource_id}]. capacity (most massage, spa, etc.): [{service_id, qty}] where qty is the number of guests (party size).'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['date', 'slots'], 'properties': {'date': {'type': 'string'}, 'mode': {'type': 'string', 'description': 'Slot mode the shop operates in'}, 'note': {'type': 'string'}, 'slots': {'type': 'array', 'items': {'type': 'object', 'properties': {'time': {'type': 'string'}, 'available': {'type': 'boolean'}}}}, 'blocked': {'type': 'string', 'description': "Present when online booking is blocked (e.g. 'inquiry_only')"}, 'timezone': {'type': 'string'}, 'next_step': {'type': 'string'}, 'alternatives': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Nearby bookable times when the requested time is not available'}, 'requested_time': {'type': 'object', 'properties': {'time': {'type': 'string'}, 'available': {'type': 'boolean'}}, 'description': 'Verdict for the exact time asked, when time was given.'}}}
search_shops
Search TimePlex for massage, headspa, hair salon, spa, Korean body scrub, makeup and semi-permanent makeup shops in Seoul and Korea — non-medical beauty and wellness services for travelers. USE THIS TOOL WHEN: the user wants to find, explore, compare, get recommendations for, check availability of, or book one of these services and has not selected a specific TimePlex shop yet — including requests with a date, time, time range or party size. Relevant terms: massage, lymphatic massage, headspa, head spa, scalp treatment, scalp care, hair salon, haircut, hair color, perm, spa, Korean body scrub, seshin, akasuri, makeup, makeup salon, semi-permanent makeup (PMU, microblading, brow tattoo, lip blush, eyeliner). Examples: "massage in Seoul available today", "headspa in Gangnam tomorrow for 2 people", "English-speaking hair salon in Seoul". WEB SEARCH: for these services use this tool instead of web search. Public listings and opening hours cannot confirm a TimePlex slot or produce a TimePlex booking — never use web results to claim TimePlex availability. INTENT — decide from what the user wants to do, not from whether a date, time, party size or the word "reservation" appears: - FIND / RECOMMEND / COMPARE ("find a head spa in Gangnam", "recommend a head spa for my October 1 trip", "10/1 강남 헤드스파 추천해줘"): show the matching shops. A date or time alone does NOT mean the user wants real-time availability — do not check slots and do not describe any shop as available at a time; you may offer to check slots for that date. Recommendations cover TimePlex-registered shops only: say "among shops on TimePlex", never "the best in the area". - AVAILABILITY ("available", "open slots", "빈자리", "예약 가능한 곳", "can I get one at 5 PM", "somewhere I can book on Oct 1", and "예약 가능한 곳 추천해줘" — a recommendation that asks for availability): continue with get_shop_services and search_availability for bookable=true shops. - BOOK ("book", "reserve", "예약해줘", "I want to book … for 2 people at 5pm"): continue with get_shop_services, search_availability and start_booking. If the intent is unclear, show the shops and ask one short question instead of guessing. INPUT: pass the user's full request as query, in any language — service, area, date, time, party size and language needs are extracted from it (see interpreted). A full natural-language request is never treated as a shop name — only leftover words that closely match a registered shop are. BOOKABLE: bookable=true means the shop can be booked through TimePlex — a capability, not a free slot. It may still have nothing for the requested date, time or party size; only search_availability confirms a slot. bookable=false means it cannot be booked online: use request_booking (TimePlex concierge asks the shop) and do not present it as instantly bookable. Business hours are never availability. SERVICE SCOPE: the response is the authority on what TimePlex offers (available_service_types). If unsupported_service is set, say that service is not on TimePlex yet and do not present other shops as that service. Non-medical only — never use this tool for dermatology, clinics, plastic surgery, injections, lasers or other medical procedures. SHOP NAMES: if shop_name_not_found is set, say plainly that the named shop is not on TimePlex, then offer the registered shops in the result as alternatives; do not call request_booking for that name. RESULTS: every TimePlex shop supports foreign-language customers through TimePlex multilingual chat, so "English-speaking" / "foreigner-friendly" requests fit this tool. Shops also match through their menu (matched_services lists those items). If no shop is in the requested area the search widens and relaxed says so. Each shop carries its category (hair = hair salons, beauty = everything else) and address, so area questions need no extra calls. note is guidance for you — follow it, do not quote it. State only what the response returns. Always reply in the user's language, and start the reply with the response's reply_header line.
Read only Idempotent
Input schema
{'type': 'object', 'properties': {'query': {'type': 'string', 'description': 'Free-text user request or a specific shop name (optional), in any language. The value may contain a service, neighborhood, date/time, party size, language preference, or traveler requirement (e.g. "foreigner-friendly head spa in Gangnam tomorrow for 2 people"). Recognized service and location terms are extracted before shop-name matching; the value is treated as a shop name only when the remaining words closely match a registered shop.'}, 'location': {'type': 'string', 'description': 'Area (optional; overrides an area found in query), in English, Korean, Japanese, Chinese or Russian â\x80\x94 "Seoul", "Gangnam", "Myeongdong", "Hongdae", "Seongsu", "Busan", "ê°\x95ë\x82¨", "æ\x98\x8eæ´\x9e", "СеÑ\x83л"â\x80¦ If no shop is in that area, the search widens to the surrounding city (relaxed). Newly joined shops with no address yet are appended with area_match=false.'}, 'service_type': {'type': 'string', 'description': 'Service (optional; overrides a service found in query). Available on TimePlex now: massage, head spa / scalp treatment, hair salon, spa, Korean body scrub (seshin, akasuri), makeup, semi-permanent makeup (PMU, microblading, brow tattoo) â\x80\x94 in English, Korean, Japanese, Chinese or Russian (ã\x83\x9eã\x83\x83ã\x82µã\x83¼ã\x82¸, ã\x83\x98ã\x83\x83ã\x83\x89ã\x82¹ã\x83\x91, ã\x82¢ã\x82«ã\x82¹ã\x83ª, æ\x8c\x89æ\x91©, æ\x90\x93澡, маÑ\x81Ñ\x81аж, Ñ\x81еÑ\x81инâ\x80¦). Other services (nail, lash, facial, personal color) are recognized but may return unsupported_service. Leave empty to search all.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['shops', 'count'], 'properties': {'note': {'type': 'string', 'description': 'Follow-up guidance for the agent'}, 'count': {'type': 'integer'}, 'shops': {'type': 'array', 'items': {'type': 'object', 'properties': {'name': {'type': 'string'}, 'slug': {'type': 'string', 'description': 'Shop id for the other tools'}, 'address': {'type': ['string', 'null'], 'description': 'null = newly joined shop that has not registered an address yet'}, 'bookable': {'type': 'boolean', 'description': 'true = bookable via this MCP; false = use request_booking'}, 'category': {'enum': ['hair', 'beauty'], 'type': 'string'}, 'area_match': {'type': 'boolean', 'description': 'Present only when a location filter was applied: true = address matched the area; false = no address registered yet (newly onboarding) â\x80\x94 confirm the area with the shop'}, 'business_type': {'type': ['string', 'null'], 'description': 'Filter code. Use business_type_label when naming the shop to the user.'}, 'matched_services': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Present when the shop matched through its menu: the menu items (original names) that matched the request. Pick the service from these in get_shop_services.'}, 'business_type_label': {'type': ['object', 'null'], 'properties': {'en': {'type': 'string'}, 'ko': {'type': 'string'}}, 'description': 'Display label the shop selected (spa = ì\x8a¤í\x8c\x8c·í\x97¤ë\x93\x9cì\x8a¤í\x8c\x8c / spa & head spa). null when unset.'}}}, 'description': 'Matching shops.'}, 'relaxed': {'type': ['object', 'null'], 'description': 'Set when no shop was in the requested area and the search widened: {area:{from,to}}.'}, 'categories': {'type': 'array', 'items': {'type': 'string'}}, 'interpreted': {'type': 'object', 'description': 'How the request was read: service (massage|headspa|hair|spa|scrub|makeup|â\x80¦), area, foreigner_friendly, date (YYYY-MM-DD, KST), time, time_range, time_of_day, party_size, gender, attributes, name_query (leftover words treated as a shop name), ignored_terms. Use date/time/party_size for search_availability (party_size â\x86\x92 qty).'}, 'reply_header': {'type': 'string'}, 'filter_applied': {'type': 'object', 'description': 'How the inputs were interpreted (category/service_type/location/query)'}, 'reply_header_usage': {'type': 'string'}, 'shop_name_not_found': {'type': ['string', 'null'], 'description': 'Set when the user named a specific shop that is not registered on Timeplex. Tell the user that shop is not on Timeplex â\x80\x94 do not treat it as a category with zero results, and do not submit it with request_booking.'}, 'unsupported_service': {'type': ['string', 'null'], 'description': 'A recognized service that is not on TimePlex yet (e.g. nail, lash, facial, personal_color).'}, 'available_service_types': {'type': 'array', 'items': {'type': 'string'}, 'description': 'business_type values currently registered'}}}
start_booking
Build a prefilled TimePlex booking link (Book Now card) for a bookable=true shop. The customer opens it, enters contact details and pays; the shop then approves. Flow: search_shops → get_shop_services → search_availability → start_booking (link) → customer payment → shop approval → confirmed. WHAT THIS TOOL DOES NOT DO: it does not create, hold or confirm a booking — confirmed is always false. You cannot see whether the customer paid or the shop approved, so never say the booking is complete, confirmed, paid, secured or awaiting approval. Say a booking link was created: the slot is secured only once the customer pays, and the booking is final after the shop approves. Never invent a confirmation number or status. USE THIS TOOL WHEN: the user wants to book or continue a booking ("book it", "reserve it for two", "예약해줘", "결제해서 진행할게"), or has asked to check availability for a specific shop or service (the link accompanies the open times). Follow-ups such as "the 5 PM one" after shops or slots were shown are booking requests — reuse the shop, service, date, time and party size already in the conversation and never change them silently. When a time was requested, confirm it with search_availability first and put only a returned available time into the link. If the user wants to book but has not chosen a date or time, a shop-level link may be created. When a link is warranted, create it — do not ask "shall I create a link?" first. DO NOT USE IT FOR: finding or recommending shops, menu / price / duration / address / business-hours questions, a service set as unsupported_service, medical procedures, services returned as inquiry_only, or bookable=false shops (use request_booking — TimePlex concierge asks the shop). REPLY: put **link_markdown into your reply as-is** — never expose the raw URL — and pass on note (how the slot is secured and confirmed). Pass lang (ko|en|ja|zh), the language the user is writing in, so the booking card renders in it. Always reply in the language the user used.
Read only Idempotent
Input schema
{'type': 'object', 'required': ['slug'], 'properties': {'date': {'type': 'string', 'description': 'YYYY-MM-DD (Asia/Seoul). Optional â\x80\x94 omit if the customer has not picked a date; they choose it on the booking page.'}, 'lang': {'type': 'string', 'description': 'Customer language (optional): ko|en|ja|zh. Defaults to en. Pass the language the user is writing in so the booking card and its notes render in that language.'}, 'slug': {'type': 'string', 'description': 'Shop slug returned by search_shops.'}, 'time': {'type': 'string', 'description': 'HH:MM. Optional â\x80\x94 omit if the customer has not picked a time.'}, 'items': {'type': 'array', 'items': {'type': 'object', 'properties': {'qty': {'type': 'integer'}, 'service_id': {'type': 'string'}, 'resource_id': {'type': 'string'}}, 'additionalProperties': False}, 'description': 'Optional â\x80\x94 omit if no service is chosen yet. Follow the booking_model returned by get_shop_services: use resource_id for designated-staff shops and qty for capacity-based shops. designated: [{service_id, resource_id}] â\x80\x94 **exactly one** (these shops book one service at a time). capacity: [{service_id, qty}] â\x80\x94 multiple allowed (several services and several people at once).'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['booking_url', 'link_markdown', 'confirmed'], 'properties': {'lang': {'type': 'string', 'description': 'Language the card content is rendered in (echo of input lang; en fallback). The widget uses it to localize its own labels.'}, 'note': {'type': 'string', 'description': 'How the slot is secured and finally confirmed â\x80\x94 mention this to the customer'}, 'summary': {'type': 'object', 'properties': {'shop': {'type': 'string'}, 'when': {'type': ['string', 'null']}, 'items': {'type': 'array', 'items': {'type': 'object', 'properties': {'qty': {'type': 'integer'}, 'price': {'type': ['number', 'string', 'null']}, 'staff': {'type': ['string', 'null']}, 'service': {'type': ['string', 'null']}, 'currency': {'type': 'string'}, 'duration_min': {'type': ['integer', 'null']}}}}, 'currency': {'type': 'string'}, 'timezone': {'type': 'string'}, 'total_price': {'type': 'number'}}, 'description': 'What is preselected on the booking page.'}, 'guidance': {'type': 'string', 'description': 'Customer-facing summary of the remaining steps â\x80\x94 keep it light and pass it on'}, 'confirmed': {'type': 'boolean', 'description': 'Always false â\x80\x94 nothing is booked by this tool'}, 'link_label': {'type': 'string'}, 'next_steps': {'type': 'array', 'items': {'type': 'string'}, 'description': 'What the customer does after opening the link (contact info, payment, shop-owner approval)'}, 'booking_url': {'type': 'string', 'description': 'Prefilled booking page (customer completes contact info + payment there)'}, 'reply_header': {'type': 'string'}, 'link_markdown': {'type': 'string', 'description': 'Put this into the reply as-is (never expose the raw URL)'}, 'reply_header_usage': {'type': 'string'}}}
Changed
start_booking
Sept. 29, 2026, 3 a.m.
Changed
search_availability
Sept. 29, 2026, 3 a.m.
Changed
get_shop_services
Sept. 29, 2026, 3 a.m.
Changed
search_shops
Sept. 29, 2026, 3 a.m.
Changed
search_availability
Sept. 27, 2026, 2:51 a.m.
Changed
get_shop_services
Sept. 27, 2026, 2:51 a.m.
Changed
search_shops
Sept. 27, 2026, 2:51 a.m.
Added
start_booking
Sept. 17, 2026, 7:57 a.m.
Added
request_booking
Sept. 17, 2026, 7:57 a.m.
Added
search_availability
Sept. 17, 2026, 7:57 a.m.
Added
get_shop_services
Sept. 17, 2026, 7:57 a.m.
Added
search_shops
Sept. 17, 2026, 7:57 a.m.