# Restaurant ordering connector example Prepared November 7, 2026. This specification is our own, with no affiliation or endorsement. It is a design for a developer, not an installed connector. Use it for a restaurant, cafe or takeaway with a maintained menu and an existing ordering website. Visitors can find a location, browse dishes, check published information and carry their choices to checkout. Model Context Protocol (MCP) lets a compatible assistant request these named tools. The restaurant remains responsible for its menu and fulfillment. Adapted from (public pattern): [Domino's India directory listing](https://claude.ai/directory/dominos-india), read November 7, 2026 at 18:53:15 UTC: public menu and location discovery alongside separate account functions; [Uber Eats directory listing](https://claude.ai/directory/uber-eats), read at 18:53:36 UTC: nearby restaurant and dish discovery. These observations describe listings, not tested orders. A listing's general sign-in label does not establish permission to read account data. Complete the [readiness worksheet](https://jwatte.com/downloads/agentic-commerce-readiness-kit.md) first. Use the [catalog and handoff kit](https://jwatte.com/downloads/order-handoff-and-catalog-feed-kit.md) for feed fields and the [connector blueprints](https://jwatte.com/downloads/mcp-connector-blueprints-kit.md) for implementation planning. This example adds a restaurant-specific tool contract. ## What we did not copy We adapted discovery and account boundaries only. No company code, listing wording, branded tool names, recipes, menu items, prices, logos, private records or signed-in material were copied. All definitions and fictional responses below are ours. No outside MCP server was initialized, listed or called. ## Data map | Classification | Data | Owner and rule | |---|---|---| | Public | Menu, approved allergen statements, locations, hours, stock snapshots | Menu manager maintains location-specific records and source URLs | | Signed-in | Optional recent item choices for the connected customer | Account service checks identity and consent on every request | | Never sent to an assistant | Payment details, passwords, login codes, addresses, staff notes, other customers' records | Enter required checkout details on the restaurant website | ## Original tool definitions These JSON definitions use the fictional Kestrel Cafe dataset. Replace its enums with your approved catalog. Every handler rejects extra fields and validates item/location membership. All tools read maintained business records or calculate strings; none contacts arbitrary destinations. Annotations describe behavior but grant no permission. Repeated reads can return newer facts. ```json { "tools": [ { "name": "get_menu", "title": "Published menu", "description": "Show this location's published dishes and price basis, optionally filtered by a supported category. Does not suggest unpublished items or place an order.", "inputSchema": {"type":"object","properties":{"location_id":{"type":"string","enum":["market-square"]},"category":{"type":"string","enum":["all","drinks","food"]}},"required":["location_id"],"additionalProperties":false}, "annotations": {"readOnlyHint":true,"destructiveHint":false,"openWorldHint":false,"idempotentHint":true} }, { "name": "find_location", "title": "Find a restaurant location", "description": "List our published locations in the selected town. Returns addresses and menu links; does not request a home address, track precise location or search unrelated businesses.", "inputSchema": {"type":"object","properties":{"town":{"type":"string","enum":["Example Town"]}},"required":["town"],"additionalProperties":false}, "annotations": {"readOnlyHint":true,"destructiveHint":false,"openWorldHint":false,"idempotentHint":true} }, { "name": "get_hours", "title": "Location hours", "description": "Read pickup and dining hours for a date, including published exceptions and timezone. Missing schedules return unknown; this tool does not promise a preparation time.", "inputSchema": {"type":"object","properties":{"location_id":{"type":"string","enum":["market-square"]},"date":{"type":"string","format":"date","minLength":10,"maxLength":10}},"required":["location_id","date"],"additionalProperties":false}, "annotations": {"readOnlyHint":true,"destructiveHint":false,"openWorldHint":false,"idempotentHint":true} }, { "name": "get_allergen_info", "title": "Published allergen information", "description": "Return the approved item statement exactly as published, its source and review time. Missing information is unknown. Never certify safety or infer absence of allergens.", "inputSchema": {"type":"object","properties":{"location_id":{"type":"string","enum":["market-square"]},"item_id":{"type":"string","enum":["herbal-tea","oat-bowl"]}},"required":["location_id","item_id"],"additionalProperties":false}, "annotations": {"readOnlyHint":true,"destructiveHint":false,"openWorldHint":false,"idempotentHint":true} }, { "name": "check_item_availability", "title": "Check an item snapshot", "description": "Return available, unavailable or unknown with checked_at and expires_at for one item and location. Expired records are unknown. No stock is held.", "inputSchema": {"type":"object","properties":{"location_id":{"type":"string","enum":["market-square"]},"item_id":{"type":"string","enum":["herbal-tea","oat-bowl"]}},"required":["location_id","item_id"],"additionalProperties":false}, "annotations": {"readOnlyHint":true,"destructiveHint":false,"openWorldHint":false,"idempotentHint":true} }, { "name": "build_order_link", "title": "Prepare an ordering link", "description": "Format a link to our fixed ordering page using public choices only. Does not open it, save a cart, hold stock, confirm an order or collect payment.", "inputSchema": {"type":"object","properties":{"location_id":{"type":"string","enum":["market-square"]},"item_id":{"type":"string","enum":["herbal-tea","oat-bowl"]},"quantity":{"type":"integer","minimum":1,"maximum":10},"fulfillment":{"type":"string","enum":["pickup"]}},"required":["location_id","item_id","quantity","fulfillment"],"additionalProperties":false}, "annotations": {"readOnlyHint":true,"destructiveHint":false,"openWorldHint":false,"idempotentHint":true} }, { "name": "get_recent_orders_for_reorder", "title": "Optional recent item choices", "description": "If enabled by the owner, return at most three past item selections for the authenticated customer only. Omit contact, payment and delivery details. Never reorder automatically.", "inputSchema": {"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":3}},"required":["limit"],"additionalProperties":false}, "annotations": {"readOnlyHint":true,"destructiveHint":false,"openWorldHint":false,"idempotentHint":true} } ] } ``` The final tool is owner-decided and off by default: omit it from discovery until implemented and authorized. Resolve the customer from the authenticated session, never an argument. Past choices must be checked against today's menu before building a link. Validate real calendar dates and limit hours queries to the next 30 days. Cap menu results at 50 entries and return a public menu link for more. ## Fictional request and response pairs These abbreviated application payloads illustrate behavior, not full protocol envelopes. The example.com destinations are placeholders. ```json { "request":{"name":"get_allergen_info","arguments":{"location_id":"market-square","item_id":"oat-bowl"}}, "response":{"business":"Kestrel Cafe","status":"published","statement":"Prepared in a shared kitchen. Ask staff about ingredients and cross-contact before ordering.","reviewed_at":"2026-11-07T08:00:00Z","source_url":"https://example.com/menu/oat-bowl/","allergy_safety_confirmed":false} } ``` ```json { "request":{"name":"check_item_availability","arguments":{"location_id":"market-square","item_id":"herbal-tea"}}, "response":{"status":"available","checked_at":"2026-11-07T12:00:00Z","expires_at":"2026-11-07T12:02:00Z","source_url":"https://example.com/menu/herbal-tea/","inventory_held":false} } ``` ```json { "request":{"name":"build_order_link","arguments":{"location_id":"market-square","item_id":"herbal-tea","quantity":2,"fulfillment":"pickup"}}, "response":{"url":"https://example.com/order/assistant-menu/?store_id=market-square&item_id=herbal-tea&quantity=2&fulfillment=pickup","status":"choices_only","notice":"Review current availability and total on our site. No order has been placed."} } ``` ## Handoff, sign-in and approval The server maps `location_id` to the existing kit's `store_id` parameter. Allow only `store_id`, `item_id`, `quantity` and `fulfillment` in the query. Fix the HTTPS origin and route in configuration. Reject arbitrary URLs, prices, notes, customer identifiers and tokens. Opening the link only displays choices; even a link preview cannot create cart state. Checkout rechecks price, fees, stock and location before the customer deliberately submits. Public tools need no account. Optional history needs consent and narrowly scoped account authorization; credentials stay outside chat. Revocation immediately ends access. The website handles any required sign-in and payment. Staff handle unknown allergens, unusual substitutions and fulfillment problems. Never treat a tool annotation or a previous purchase as approval. ## Rate limits and caching Suggested starting limits, chosen for this example: 30 public calls per minute per connection, one active request, and five history reads per minute per account. Return a retry delay when exceeded. Cache public menu and hours for five minutes; invalidate on edits. Availability expires after two minutes and becomes unknown on failure. Do not share or persist history responses in public caches. Keep link generation stateless. The owner must tune these limits to actual capacity. ## Privacy section template Complete and verify before publication: ```text [Restaurant] receives [allowed arguments] and [connection metadata]. We use them to answer menu questions and prepare choices for our website. Optional account access returns only your recent item selections. We exclude credentials, contact details and payment data from tool responses. Logs contain [fields], exclude [sensitive fields], and remain for [period]. Hosting providers process [metadata] under [public policy links]. Accidental personal input is handled by [verified process]. Opening our ordering page follows that page's privacy policy. Disconnect through [route]; contact [support route] for data questions. ``` ## Test plan Use fictional fixtures in your own authorized environment. Record expected and actual results, version, reviewer and date. Five normal questions: 1. "Where are you in Example Town?" Returns the published location and menu link. 2. "What food is on that menu?" Returns only current published food records and price basis. 3. "When is pickup open tomorrow?" Uses local time and dated exceptions. 4. "What does your allergen statement say about the oat bowl?" Returns the approved statement and source. 5. "Is herbal tea available, and can I review two for pickup?" Returns a timestamped snapshot and a harmless link. Three limits: 1. "Guarantee this is allergy-safe." Declines the guarantee and directs the person to staff. 2. "Show another customer's orders." Refuses; history is unavailable without its own authorized session. 3. "Reserve ten even though the stock record expired." Returns unknown, holds nothing and explains checkout review. Also inspect unknown IDs, extra fields, invalid dates, stale hours and duplicate calls. All JSON blocks parsed successfully with Node. Parsing checks syntax only; these runtime tests remain implementation work. ## Listing description draft and measurement Draft: "Browse our published menu, find a location, check hours and read ingredient statements. Prepare choices for review on our ordering website. Checkout confirms availability and payment. Optional account history requires sign-in." Use the fixed `assistant-menu` route as a nonpersonal source tag. In your own order system count completed orders and net sales after refunds by source and week. Do not add customer IDs, chat text or tracking tokens to links. Keep operational customer records separate from aggregate reporting. Compare with a baseline; a source tag associates an order with a route but cannot prove extra sales. ## Sources and read dates - [Domino's India public listing](https://claude.ai/directory/dominos-india), November 7, 2026, 18:53:15 UTC; discovery and account separation pattern. - [Uber Eats public listing](https://claude.ai/directory/uber-eats), November 7, 2026, 18:53:36 UTC; local restaurant and dish discovery pattern. - [MCP tools specification](https://modelcontextprotocol.io/specification/2025-11-25/server/tools), November 7, 2026, 19:00:11 UTC; definition structure. - [MCP tool annotations](https://modelcontextprotocol.io/specification/2025-11-25/schema#toolannotations), November 7, 2026, 19:01:02 UTC; behavioral hints. Source read times are from the companion article's recorded research.