MCP 서버

Thmenu

com.thmenu/thmenu

이 MCP로 할 수 있는 일

Provides restaurant discovery, menus, carts, reservations, orders, loyalty, delivery checkout, waiter requests, and restaurant owner reporting and draft content tools.

apply_promo
Preview a promo code
Validate a promo code (eligibility preview only — does NOT reserve a slot). Returns valid=true with discount info when the code is currently redeemable; pass the same code as place_order.promo_code to actually apply + redeem it (the slot is consumed only when the order lands).
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'required': ['agent_session_id', 'code'], 'properties': {'code': {'type': 'string', 'maxLength': 64, 'minLength': 1}, 'agent_session_id': {'type': 'string'}}}
cancel_order
Cancel an order
Cancel an order placed via the same agent_session_id. Atomic — only succeeds while the order is still in "pending" or "confirmed" (the early KDS-accept state). Once the kitchen starts preparing, you must escalate to waiter_call. Idempotent: replays return the original outcome. Idempotency-Key header REQUIRED.
파괴적 작업 멱등성
입력 스키마
{'type': 'object', 'required': ['agent_session_id', 'order_id'], 'properties': {'order_id': {'type': 'string'}, 'agent_session_id': {'type': 'string'}}}
cancel_reservation
Cancel a reservation request
Cancel a reservation using the 6-character confirmation code the GUEST received by email/SMS (the code is the authorisation; ask the guest for it — this tool never issues or reveals codes). Thin wrapper over the venue's own cancellation endpoint, which answers uniformly: `status` is "cancelled" or "noop" (unknown code · already cancelled · seated/completed · less than 30 minutes away — it does not say which). Only report a cancellation to the guest when `cancelled` is true. PUBLIC tool, no auth.
파괴적 작업 멱등성
입력 스키마
{'type': 'object', 'required': ['confirmation_code'], 'properties': {'confirmation_code': {'type': 'string', 'maxLength': 12, 'minLength': 6}}}
check_loyalty
Loyalty balance
Look up a loyalty member by member_id. Returns balance, tier, lifetime_points, and the most recent 10 transactions so the agent can ground its recommendation ("you have 320 points, enough for a free coffee").
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'required': ['agent_session_id', 'member_id'], 'properties': {'member_id': {'type': 'string'}, 'agent_session_id': {'type': 'string'}}}
create_cart
Create a cart
Build an anonymous takeaway or delivery cart for a listed restaurant and get a one-time confirmation link for the guest. PUBLIC tool, no auth. Table orders are not supported here (they stay on the QR menu). Send the guest to confirm_url. Prices are re-read there from the live menu; name, phone, delivery address and payment are entered by the guest on that page — never through this tool. Nothing is ordered until the guest confirms. The link expires 30 minutes after creation and can be used once.
입력 스키마
{'type': 'object', 'required': ['restaurant', 'order_type', 'items'], 'properties': {'note': {'type': 'string', 'maxLength': 500, 'description': "Order-level note for the kitchen. Do not put the guest's name, phone or address here."}, 'items': {'type': 'array', 'items': {'type': 'object', 'required': ['product_id', 'quantity'], 'properties': {'note': {'type': 'string', 'maxLength': 200}, 'quantity': {'type': 'integer', 'maximum': 99, 'minimum': 1}, 'product_id': {'type': 'string'}}}, 'maxItems': 50, 'minItems': 1}, 'order_type': {'enum': ['takeaway', 'delivery'], 'type': 'string'}, 'restaurant': {'type': 'string', 'description': 'Restaurant slug (from search_restaurants / list_public_menus) or id.'}, 'scheduled_for': {'type': 'string', 'description': 'ISO date-time for a scheduled pickup/delivery (optional; the venue may refuse on the confirmation page).'}}}
draft_product_description
Draft a product description
Propose a new description for one of your products. Nothing goes live: the text is saved as a DRAFT change set the owner reviews, previews and publishes (or discards) in the admin panel.
입력 스키마
{'type': 'object', 'required': ['product_id', 'description'], 'properties': {'product_id': {'type': 'string', 'description': 'Product id from menu_audit or get_restaurant_menu.'}, 'description': {'type': 'string', 'maxLength': 2000, 'description': 'Proposed description in the menu language. Plain text, no links, no claims you cannot verify.'}}, 'additionalProperties': False}
draft_site_text
Draft the website text pack
Propose the public website text of your restaurant — tagline, about paragraph, SEO title and SEO description — as a DRAFT change set. Only declared facts are allowed: no numbers, awards, links or markup; validation rejects anything else. The owner publishes from the admin panel.
입력 스키마
{'type': 'object', 'required': ['tagline', 'about', 'seo_title', 'seo_description'], 'properties': {'about': {'type': 'string', 'maxLength': 700}, 'tagline': {'type': 'string', 'maxLength': 80}, 'seo_title': {'type': 'string', 'maxLength': 60}, 'seo_description': {'type': 'string', 'maxLength': 160}}, 'additionalProperties': False}
draft_translation
Draft a menu translation
Propose a translation (name and/or description) of one product or category into one menu language. Nothing goes live: it is saved as a DRAFT change set the owner reviews and publishes in the admin panel; manual translations override machine translation once published.
입력 스키마
{'type': 'object', 'required': ['entity', 'entity_id', 'locale'], 'properties': {'name': {'type': 'string', 'maxLength': 2000, 'description': 'Translated name (optional). Keep brand names as they are.'}, 'entity': {'enum': ['product', 'category'], 'type': 'string'}, 'locale': {'enum': ['tr', 'en', 'de', 'fr', 'es', 'it', 'nl', 'pt', 'ru', 'ar', 'zh', 'ja', 'ko', 'pl', 'sv', 'da', 'fi', 'no', 'cs', 'hu', 'ro', 'bg', 'el', 'hr', 'sk', 'sl', 'lt', 'lv', 'he', 'fa', 'sw'], 'type': 'string', 'description': 'Target menu language (two letters), different from the menu source language.'}, 'entity_id': {'type': 'string', 'description': 'Product or category id from get_restaurant_menu / menu_audit.'}, 'description': {'type': 'string', 'maxLength': 2000, 'description': 'Translated description (optional). Plain text, no links, same meaning as the source — never add ingredients or claims.'}}, 'additionalProperties': False}
get_cart
Cart contents
Read an anonymous cart by cart_id: state (open · consumed · expired), the one-time confirmation link while open, lines re-priced from the live menu, and the order id once the guest has confirmed. PUBLIC tool, no auth.
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'required': ['cart_id'], 'properties': {'cart_id': {'type': 'string', 'pattern': '^[a-f0-9]{32}$'}}}
get_faq
Frequently asked questions
Return the FAQ entries from the public /faq page in the requested locale (31 locales; unknown locale falls back to en and the response says which locale was served). Useful for grounding answers to common product questions.
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'properties': {'locale': {'type': 'string', 'default': 'en'}}}
get_order_status
Order status
Poll the current status of an order. Returns status, prepared_items_count, total_items_count, eta_minutes (if available), and an optional customer-facing message. Safe to call every 30 seconds; do NOT poll faster.
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'required': ['agent_session_id', 'order_id'], 'properties': {'order_id': {'type': 'string'}, 'agent_session_id': {'type': 'string'}}}
get_pricing
Plans and prices
Return the canonical two-track subscription matrix: the restaurant track (Starter, Lite, Pro, Platinum, Diamond) plus the dedicated Hotels track (Hotels, Hotels+). Billing is YEARLY ONLY — each tier carries its USD yearly list price and the founding-cohort yearly price, plus the feature list. Generated from the same source as the public pricing page; stable identifiers — safe to cache.
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'properties': {}}
get_reservation_slots
Reservation slots
List bookable 30-minute reservation slots for the next 1–7 days (venue timezone) for a listed restaurant with a reservation module. busy_count is the number of existing requests at that slot and is informational. A reservation is a REQUEST that the restaurant confirms; no per-slot capacity cap is configured, so busy_count is informational only. Never tell the guest a table is guaranteed or "available" — say the request will be sent and the restaurant will confirm. PUBLIC tool, no auth.
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'required': ['restaurant'], 'properties': {'days': {'type': 'integer', 'default': 2, 'maximum': 7, 'minimum': 1}, 'restaurant': {'type': 'string'}}}
get_restaurant
Restaurant profile
Fetch a public restaurant profile by slug: name, description, address/city/country, currency, timezone, phone, menu URL, opening hours (7 days, minutes from midnight; a close_minute above 1440 ends after midnight on the next day, e.g. 1560 = 02:00) with isOpenNow evaluated in the venue's own timezone (null when hours are unknown), owner-declared attributes (cuisine, dietary, …; null = not declared, never "no"), derived channels (order · reservation · pickup · delivery), policies derived from the venue's settings (ordering accepted / holiday mode / staff approval / payment timing / scheduled orders, takeaway & delivery ETA and fees, reservation party cap, table calls, tip cap), per-field owner verification timestamps, categories and product count. Only restaurants opted into the public directory are visible.
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'required': ['slug'], 'properties': {'slug': {'type': 'string', 'description': 'Restaurant slug, e.g. lily-rose-bistro'}}}
get_restaurant_menu
Restaurant menu
Fetch the full public menu for a restaurant — categories, products, prices, allergens, nutrition. Use this to build the cart you pass to place_order. PUBLIC tool, no auth required. `allergen_codes` are EU 1169/2011 Annex II keys (gluten, crustaceans, eggs, fish, peanuts, soy, milk, nuts, celery, mustard, sesame, sulphites, lupin, molluscs) given ONLY when the venue's allergen name matches the regulation list exactly; a venue-specific allergen appears in `allergens` without a code. Allergen lists come from the venue (or were AI-suggested and then saved by the venue where `allergen_disclosure.source` says so). `allergen_disclosure.as_of` is when the venue last edited the item record, not a verification date. Follow the top-level `disclosure.agent_instructions`; show `disclosure.text` to the guest in their language whenever an allergen or dietary question comes up; `dietary_flags` only ever warn (true) — null is unknown, never "free of".
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'required': ['restaurant_id'], 'properties': {'locale': {'type': 'string', 'default': 'en'}, 'restaurant_id': {'type': 'string'}}}
join_loyalty
Join the loyalty programme
Enrol the authenticated customer in the restaurant loyalty programme. Returns the member id, current points balance, and tier. Safe to call even if the customer is already enrolled — returns existing data in that case. Requires an active agent_session_id and the customer email or phone.
입력 스키마
{'type': 'object', 'required': ['agent_session_id'], 'properties': {'email': {'type': 'string', 'description': 'Customer email (either email or phone required).'}, 'phone': {'type': 'string', 'description': 'Customer phone in E.164 format (either email or phone required).'}, 'display_name': {'type': 'string', 'description': 'Optional display name shown in the loyalty dashboard.'}, 'agent_session_id': {'type': 'string', 'description': 'Active session id from start_order_session.'}}}
list_public_menus
Public restaurant directory
List restaurants that have opted into the public directory (directory_opt_in = 1 — the same flag the owner sets under "AI visibility"). Returns slug, name, city, country, and the menu URL. Paginated.
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'properties': {'page': {'type': 'integer', 'default': 1, 'minimum': 1}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 50, 'minimum': 1}}}
menu_audit
Menu completeness audit
List the active products of your restaurant that lack a usable description, an image, or an allergen declaration. Read-only; nothing is changed.
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'properties': {}, 'additionalProperties': False}
place_order
Place an order
Place an order against the agent_session_id from start_order_session. Atomically inserts the order + items, applies server-side canonical pricing + tax (do NOT trust the unit_price you compute — we re-read it from D1), decrements inventory, optionally redeems a promo code, and creates a Stripe hosted Checkout Session so the customer can pay + authenticate on their own device. Returns order_id, total_cents (tax-inclusive), currency, promo_discount, and a hosted_confirm_url (a Stripe checkout link) to share with the human. Idempotency-Key header REQUIRED.
멱등성
입력 스키마
{'type': 'object', 'required': ['agent_session_id', 'items'], 'properties': {'note': {'type': 'string', 'description': 'Optional order-level note (max 500 chars).'}, 'items': {'type': 'array', 'items': {'type': 'object', 'required': ['product_id', 'quantity'], 'properties': {'quantity': {'type': 'integer', 'maximum': 999, 'minimum': 1}, 'product_id': {'type': 'string'}}}, 'maxItems': 100, 'minItems': 1}, 'room_id': {'type': 'string', 'description': 'Diamond tier only — hotel room id.'}, 'table_id': {'type': 'string', 'description': 'Optional table id when ordering at a table.'}, 'guest_name': {'type': 'string', 'description': 'Required when room_id is set.'}, 'order_type': {'enum': ['dine_in', 'takeaway'], 'type': 'string', 'description': "Channel: 'dine_in' (default — table or room) or 'takeaway' (pickup; requires customer_name + customer_phone, ignores table_id/room_id, only when the restaurant has takeaway enabled — else channel_not_available). Delivery is not offered to agents."}, 'promo_code': {'type': 'string', 'maxLength': 64, 'description': 'Optional promo code to redeem at order time (validate first with apply_promo). The redemption slot is consumed only when this order lands.'}, 'customer_name': {'type': 'string', 'maxLength': 80, 'description': 'Required for takeaway — who picks the order up.'}, 'customer_phone': {'type': 'string', 'maxLength': 24, 'description': 'Required for takeaway — reachable phone (digits, +, spaces/dashes tolerated).'}, 'agent_session_id': {'type': 'string'}}}
request_bill
Request the bill
Ask the venue to bring the bill for a table. INSERTs a bill_requests row + fires the admin push notification. The split_type defaults to "full"; pass "personal" for German-style per-device splits.
입력 스키마
{'type': 'object', 'required': ['agent_session_id', 'table_id'], 'properties': {'note': {'type': 'string', 'maxLength': 500}, 'table_id': {'type': 'string'}, 'split_type': {'enum': ['full', 'personal'], 'type': 'string', 'default': 'full'}, 'agent_session_id': {'type': 'string'}}}
request_reservation
Request a reservation
Create an anonymous reservation REQUEST (date-time, party size, note) for a listed restaurant and get a one-time confirmation link. PUBLIC tool, no auth. Send the guest to confirm_url: they enter their name and email or phone there and submit the request themselves — never through this tool. The restaurant then confirms or declines; the guest receives the confirmation code by email/SMS. A reservation is a REQUEST that the restaurant confirms; no per-slot capacity cap is configured, so busy_count is informational only. Never tell the guest a table is guaranteed or "available" — say the request will be sent and the restaurant will confirm.
입력 스키마
{'type': 'object', 'required': ['restaurant', 'reserved_at', 'party_size'], 'properties': {'note': {'type': 'string', 'maxLength': 300, 'description': "Occasion, seating preference, accessibility needs. Do not put the guest's name, phone or email here."}, 'party_size': {'type': 'integer', 'maximum': 50, 'minimum': 1}, 'restaurant': {'type': 'string'}, 'reserved_at': {'type': 'string', 'description': 'ISO date-time; at least 30 minutes ahead, at most 90 days.'}}}
reservation_summary
Upcoming reservations
Reservation requests of your restaurant for the next 14 days grouped by day and status, with pending requests that still need an answer. Read-only; no guest contact details.
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'properties': {}, 'additionalProperties': False}
sales_summary
Orders summary (7 and 30 days)
Order counts by status, order total sums, top products by quantity and busiest hours for the last 7 and 30 days of your restaurant. Read-only.
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'properties': {}, 'additionalProperties': False}
search_products
Search products
Search products inside a single restaurant by keyword. Returns up to 20 matching products with name, description, price, allergen tags, and the deep-link URL. Restaurant must be in the public directory.
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'required': ['slug', 'query'], 'properties': {'slug': {'type': 'string', 'description': 'Restaurant slug.'}, 'limit': {'type': 'integer', 'default': 10, 'maximum': 20, 'minimum': 1}, 'query': {'type': 'string', 'description': 'Free-text search across name + description.'}, 'locale': {'type': 'string', 'default': 'en'}}}
search_restaurants
Search restaurants
Search the public directory (opt-in venues only) by location, opening status, cuisine, dietary options, declared attributes and ordering channel. Neutral ranking (AI-K6): distance in 0.5 km bands when `near` is given → availability (open now first; unknown hours before closed) → profile freshness (owner-verified within 90 days first) → name. Subscription tier never affects order. Cuisine, dietary and other attributes are owner declarations, not verified facts; venues without a declaration are excluded only when an attribute filter is used, and venues without coordinates only when `near` is used. Returns slug, name, city, country, distance_km, is_open_now (serve-time, in the venue's own timezone; null when hours are unknown), channels (order · reservation · pickup · delivery), declared attributes, freshness and the menu URL. Paginated.
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'properties': {'q': {'type': 'string', 'description': 'Free text over name and description (min 2 chars).'}, 'city': {'type': 'string'}, 'near': {'type': 'object', 'required': ['lat', 'lng'], 'properties': {'lat': {'type': 'number'}, 'lng': {'type': 'number'}}, 'description': 'Search centre. Venues without coordinates are excluded when set.'}, 'page': {'type': 'integer', 'default': 1, 'minimum': 1}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 50, 'minimum': 1}, 'channel': {'enum': ['order', 'reservation', 'pickup', 'delivery'], 'type': 'string', 'description': "order = digital ordering at the table; reservation; pickup = takeaway; delivery = venue's own delivery."}, 'country': {'type': 'string', 'description': 'ISO 3166-1 alpha-2'}, 'cuisine': {'type': 'array', 'items': {'enum': ['turkish', 'kebab', 'ottoman', 'anatolian', 'aegean', 'black_sea', 'mediterranean', 'middle_eastern', 'lebanese', 'persian', 'georgian', 'greek', 'balkan', 'romanian', 'polish', 'eastern_european', 'russian', 'italian', 'pizza', 'pasta', 'french', 'spanish', 'tapas', 'portuguese', 'german', 'austrian', 'british', 'irish', 'scandinavian', 'dutch', 'american', 'burger', 'steakhouse', 'bbq', 'tex_mex', 'mexican', 'latin_american', 'brazilian', 'peruvian', 'caribbean', 'japanese', 'sushi', 'ramen', 'chinese', 'korean', 'thai', 'vietnamese', 'indian', 'pakistani', 'indonesian', 'malaysian', 'filipino', 'african', 'ethiopian', 'moroccan', 'seafood', 'grill', 'vegetarian', 'vegan', 'healthy', 'cafe', 'coffee', 'tea_house', 'bakery', 'patisserie', 'dessert', 'ice_cream', 'breakfast_brunch', 'fast_food', 'street_food', 'fusion', 'international', 'fine_dining', 'bistro', 'pub', 'bar', 'wine_bar', 'cocktail_bar', 'juice_bar', 'hotel_restaurant', 'food_court'], 'type': 'string'}, 'description': 'All listed cuisines must be declared by the venue.'}, 'dietary': {'type': 'array', 'items': {'enum': ['vegetarian_options', 'vegan_options', 'gluten_free_options', 'lactose_free_options', 'halal', 'kosher'], 'type': 'string'}, 'description': 'Owner declaration, not a certification.'}, 'open_now': {'type': 'boolean', 'default': False, 'description': 'Only venues open right now in their own timezone; venues with unknown hours are excluded when true.'}, 'radius_km': {'type': 'number', 'default': 10, 'maximum': 100, 'minimum': 0.5}, 'attributes': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Any declared attribute token (meals, family, outdoor, accessibility, cuisine, dietary).'}}}
start_order_session
Start an order session
Open a 30-minute transactional window for an AI agent against a specific restaurant. Returns an agent_session_id you MUST pass to every downstream order tool (place_order, cancel_order, request_bill, waiter_call, apply_promo). Also returns the customer-facing confirmation URL — share it with the human so they can review the cart before checkout.
입력 스키마
{'type': 'object', 'required': ['restaurant_id'], 'properties': {'restaurant_id': {'type': 'string', 'description': 'Canonical restaurant id from get_restaurant or search_products.'}}}
waiter_call
Call a waiter
Flag a waiter to the table. INSERTs a waiter_calls row + fires the admin push notification. Pass an optional human-readable message (max 500 chars) the staff sees in the dashboard.
입력 스키마
{'type': 'object', 'required': ['agent_session_id', 'table_id'], 'properties': {'message': {'type': 'string', 'maxLength': 500}, 'table_id': {'type': 'string'}, 'agent_session_id': {'type': 'string'}}}
추가됨
draft_translation
2026년 10월 3일 2:40 AM
추가됨
draft_site_text
2026년 10월 3일 2:40 AM
추가됨
draft_product_description
2026년 10월 3일 2:40 AM
추가됨
reservation_summary
2026년 10월 3일 2:40 AM
추가됨
sales_summary
2026년 10월 3일 2:40 AM
추가됨
menu_audit
2026년 10월 3일 2:40 AM
추가됨
cancel_reservation
2026년 10월 3일 2:40 AM
추가됨
request_reservation
2026년 10월 3일 2:40 AM
추가됨
get_reservation_slots
2026년 10월 3일 2:40 AM
추가됨
get_cart
2026년 10월 3일 2:40 AM
추가됨
create_cart
2026년 10월 3일 2:40 AM
추가됨
join_loyalty
2026년 10월 3일 2:40 AM
추가됨
apply_promo
2026년 10월 3일 2:40 AM
추가됨
check_loyalty
2026년 10월 3일 2:40 AM
추가됨
get_restaurant_menu
2026년 10월 3일 2:40 AM
추가됨
waiter_call
2026년 10월 3일 2:40 AM
추가됨
request_bill
2026년 10월 3일 2:40 AM
추가됨
get_order_status
2026년 10월 3일 2:40 AM
추가됨
cancel_order
2026년 10월 3일 2:40 AM
추가됨
place_order
2026년 10월 3일 2:40 AM
추가됨
start_order_session
2026년 10월 3일 2:40 AM
추가됨
search_restaurants
2026년 10월 3일 2:40 AM
추가됨
list_public_menus
2026년 10월 3일 2:40 AM
추가됨
search_products
2026년 10월 3일 2:40 AM
추가됨
get_restaurant
2026년 10월 3일 2:40 AM
추가됨
get_faq
2026년 10월 3일 2:40 AM
추가됨
get_pricing
2026년 10월 3일 2:40 AM