# Objednávka obědů – MCP server reference

> Machine-readable reference of the Objednávka obědů MCP server: a remote MCP server that lets an AI assistant act as one signed-in diner of a Czech canteen ordering system (menus, orders, payments, messages, profile) under the same rules as the diner's mobile app. This MCP server is in BETA.

Generated live from the server's tool registry (45 tools). Human documentation (Czech): https://www.objednavkaobedu.cz/dokumentace/ai-asistent-mcp/ · Site index for LLMs: https://www.objednavkaobedu.cz/llms.txt

## Connection

- Endpoint: https://www.objednavkaobedu.cz/mcp
- Transport: Streamable HTTP, JSON-RPC 2.0, MCP protocol version `2025-06-18`. POST only, single `application/json` response (no SSE stream; GET returns 405). Stateless: no `Mcp-Session-Id`.
- Methods: `initialize`, `ping`, `tools/list`, `tools/call`. `initialize` returns `serverInfo.name` = `objednavka-obedu-mcp` and the operating instructions below.
- Every request carries `Authorization: Bearer <access token>`. Browser requests with an `Origin` header must come from an allowed origin.
- Canteens on their own (white-label) domain are still reached through this endpoint.

## Authorization (OAuth 2.1)

- Protected resource metadata (RFC 9728): https://www.objednavkaobedu.cz/.well-known/oauth-protected-resource/mcp
- Authorization server metadata (RFC 8414): https://www.objednavkaobedu.cz/.well-known/oauth-authorization-server
- Authorize: https://www.objednavkaobedu.cz/mcp-oauth/authorize · Token: https://www.objednavkaobedu.cz/mcp-oauth/token · Revoke (RFC 7009): https://www.objednavkaobedu.cz/mcp-oauth/revoke
- Dynamic client registration (RFC 7591): POST https://www.objednavkaobedu.cz/mcp-oauth/register, public client without secret.
- Grants: `authorization_code` with mandatory PKCE `S256`, and `refresh_token` (rotating; reuse of a spent refresh token revokes the connection). Send `resource` = the endpoint URL.
- Disconnection: the diner can disconnect a client (or all) in their web profile, and any password change (web, mobile app, administrator, `change_password`) disconnects every client at once – access tokens stop working immediately (401 `invalid_token`) and refresh tokens issued before the change are refused; the user must sign in again.
- Lifetimes: authorization code 10 min, access token 1 hour (JWT RS256), refresh token 30 days.
- The diner signs in on the server's own login page and approves the requested scopes. No password ever goes through the AI client.
- No / invalid / expired token, or a blocked or unapproved account: HTTP 401 with `WWW-Authenticate: Bearer resource_metadata="…"`.

## Scopes

`tools/list` shows only tools the token's scopes allow. Calling a tool without its scope: HTTP 403, JSON-RPC error `-32002` with `data.required_scope` and `WWW-Authenticate: Bearer error="insufficient_scope", scope="…"` (step-up: re-authorize with the wider scope; a refresh does not add scopes).

| Scope | Consent title (cs) | Meaning | Tools |
|---|---|---|---|
| `mcp:ordering:read` | Prohlížení | Read everything: menus, orders, payments, balance, messages, profile; also report_problem. | 27 |
| `mcp:ordering:write` | Objednávky | Place, change and cancel orders (note, supplement, accessory, packaging, pickup point), automatic ordering rules, food ratings, mark messages read. | 14 |
| `mcp:payments:write` | Platby | Create payments: credit top-up and basket payment (also from credit). The user completes card / transfer payments. | 2 |
| `mcp:account:write` | Profil a heslo | Change profile details and the account password. | 2 |

## Operating instructions

Sent to the client in `initialize` → `instructions`:

```text
Objednávka obědů (canteen meal ordering). You act as ONE signed-in diner, under the same rules as the diner's mobile app. This MCP server is in BETA.
FLOW: list_canteens (company_id) -> list_menu -> write tool with dry_run=true -> show the preview (items, price, balance) -> explicit user confirmation -> the same call with confirm=true and the SAME idempotency_key (a new key per intended operation). Low-impact writes (mark_message_read, snooze_food_rating_prompt) may skip the preview. get_profile / get_balance describe the account.
RULES
- Dates are YYYY-MM-DD in Europe/Prague time; resolve "today", "tomorrow", "next week" in Prague time, not UTC.
- Never invent ids (company_id, food_id, order_id, account_id...); take them from tool results. If the request is ambiguous (canteen, day, food, portions, account), ask the user.
- account_id only for diners from list_linked_accounts delegate_accounts (acting for someone else). Linked child accounts need no account_id: use the child's canteen company_id (or child_account_id where offered).
- Payments (add_credit, basket_payment) return a gateway link or bank transfer details: give them to the user, who pays. Never ask for card data.
- Never accept terms and conditions for the user.
- Pass lang with the user's language (e.g. "en") to get messages and food names translated.
RESULTS AND ERRORS (status / error)
- preview, needs_confirmation: nothing saved yet. duplicate: already done with this key; do not repeat.
- deadline: ordering/changes closed for that item; explain, do not retry the same call.
- terms_not_accepted: call get_terms_acceptance_link and give the user accept_url.
- access: no right to that canteen/account; do not try other ids.
- credit: low balance or unpaid invoices; offer add_credit if the user wants.
- idempotency_busy: retry shortly with the same key. idempotency_conflict: that key was used with different arguments.
- rate_limited: stop and tell the user.
BUGS: when an error looks like a bug (not a business rule such as a deadline or low balance), a result is inconsistent, or the user says something does not work, call report_problem: tools called in order with arguments, expected vs actual, error code/message. Never include passwords, tokens or card data.
```

