Skip to content

Thmenu

by thmenu.com · remote · no sign-in to list tools · v0.5.0 · published by com.thmenu

Restaurant menus, carts, reservations and owner drafts for AI agents (Thmenu MCP).

Deletes · 2Changes · 14

27 tools: 2 can delete or cancel things, 14 change things and 11 only read.

Scanned Oct 21, 2026

1 check matched something in the tool definitions. No finding is not a safety guarantee. How the checks work.

claude mcp add --transport http thmenu https://mcp.thmenu.com/

Findings

Matches of fixed checks, with the text they matched.

1 warn
  • The server marks "apply_promo" read-only (readOnlyHint: true), and its own name, description or input give the class "write".

    Matched text

    annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}; The name "apply_promo" says "apply": a word for a change.

    What this check looks for

Tools

Open a tool for its reasons and full description. Descriptions are the publisher's own words, shown as they are.

27 tools

Deletes or cancels 2Claude Code: deny
  • cancel_orderCancel an order placed via the same agent_session_id.No findings

    Why it is in this group

    • The name "cancel_order" says "cancel": a word for removing or ending something.
    • The server marks it destructive (destructiveHint: true).
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: false
    • destructiveHint: true
    • idempotentHint: true
    • openWorldHint: false
  • cancel_reservationCancel 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 reveal…No findings

    Why it is in this group

    • The name "cancel_reservation" says "cancel": a word for removing or ending something.
    • The server marks it destructive (destructiveHint: true).
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: false
    • destructiveHint: true
    • idempotentHint: true
    • openWorldHint: false
Changes things 14Claude Code: ask
  • apply_promoValidate a promo code (eligibility preview only — does NOT reserve a slot).1 finding

    Why it is in this group

    • The name "apply_promo" says "apply": a word for a change.
    • The input takes a statement or command to run (input.code), which can change anything it can reach.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.

    Findings

    • Warn

      The server marks "apply_promo" read-only (readOnlyHint: true), and its own name, description or input give the class "write".

      Matched text

      annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}; The name "apply_promo" says "apply": a word for a change.

      What this check looks for
    Description, as the server wrote it
    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).

    Annotations the server declares

    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • check_loyaltyLook up a loyalty member by member_id.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
    Description, as the server wrote it
    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").

    Annotations the server declares

    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • create_cartBuild an anonymous takeaway or delivery cart for a listed restaurant and get a one-time confirmation link for the guest.No findings

    Why it is in this group

    • The name "create_cart" says "create": a word for a change.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: false
  • draft_product_descriptionPropose a new description for one of your products.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: false
  • draft_site_textPropose the public website text of your restaurant — tagline, about paragraph, SEO title and SEO description — as a DRAFT change set.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: false
  • draft_translationPropose a translation (name and/or description) of one product or category into one menu language.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: false
  • join_loyaltyLoyalty sign-up for a guest.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    Loyalty sign-up for a guest. The guest must confirm their own e-mail, so joining happens on the restaurant's menu (My thmenu → Loyalty); this tool answers with that instruction and never reveals whether an e-mail or phone is already enrolled. Requires an active agent_session_id.

    Annotations the server declares

    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: false
  • place_orderPlace an order against the agent_session_id from start_order_session.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    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 and optionally redeems a promo code. The guest pays at the venue (payment_status 'unpaid'). At a venue that takes payment before preparing (pay_first: true) the order is held as 'awaiting' and payment_url is returned: give it to the guest — they pay on the restaurant's own checkout, exactly like a guest ordering from the table; the kitchen gets the order once it is paid, and an unpaid order expires. This tool never charges anything itself. Returns order_id, total_cents (tax-inclusive), currency, promo_discount and, when pay_first, payment_url. Idempotency-Key header REQUIRED.

    Annotations the server declares

    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • request_billAsk the venue to bring the bill for a table.No findings

    Why it is in this group

    • The name "request_bill" says "request": a word for a change.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: false
  • request_reservationCreate an anonymous reservation REQUEST (date-time, party size, note) for a listed restaurant and get a one-time confirmation link.No findings

    Why it is in this group

    • The name "request_reservation" says "request": a word for a change.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: false
  • reservation_summaryReservation requests of your restaurant for the next 14 days grouped by day and status, with pending requests that still need an answer.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • sales_summaryOrder counts by status, order total sums, top products by quantity and busiest hours for the last 7 and 30 days of your restaurant.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • start_order_sessionOpen a 30-minute transactional window for an AI agent against a specific restaurant.No findings

    Why it is in this group

    • The name "start_order_session" says "start": a word for a change.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: false
  • waiter_callFlag a waiter to the table.No findings

    Why it is in this group

    • The name "waiter_call" says "call": a word for a change.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: false