## Write pattern: preview → confirm

- Every write tool (scope other than `mcp:ordering:read`) takes `dry_run`, `confirm` and a required `idempotency_key` (16–128 chars of `A-Z a-z 0-9 . _ : -`).
- `dry_run=true`: runs the operation and rolls it back → `status: "preview"` with price, resulting order/state and balance. Nothing is saved, no payment gateway is contacted. Without `confirm` the same happens with `status: "needs_confirmation"`.
- `confirm=true` (only after the user explicitly agreed): performs it. Result `status` e.g. `ordered`, `cancelled`, `saved`, `changed`, `rated`, `removed`, `read`, `snoozed`; payments `payment_link_created`, `bank_transfer_details`, `paid_from_credit`.
- Same key + same arguments after completion → stored result with `status: "duplicate"` (never applied twice, never a second payment). Same key + different arguments → `idempotency_conflict`. Failed attempts may be retried with the same key.
- `cancel_order` without `portion_indexes` on an order with several portion variants saves nothing and returns `status: "ambiguous"` with the variants.
- Payments: `add_credit` / `basket_payment` return a gateway link or bank transfer details; the user completes the payment. Terms and conditions cannot be accepted through MCP.

## Results and errors

- Tool result: `content[0]` is the JSON text of `structuredContent`; PDF tools add an embedded resource (base64). `isError` marks a business error.
- Business error: HTTP 200, `isError: true`, `structuredContent` = `{error, message, detail?, beta, report}` — `error` is a stable code, `detail` the original message of the canteen system in `lang`.
- Protocol errors (JSON-RPC): `-32700` invalid JSON, `-32600` invalid request, `-32601` unknown method, `-32602` unknown tool or arguments not matching the tool's inputSchema, `-32603` internal error, `-32001` unauthorized (HTTP 401), `-32002` missing scope (HTTP 403).

| error | Meaning / what to do |
|---|---|
| `deadline` | The ordering / change deadline for that item has passed. Explain it; do not retry the same call. |
| `credit` | Balance too low or unpaid invoices. The user may top up (add_credit) or settle first. |
| `access` | No access to that canteen, account or delegate (acting for someone else). Do not try other ids. |
| `terms_not_accepted` | The diner must accept the terms first: get_terms_acceptance_link, give the user accept_url. Never accept for them. |
| `soup_limit` | More soups than main courses are not allowed. |
| `permanent_offer_date_required` | A permanent-offer item needs date_on (YYYY-MM-DD). |
| `invalid_date` | Invalid date; use YYYY-MM-DD. |
| `range_too_large` | Date range too large (max 31 days). |
| `invalid_indexes` | Invalid portion_indexes (see cancel_options). |
| `invalid_arguments` | Arguments rejected by the tool (e.g. unsupported lang, nothing to change). |
| `not_found` | No matching order or record (or it does not belong to the diner). |
| `rule_not_found` | No automatic ordering rule with that id (see list_auto_orders). |
| `message_not_found` | Message not found (see list_messages). |
| `document_not_found` | Document does not exist or is not accessible for this account. |
| `not_rateable` | This food can no longer be rated (see list_food_ratings). |
| `current_password_required` | change_password needs current_password. |
| `invalid_current_password` | current_password is not correct. |
| `idempotency_conflict` | This idempotency_key was already used with different arguments; use a new key for a different operation. |
| `idempotency_busy` | The same operation (same key) is running right now; retry shortly with the same key. |
| `too_large` | The PDF is too large to return (limit 5 MB); for conditions use format "text". |
| `rate_limited` | Limit exceeded (problem reports). Stop and tell the user. |
| `rejected` | Refused by another business rule of the canteen; the reason is in message / detail. Explain it to the user. |
| `error` | Unexpected failure. Retry once later; if it persists, report_problem. |

## Limits

- Date ranges (`from`/`to`): max 31 days. Dates are `YYYY-MM-DD` in the Europe/Prague time zone.
- PDF results: max 5 MB.
- `report_problem`: 10 reports per hour per diner (200 per hour in total).
- Dynamic client registration: 60 per hour per IP address.
- Everything else follows the canteen's own rules (deadlines, credit, order limits), exactly as in the mobile app.

## BETA and problem reports

This MCP server is in BETA. If this looks like a bug or unexpected behaviour (not an ordinary business rule such as a passed deadline or low balance), call the report_problem tool: say which tools you called in which order and with which arguments (no passwords or payment data), what you expected, what happened and the error code/message you received. The report has no effect on orders or the account and returns a `report_id` for the user.

## Common parameters

Parameters shared by many tools with identical meaning; tool entries below list them by name only.

- `account_id` (integer, ≥1): Act on behalf of another diner (delegate / "zástup"), exactly like account switching in the mobile app. Omit for the user's own account. Allowed only when the user may act for that account (same rules as the mobile app).
- `company_id` (integer, ≥1): Canteen (menu list) id.
- `confirm` (boolean): Must be true to actually perform the change (after the user confirmed the preview).
- `date_on` (string, pattern `^\d{4}-\d{2}-\d{2}$`): Required for permanent-offer items.
- `deadline_mode` (string, one of `soft` | `hard`): Ordering deadline mode like the mobile app switch: "soft" (default, regular deadline) or "hard" (after the soft deadline, only where the canteen allows it).
- `dry_run` (boolean): Preview only: runs the operation and rolls it back, nothing is saved.
- `food_id` (integer, ≥1): Ordered food id.
- `idempotency_key` (string, 16–128 chars, pattern `^[A-Za-z0-9._:-]+$`): Stable unique key per intended operation; retries with the same key never apply twice.
- `lang` (string, pattern `^[A-Za-z]{2}([_-][A-Za-z]{2})?$`): Language of texts returned by the canteen system (messages, errors, translated food names), e.g. "en", "de", "sk", "uk" or "cs_CZ". Must be a language the system supports (an unsupported one returns invalid_arguments). Omit to use the diner's language from their profile.

## Tools

### Scope `mcp:ordering:read` (read)

#### basket_credit_preview

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

For an e-shop canteen (pay-before-order basket): how the basket total will be paid - basketTotal, how much the user's available credit covers (creditToApply) and what remains to pay via a payment method (amountToPay), computed by the same server code as the actual payment. Call this before basket_payment to tell the user the amount; if amountToPay is 0 the basket is paid entirely from credit. Use basket_food to see the basket items.

Parameters:
- `company_id` (integer, ≥1, **required**): E-shop canteen (menu list) id.

Common parameters: `account_id`, `lang`

#### basket_food

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

Show the unpaid basket of an instant-payment (e-shop) canteen: foods added with place_order, amounts, prices and remaining time to pay (remaining, ms). Call this when the user asks what is in the basket.

Common parameters: `company_id` (required), `account_id`, `lang`

#### cancel_options

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

List the distinct portions (variants by supplement / accessory / packaging) of an ordered food with their portion indexes. Call this before cancel_order when the user wants to cancel only some portions, or before set_supplement / set_accessory / set_packaging to find the portion index. Empty variants = nothing ordered (or an e-shop basket canteen).

Common parameters: `company_id` (required), `food_id` (required), `date_on`, `account_id`, `lang`

#### credit_movements

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

Show the user's credit account for a year - current credit balance and credit movements (top-ups, refunds for cancelled e-shop orders, basket payments from credit) - the "Credit account" section of the mobile app. Call this when the user asks where their credit went or whether a top-up / refund arrived. child_account_id shows a linked child account; account_id a diner the user acts for (delegate, needs history permission).

Parameters:
- `year` (integer, 2000–2100): Calendar year (default: current year).
- `child_account_id` (integer, ≥1): Linked child account (profile childAdmins) whose payments to list.

Common parameters: `account_id`, `lang`

#### get_balance

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

Show the user's current credit balance and payment mode (and balances of linked child accounts). Call this when the user asks about their balance or whether they can afford an order. Pass account_id for a diner the user acts for (delegate).

Common parameters: `account_id`, `lang`

#### get_canteen_info

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