Only reads 11Claude Code: allow
  • get_cartRead 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…No findings

    Why it is in this group

    • The name "get_cart" says "get": a word for reading.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • get_faqReturn 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).No findings

    Why it is in this group

    • The name "get_faq" says "get": a word for reading.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • get_order_statusPoll the current status of an order.No findings

    Why it is in this group

    • The name "get_order_status" says "get": a word for reading.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • get_pricingReturn Thmenu's commercial model as structured facts: free forever, every feature included, no subscription and no trial; the only charge is a platform fee in basis points on payme…No findings

    Why it is in this group

    • The name "get_pricing" says "get": a word for reading.
    Description, as the server wrote it
    Return Thmenu's commercial model as structured facts: free forever, every feature included, no subscription and no trial; the only charge is a platform fee in basis points on payment volume processed through Thmenu (the payment processor's own fee is separate); cash or external payments carry no Thmenu fee. Generated from the code that charges it — safe to cache.

    Annotations the server declares

    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • get_reservation_slotsList bookable 30-minute reservation slots for the next 1–7 days (venue timezone) for a listed restaurant with a reservation module.No findings

    Why it is in this group

    • The name "get_reservation_slots" says "get": a word for reading.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • get_restaurantFetch 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_minut…No findings

    Why it is in this group

    • The name "get_restaurant" says "get": a word for reading.
    Description, as the server wrote it
    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, and `graph` — the canonical Restaurant Graph node's agent fields: verification state (UNCLAIMED · CLAIMED · SUSPENDED · HIDDEN; VERIFIED only when a human verified it), channel_states (each channel true/false/null with a reason — null means unknown, never "no"; TABLE_AVAILABLE only from tables staff confirmed ready), menu languages with coverage, and payment availability. Only restaurants opted into the public directory are visible.

    Annotations the server declares

    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • get_restaurant_menuFetch the full public menu for a restaurant — categories, products, prices, allergens, nutrition.No findings

    Why it is in this group

    • The name "get_restaurant_menu" says "get": a word for reading.
    Description, as the server wrote it
    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".

    Annotations the server declares

    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • list_public_menusList restaurants that have opted into the public directory (directory_opt_in = 1 — the same flag the owner sets under "AI visibility").No findings

    Why it is in this group

    • The name "list_public_menus" says "list": a word for reading.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • menu_auditList the active products of your restaurant that lack a usable description, an image, or an allergen declaration.No findings

    Why it is in this group

    • The description's first verb is "list": a word for reading.
    Description, as the server wrote it
    List the active products of your restaurant that lack a usable description, an image, or an allergen declaration. Read-only; nothing is changed.

    Annotations the server declares

    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • search_productsSearch products inside a single restaurant by keyword.No findings

    Why it is in this group

    • The name "search_products" says "search": a word for reading.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • search_restaurantsSearch the public directory (opt-in venues only) by location, opening status, cuisine, dietary options, declared attributes, ordering channel, declared price level and menu languag…No findings

    Why it is in this group

    • The name "search_restaurants" says "search": a word for reading.
    Description, as the server wrote it
    Search the public directory (opt-in venues only) by location, opening status, cuisine, dietary options, declared attributes, ordering channel, declared price level and menu language — and, right now, a free table or an open waitlist (the restaurant graph's channel states). Neutral ranking (AI-K6): distance in 0.5 km bands when `near` is given → availability (open now first; unknown hours before closed; a venue in holiday mode counts as closed) → profile freshness (owner-verified within 90 days first) → name. Payment to Thmenu never affects order. Cuisine, dietary, price level and other attributes are owner declarations, not verified facts; venues without a declaration are excluded only when an attribute or price 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; false while the venue is in holiday mode), channels (order · reservation · pickup · delivery), declared attributes, freshness and the menu URL. Paginated.

    Annotations the server declares

    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false

This is not a safety rating, and no finding is not a safety guarantee. The groups and findings come from fixed checks of the tool definitions the server returned on the date shown, not from its code or what it does when called. How the checks work.

Install

Pinned to version 0.5.0. Values in angle brackets are yours to fill in.

claude mcp add --transport http thmenu https://mcp.thmenu.com/

Run in a terminal.

Claude Code permissions

Allow the reads, ask before a change, deny the deletes. Paste into .claude/settings.json.

.claude/settings.json
{
  "permissions": {
    "allow": [
      "mcp__thmenu__get_pricing",
      "mcp__thmenu__get_faq",
      "mcp__thmenu__get_restaurant",
      "mcp__thmenu__search_products",
      "mcp__thmenu__list_public_menus",
      "mcp__thmenu__search_restaurants",
      "mcp__thmenu__get_order_status",
      "mcp__thmenu__get_restaurant_menu",
      "mcp__thmenu__get_cart",
      "mcp__thmenu__get_reservation_slots",
      "mcp__thmenu__menu_audit"
    ],
    "ask": [
      "mcp__thmenu__start_order_session",
      "mcp__thmenu__place_order",
      "mcp__thmenu__request_bill",
      "mcp__thmenu__waiter_call",
      "mcp__thmenu__check_loyalty",
      "mcp__thmenu__apply_promo",
      "mcp__thmenu__join_loyalty",
      "mcp__thmenu__create_cart",
      "mcp__thmenu__request_reservation",
      "mcp__thmenu__sales_summary",
      "mcp__thmenu__reservation_summary",
      "mcp__thmenu__draft_product_description",
      "mcp__thmenu__draft_site_text",
      "mcp__thmenu__draft_translation"
    ],
    "deny": [
      "mcp__thmenu__cancel_order",
      "mcp__thmenu__cancel_reservation"
    ]
  }
}

Tools that only read are allowed, tools that change things ask first, tools that delete or cancel are denied. It assumes the server is installed as thmenu. Review it before you use it.