Show details of a canteen (menu list): name, address, ordering deadlines (soft/hard, incl. the user's pickup-point override), support contacts, payment flags (allow_payments, instant/basket payments, e-shop credit), whether notes are allowed, info text. Without company_id returns the user's default canteen. Use list_canteens to find company_id.

Parameters:
- `company_id` (integer, ≥1): Canteen (menu list) id; omit for the default canteen.

Common parameters: `lang`

#### get_conditions_document

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

Get the terms and conditions ("terms") or the privacy policy ("gdpr") of the catering organization, the same document as in the mobile app. format "pdf" (default) returns an embedded PDF resource (base64) - call only when the user wants the file; format "text" returns plain text for answering questions about the document. parent_company_id defaults to the user's organization (use get_organization_info / list_linked_accounts for others).

Parameters:
- `type` (string, one of `terms` | `gdpr`, **required**): "terms" = terms and conditions, "gdpr" = privacy policy.
- `format` (string, one of `pdf` | `text`): "pdf" (default) or "text".
- `parent_company_id` (integer, ≥1): Organization id; omit for the user's own organization.

Common parameters: `lang`

#### get_important_message

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

Get the newest unread IMPORTANT message that the mobile app would show in a pop-up (message = null when there is none). Good to call at the start of a conversation and tell the user about it; once the user has seen it, call mark_message_read (after that this tool stops returning it; the pop-up in the app and on the web stays until the user confirms it there). Own account only.

Common parameters: `lang`

#### get_message

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

Get the full text of one message from list_messages (subject, HTML and plain body, important flag, read state), in the user's language like the mobile app. It does NOT mark the message as read - after you actually showed it to the user, call mark_message_read. Own account only.

Parameters:
- `message_id` (integer, ≥1, **required**): Message id (list_messages id).

Common parameters: `lang`

#### get_organization_info

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

Show the catering organization (provider / "firma") of the account: name, contact, invoicing identity and enabled features (payments, automatic orders, messaging, food rating, delegate switching, terms documents, locked delivery details). Call when the user asks who runs the canteen, how to contact them, or whether a feature is available. Pass child_account_id for a linked child account (from list_linked_accounts child_accounts) or account_id for a delegate.

Parameters:
- `child_account_id` (integer, ≥1): Linked child account id (list_linked_accounts child_accounts).

Common parameters: `account_id`, `lang`

#### get_profile

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

Show the diner's profile: name, contact, delivery and invoicing details, pickup point and the pickup points they may choose, payment mode, balance, notification settings, flags (need_change_password, force_accept_terms, terms_acceptance_required - if true, use get_terms_acceptance_link; never accept terms for the user, is_locked) and linked child accounts. Call before update_profile (to show current values) or when the user asks about their account. For just the balance use get_balance. Pass account_id for a diner the user acts for (delegate). "summary" is a compact overview, "profile" the editable details (same fields as update_profile) and selectable_pickup_points.

Common parameters: `account_id`, `lang`

#### get_terms_acceptance_link

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

Check whether the diner must accept the canteen's terms and conditions / privacy policy, and get a link to the web page where the diner accepts them. You (the AI) can NEVER accept the terms on the diner's behalf: if "terms_acceptance_required" is true, show the "accept_url" to the user and ask them to open it, log in themselves and accept. The link contains no login credentials. Read the documents themselves with get_conditions_document. Works only for the user's own account.

Common parameters: `lang`

#### list_accessible_canteens

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

Lightweight list (id + name) of all canteens (menu lists) of the user's own account, as the mobile app uses it for filters (messages, notification settings per canteen). For ordering use list_canteens, which returns the ordering settings and child-account canteens.

Common parameters: `lang`

#### list_auto_orders

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

List the user's automatic ordering rules on a canteen, like the "Automatic orders" screen of the mobile app. Each rule orders, every week on day_in_week (1 = Monday ... 7 = Sunday), the food_order-th food (1 = first on the menu) of food_type (1 lunch, 2 soup, 3 breakfast, 4 dinner, 6 morning snack, 7 afternoon snack, 8 second dinner, 9 salad, 10 dessert, 11 starter, 12 specialty), amount portions. Call before add_auto_order / cancel_auto_order (rule id). Pass account_id for a diner the user acts for (delegate).

Common parameters: `company_id` (required), `account_id`, `lang`

#### list_canteens

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

List the canteens (menu lists) the user can order from - the same list as the mobile app, including canteens of linked child accounts. Call this first to get company_id for list_menu / place_order, or when the user asks where they can order. Pass account_id to list canteens of a diner the user acts for (delegate).

Common parameters: `account_id`, `lang`

#### list_food_ratings

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

List the foods the user ate recently and can rate (the rating window of the last daysBack days, up to yesterday), with the user's current stars/comment (null = not rated yet) and pendingCount of unrated foods, like the ratings screen of the mobile app. Call this before rate_food / remove_food_rating to get food_id and date_on. Empty when the canteen does not use food rating. Own account only (ratings are personal, no account_id).

Common parameters: `lang`

#### list_linked_accounts

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

List the accounts the user can switch to, like the account switcher in the mobile app. "delegate_accounts" are diners the user may act for (delegate / "zástup"): pass their account_id to other tools (list_menu, place_order, get_profile, ...) to act on their behalf - there is no session switch, every call carries account_id. "child_accounts" are linked accounts (e.g. children) - they need no account_id, tools pick them automatically by the canteen company_id. Call when the user wants to order or check something for someone else.

Common parameters: `lang`

#### list_menu

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

Show the food menu of a canteen over a date range (max 31 days), like the mobile app: per day whether ordering is open (can_order, deadline, blocked), the foods (food_id, type_name, name, price, allergen codes, can_order), the choices for ordered portions (supplement_choices, accessory_choices, packaging_choices), what the user already ordered (ordered_amount, ordered_portions grouped by variant with portion indexes for set_* / cancel_order; can_cancel stays true when only cancelling is allowed) and permanent-offer availability and orders. On an instant-payment (e-shop) canteen (instant_payments=true) ordered_amount is the unpaid basket and purchased_amount the paid portions (cancel those with cancel_purchased). Call this when the user asks what food is available. Use list_canteens first to get company_id. Days are keyed by date (YYYY-MM-DD). Pass account_id when acting for another diner (delegate).

Parameters:
- `company_id` (integer, ≥1, **required**): Canteen (menu list) id from list_canteens.
- `from` (string, pattern `^\d{4}-\d{2}-\d{2}$`, **required**): First day (YYYY-MM-DD).
- `to` (string, pattern `^\d{4}-\d{2}-\d{2}$`, **required**): Last day (YYYY-MM-DD), at most 31 days after from.

Common parameters: `deadline_mode`, `account_id`, `lang`

#### list_messages

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

List messages sent to the user by the canteen / company (inbox, newest first) with a short preview, read flag and the unread count, like the messages screen of the mobile app. Listing does NOT mark anything as read; use get_message for the full text. Own account only (no account_id).

Parameters:
- `limit` (integer, 1–100): Page size (default 20).
- `offset` (integer, ≥0): Paging offset (default 0).

Common parameters: `lang`

#### list_payments

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

List the user's payment documents for a year - the "Payments" screen of the mobile app (invoices, receipts, top-ups, credit notes; price, variable symbol, paid state, document availability). Call this when the user asks about invoices, what they paid or what is unpaid. In e-shop canteens the credit movements (top-ups, refunds, basket payments from credit) are listed by credit_movements instead. A row with avaibleDocument=true can be downloaded with payment_document (payment id = id). child_account_id lists a linked child account; account_id a diner the user acts for (delegate, needs history permission).

Parameters:
- `year` (integer, 2000–2100): Calendar year (default: current year).
- `child_account_id` (integer, ≥1): Linked child account (profile childAdmins) whose payments to list.

Common parameters: `account_id`, `lang`

#### menu_pdf

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

Download the printable weekly menu (PDF) of a canteen for the week containing the given date, the same file as "PDF" in the mobile app. Returned as an embedded PDF resource (base64). Call only when the user wants the file; for answering questions about the menu use list_menu.

Parameters:
- `date` (string, pattern `^\d{4}-\d{2}-\d{2}$`, **required**): Any day of the week (YYYY-MM-DD).

Common parameters: `company_id` (required), `lang`

#### order_fee_rules

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

List the order fee rules that apply to the user (e.g. a delivery / small-order fee: feePrice is charged when the order value is between priceFrom and priceTo, valid dateFrom-dateTo), like the mobile app. Call when the user asks why a fee was charged or before placing a small order. Empty rules = no fees. Own account only.

Common parameters: `lang`

#### order_history

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

List the user's orders over a date range (max 31 days) - the mobile app's order overview: per day the orders (order_id, canteen, food, amount, unit and total price, portions grouped by supplement/accessories/packaging, pickup point, customer note, rating; is_fee marks service/delivery fees, is_compensation employer-contribution rows). Call this when the user asks what they have ordered. Optional company_id narrows to one canteen. child_account_id shows a linked child account's orders; account_id a diner the user acts for (delegate, needs history permission).

Parameters:
- `from` (string, pattern `^\d{4}-\d{2}-\d{2}$`, **required**): First day (YYYY-MM-DD).
- `to` (string, pattern `^\d{4}-\d{2}-\d{2}$`, **required**): Last day (YYYY-MM-DD), at most 31 days after from.
- `company_id` (integer, ≥1): Only orders of this canteen.
- `child_account_id` (integer, ≥1): Linked child account (profile childAdmins) whose orders to list.

Common parameters: `account_id`, `lang`

#### payment_document

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

Download the PDF document (invoice / receipt / credit note) of one payment, the same file as in the mobile app's Payments screen. Only payments of the user or their linked child accounts that have a document (avaibleDocument=true in list_payments). Returned as an embedded PDF resource (base64). Call only when the user wants the file; for amounts and states use list_payments.

Parameters:
- `payment_id` (integer, ≥1, **required**): Payment id (id from list_payments).

Common parameters: `lang`

#### permanent_offer_catalog

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

List the permanent offer (items orderable every day, e.g. salads, drinks) of a canteen for a given day, grouped by category, with prices and whether each item can still be ordered (canOrder, deadlines). Call this when list_menu shows permanent_offer for a day or the user asks for permanent-offer items; then order with place_order including date_on.

Parameters:
- `company_id` (integer, ≥1, **required**): Regular canteen (menu list) id from list_canteens.
- `date_on` (string, pattern `^\d{4}-\d{2}-\d{2}$`, **required**): Day to order for (YYYY-MM-DD).

Common parameters: `deadline_mode`, `account_id`, `lang`

#### report_problem

read · scope `mcp:ordering:read` · annotations: readOnlyHint=false, destructiveHint=false, idempotentHint=false, openWorldHint=false

Report a problem with this MCP server to its developers (the service is in BETA). Use it after a tool returned an error that looks like a bug (not an ordinary business rule such as a passed deadline or low balance), after an unexpected or inconsistent result, or when the user complains that something does not work. Describe how you caused it: which tools you called in which order with which arguments, what you expected and what actually happened, and the error code/message you received. Never include passwords, tokens, card numbers or other payment data. Has no effect on orders or the account; returns a report_id you can give to the user. Limited to 10 reports per hour.

Parameters:
- `summary` (string, 3–200 chars, **required**): One-line summary of the problem.
- `steps` (string, 3–4000 chars, **required**): What you did, in order: tools called, their arguments (without secrets) and the results that matter.
- `expected` (string, 1–1000 chars, **required**): What you expected to happen.
- `actual` (string, 1–1000 chars, **required**): What actually happened.
- `error_code` (string, 1–64 chars): Error code received (e.g. the "error" field of the tool result or the JSON-RPC error code), if any.
- `error_message` (string, 1–1000 chars): Error message received, if any.
- `related_tool` (string, pattern `^[a-z0-9_]{1,64}$`): Name of the tool that misbehaved, if one.
- `request_ids` (array of string, 1–128 chars, ≤10 items): Related identifiers (idempotency keys, order/payment ids, JSON-RPC ids), if any.
- `severity` (string, one of `low` | `medium` | `high` | `critical`): low = cosmetic, medium = wrong/unclear result (default), high = user cannot complete a task, critical = wrong money/order state.
- `user_reported` (boolean): True when the user themselves complained about the problem.

Common parameters: `lang`

#### unread_message_count

read · scope `mcp:ordering:read` · annotations: readOnlyHint=true

Number of unread messages in the user's inbox (the badge in the mobile app). Cheap; use list_messages to see them. Own account only.

Common parameters: `lang`

### Scope `mcp:ordering:write` (write)

#### add_auto_order

write · scope `mcp:ordering:write` · annotations: destructiveHint=false, idempotentHint=true

Add an automatic ordering rule (or change the amount of an existing rule with the same day, type and position), like in the mobile app: every week on day_in_week the system orders the food_order-th food of food_type automatically. Codes: day_in_week 1 = Monday ... 7 = Sunday; food_type 1 lunch, 2 soup, 3 breakfast, 4 dinner, 6 morning snack, 7 afternoon snack, 8 second dinner, 9 salad, 10 dessert, 11 starter, 12 specialty; food_order 1 = first food of that type on the menu. The agent MUST explain the rule to the user and get confirmation before calling with confirm=true; preview first with dry_run=true (state shows the resulting rules). Pass a stable idempotency_key.

Parameters:
- `day_in_week` (integer, 1–7, **required**): Day of week: 1 = Monday ... 7 = Sunday.
- `food_order` (integer, 1–20, **required**): Position of the food of that type on the day's menu (1 = first).
- `food_type` (integer, one of `1` | `2` | `3` | `4` | `6` | `7` | `8` | `9` | `10` | `11` | `12`, **required**): Food type code (see tool description).
- `amount` (integer, 1–99): Portions per order (default 1).

Common parameters: `company_id` (required), `account_id`, `dry_run`, `confirm`, `idempotency_key` (required), `lang`

#### cancel_auto_order

write · scope `mcp:ordering:write` · annotations: destructiveHint=true, idempotentHint=true

Delete an automatic ordering rule (rule id from list_auto_orders), like in the mobile app. Orders already created by the rule are NOT cancelled (use cancel_order for those). DESTRUCTIVE: the agent MUST get explicit user confirmation before calling with confirm=true; preview first with dry_run=true. Pass a stable idempotency_key.

Parameters:
- `rule_id` (integer, ≥1, **required**): Rule id from list_auto_orders.

Common parameters: `company_id` (required), `account_id`, `dry_run`, `confirm`, `idempotency_key` (required), `lang`

#### cancel_order

write · scope `mcp:ordering:write` · annotations: destructiveHint=true, idempotentHint=true

Cancel an ordered food - all portions, or specific ones via portion_indexes (see cancel_options), like cancelling in the mobile app. Identify the order by order_id (from order_history), or by company_id + food_id (+ date_on for permanent-offer items). If the order has several different portions (supplement/accessory/packaging) and no portion_indexes are given, nothing is cancelled and the variants to choose from are returned (status "ambiguous"). Not for paid e-shop orders (use cancel_purchased) nor basket items (use place_order with amount 0). DESTRUCTIVE: the agent MUST get explicit user confirmation before calling with confirm=true. Preview first with dry_run=true (or without confirm). Pass a stable idempotency_key.

Parameters:
- `order_id` (integer, ≥1): Order id from order_history.
- `date_on` (string, pattern `^\d{4}-\d{2}-\d{2}$`): Day of the order; required for permanent-offer items.
- `portion_indexes` (array of integer, ≥0, ≤20 items, unique): Indexes of portions to cancel (from cancel_options variants). Omit to cancel all portions.

Common parameters: `company_id`, `food_id`, `deadline_mode`, `account_id`, `dry_run`, `confirm`, `idempotency_key` (required), `lang`

Provide exactly one of: `order_id` | `company_id` + `food_id`.

#### cancel_purchased

write · scope `mcp:ordering:write` · annotations: destructiveHint=true, idempotentHint=true

Cancel an already PAID e-shop (instant-payment) order - the whole order or chosen portions - and refund it to the user's e-shop credit, like in the mobile app. Only on canteens that allow it (list_canteens allow_eshop_credit); not for permanent-offer items. For unpaid basket items use place_order with amount 0 instead. DESTRUCTIVE: the agent MUST get explicit user confirmation before calling with confirm=true; preview first with dry_run=true (shows the refund). Pass a stable idempotency_key.

Parameters:
- `food_id` (integer, ≥1, **required**): Paid food id.
- `portion_indexes` (array of integer, ≥0, ≤20 items, unique): Portions to cancel; omit to cancel the whole order.

Common parameters: `company_id` (required), `deadline_mode`, `account_id`, `dry_run`, `confirm`, `idempotency_key` (required), `lang`

#### change_order_pickup_point

write · scope `mcp:ordering:write` · annotations: destructiveHint=true, idempotentHint=true

Change the pickup point (delivery place / "odberne misto") of all the user's orders on one day in a canteen, like in the mobile app. Only pickup points the user may choose (get_profile profile.selectable_pickup_points) are accepted, and only before the ordering deadline. The agent MUST get user confirmation before calling with confirm=true; preview first with dry_run=true. Pass a stable idempotency_key.

Parameters:
- `pickup_point_id` (integer, ≥1, **required**): Pickup point (admin firm) id the user may choose.
- `date` (string, pattern `^\d{4}-\d{2}-\d{2}$`, **required**): Day of the orders (YYYY-MM-DD).

Common parameters: `company_id` (required), `account_id`, `dry_run`, `confirm`, `idempotency_key` (required), `lang`

#### mark_message_read

write · scope `mcp:ordering:write` · annotations: destructiveHint=false, idempotentHint=true

Mark a message as read, like opening it in the mobile app. It does not dismiss the important-message pop-up in the app or on the web — the user confirms that there themselves. Call it only after the user has actually seen the message content (get_message / get_important_message). Repeating it is harmless (firstRead=false). Needs confirm=true to be saved; dry_run=true previews. Pass a stable idempotency_key. Own account only.

Parameters:
- `message_id` (integer, ≥1, **required**): Message id.

Common parameters: `dry_run`, `confirm`, `idempotency_key` (required), `lang`

#### place_order

write · scope `mcp:ordering:write` · annotations: destructiveHint=false, idempotentHint=true

Order a food (sets the ordered number of portions), exactly like the "+" in the mobile app. amount is the resulting total number of portions of that food (not an increment); 0 removes it. For permanent-offer items (see permanent_offer_catalog) date_on (YYYY-MM-DD) is required. On an instant-payment (e-shop) canteen the food goes to the basket (see basket_food) and is paid later. SPENDS CREDIT: the agent MUST get explicit user confirmation before calling with confirm=true. Call first with dry_run=true (or without confirm) to preview price, resulting order and balance, show it to the user, then call again with confirm=true and the same stable idempotency_key.

Parameters:
- `company_id` (integer, ≥1, **required**): Canteen (menu list) id from list_canteens.
- `food_id` (integer, ≥1, **required**): Food id from list_menu or permanent_offer_catalog.
- `amount` (integer, 0–20, **required**): Resulting number of portions (0 = remove).
- `date_on` (string, pattern `^\d{4}-\d{2}-\d{2}$`): Required for permanent-offer items: the day to order for.

Common parameters: `deadline_mode`, `account_id`, `dry_run`, `confirm`, `idempotency_key` (required), `lang`

#### rate_food

write · scope `mcp:ordering:write` · annotations: destructiveHint=false, idempotentHint=true

Rate a food the user ate (1-5 stars, optional comment), or change an existing rating, like in the mobile app. Only foods from list_food_ratings can be rated (own past orders within the rating window, canteen with rating enabled). Use the user's own stars and words - never invent a rating. The result may contain googleReviewUrl (an invitation to review the canteen on Google after good ratings) - offer it to the user. Needs confirm=true to be saved; dry_run=true previews. Pass a stable idempotency_key. Own account only.

Parameters:
- `food_id` (integer, ≥1, **required**): Food id (list_food_ratings foodId).
- `date_on` (string, pattern `^\d{4}-\d{2}-\d{2}$`, **required**): Day the food was eaten, YYYY-MM-DD (list_food_ratings dateOn).
- `stars` (integer, 1–5, **required**): Stars 1 (worst) - 5 (best).
- `comment` (string, ≤1000 chars): Optional comment for the kitchen.

Common parameters: `dry_run`, `confirm`, `idempotency_key` (required), `lang`

#### remove_food_rating

write · scope `mcp:ordering:write` · annotations: destructiveHint=true, idempotentHint=true

Delete the user's own rating of a food (stars and comment), like in the mobile app; the food becomes unrated again. Only within the rating window (see list_food_ratings). DESTRUCTIVE: the agent MUST get explicit user confirmation before calling with confirm=true; preview first with dry_run=true. Pass a stable idempotency_key. Own account only.

Parameters:
- `food_id` (integer, ≥1, **required**): Food id (list_food_ratings foodId).
- `date_on` (string, pattern `^\d{4}-\d{2}-\d{2}$`, **required**): Day the food was eaten, YYYY-MM-DD (list_food_ratings dateOn).

Common parameters: `dry_run`, `confirm`, `idempotency_key` (required), `lang`

#### save_order_note

write · scope `mcp:ordering:write` · annotations: destructiveHint=false, idempotentHint=true

Save the customer note for an ordered food (a message for the kitchen, e.g. "no onion"), like in the mobile app. Only where the canteen allows notes (list_canteens allow_customer_note). An empty note clears it. The agent MUST get user confirmation before calling with confirm=true; preview first with dry_run=true. Pass a stable idempotency_key.

Parameters:
- `note` (string, ≤2000 chars, **required**): Note text ("" clears the note).

Common parameters: `company_id` (required), `food_id` (required), `date_on`, `account_id`, `dry_run`, `confirm`, `idempotency_key` (required), `lang`

#### set_accessory

write · scope `mcp:ordering:write` · annotations: destructiveHint=true, idempotentHint=true

Add or remove an accessory (extra item such as bread or cutlery, keyed by code) for one portion of an ordered food, like in the mobile app. Accessory codes are in list_menu (food accessory_choices). Changes the price: the agent MUST get explicit user confirmation before calling with confirm=true; preview first with dry_run=true. Pass a stable idempotency_key.

Parameters:
- `portion_index` (integer, 0–99, **required**): Index of the portion (0 = first; see list_menu ordered_portions or cancel_options variants).
- `accessory_code` (string, 1–64 chars, **required**): Accessory code (accessory_code from food accessory_choices in list_menu).
- `checked` (boolean, **required**): true = add the accessory, false = remove it.

Common parameters: `company_id` (required), `food_id` (required), `date_on`, `deadline_mode`, `account_id`, `dry_run`, `confirm`, `idempotency_key` (required), `lang`

#### set_packaging

write · scope `mcp:ordering:write` · annotations: destructiveHint=true, idempotentHint=true

Choose the packaging (e.g. disposable box vs. own container) for one portion of an ordered food, like in the mobile app. The packagings the user may choose are in list_menu (food packaging_choices; per user). May change the price: the agent MUST get explicit user confirmation before calling with confirm=true; preview first with dry_run=true. Pass a stable idempotency_key.

Parameters:
- `portion_index` (integer, 0–99, **required**): Index of the portion (0 = first; see list_menu ordered_portions or cancel_options variants).
- `packaging_id` (integer, ≥1, **required**): Packaging id.

Common parameters: `company_id` (required), `food_id` (required), `date_on`, `deadline_mode`, `account_id`, `dry_run`, `confirm`, `idempotency_key` (required), `lang`

#### set_supplement

write · scope `mcp:ordering:write` · annotations: destructiveHint=true, idempotentHint=true

Choose the side dish (supplement) for one portion of an ordered food, like in the mobile app. Supplement ids are in list_menu (food supplement_choices; only foods with more than one side dish offer a choice; portion indexes in ordered_portions). May change the price: the agent MUST get explicit user confirmation before calling with confirm=true; preview first with dry_run=true. Pass a stable idempotency_key.

Parameters:
- `portion_index` (integer, 0–99, **required**): Index of the portion (0 = first; see list_menu ordered_portions or cancel_options variants).
- `supplement_id` (integer, ≥1, **required**): Supplement id from the food in list_menu.

Common parameters: `company_id` (required), `food_id` (required), `date_on`, `deadline_mode`, `account_id`, `dry_run`, `confirm`, `idempotency_key` (required), `lang`

#### snooze_food_rating_prompt

write · scope `mcp:ordering:write` · annotations: destructiveHint=false, idempotentHint=true

Postpone the "rate your meals" reminder (the "Not now" button in the mobile app and on the web) for about a day. Call only when the user explicitly says they do not want to rate now. Needs confirm=true to be saved; dry_run=true previews. Pass a stable idempotency_key. Own account only.

Common parameters: `dry_run`, `confirm`, `idempotency_key` (required), `lang`

### Scope `mcp:payments:write` (write)

#### add_credit

write · scope `mcp:payments:write` · annotations: destructiveHint=false, idempotentHint=true

Top up the user's credit (or pay back a negative balance) exactly like "Add credit" in the mobile app. Returns a payment gateway link for the user to open and pay, or bank transfer details (account, amount, variable symbol). Which payment methods work depends on the canteen settings; a method that is not allowed returns an error. Not available in the "cash" payment mode. Always call with dry_run=true first (validates everything, contacts no gateway, creates nothing), show the amount and method to the user, and only after their explicit confirmation call again with confirm=true and the same idempotency_key. Retrying with the same key returns the same link and never creates a second payment. child_account_id tops up a linked child account; account_id a diner the user acts for (delegate).

Parameters:
- `amount` (number, ≥1, **required**): Amount in CZK (at least 1; decimals allowed, like the mobile app).
- `payment_method` (string, one of `bank_transfer` | `pays` | `sodexo` | `test` | `webpay` | `viva`, **required**): How to pay: bank_transfer (returns account + variable symbol), or an online gateway (pays, sodexo, webpay, viva; test only on test setups) which returns a payment link.
- `child_account_id` (integer, ≥1): Linked child account (profile childAdmins) to top up.

Common parameters: `account_id`, `dry_run`, `confirm`, `idempotency_key` (required), `lang`

#### basket_payment

write · scope `mcp:payments:write` · annotations: destructiveHint=false, idempotentHint=true

Pay the basket of an e-shop canteen (pay-before-order) exactly like "Pay" in the mobile app: the available credit is used first (see basket_credit_preview); if it covers the whole basket the orders are created immediately (payment_method not needed), otherwise the rest is paid via payment_method and a payment gateway link (or bank transfer details) is returned for the user to open and pay - the orders are created after the gateway confirms the payment. Always call with dry_run=true first (validates, contacts no gateway, creates nothing) and show the basket and amount to the user; only after their explicit confirmation call again with confirm=true and the same idempotency_key. Retrying with the same key never pays twice. Items no longer orderable are removed from the basket on confirm and the call fails - then show the basket again. account_id = a diner the user acts for (delegate).

Parameters:
- `company_id` (integer, ≥1, **required**): E-shop canteen (menu list) id.
- `payment_method` (string, one of `bank_transfer` | `pays` | `sodexo` | `comgate` | `test` | `webpay` | `viva`): How to pay the part not covered by credit. Omit only when the credit covers the whole basket (amountToPay 0 in basket_credit_preview).

Common parameters: `account_id`, `dry_run`, `confirm`, `idempotency_key` (required), `lang`

### Scope `mcp:account:write` (write)

#### change_password

write · scope `mcp:account:write` · annotations: destructiveHint=true, idempotentHint=true

Change the user's own login password, like the mobile app. current_password is required unless the account must change a generated password (get_profile summary.need_change_password). New password: at least 6 characters. Never invent, suggest, store or repeat passwords - use exactly what the user typed. This is a security-sensitive change: the agent MUST get explicit user confirmation before calling with confirm=true; dry_run=true only verifies the current password and rules, nothing is saved. After a successful change ALL AI connections of the account are disconnected, including this one: tell the user they must reconnect (sign in again) before any further request. Pass a stable idempotency_key.

Parameters:
- `new_password` (string, 6–255 chars, **required**): The new password (min. 6 characters).
- `current_password` (string, 1–255 chars): The current password (required unless a password change is forced).

Common parameters: `dry_run`, `confirm`, `idempotency_key` (required), `lang`

#### update_profile

write · scope `mcp:account:write` · annotations: destructiveHint=false, idempotentHint=true

Update the user's own profile like the profile screen of the mobile app: name, e-mail, phone, delivery address, invoicing details, notification settings. Only the fields passed are changed. An empty string is rejected for first_name, surname and email (a valid, unique e-mail is required); for the other text fields it clears the value. Call get_profile first to show the current values. If the organization locks delivery details, street/city/zip/delivery_company are ignored (reported in ignored_fields). notification_settings replaces the whole object - start from get_profile profile.notification_settings. The agent MUST get user confirmation before calling with confirm=true; preview first with dry_run=true. Pass a stable idempotency_key. Only for the user's own account (no delegates).

Parameters:
- `first_name` (string, ≤255 chars): First name.
- `surname` (string, ≤255 chars): Surname.
- `email` (string, ≤255 chars): E-mail (must be unique).
- `phone` (string, ≤50 chars): Phone number.
- `delivery_company` (string, ≤255 chars): Delivery: company / recipient name.
- `street` (string, ≤255 chars): Delivery: street and number.
- `city` (string, ≤255 chars): Delivery: city.
- `zip` (string, ≤20 chars): Delivery: postal code.
- `invoice_name` (string, ≤255 chars): Invoicing: name.
- `invoice_ic` (string, ≤20 chars): Invoicing: company ID (IČO).
- `invoice_dic` (string, ≤20 chars): Invoicing: VAT ID (DIČ).
- `invoice_street` (string, ≤255 chars): Invoicing: street.
- `invoice_city` (string, ≤255 chars): Invoicing: city.
- `invoice_zip` (string, ≤20 chars): Invoicing: postal code.
- `notification_settings` (object): Mobile app notification settings object (replaces the whole object).

Common parameters: `dry_run`, `confirm`, `idempotency_key` (required), `lang`
